Merge "Merge upstream SHA 04cb763" am: 9a337512d9 * commit '9a337512d97e37afc142dee4fd50a41b741a87d2': (797 commits) Add tests for verifying transport feedback for audio and video. Eliminate defines in talk/ Revert of Update with new default boringssl no-aes cipher suites. Re-enable tests. (patchset #3 id:40001 of https://codereview.webrtc.org/1550773002/ ) Remove assert which was incorrectly added to TcpPort::OnSentPacket. Reland Connect TurnPort and TCPPort to AsyncPacketSocket::SignalSentPacket. Update with new default boringssl no-aes cipher suites. Re-enable tests. Revert of Connect TurnPort and TCPPort to AsyncPacketSocket::SignalSentPacket. (patchset #3 id:40001 of https://codereview.webrtc.org/1577873003/ ) Re-land: "Use an explicit identifier in Config" Connect TurnPort and TCPPort to AsyncPacketSocket::SignalSentPacket. Revert of Delete remnants of non-square pixel support from cricket::VideoFrame. (patchset #1 id:1 of https://codereview.webrtc.org/1586613002/ ) Remove libfuzzer trybot from default trybot set. Add ramp-up tests for transport sequence number with and w/o audio. Delete remnants of non-square pixel support from cricket::VideoFrame. Fix IPAddress::ToSensitiveString() to avoid dependency on inet_ntop(). Revert of Storing raw audio sink for default audio track. (patchset #7 id:120001 of https://codereview.chromium.org/1551813002/ ) Re-enable tests that failed under Linux_Msan. Revert of Use an explicit identifier in Config (patchset #4 id:60001 of https://codereview.webrtc.org/1538643004/ ) Roll chromium_revision 346fea9..099be58 (369082:369139) Disable WebRtcVideoChannel2BaseTest.SendManyResizeOnce for TSan Add build_protobuf variable. ...
diff --git a/.gitignore b/.gitignore index b29171c..7090f4a 100644 --- a/.gitignore +++ b/.gitignore
@@ -44,11 +44,9 @@ /chromium/.last_sync_chromium /chromium/_bad_scm /chromium/src -/google_apis /gyp-mac-tool /links /links.db -/net /out /resources/**/*.aecdump /resources/**/*.bin @@ -79,7 +77,6 @@ /testing /third_party/WebKit/Tools/Scripts /third_party/android_platform -/third_party/android_testrunner /third_party/android_tools /third_party/appurify-python /third_party/asan @@ -87,6 +84,7 @@ /third_party/binutils /third_party/boringssl /third_party/BUILD.gn +/third_party/catapult /third_party/clang_format /third_party/class-dump /third_party/colorama @@ -94,6 +92,7 @@ /third_party/directxsdk /third_party/drmemory /third_party/expat +/third_party/ffmpeg /third_party/gaeunit /third_party/gflags/src /third_party/google-visualization-python @@ -105,6 +104,7 @@ /third_party/junit /third_party/junit-jar /third_party/libc++ +/third_party/libc++-static /third_party/libc++abi /third_party/libevent /third_party/libjingle @@ -123,6 +123,7 @@ /third_party/nss /third_party/oauth2 /third_party/ocmock +/third_party/openh264 /third_party/openmax_dl /third_party/opus /third_party/proguard @@ -139,7 +140,6 @@ /third_party/zlib /tools/android /tools/clang -/tools/find_depot_tools.py /tools/generate_library_loader /tools/gn /tools/grit @@ -148,21 +148,15 @@ /tools/memory /tools/protoc_wrapper /tools/python -/tools/relocation_packer /tools/sanitizer_options /tools/swarming_client +/tools/telemetry /tools/tsan_suppressions /tools/valgrind /tools/vim /tools/win /tools/xdisplaycheck /tools/whitespace.txt -/webrtc/examples/android/media_demo/bin -/webrtc/examples/android/media_demo/gen -/webrtc/examples/android/media_demo/libs -/webrtc/examples/android/media_demo/local.properties -/webrtc/examples/android/media_demo/obj -/webrtc/examples/android/media_demo/proguard-project.txt /webrtc/examples/android/opensl_loopback/bin /webrtc/examples/android/opensl_loopback/gen /webrtc/examples/android/opensl_loopback/libs @@ -172,9 +166,5 @@ /webrtc/modules/audio_device/android/test/bin/ /webrtc/modules/audio_device/android/test/gen/ /webrtc/modules/audio_device/android/test/libs/ -/webrtc/video_engine/test/android/bin -/webrtc/video_engine/test/android/gen -/webrtc/video_engine/test/android/libs -/webrtc/video_engine/test/android/obj /x86-generic_out/ /xcodebuild
diff --git a/.gn b/.gn index d078116..f849ef7 100644 --- a/.gn +++ b/.gn
@@ -35,6 +35,7 @@ "//build/config/linux/pkg_config.gni", "//build/config/mac/mac_sdk.gni", "//build/config/posix/BUILD.gn", + "//build/config/sysroot.gni", "//build/config/win/visual_studio_version.gni", "//build/gn_helpers.py", "//build/gypi_to_gn.py", @@ -42,6 +43,7 @@ "//build/toolchain/mac/BUILD.gn", "//build/toolchain/win/BUILD.gn", "//third_party/boringssl/BUILD.gn", + "//third_party/openh264/BUILD.gn", "//third_party/opus/BUILD.gn", "//webrtc/modules/video_render/BUILD.gn", ]
diff --git a/AUTHORS b/AUTHORS index 0d9ff5a..6f11ee6 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -1,6 +1,7 @@ # 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> @@ -22,6 +23,7 @@ Paul Kapustin <pkapustin@gmail.com> Rafael Lopez Diez <rafalopezdiez@gmail.com> Ralph Giles <giles@ghostscript.com> +Riku Voipio <riku.voipio@linaro.org> Robert Nagy <robert.nagy@gmail.com> Ryan Yoakum <ryoakum@skobalt.com> Sarah Thompson <sarah@telergy.com> @@ -30,8 +32,10 @@ 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.
diff --git a/DEPS b/DEPS index 3ceff79..dcf56bc 100644 --- a/DEPS +++ b/DEPS
@@ -6,7 +6,7 @@ vars = { 'extra_gyp_flag': '-Dextra_gyp_flag=0', 'chromium_git': 'https://chromium.googlesource.com', - 'chromium_revision': '657e8d9a9139da0735d73fc0fc6d90a05f980319', + 'chromium_revision': '099be58b08dadb64b1dc9f359ae097e978df5416', } # NOTE: Prefer revision numbers to tags for svn deps. Use http rather than @@ -24,7 +24,7 @@ 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', }, } @@ -102,6 +102,7 @@ '--recursive', '--num_threads=10', '--no_auth', + '--quiet', '--bucket', 'chromium-webrtc-resources', 'src/resources'], },
diff --git a/OWNERS b/OWNERS index 3ecf2a2..5812db5 100644 --- a/OWNERS +++ b/OWNERS
@@ -1,4 +1,3 @@ -andrew@webrtc.org henrika@webrtc.org mflodman@webrtc.org niklas.enbom@webrtc.org
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index e7ceac9..08dd68d 100755 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -14,6 +14,100 @@ import sys +# Directories that will be scanned by cpplint by the presubmit script. +CPPLINT_DIRS = [ + 'webrtc/audio', + 'webrtc/call', + 'webrtc/common_video', + 'webrtc/examples', + 'webrtc/modules/remote_bitrate_estimator', + 'webrtc/modules/rtp_rtcp', + 'webrtc/modules/video_coding', + 'webrtc/modules/video_processing', + 'webrtc/sound', + 'webrtc/tools', + 'webrtc/video', +] + +# List of directories of "supported" native APIs. That means changes to headers +# will be done in a compatible way following this scheme: +# 1. Non-breaking changes are made. +# 2. The old APIs as marked as deprecated (with comments). +# 3. Deprecation is announced to discuss-webrtc@googlegroups.com and +# webrtc-users@google.com (internal list). +# 4. (later) The deprecated APIs are removed. +# Directories marked as DEPRECATED should not be used. They're only present in +# the list to support legacy downstream code. +NATIVE_API_DIRS = ( + 'talk/app/webrtc', + 'webrtc', + 'webrtc/base', # DEPRECATED. + 'webrtc/common_audio/include', # DEPRECATED. + 'webrtc/modules/audio_coding/include', + 'webrtc/modules/audio_conference_mixer/include', # DEPRECATED. + 'webrtc/modules/audio_device/include', + 'webrtc/modules/audio_processing/include', + 'webrtc/modules/bitrate_controller/include', + 'webrtc/modules/include', + 'webrtc/modules/remote_bitrate_estimator/include', + 'webrtc/modules/rtp_rtcp/include', + 'webrtc/modules/rtp_rtcp/source', # DEPRECATED. + 'webrtc/modules/utility/include', + 'webrtc/modules/video_coding/codecs/h264/include', + 'webrtc/modules/video_coding/codecs/i420/include', + 'webrtc/modules/video_coding/codecs/vp8/include', + 'webrtc/modules/video_coding/codecs/vp9/include', + 'webrtc/modules/video_coding/include', + 'webrtc/system_wrappers/include', # DEPRECATED. + 'webrtc/voice_engine/include', +) + + +def _VerifyNativeApiHeadersListIsValid(input_api, output_api): + """Ensures the list of native API header directories is up to date.""" + non_existing_paths = [] + native_api_full_paths = [ + input_api.os_path.join(input_api.PresubmitLocalPath(), + *path.split('/')) for path in NATIVE_API_DIRS] + for path in native_api_full_paths: + if not os.path.isdir(path): + non_existing_paths.append(path) + if non_existing_paths: + return [output_api.PresubmitError( + 'Directories to native API headers have changed which has made the ' + 'list in PRESUBMIT.py outdated.\nPlease update it to the current ' + 'location of our native APIs.', + non_existing_paths)] + return [] + + +def _CheckNativeApiHeaderChanges(input_api, output_api): + """Checks to remind proper changing of native APIs.""" + files = [] + for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): + if f.LocalPath().endswith('.h'): + for path in NATIVE_API_DIRS: + if os.path.dirname(f.LocalPath()) == path: + files.append(f) + + if files: + return [output_api.PresubmitNotifyResult( + 'You seem to be changing native API header files. Please make sure ' + 'you:\n' + ' 1. Make compatible changes that don\'t break existing clients.\n' + ' 2. Mark the old APIs as deprecated.\n' + ' 3. Create a timeline and plan for when the deprecated method will ' + 'be removed (preferably 3 months or so).\n' + ' 4. Update/inform existing downstream code owners to stop using the ' + 'deprecated APIs: \n' + 'send announcement to discuss-webrtc@googlegroups.com and ' + 'webrtc-users@google.com.\n' + ' 5. (after ~3 months) remove the deprecated API.\n' + 'Related files:', + files)] + return [] + + def _CheckNoIOStreamInHeaders(input_api, output_api): """Checks to make sure no .h files include <iostream>.""" files = [] @@ -54,6 +148,14 @@ 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))] +def _IsLintWhitelisted(whitelist_dirs, file_path): + """ Checks if a file is whitelisted for lint check.""" + for path in whitelist_dirs: + if os.path.dirname(file_path).startswith(path): + return True + return False + + def _CheckApprovedFilesLintClean(input_api, output_api, source_file_filter=None): """Checks that all new or whitelisted .cc and .h files pass cpplint.py. @@ -68,12 +170,9 @@ # pylint: disable=W0212 cpplint._cpplint_state.ResetErrorCounts() - # Justifications for each filter: - # - # - build/header_guard : WebRTC coding style says they should be prefixed - # with WEBRTC_, which is not possible to configure in - # cpplint.py. - cpplint._SetFilters('-build/header_guard') + # Create a platform independent whitelist for the CPPLINT_DIRS. + whitelist_dirs = [input_api.os_path.join(*path.split('/')) + for path in CPPLINT_DIRS] # Use the strictest verbosity level for cpplint.py (level 1) which is the # default when running cpplint.py from command line. @@ -83,7 +182,7 @@ files = [] for f in input_api.AffectedSourceFiles(source_file_filter): # Note that moved/renamed files also count as added. - if f.Action() == 'A': + if f.Action() == 'A' or _IsLintWhitelisted(whitelist_dirs, f.LocalPath()): files.append(f.AbsoluteLocalPath()) for file_name in files: @@ -256,6 +355,14 @@ def _CommonChecks(input_api, output_api): """Checks common to both upload and commit.""" results = [] + # Filter out files that are in objc or ios dirs from being cpplint-ed since + # they do not follow C++ lint rules. + black_list = input_api.DEFAULT_BLACK_LIST + ( + r".*\bobjc[\\\/].*", + ) + source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list) + results.extend(_CheckApprovedFilesLintClean( + input_api, output_api, source_file_filter)) results.extend(input_api.canned_checks.RunPylint(input_api, output_api, black_list=(r'^.*gviz_api\.py$', r'^.*gaeunit\.py$', @@ -305,7 +412,7 @@ input_api, output_api)) results.extend(input_api.canned_checks.CheckChangeTodoHasOwner( input_api, output_api)) - results.extend(_CheckApprovedFilesLintClean(input_api, output_api)) + results.extend(_CheckNativeApiHeaderChanges(input_api, output_api)) results.extend(_CheckNoIOStreamInHeaders(input_api, output_api)) results.extend(_CheckNoFRIEND_TEST(input_api, output_api)) results.extend(_CheckGypChanges(input_api, output_api)) @@ -325,6 +432,7 @@ def CheckChangeOnCommit(input_api, output_api): results = [] results.extend(_CommonChecks(input_api, output_api)) + results.extend(_VerifyNativeApiHeadersListIsValid(input_api, output_api)) results.extend(input_api.canned_checks.CheckOwners(input_api, output_api)) results.extend(input_api.canned_checks.CheckChangeWasUploaded( input_api, output_api))
diff --git a/WATCHLISTS b/WATCHLISTS index c89a28e..ba7af53 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -16,14 +16,14 @@ }, 'all_webrtc': { # NOTE: if you like this you might like webrtc-reviews@webrtc.org! - 'filepath': 'webrtc/.*', + 'filepath': '^webrtc/.*', }, 'root_files': { # webrtc/build/ and non-recursive contents of ./ and webrtc/ - 'filepath': '^[^/]*$|webrtc/[^/]*$|webrtc/build/.*', + 'filepath': '^[^/]*$|^webrtc/[^/]*$|^webrtc/build/.*', }, 'documented_interfaces': { - 'filepath': 'webrtc/[^/]*\.h$|'\ + 'filepath': '^webrtc/[^/]*\.h$|'\ 'webrtc/voice_engine/include/.*', }, 'build_files': { @@ -32,9 +32,14 @@ 'java_files': { 'filepath': '\.java$|\.xml$', }, - 'video_engine': { - 'filepath': 'webrtc/video_engine/.*|'\ - 'webrtc/video/.*', + 'audio': { + 'filepath': 'webrtc/audio/.*', + }, + 'call': { + 'filepath': 'webrtc/call/.*', + }, + 'video': { + 'filepath': 'webrtc/video/.*', }, 'voice_engine': { 'filepath': 'webrtc/voice_engine/.*', @@ -89,59 +94,93 @@ 'WATCHLISTS': { 'this_file': [''], 'all_webrtc': ['tterriberry@mozilla.com'], - 'root_files': ['andrew@webrtc.org', - 'niklas.enbom@webrtc.org', - 'yujie.mao@webrtc.org', + 'root_files': ['niklas.enbom@webrtc.org', + 'peah@webrtc.org', 'qiang.lu@intel.com', - 'peah@webrtc.org'], + 'yujie.mao@webrtc.org'], 'documented_interfaces': ['interface-changes@webrtc.org', 'rwolff@gocast.it'], 'common_audio': ['aluebs@webrtc.org', 'andrew@webrtc.org', + 'audio-team@agora.io', 'bjornv@webrtc.org', + 'minyue@webrtc.org', 'peah@webrtc.org'], - 'video_engine': ['andresp@webrtc.org', - 'mflodman@webrtc.org', - 'perkj@webrtc.org', - 'stefan@webrtc.org', - 'yujie.mao@webrtc.org', - 'solenberg@webrtc.org'], - 'voice_engine': ['henrika@webrtc.org', + 'audio': ['solenberg@webrtc.org', + 'tina.legrand@webrtc.org'], + 'call': ['mflodman@webrtc.org', + 'pbos@webrtc.org', + 'solenberg@webrtc.org', + 'stefan@webrtc.org'], + 'video': ['andresp@webrtc.org', + 'mflodman@webrtc.org', + 'pbos@webrtc.org', + 'perkj@webrtc.org', + 'solenberg@webrtc.org', + 'stefan@webrtc.org', + 'video-team@agora.io', + 'yujie.mao@webrtc.org', + 'zhengzhonghou@agora.io'], + 'voice_engine': ['andrew@webrtc.org', + 'audio-team@agora.io', + 'henrika@webrtc.org', 'henrik.lundin@webrtc.org', - 'solenberg@webrtc.org', - 'peah@webrtc.org'], + 'minyue@webrtc.org', + 'peah@webrtc.org', + 'solenberg@webrtc.org'], 'video_capture': ['mflodman@webrtc.org', - 'perkj@webrtc.org'], + 'perkj@webrtc.org', + 'sdk-team@agora.io', + 'zhengzhonghou@agora.io'], 'video_render': ['mflodman@webrtc.org', - 'perkj@webrtc.org'], - 'audio_device': ['henrika@webrtc.org', - 'peah@webrtc.org'], - 'audio_coding': ['tina.legrand@webrtc.org', + 'perkj@webrtc.org', + 'sdk-team@agora.io', + 'zhengzhonghou@agora.io'], + 'audio_device': ['audio-team@agora.io', + 'henrika@webrtc.org', + 'peah@webrtc.org', + 'sdk-team@agora.io'], + 'audio_coding': ['audio-team@agora.io', 'henrik.lundin@webrtc.org', 'kwiberg@webrtc.org', - 'peah@webrtc.org'], - 'neteq': ['henrik.lundin@webrtc.org'], + 'minyue@webrtc.org', + 'peah@webrtc.org', + 'tina.legrand@webrtc.org'], + 'neteq': ['audio-team@agora.io', + 'henrik.lundin@webrtc.org', + 'minyue@webrtc.org'], 'audio_processing': ['aluebs@webrtc.org', 'andrew@webrtc.org', + 'audio-team@agora.io', 'bjornv@webrtc.org', - 'kwiberg@webrtc.org', 'henrik.lundin@webrtc.org', + 'kwiberg@webrtc.org', + 'minyue@webrtc.org', 'peah@webrtc.org', 'solenberg@webrtc.org'], - 'video_coding': ['stefan@webrtc.org', - 'mflodman@webrtc.org'], - 'video_processing': ['stefan@webrtc.org'], - 'bitrate_controller': ['stefan@webrtc.org', - 'mflodman@webrtc.org'], - 'remote_bitrate_estimator': ['stefan@webrtc.org', - 'mflodman@webrtc.org'], - 'pacing': ['stefan@webrtc.org', - 'mflodman@webrtc.org'], + 'video_coding': ['mflodman@webrtc.org', + 'stefan@webrtc.org', + 'video-team@agora.io', + 'zhengzhonghou@agora.io'], + 'video_processing': ['stefan@webrtc.org', + 'video-team@agora.io', + 'zhengzhonghou@agora.io'], + 'bitrate_controller': ['mflodman@webrtc.org', + 'stefan@webrtc.org', + 'zhuangzesen@agora.io'], + 'remote_bitrate_estimator': ['mflodman@webrtc.org', + 'stefan@webrtc.org', + 'zhuangzesen@agora.io'], + 'pacing': ['mflodman@webrtc.org', + 'stefan@webrtc.org', + 'zhuangzesen@agora.io'], 'rtp_rtcp': ['mflodman@webrtc.org', - 'stefan@webrtc.org'], - 'system_wrappers': ['mflodman@webrtc.org', + 'stefan@webrtc.org', + 'zhuangzesen@agora.io'], + 'system_wrappers': ['fengyue@agora.io', 'henrika@webrtc.org', - 'andrew@webrtc.org', - 'peah@webrtc.org'], + 'mflodman@webrtc.org', + 'peah@webrtc.org', + 'zhengzhonghou@agora.io'], }, }
diff --git a/all.gyp b/all.gyp index 40dbc13..0b11c8f 100644 --- a/all.gyp +++ b/all.gyp
@@ -24,7 +24,6 @@ 'conditions': [ ['include_examples==1', { 'dependencies': [ - 'webrtc/libjingle_examples.gyp:*', 'webrtc/webrtc_examples.gyp:*', ], }],
diff --git a/chromium/.gclient b/chromium/.gclient index 7f46333..9d5dfcf 100644 --- a/chromium/.gclient +++ b/chromium/.gclient
@@ -10,7 +10,6 @@ 'src/chrome/tools/test/reference_build/chrome_win': None, 'src/native_client': None, 'src/third_party/cld_2/src': None, - 'src/third_party/ffmpeg': None, 'src/third_party/hunspell_dictionaries': None, 'src/third_party/liblouis/src': None, 'src/third_party/pdfium': None,
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index 80f6f60..4c49280 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg
@@ -30,6 +30,8 @@ builders { name: "android_rel" } builders { name: "android_arm64_rel" } builders { name: "android_clang_dbg" } + builders { name: "android_compile_x86_dbg" } + builders { name: "android_compile_x64_dbg" } builders { name: "android_gn_dbg" } builders { name: "android_gn_rel" } builders { name: "ios_arm64_dbg" } @@ -38,27 +40,34 @@ builders { name: "ios_rel" } builders { name: "ios32_sim_dbg" } builders { name: "ios64_sim_dbg" } - builders { name: "linux_compile_dbg" } builders { name: "linux_asan" } + builders { name: "linux_baremetal" } + builders { name: "linux_compile_dbg" } builders { name: "linux_gn_dbg" } builders { name: "linux_gn_rel" } + # Disabled, see http://crbug.com/577566 for details. + #builders { name: "linux_libfuzzer_rel" } builders { name: "linux_msan" } builders { name: "linux_rel" } builders { name: "linux_tsan2" } - builders { name: "mac_compile_dbg" } - builders { name: "mac_compile_x64_dbg" } builders { name: "mac_asan" } + builders { name: "mac_baremetal" } + builders { name: "mac_compile_dbg" } builders { name: "mac_rel" } - builders { name: "mac_x64_gn_dbg" } - builders { name: "mac_x64_gn_rel" } - builders { name: "mac_x64_rel" } + builders { name: "mac_gn_dbg" } + builders { name: "mac_gn_rel" } builders { name: "presubmit" } + builders { name: "win_baremetal" } + builders { name: "win_clang_dbg" } + builders { name: "win_clang_rel" } builders { name: "win_compile_dbg" } + builders { name: "win_drmemory_light" } builders { name: "win_rel" } + builders { name: "win_x64_clang_dbg" } + builders { name: "win_x64_clang_rel" } builders { name: "win_x64_gn_dbg" } builders { name: "win_x64_gn_rel" } builders { name: "win_x64_rel" } - builders { name: "win_drmemory_light" } } } }
diff --git a/resources/audio_coding/neteq4_network_stats.dat.sha1 b/resources/audio_coding/neteq4_network_stats.dat.sha1 index 72a9499..f51a02a 100644 --- a/resources/audio_coding/neteq4_network_stats.dat.sha1 +++ b/resources/audio_coding/neteq4_network_stats.dat.sha1
@@ -1 +1 @@ -e5e2d0ff26d16339cf0f37a3512bfa2d390a9a9a \ No newline at end of file +2cf380a05ee07080bd72471e8ec7777a39644ec9 \ No newline at end of file
diff --git a/resources/audio_coding/neteq4_opus_network_stats.dat.sha1 b/resources/audio_coding/neteq4_opus_network_stats.dat.sha1 new file mode 100644 index 0000000..6a9e7ee --- /dev/null +++ b/resources/audio_coding/neteq4_opus_network_stats.dat.sha1
@@ -0,0 +1 @@ +cc9fa62d0a8f46ffebc782aea2610dda67bb5558 \ No newline at end of file
diff --git a/resources/audio_coding/neteq4_opus_ref.pcm.sha1 b/resources/audio_coding/neteq4_opus_ref.pcm.sha1 new file mode 100644 index 0000000..5cecc50 --- /dev/null +++ b/resources/audio_coding/neteq4_opus_ref.pcm.sha1
@@ -0,0 +1 @@ +301895f1aaa9cd9eae0f5d04d179d63491d744cc \ No newline at end of file
diff --git a/resources/audio_coding/neteq4_opus_ref_win_32.pcm.sha1 b/resources/audio_coding/neteq4_opus_ref_win_32.pcm.sha1 new file mode 100644 index 0000000..b7cf990 --- /dev/null +++ b/resources/audio_coding/neteq4_opus_ref_win_32.pcm.sha1
@@ -0,0 +1 @@ +fbad99878c7a26958e755190027c976692708334 \ No newline at end of file
diff --git a/resources/audio_coding/neteq4_opus_ref_win_64.pcm.sha1 b/resources/audio_coding/neteq4_opus_ref_win_64.pcm.sha1 new file mode 100644 index 0000000..b7cf990 --- /dev/null +++ b/resources/audio_coding/neteq4_opus_ref_win_64.pcm.sha1
@@ -0,0 +1 @@ +fbad99878c7a26958e755190027c976692708334 \ No newline at end of file
diff --git a/resources/audio_coding/neteq4_opus_rtcp_stats.dat.sha1 b/resources/audio_coding/neteq4_opus_rtcp_stats.dat.sha1 new file mode 100644 index 0000000..05570b8 --- /dev/null +++ b/resources/audio_coding/neteq4_opus_rtcp_stats.dat.sha1
@@ -0,0 +1 @@ +e37c797e3de6a64dda88c9ade7a013d022a2e1e0 \ No newline at end of file
diff --git a/resources/audio_coding/neteq4_rtcp_stats.dat.sha1 b/resources/audio_coding/neteq4_rtcp_stats.dat.sha1 index ae63c76..1fa337b 100644 --- a/resources/audio_coding/neteq4_rtcp_stats.dat.sha1 +++ b/resources/audio_coding/neteq4_rtcp_stats.dat.sha1
@@ -1 +1 @@ -948753a2087fbb5b74a3ea0b1aef8593c9c30b10 \ No newline at end of file +b8880bf9fed2487efbddcb8d94b9937a29ae521d \ No newline at end of file
diff --git a/resources/audio_coding/neteq_network_stats.dat.sha1 b/resources/audio_coding/neteq_network_stats.dat.sha1 deleted file mode 100644 index e02ad84..0000000 --- a/resources/audio_coding/neteq_network_stats.dat.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e3c189b500d92fd0f10cb4c770c298cee7008749 \ No newline at end of file
diff --git a/resources/audio_coding/neteq_network_stats_win_32.dat.sha1 b/resources/audio_coding/neteq_network_stats_win_32.dat.sha1 deleted file mode 100644 index a197fc1..0000000 --- a/resources/audio_coding/neteq_network_stats_win_32.dat.sha1 +++ /dev/null
@@ -1 +0,0 @@ -343061419a64ca99323fc0d25a43149a5d40cf07 \ No newline at end of file
diff --git a/resources/audio_coding/neteq_opus.rtp.sha1 b/resources/audio_coding/neteq_opus.rtp.sha1 new file mode 100644 index 0000000..ff5b8fe --- /dev/null +++ b/resources/audio_coding/neteq_opus.rtp.sha1
@@ -0,0 +1 @@ +21c8f8aaf9518a629d6c6def87fe6ea1305d5c91 \ No newline at end of file
diff --git a/resources/audio_coding/neteq_rtcp_stats.dat.sha1 b/resources/audio_coding/neteq_rtcp_stats.dat.sha1 deleted file mode 100644 index 42d37ac..0000000 --- a/resources/audio_coding/neteq_rtcp_stats.dat.sha1 +++ /dev/null
@@ -1 +0,0 @@ -759d57e87517e0290144add9ba53d5c6dec1c27e \ No newline at end of file
diff --git a/resources/audio_coding/neteq_universal_ref.pcm.sha1 b/resources/audio_coding/neteq_universal_ref.pcm.sha1 deleted file mode 100644 index 95e9de7..0000000 --- a/resources/audio_coding/neteq_universal_ref.pcm.sha1 +++ /dev/null
@@ -1 +0,0 @@ -236da353f05d329f6c83e441b80dbfcc18706cfb \ No newline at end of file
diff --git a/resources/audio_coding/neteq_universal_ref_win_32.pcm.sha1 b/resources/audio_coding/neteq_universal_ref_win_32.pcm.sha1 deleted file mode 100644 index 47c90cf..0000000 --- a/resources/audio_coding/neteq_universal_ref_win_32.pcm.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1d2d353be4345d30506866ca32fa72825c6d65b8 \ No newline at end of file
diff --git a/setup_links.py b/setup_links.py index 9aeb1e8..492c38b 100755 --- a/setup_links.py +++ b/setup_links.py
@@ -34,17 +34,16 @@ DIRECTORIES = [ 'build', 'buildtools', - 'google_apis', # Needed by build/common.gypi. - 'net', 'testing', 'third_party/binutils', 'third_party/boringssl', 'third_party/colorama', 'third_party/drmemory', 'third_party/expat', - 'third_party/icu', + 'third_party/ffmpeg', 'third_party/instrumented_libraries', 'third_party/jsoncpp', + 'third_party/libc++-static', 'third_party/libjpeg', 'third_party/libjpeg_turbo', 'third_party/libsrtp', @@ -55,6 +54,7 @@ 'third_party/lss', 'third_party/nss', 'third_party/ocmock', + 'third_party/openh264', 'third_party/openmax_dl', 'third_party/opus', 'third_party/proguard', @@ -84,10 +84,11 @@ DIRECTORIES += [ 'base', 'third_party/android_platform', - 'third_party/android_testrunner', 'third_party/android_tools', 'third_party/appurify-python', 'third_party/ashmem', + 'third_party/catapult', + 'third_party/icu', 'third_party/ijar', 'third_party/jsr-305', 'third_party/junit', @@ -99,13 +100,12 @@ 'third_party/robolectric', 'tools/android', 'tools/grit', - 'tools/relocation_packer' + 'tools/telemetry', ] if 'ios' in target_os: DIRECTORIES.append('third_party/class-dump') FILES = { - 'tools/find_depot_tools.py': None, 'tools/isolate_driver.py': None, 'third_party/BUILD.gn': None, }
diff --git a/sync_chromium.py b/sync_chromium.py index 442ddcd..b37e0da 100755 --- a/sync_chromium.py +++ b/sync_chromium.py
@@ -31,7 +31,7 @@ # Bump this whenever the algorithm changes and you need bots/devs to re-sync, # ignoring the .last_sync_chromium file -SCRIPT_VERSION = 5 +SCRIPT_VERSION = 7 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) CHROMIUM_NO_HISTORY = 'CHROMIUM_NO_HISTORY'
diff --git a/talk/app/webrtc/OWNERS b/talk/app/webrtc/OWNERS index ffd78e1..20a1fdf 100644 --- a/talk/app/webrtc/OWNERS +++ b/talk/app/webrtc/OWNERS
@@ -1,5 +1,5 @@ glaznev@webrtc.org -juberti@google.com -perkj@google.com +juberti@webrtc.org +perkj@webrtc.org tkchin@webrtc.org -tommi@google.com +tommi@webrtc.org
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java index 1c01ffa..63c05fb 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java
@@ -28,7 +28,6 @@ import android.graphics.SurfaceTexture; import android.opengl.GLES20; -import android.opengl.Matrix; import android.test.ActivityTestCase; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; @@ -36,9 +35,6 @@ import java.nio.ByteBuffer; import java.util.Random; -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLContext; - public final class GlRectDrawerTest extends ActivityTestCase { // Resolution of the test image. private static final int WIDTH = 16; @@ -46,7 +42,7 @@ // Seed for random pixel creation. private static final int SEED = 42; // When comparing pixels, allow some slack for float arithmetic and integer rounding. - private static final float MAX_DIFF = 1.0f; + private static final float MAX_DIFF = 1.5f; private static float normalizedByte(byte b) { return (b & 0xFF) / 255.0f; @@ -100,7 +96,7 @@ @SmallTest public void testRgbRendering() { // Create EGL base with a pixel buffer as display output. - final EglBase eglBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); + final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER); eglBase.createPbufferSurface(WIDTH, HEIGHT); eglBase.makeCurrent(); @@ -119,7 +115,7 @@ // Draw the RGB frame onto the pixel buffer. final GlRectDrawer drawer = new GlRectDrawer(); - drawer.drawRgb(rgbTexture, RendererCommon.identityMatrix()); + drawer.drawRgb(rgbTexture, RendererCommon.identityMatrix(), 0, 0, WIDTH, HEIGHT); // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. Nexus 9. final ByteBuffer rgbaData = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4); @@ -137,7 +133,7 @@ @SmallTest public void testYuvRendering() { // Create EGL base with a pixel buffer as display output. - EglBase eglBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); + EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER); eglBase.createPbufferSurface(WIDTH, HEIGHT); eglBase.makeCurrent(); @@ -166,7 +162,7 @@ // Draw the YUV frame onto the pixel buffer. final GlRectDrawer drawer = new GlRectDrawer(); - drawer.drawYuv(yuvTextures, RendererCommon.identityMatrix()); + drawer.drawYuv(yuvTextures, RendererCommon.identityMatrix(), 0, 0, WIDTH, HEIGHT); // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. Nexus 9. final ByteBuffer data = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4); @@ -231,8 +227,9 @@ private final int rgbTexture; public StubOesTextureProducer( - EGLContext sharedContext, SurfaceTexture surfaceTexture, int width, int height) { - eglBase = new EglBase(sharedContext, EglBase.ConfigType.PLAIN); + EglBase.Context sharedContext, SurfaceTexture surfaceTexture, int width, + int height) { + eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PLAIN); surfaceTexture.setDefaultBufferSize(width, height); eglBase.createSurface(surfaceTexture); assertEquals(eglBase.surfaceWidth(), width); @@ -253,7 +250,7 @@ GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, WIDTH, HEIGHT, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, rgbPlane); // Draw the RGB data onto the SurfaceTexture. - drawer.drawRgb(rgbTexture, RendererCommon.identityMatrix()); + drawer.drawRgb(rgbTexture, RendererCommon.identityMatrix(), 0, 0, WIDTH, HEIGHT); eglBase.swapBuffers(); } @@ -266,14 +263,14 @@ } // Create EGL base with a pixel buffer as display output. - final EglBase eglBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); + final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER); eglBase.createPbufferSurface(WIDTH, HEIGHT); // Create resources for generating OES textures. final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(eglBase.getContext()); + SurfaceTextureHelper.create(eglBase.getEglBaseContext()); final StubOesTextureProducer oesProducer = new StubOesTextureProducer( - eglBase.getContext(), surfaceTextureHelper.getSurfaceTexture(), WIDTH, HEIGHT); + eglBase.getEglBaseContext(), surfaceTextureHelper.getSurfaceTexture(), WIDTH, HEIGHT); final SurfaceTextureHelperTest.MockTextureListener listener = new SurfaceTextureHelperTest.MockTextureListener(); surfaceTextureHelper.setListener(listener); @@ -291,7 +288,7 @@ // Draw the OES texture on the pixel buffer. eglBase.makeCurrent(); final GlRectDrawer drawer = new GlRectDrawer(); - drawer.drawOes(listener.oesTextureId, listener.transformMatrix); + drawer.drawOes(listener.oesTextureId, listener.transformMatrix, 0, 0, WIDTH, HEIGHT); // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. Nexus 9. final ByteBuffer rgbaData = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4);
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/MediaCodecVideoEncoderTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/MediaCodecVideoEncoderTest.java new file mode 100644 index 0000000..b1ec5dd --- /dev/null +++ b/talk/app/webrtc/androidtests/src/org/webrtc/MediaCodecVideoEncoderTest.java
@@ -0,0 +1,180 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.webrtc; + +import android.annotation.TargetApi; +import android.opengl.GLES11Ext; +import android.opengl.GLES20; +import android.os.Build; +import android.test.ActivityTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import org.webrtc.MediaCodecVideoEncoder.OutputBufferInfo; + +import java.nio.ByteBuffer; + +@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) +public final class MediaCodecVideoEncoderTest extends ActivityTestCase { + final static String TAG = "MediaCodecVideoEncoderTest"; + + @SmallTest + public static void testInitializeUsingByteBuffer() { + if (!MediaCodecVideoEncoder.isVp8HwSupported()) { + Log.i(TAG, + "Hardware does not support VP8 encoding, skipping testInitReleaseUsingByteBuffer"); + return; + } + MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder(); + assertTrue(encoder.initEncode( + MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480, 300, 30, null)); + encoder.release(); + } + + @SmallTest + public static void testInitilizeUsingTextures() { + if (!MediaCodecVideoEncoder.isVp8HwSupportedUsingTextures()) { + Log.i(TAG, "hardware does not support VP8 encoding, skipping testEncoderUsingTextures"); + return; + } + EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN); + MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder(); + assertTrue(encoder.initEncode( + MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480, 300, 30, + eglBase.getEglBaseContext())); + encoder.release(); + eglBase.release(); + } + + @SmallTest + public static void testInitializeUsingByteBufferReInitilizeUsingTextures() { + if (!MediaCodecVideoEncoder.isVp8HwSupportedUsingTextures()) { + Log.i(TAG, "hardware does not support VP8 encoding, skipping testEncoderUsingTextures"); + return; + } + MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder(); + assertTrue(encoder.initEncode( + MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480, 300, 30, + null)); + encoder.release(); + EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN); + assertTrue(encoder.initEncode( + MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480, 300, 30, + eglBase.getEglBaseContext())); + encoder.release(); + eglBase.release(); + } + + @SmallTest + public static void testEncoderUsingByteBuffer() throws InterruptedException { + if (!MediaCodecVideoEncoder.isVp8HwSupported()) { + Log.i(TAG, "Hardware does not support VP8 encoding, skipping testEncoderUsingByteBuffer"); + return; + } + + final int width = 640; + final int height = 480; + final int min_size = width * height * 3 / 2; + final long presentationTimestampUs = 2; + + MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder(); + + assertTrue(encoder.initEncode( + MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, width, height, 300, 30, null)); + ByteBuffer[] inputBuffers = encoder.getInputBuffers(); + assertNotNull(inputBuffers); + assertTrue(min_size <= inputBuffers[0].capacity()); + + int bufferIndex; + do { + Thread.sleep(10); + bufferIndex = encoder.dequeueInputBuffer(); + } while (bufferIndex == -1); // |-1| is returned when there is no buffer available yet. + + assertTrue(bufferIndex >= 0); + assertTrue(bufferIndex < inputBuffers.length); + assertTrue(encoder.encodeBuffer(true, bufferIndex, min_size, presentationTimestampUs)); + + OutputBufferInfo info; + do { + info = encoder.dequeueOutputBuffer(); + Thread.sleep(10); + } while (info == null); + assertTrue(info.index >= 0); + assertEquals(presentationTimestampUs, info.presentationTimestampUs); + assertTrue(info.buffer.capacity() > 0); + encoder.releaseOutputBuffer(info.index); + + encoder.release(); + } + + @SmallTest + public static void testEncoderUsingTextures() throws InterruptedException { + if (!MediaCodecVideoEncoder.isVp8HwSupportedUsingTextures()) { + Log.i(TAG, "Hardware does not support VP8 encoding, skipping testEncoderUsingTextures"); + return; + } + + final int width = 640; + final int height = 480; + final long presentationTs = 2; + + final EglBase14 eglOesBase = new EglBase14(null, EglBase.CONFIG_PIXEL_BUFFER); + eglOesBase.createDummyPbufferSurface(); + eglOesBase.makeCurrent(); + int oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); + + // TODO(perkj): This test is week since we don't fill the texture with valid data with correct + // width and height and verify the encoded data. Fill the OES texture and figure out a way to + // verify that the output make sense. + + MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder(); + + assertTrue(encoder.initEncode( + MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, width, height, 300, 30, + eglOesBase.getEglBaseContext())); + assertTrue(encoder.encodeTexture(true, oesTextureId, RendererCommon.identityMatrix(), + presentationTs)); + GlUtil.checkNoGLES2Error("encodeTexture"); + + // It should be Ok to delete the texture after calling encodeTexture. + GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0); + + OutputBufferInfo info = encoder.dequeueOutputBuffer(); + while (info == null) { + info = encoder.dequeueOutputBuffer(); + Thread.sleep(20); + } + assertTrue(info.index != -1); + assertTrue(info.buffer.capacity() > 0); + assertEquals(presentationTs, info.presentationTimestampUs); + encoder.releaseOutputBuffer(info.index); + + encoder.release(); + eglOesBase.release(); + } +}
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java index 882fde1..9e0164d 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java
@@ -37,8 +37,6 @@ import java.nio.ByteBuffer; -import javax.microedition.khronos.egl.EGL10; - public final class SurfaceTextureHelperTest extends ActivityTestCase { /** * Mock texture listener with blocking wait functionality. @@ -99,6 +97,14 @@ } } + /** Assert that two integers are close, with difference at most + * {@code threshold}. */ + public static void assertClose(int threshold, int expected, int actual) { + if (Math.abs(expected - actual) <= threshold) + return; + failNotEquals("Not close enough, threshold " + threshold, expected, actual); + } + /** * Test normal use by receiving three uniform texture frames. Texture frames are returned as early * as possible. The texture pixel values are inspected by drawing the texture frame to a pixel @@ -109,20 +115,21 @@ final int width = 16; final int height = 16; // Create EGL base with a pixel buffer as display output. - final EglBase eglBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); + final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER); eglBase.createPbufferSurface(width, height); final GlRectDrawer drawer = new GlRectDrawer(); // Create SurfaceTextureHelper and listener. final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(eglBase.getContext()); + SurfaceTextureHelper.create(eglBase.getEglBaseContext()); final MockTextureListener listener = new MockTextureListener(); surfaceTextureHelper.setListener(listener); surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height); // Create resources for stubbing an OES texture producer. |eglOesBase| has the SurfaceTexture in // |surfaceTextureHelper| as the target EGLSurface. - final EglBase eglOesBase = new EglBase(eglBase.getContext(), EglBase.ConfigType.PLAIN); + final EglBase eglOesBase = + EglBase.create(eglBase.getEglBaseContext(), EglBase.CONFIG_PLAIN); eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); assertEquals(eglOesBase.surfaceWidth(), width); assertEquals(eglOesBase.surfaceHeight(), height); @@ -142,7 +149,7 @@ // Wait for an OES texture to arrive and draw it onto the pixel buffer. listener.waitForNewFrame(); eglBase.makeCurrent(); - drawer.drawOes(listener.oesTextureId, listener.transformMatrix); + drawer.drawOes(listener.oesTextureId, listener.transformMatrix, 0, 0, width, height); surfaceTextureHelper.returnTextureFrame(); @@ -176,19 +183,20 @@ final int width = 16; final int height = 16; // Create EGL base with a pixel buffer as display output. - final EglBase eglBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); + final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER); eglBase.createPbufferSurface(width, height); // Create SurfaceTextureHelper and listener. final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(eglBase.getContext()); + SurfaceTextureHelper.create(eglBase.getEglBaseContext()); final MockTextureListener listener = new MockTextureListener(); surfaceTextureHelper.setListener(listener); surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height); // Create resources for stubbing an OES texture producer. |eglOesBase| has the SurfaceTexture in // |surfaceTextureHelper| as the target EGLSurface. - final EglBase eglOesBase = new EglBase(eglBase.getContext(), EglBase.ConfigType.PLAIN); + final EglBase eglOesBase = + EglBase.create(eglBase.getEglBaseContext(), EglBase.CONFIG_PLAIN); eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); assertEquals(eglOesBase.surfaceWidth(), width); assertEquals(eglOesBase.surfaceHeight(), height); @@ -212,7 +220,7 @@ // Draw the pending texture frame onto the pixel buffer. eglBase.makeCurrent(); final GlRectDrawer drawer = new GlRectDrawer(); - drawer.drawOes(listener.oesTextureId, listener.transformMatrix); + drawer.drawOes(listener.oesTextureId, listener.transformMatrix, 0, 0, width, height); drawer.release(); // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. Nexus 9. @@ -240,11 +248,11 @@ public static void testDisconnect() throws InterruptedException { // Create SurfaceTextureHelper and listener. final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(EGL10.EGL_NO_CONTEXT); + SurfaceTextureHelper.create(null); final MockTextureListener listener = new MockTextureListener(); surfaceTextureHelper.setListener(listener); // Create EglBase with the SurfaceTexture as target EGLSurface. - final EglBase eglBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PLAIN); + final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PLAIN); eglBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); eglBase.makeCurrent(); // Assert no frame has been received yet. @@ -276,7 +284,7 @@ @SmallTest public static void testDisconnectImmediately() { final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(EGL10.EGL_NO_CONTEXT); + SurfaceTextureHelper.create(null); surfaceTextureHelper.disconnect(); } @@ -292,14 +300,14 @@ // Create SurfaceTextureHelper and listener. final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(EGL10.EGL_NO_CONTEXT, handler); + SurfaceTextureHelper.create(null, handler); // Create a mock listener and expect frames to be delivered on |thread|. final MockTextureListener listener = new MockTextureListener(thread); surfaceTextureHelper.setListener(listener); // Create resources for stubbing an OES texture producer. |eglOesBase| has the // SurfaceTexture in |surfaceTextureHelper| as the target EGLSurface. - final EglBase eglOesBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PLAIN); + final EglBase eglOesBase = EglBase.create(null, EglBase.CONFIG_PLAIN); eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); eglOesBase.makeCurrent(); // Draw a frame onto the SurfaceTexture. @@ -313,7 +321,119 @@ // Return the frame from this thread. surfaceTextureHelper.returnTextureFrame(); + surfaceTextureHelper.disconnect(handler); + } + + /** + * Test use SurfaceTextureHelper on a separate thread. A uniform texture frame is created and + * received on a thread separate from the test thread and returned after disconnect. + */ + @MediumTest + public static void testLateReturnFrameOnSeparateThread() throws InterruptedException { + final HandlerThread thread = new HandlerThread("SurfaceTextureHelperTestThread"); + thread.start(); + final Handler handler = new Handler(thread.getLooper()); + + // Create SurfaceTextureHelper and listener. + final SurfaceTextureHelper surfaceTextureHelper = + SurfaceTextureHelper.create(null, handler); + // Create a mock listener and expect frames to be delivered on |thread|. + final MockTextureListener listener = new MockTextureListener(thread); + surfaceTextureHelper.setListener(listener); + + // Create resources for stubbing an OES texture producer. |eglOesBase| has the + // SurfaceTexture in |surfaceTextureHelper| as the target EGLSurface. + final EglBase eglOesBase = EglBase.create(null, EglBase.CONFIG_PLAIN); + eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); + eglOesBase.makeCurrent(); + // Draw a frame onto the SurfaceTexture. + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + // swapBuffers() will ultimately trigger onTextureFrameAvailable(). + eglOesBase.swapBuffers(); + eglOesBase.release(); + + // Wait for an OES texture to arrive. + listener.waitForNewFrame(); + + surfaceTextureHelper.disconnect(handler); + + surfaceTextureHelper.returnTextureFrame(); + } + + @MediumTest + public static void testTexturetoYUV() throws InterruptedException { + final int width = 16; + final int height = 16; + + final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PLAIN); + + // Create SurfaceTextureHelper and listener. + final SurfaceTextureHelper surfaceTextureHelper = + SurfaceTextureHelper.create(eglBase.getEglBaseContext()); + final MockTextureListener listener = new MockTextureListener(); + surfaceTextureHelper.setListener(listener); + surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height); + + // Create resources for stubbing an OES texture producer. |eglBase| has the SurfaceTexture in + // |surfaceTextureHelper| as the target EGLSurface. + + eglBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); + assertEquals(eglBase.surfaceWidth(), width); + assertEquals(eglBase.surfaceHeight(), height); + + final int red[] = new int[] {79, 144, 185}; + final int green[] = new int[] {66, 210, 162}; + final int blue[] = new int[] {161, 117, 158}; + + final int ref_y[] = new int[] {81, 180, 168}; + final int ref_u[] = new int[] {173, 93, 122}; + final int ref_v[] = new int[] {127, 103, 140}; + + // Draw three frames. + for (int i = 0; i < 3; ++i) { + // Draw a constant color frame onto the SurfaceTexture. + eglBase.makeCurrent(); + GLES20.glClearColor(red[i] / 255.0f, green[i] / 255.0f, blue[i] / 255.0f, 1.0f); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + // swapBuffers() will ultimately trigger onTextureFrameAvailable(). + eglBase.swapBuffers(); + + // Wait for an OES texture to arrive. + listener.waitForNewFrame(); + + // Memory layout: Lines are 16 bytes. First 16 lines are + // the Y data. These are followed by 8 lines with 8 bytes of U + // data on the left and 8 bytes of V data on the right. + // + // Offset + // 0 YYYYYYYY YYYYYYYY + // 16 YYYYYYYY YYYYYYYY + // ... + // 240 YYYYYYYY YYYYYYYY + // 256 UUUUUUUU VVVVVVVV + // 272 UUUUUUUU VVVVVVVV + // ... + // 368 UUUUUUUU VVVVVVVV + // 384 buffer end + ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 3 / 2); + surfaceTextureHelper.textureToYUV(buffer, width, height, width, + listener.oesTextureId, listener.transformMatrix); + + surfaceTextureHelper.returnTextureFrame(); + + // Allow off-by-one differences due to different rounding. + while (buffer.position() < width*height) { + assertClose(1, buffer.get() & 0xff, ref_y[i]); + } + while (buffer.hasRemaining()) { + if (buffer.position() % width < width/2) + assertClose(1, buffer.get() & 0xff, ref_u[i]); + else + assertClose(1, buffer.get() & 0xff, ref_v[i]); + } + } + surfaceTextureHelper.disconnect(); - thread.quitSafely(); + eglBase.release(); } }
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceViewRendererOnMeasureTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceViewRendererOnMeasureTest.java index 47fe780..341c632 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceViewRendererOnMeasureTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceViewRendererOnMeasureTest.java
@@ -36,8 +36,6 @@ import java.util.Arrays; import java.util.List; -import javax.microedition.khronos.egl.EGL10; - public final class SurfaceViewRendererOnMeasureTest extends ActivityTestCase { /** * List with all possible scaling types. @@ -111,7 +109,7 @@ } // Test behaviour after SurfaceViewRenderer.init() is called, but still no frame. - surfaceViewRenderer.init(EGL10.EGL_NO_CONTEXT, null); + surfaceViewRenderer.init((EglBase.Context) null, null); for (RendererCommon.ScalingType scalingType : scalingTypes) { for (int measureSpecMode : measureSpecModes) { final int zeroMeasureSize = MeasureSpec.makeMeasureSpec(0, measureSpecMode); @@ -134,7 +132,7 @@ public void testFrame1280x720() { final SurfaceViewRenderer surfaceViewRenderer = new SurfaceViewRenderer(getInstrumentation().getContext()); - surfaceViewRenderer.init(EGL10.EGL_NO_CONTEXT, null); + surfaceViewRenderer.init((EglBase.Context) null, null); // Test different rotation degress, but same rotated size. for (int rotationDegree : new int[] {0, 90, 180, 270}) {
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java index dbbe596..1b97201 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java
@@ -29,7 +29,6 @@ import android.test.ActivityTestCase; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; -import android.util.Log; import android.util.Size; import org.webrtc.CameraEnumerationAndroid.CaptureFormat; @@ -37,8 +36,6 @@ import java.util.HashSet; import java.util.Set; -import javax.microedition.khronos.egl.EGL10; - @SuppressWarnings("deprecation") public class VideoCapturerAndroidTest extends ActivityTestCase { static final String TAG = "VideoCapturerAndroidTest"; @@ -87,8 +84,10 @@ @SmallTest public void testCreateAndReleaseUsingTextures() { + EglBase eglBase = EglBase.create(); VideoCapturerAndroidTestFixtures.release( - VideoCapturerAndroid.create("", null, EGL10.EGL_NO_CONTEXT)); + VideoCapturerAndroid.create("", null, eglBase.getEglBaseContext())); + eglBase.release(); } @SmallTest @@ -108,12 +107,13 @@ VideoCapturerAndroidTestFixtures.startCapturerAndRender(capturer); } - // TODO(perkj): Enable once VideoCapture to texture support has landed in C++. @SmallTest - public void DISABLED_testStartVideoCapturerUsingTextures() throws InterruptedException { + public void testStartVideoCapturerUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); VideoCapturerAndroid capturer = - VideoCapturerAndroid.create("", null, EGL10.EGL_NO_CONTEXT); + VideoCapturerAndroid.create("", null, eglBase.getEglBaseContext()); VideoCapturerAndroidTestFixtures.startCapturerAndRender(capturer); + eglBase.release(); } @SmallTest @@ -151,11 +151,13 @@ VideoCapturerAndroidTestFixtures.switchCamera(capturer); } - // TODO(perkj): Enable once VideoCapture to texture support has landed in C++. @SmallTest - public void DISABLED_testSwitchVideoCapturerUsingTextures() throws InterruptedException { - VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null, EGL10.EGL_NO_CONTEXT); + public void testSwitchVideoCapturerUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); + VideoCapturerAndroid capturer = + VideoCapturerAndroid.create("", null, eglBase.getEglBaseContext()); VideoCapturerAndroidTestFixtures.switchCamera(capturer); + eglBase.release(); } @MediumTest @@ -179,12 +181,14 @@ @MediumTest public void testCameraCallsAfterStopUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); final String deviceName = CameraEnumerationAndroid.getDeviceName(0); final VideoCapturerAndroid capturer = VideoCapturerAndroid.create(deviceName, null, - EGL10.EGL_NO_CONTEXT); + eglBase.getEglBaseContext()); VideoCapturerAndroidTestFixtures.cameraCallsAfterStop(capturer, getInstrumentation().getContext()); + eglBase.release(); } @SmallTest @@ -195,11 +199,13 @@ VideoCapturerAndroidTestFixtures.stopRestartVideoSource(capturer); } - // TODO(perkj): Enable once VideoCapture to texture support has landed in C++. @SmallTest - public void DISABLED_testStopRestartVideoSourceUsingTextures() throws InterruptedException { - VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null, EGL10.EGL_NO_CONTEXT); + public void testStopRestartVideoSourceUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); + VideoCapturerAndroid capturer = + VideoCapturerAndroid.create("", null, eglBase.getEglBaseContext()); VideoCapturerAndroidTestFixtures.stopRestartVideoSource(capturer); + eglBase.release(); } @SmallTest @@ -215,14 +221,51 @@ @SmallTest public void testStartStopWithDifferentResolutionsUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); String deviceName = CameraEnumerationAndroid.getDeviceName(0); VideoCapturerAndroid capturer = - VideoCapturerAndroid.create(deviceName, null, EGL10.EGL_NO_CONTEXT); + VideoCapturerAndroid.create(deviceName, null, eglBase.getEglBaseContext()); VideoCapturerAndroidTestFixtures.startStopWithDifferentResolutions(capturer, getInstrumentation().getContext()); + eglBase.release(); } @SmallTest + // This test that an error is reported if the camera is already opened + // when VideoCapturerAndroid is started. + public void testStartWhileCameraAlreadyOpened() throws InterruptedException { + String deviceName = CameraEnumerationAndroid.getDeviceName(0); + VideoCapturerAndroid capturer = + VideoCapturerAndroid.create(deviceName, null); + VideoCapturerAndroidTestFixtures.startWhileCameraIsAlreadyOpen( + capturer, getInstrumentation().getContext()); + } + + @SmallTest + // This test that VideoCapturerAndroid can be started, even if the camera is already opened + // if the camera is closed while VideoCapturerAndroid is re-trying to start. + public void testStartWhileCameraIsAlreadyOpenAndCloseCamera() throws InterruptedException { + String deviceName = CameraEnumerationAndroid.getDeviceName(0); + VideoCapturerAndroid capturer = + VideoCapturerAndroid.create(deviceName, null); + VideoCapturerAndroidTestFixtures.startWhileCameraIsAlreadyOpenAndCloseCamera( + capturer, getInstrumentation().getContext()); + } + + @SmallTest + // This test that VideoCapturerAndroid.stop can be called while VideoCapturerAndroid is + // re-trying to start. + public void startWhileCameraIsAlreadyOpenAndStop() throws InterruptedException { + String deviceName = CameraEnumerationAndroid.getDeviceName(0); + VideoCapturerAndroid capturer = + VideoCapturerAndroid.create(deviceName, null); + VideoCapturerAndroidTestFixtures.startWhileCameraIsAlreadyOpenAndStop( + capturer, getInstrumentation().getContext()); + } + + + + @SmallTest // This test what happens if buffers are returned after the capturer have // been stopped and restarted. It does not test or use the C++ layer. public void testReturnBufferLate() throws InterruptedException { @@ -235,11 +278,13 @@ @SmallTest public void testReturnBufferLateUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); String deviceName = CameraEnumerationAndroid.getDeviceName(0); VideoCapturerAndroid capturer = - VideoCapturerAndroid.create(deviceName, null, EGL10.EGL_NO_CONTEXT); + VideoCapturerAndroid.create(deviceName, null, eglBase.getEglBaseContext()); VideoCapturerAndroidTestFixtures.returnBufferLate(capturer, getInstrumentation().getContext()); + eglBase.release(); } @MediumTest @@ -251,11 +296,45 @@ VideoCapturerAndroidTestFixtures.returnBufferLateEndToEnd(capturer); } - // TODO(perkj): Enable once VideoCapture to texture support has landed in C++. @MediumTest - public void DISABLED_testReturnBufferLateEndToEndUsingTextures() throws InterruptedException { + public void testReturnBufferLateEndToEndUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); final VideoCapturerAndroid capturer = - VideoCapturerAndroid.create("", null, EGL10.EGL_NO_CONTEXT); + VideoCapturerAndroid.create("", null, eglBase.getEglBaseContext()); VideoCapturerAndroidTestFixtures.returnBufferLateEndToEnd(capturer); + eglBase.release(); + } + + @MediumTest + // This test that CameraEventsHandler.onError is triggered if video buffers are not returned to + // the capturer. + public void testCameraFreezedEventOnBufferStarvationUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); + VideoCapturerAndroidTestFixtures.CameraEvents cameraEvents = + VideoCapturerAndroidTestFixtures.createCameraEvents(); + VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", cameraEvents, + eglBase.getEglBaseContext()); + VideoCapturerAndroidTestFixtures.cameraFreezedEventOnBufferStarvationUsingTextures(capturer, + cameraEvents, getInstrumentation().getContext()); + eglBase.release(); + } + + @MediumTest + // This test that frames forwarded to a renderer is scaled if onOutputFormatRequest is + // called. This test both Java and C++ parts of of the stack. + public void testScaleCameraOutput() throws InterruptedException { + VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null); + VideoCapturerAndroidTestFixtures.scaleCameraOutput(capturer); + } + + @MediumTest + // This test that frames forwarded to a renderer is scaled if onOutputFormatRequest is + // called. This test both Java and C++ parts of of the stack. + public void testScaleCameraOutputUsingTextures() throws InterruptedException { + EglBase eglBase = EglBase.create(); + VideoCapturerAndroid capturer = + VideoCapturerAndroid.create("", null, eglBase.getEglBaseContext()); + VideoCapturerAndroidTestFixtures.scaleCameraOutput(capturer); + eglBase.release(); } }
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java index 11b3ce9..0b42e33 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java
@@ -29,6 +29,7 @@ import android.content.Context; import android.hardware.Camera; +import org.webrtc.VideoCapturerAndroidTestFixtures; import org.webrtc.CameraEnumerationAndroid.CaptureFormat; import org.webrtc.VideoRenderer.I420Frame; @@ -42,16 +43,32 @@ static class RendererCallbacks implements VideoRenderer.Callbacks { private int framesRendered = 0; private Object frameLock = 0; + private int width = 0; + private int height = 0; @Override public void renderFrame(I420Frame frame) { synchronized (frameLock) { ++framesRendered; + width = frame.rotatedWidth(); + height = frame.rotatedHeight(); frameLock.notify(); } VideoRenderer.renderFrameDone(frame); } + public int frameWidth() { + synchronized (frameLock) { + return width; + } + } + + public int frameHeight() { + synchronized (frameLock) { + return height; + } + } + public int WaitForNextFrameToRender() throws InterruptedException { synchronized (frameLock) { frameLock.wait(); @@ -102,11 +119,11 @@ } @Override - public void onByteBufferFrameCaptured(byte[] frame, int length, int width, int height, - int rotation, long timeStamp) { + public void onByteBufferFrameCaptured(byte[] frame, int width, int height, int rotation, + long timeStamp) { synchronized (frameLock) { ++framesCaptured; - frameSize = length; + frameSize = frame.length; frameWidth = width; frameHeight = height; timestamps.add(timeStamp); @@ -115,7 +132,8 @@ } @Override public void onTextureFrameCaptured( - int width, int height, int oesTextureId, float[] transformMatrix, long timeStamp) { + int width, int height, int oesTextureId, float[] transformMatrix, int rotation, + long timeStamp) { synchronized (frameLock) { ++framesCaptured; frameWidth = width; @@ -174,9 +192,20 @@ VideoCapturerAndroid.CameraEventsHandler { public boolean onCameraOpeningCalled; public boolean onFirstFrameAvailableCalled; + public final Object onCameraFreezedLock = new Object(); + private String onCameraFreezedDescription; @Override - public void onCameraError(String errorDescription) { } + public void onCameraError(String errorDescription) { + } + + @Override + public void onCameraFreezed(String errorDescription) { + synchronized (onCameraFreezedLock) { + onCameraFreezedDescription = errorDescription; + onCameraFreezedLock.notifyAll(); + } + } @Override public void onCameraOpening(int cameraId) { @@ -190,6 +219,13 @@ @Override public void onCameraClosed() { } + + public String WaitForCameraFreezed() throws InterruptedException { + synchronized (onCameraFreezedLock) { + onCameraFreezedLock.wait(); + return onCameraFreezedDescription; + } + } } static public CameraEvents createCameraEvents() { @@ -275,8 +311,8 @@ assertTrue(observer.WaitForCapturerToStart()); observer.WaitForNextCapturedFrame(); capturer.stopCapture(); - for (long timeStamp : observer.getCopyAndResetListOftimeStamps()) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } capturer.dispose(); @@ -296,9 +332,10 @@ // Make sure camera is started and then stop it. assertTrue(observer.WaitForCapturerToStart()); capturer.stopCapture(); - for (long timeStamp : observer.getCopyAndResetListOftimeStamps()) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } + // We can't change |capturer| at this point, but we should not crash. capturer.switchCamera(null); capturer.onOutputFormatRequest(640, 480, 15); @@ -357,17 +394,90 @@ if (capturer.isCapturingToTexture()) { assertEquals(0, observer.frameSize()); } else { - assertEquals(format.frameSize(), observer.frameSize()); + assertTrue(format.frameSize() <= observer.frameSize()); } capturer.stopCapture(); - for (long timestamp : observer.getCopyAndResetListOftimeStamps()) { - capturer.returnBuffer(timestamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } } capturer.dispose(); assertTrue(capturer.isReleased()); } + static void waitUntilIdle(VideoCapturerAndroid capturer) throws InterruptedException { + final CountDownLatch barrier = new CountDownLatch(1); + capturer.getCameraThreadHandler().post(new Runnable() { + @Override public void run() { + barrier.countDown(); + } + }); + barrier.await(); + } + + static public void startWhileCameraIsAlreadyOpen( + VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { + Camera camera = Camera.open(capturer.getCurrentCameraId()); + + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { + // The first opened camera client will be evicted. + assertTrue(observer.WaitForCapturerToStart()); + capturer.stopCapture(); + } else { + assertFalse(observer.WaitForCapturerToStart()); + } + + capturer.dispose(); + camera.release(); + } + + static public void startWhileCameraIsAlreadyOpenAndCloseCamera( + VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { + Camera camera = Camera.open(capturer.getCurrentCameraId()); + + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + waitUntilIdle(capturer); + + camera.release(); + + // Make sure camera is started and first frame is received and then stop it. + assertTrue(observer.WaitForCapturerToStart()); + observer.WaitForNextCapturedFrame(); + capturer.stopCapture(); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); + } + capturer.dispose(); + assertTrue(capturer.isReleased()); + } + + static public void startWhileCameraIsAlreadyOpenAndStop( + VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { + Camera camera = Camera.open(capturer.getCurrentCameraId()); + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + capturer.stopCapture(); + capturer.dispose(); + assertTrue(capturer.isReleased()); + camera.release(); + } + static public void returnBufferLate(VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { FakeCapturerObserver observer = new FakeCapturerObserver(); @@ -387,9 +497,8 @@ capturer.startCapture(format.width, format.height, format.maxFramerate, appContext, observer); observer.WaitForCapturerToStart(); - - for (Long timeStamp : listOftimestamps) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } observer.WaitForNextCapturedFrame(); @@ -397,9 +506,10 @@ listOftimestamps = observer.getCopyAndResetListOftimeStamps(); assertTrue(listOftimestamps.size() >= 1); - for (Long timeStamp : listOftimestamps) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } + capturer.dispose(); assertTrue(capturer.isReleased()); } @@ -410,6 +520,7 @@ final VideoSource source = factory.createVideoSource(capturer, new MediaConstraints()); final VideoTrack track = factory.createVideoTrack("dummy", source); final FakeAsyncRenderer renderer = new FakeAsyncRenderer(); + track.addRenderer(new VideoRenderer(renderer)); // Wait for at least one frame that has not been returned. assertFalse(renderer.waitForPendingFrames().isEmpty()); @@ -420,9 +531,7 @@ track.dispose(); source.dispose(); factory.dispose(); - - // The pending frames should keep the JNI parts and |capturer| alive. - assertFalse(capturer.isReleased()); + assertTrue(capturer.isReleased()); // Return the frame(s), on a different thread out of spite. final List<I420Frame> pendingFrames = renderer.waitForPendingFrames(); @@ -436,8 +545,71 @@ }); returnThread.start(); returnThread.join(); + } - // Check that frames have successfully returned. This will cause |capturer| to be released. + static public void cameraFreezedEventOnBufferStarvationUsingTextures( + VideoCapturerAndroid capturer, + CameraEvents events, Context appContext) throws InterruptedException { + assertTrue("Not capturing to textures.", capturer.isCapturingToTexture()); + + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + // Make sure camera is started. + assertTrue(observer.WaitForCapturerToStart()); + // Since we don't return the buffer, we should get a starvation message if we are + // capturing to a texture. + assertEquals("Camera failure. Client must return video buffers.", + events.WaitForCameraFreezed()); + + capturer.stopCapture(); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); + } + + capturer.dispose(); assertTrue(capturer.isReleased()); } + + static public void scaleCameraOutput(VideoCapturerAndroid capturer) throws InterruptedException { + PeerConnectionFactory factory = new PeerConnectionFactory(); + VideoSource source = + factory.createVideoSource(capturer, new MediaConstraints()); + VideoTrack track = factory.createVideoTrack("dummy", source); + RendererCallbacks renderer = new RendererCallbacks(); + track.addRenderer(new VideoRenderer(renderer)); + assertTrue(renderer.WaitForNextFrameToRender() > 0); + + final int startWidth = renderer.frameWidth(); + final int startHeight = renderer.frameHeight(); + final int frameRate = 30; + final int scaledWidth = startWidth / 2; + final int scaledHeight = startHeight / 2; + + // Request the captured frames to be scaled. + capturer.onOutputFormatRequest(scaledWidth, scaledHeight, frameRate); + + boolean gotExpectedResolution = false; + int numberOfInspectedFrames = 0; + + do { + renderer.WaitForNextFrameToRender(); + ++numberOfInspectedFrames; + + gotExpectedResolution = (renderer.frameWidth() == scaledWidth + && renderer.frameHeight() == scaledHeight); + } while (!gotExpectedResolution && numberOfInspectedFrames < 30); + + source.stop(); + track.dispose(); + source.dispose(); + factory.dispose(); + assertTrue(capturer.isReleased()); + + assertTrue(gotExpectedResolution); + } + }
diff --git a/talk/app/webrtc/androidvideocapturer.cc b/talk/app/webrtc/androidvideocapturer.cc index afcfb5b..d8f1217 100644 --- a/talk/app/webrtc/androidvideocapturer.cc +++ b/talk/app/webrtc/androidvideocapturer.cc
@@ -26,6 +26,7 @@ */ #include "talk/app/webrtc/androidvideocapturer.h" +#include "talk/app/webrtc/java/jni/native_handle_impl.h" #include "talk/media/webrtc/webrtcvideoframe.h" #include "webrtc/base/common.h" #include "webrtc/base/json.h" @@ -57,11 +58,13 @@ const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, int rotation, int64_t time_stamp_in_ns) { + RTC_DCHECK(rotation == 0 || rotation == 90 || rotation == 180 || + rotation == 270); buffer_ = buffer; captured_frame_.width = buffer->width(); captured_frame_.height = buffer->height(); captured_frame_.time_stamp = time_stamp_in_ns; - captured_frame_.rotation = rotation; + captured_frame_.rotation = static_cast<webrtc::VideoRotation>(rotation); } void ClearCapturedFrame() { @@ -85,7 +88,7 @@ rtc::scoped_ptr<cricket::VideoFrame> frame(new cricket::WebRtcVideoFrame( ShallowCenterCrop(buffer_, dst_width, dst_height), - captured_frame->time_stamp, captured_frame->GetRotation())); + captured_frame->time_stamp, captured_frame->rotation)); // Caller takes ownership. // TODO(magjed): Change CreateAliasedFrame() to return a rtc::scoped_ptr. return apply_rotation_ ? frame->GetCopyWithRotationApplied()->Copy() @@ -99,10 +102,17 @@ int output_width, int output_height) const override { if (buffer_->native_handle() != nullptr) { - // TODO(perkj): Implement CreateAliasedFrame properly for textures. - rtc::scoped_ptr<cricket::VideoFrame> frame(new cricket::WebRtcVideoFrame( - buffer_, input_frame->time_stamp, input_frame->GetRotation())); - return frame.release(); + // TODO(perkj) Implement cropping. + RTC_CHECK_EQ(cropped_input_width, buffer_->width()); + RTC_CHECK_EQ(cropped_input_height, buffer_->height()); + rtc::scoped_refptr<webrtc::VideoFrameBuffer> scaled_buffer( + static_cast<webrtc_jni::AndroidTextureBuffer*>(buffer_.get()) + ->ScaleAndRotate(output_width, output_height, + apply_rotation_ ? input_frame->rotation : + webrtc::kVideoRotation_0)); + return new cricket::WebRtcVideoFrame( + scaled_buffer, input_frame->time_stamp, + apply_rotation_ ? webrtc::kVideoRotation_0 : input_frame->rotation); } return VideoFrameFactory::CreateAliasedFrame(input_frame, cropped_input_width,
diff --git a/talk/app/webrtc/androidvideocapturer.h b/talk/app/webrtc/androidvideocapturer.h index df783bd..c665eab 100644 --- a/talk/app/webrtc/androidvideocapturer.h +++ b/talk/app/webrtc/androidvideocapturer.h
@@ -32,7 +32,7 @@ #include "talk/media/base/videocapturer.h" #include "webrtc/base/thread_checker.h" -#include "webrtc/common_video/interface/video_frame_buffer.h" +#include "webrtc/common_video/include/video_frame_buffer.h" namespace webrtc {
diff --git a/talk/app/webrtc/audiotrack.cc b/talk/app/webrtc/audiotrack.cc index b0c9129..b3223cd 100644 --- a/talk/app/webrtc/audiotrack.cc +++ b/talk/app/webrtc/audiotrack.cc
@@ -27,27 +27,82 @@ #include "talk/app/webrtc/audiotrack.h" -#include <string> +#include "webrtc/base/checks.h" + +using rtc::scoped_refptr; namespace webrtc { -static const char kAudioTrackKind[] = "audio"; +const char MediaStreamTrackInterface::kAudioKind[] = "audio"; + +// static +scoped_refptr<AudioTrack> AudioTrack::Create( + const std::string& id, + const scoped_refptr<AudioSourceInterface>& source) { + return new rtc::RefCountedObject<AudioTrack>(id, source); +} AudioTrack::AudioTrack(const std::string& label, - AudioSourceInterface* audio_source) - : MediaStreamTrack<AudioTrackInterface>(label), - audio_source_(audio_source) { + const scoped_refptr<AudioSourceInterface>& source) + : MediaStreamTrack<AudioTrackInterface>(label), audio_source_(source) { + if (audio_source_) { + audio_source_->RegisterObserver(this); + OnChanged(); + } +} + +AudioTrack::~AudioTrack() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + set_state(MediaStreamTrackInterface::kEnded); + if (audio_source_) + audio_source_->UnregisterObserver(this); } std::string AudioTrack::kind() const { - return kAudioTrackKind; + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + return kAudioKind; } -rtc::scoped_refptr<AudioTrack> AudioTrack::Create( - const std::string& id, AudioSourceInterface* source) { - rtc::RefCountedObject<AudioTrack>* track = - new rtc::RefCountedObject<AudioTrack>(id, source); - return track; +AudioSourceInterface* AudioTrack::GetSource() const { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + return audio_source_.get(); +} + +void AudioTrack::AddSink(AudioTrackSinkInterface* sink) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (audio_source_) + audio_source_->AddSink(sink); +} + +void AudioTrack::RemoveSink(AudioTrackSinkInterface* sink) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (audio_source_) + audio_source_->RemoveSink(sink); +} + +void AudioTrack::OnChanged() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (state() == kFailed) + return; // We can't recover from this state (do we ever set it?). + + TrackState new_state = kInitializing; + + // |audio_source_| must be non-null if we ever get here. + switch (audio_source_->state()) { + case MediaSourceInterface::kLive: + case MediaSourceInterface::kMuted: + new_state = kLive; + break; + case MediaSourceInterface::kEnded: + new_state = kEnded; + break; + case MediaSourceInterface::kInitializing: + default: + // use kInitializing. + break; + } + + set_state(new_state); } } // namespace webrtc
diff --git a/talk/app/webrtc/audiotrack.h b/talk/app/webrtc/audiotrack.h index 750f272..55f4837 100644 --- a/talk/app/webrtc/audiotrack.h +++ b/talk/app/webrtc/audiotrack.h
@@ -28,40 +28,47 @@ #ifndef TALK_APP_WEBRTC_AUDIOTRACK_H_ #define TALK_APP_WEBRTC_AUDIOTRACK_H_ +#include <string> + #include "talk/app/webrtc/mediastreaminterface.h" #include "talk/app/webrtc/mediastreamtrack.h" #include "talk/app/webrtc/notifier.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/base/thread_checker.h" namespace webrtc { -class AudioTrack : public MediaStreamTrack<AudioTrackInterface> { +class AudioTrack : public MediaStreamTrack<AudioTrackInterface>, + public ObserverInterface { + protected: + // Protected ctor to force use of factory method. + AudioTrack(const std::string& label, + const rtc::scoped_refptr<AudioSourceInterface>& source); + ~AudioTrack() override; + public: static rtc::scoped_refptr<AudioTrack> Create( - const std::string& id, AudioSourceInterface* source); + const std::string& id, + const rtc::scoped_refptr<AudioSourceInterface>& source); - // AudioTrackInterface implementation. - AudioSourceInterface* GetSource() const override { - return audio_source_.get(); - } - // TODO(xians): Implement these methods. - void AddSink(AudioTrackSinkInterface* sink) override {} - void RemoveSink(AudioTrackSinkInterface* sink) override {} - bool GetSignalLevel(int* level) override { return false; } - rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override { - return NULL; - } - cricket::AudioRenderer* GetRenderer() override { return NULL; } - + private: // MediaStreamTrack implementation. std::string kind() const override; - protected: - AudioTrack(const std::string& label, AudioSourceInterface* audio_source); + // AudioTrackInterface implementation. + AudioSourceInterface* GetSource() const override; + + void AddSink(AudioTrackSinkInterface* sink) override; + void RemoveSink(AudioTrackSinkInterface* sink) override; + + // ObserverInterface implementation. + void OnChanged() override; private: - rtc::scoped_refptr<AudioSourceInterface> audio_source_; + const rtc::scoped_refptr<AudioSourceInterface> audio_source_; + rtc::ThreadChecker thread_checker_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioTrack); }; } // namespace webrtc
diff --git a/talk/app/webrtc/dtlsidentitystore.cc b/talk/app/webrtc/dtlsidentitystore.cc index 2758779..390ec0d 100644 --- a/talk/app/webrtc/dtlsidentitystore.cc +++ b/talk/app/webrtc/dtlsidentitystore.cc
@@ -27,6 +27,8 @@ #include "talk/app/webrtc/dtlsidentitystore.h" +#include <utility> + #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" #include "webrtc/base/logging.h" @@ -72,7 +74,7 @@ // Posting to |this| avoids touching |store_| on threads other than // |signaling_thread_| and thus avoids having to use locks. IdentityResultMessageData* msg = new IdentityResultMessageData( - new IdentityResult(key_type_, identity.Pass())); + new IdentityResult(key_type_, std::move(identity))); signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg); } @@ -93,7 +95,7 @@ static_cast<IdentityResultMessageData*>(msg->pdata)); if (store_) { store_->OnIdentityGenerated(pdata->data()->key_type_, - pdata->data()->identity_.Pass()); + std::move(pdata->data()->identity_)); } } break; @@ -152,7 +154,7 @@ rtc::scoped_ptr<IdentityResultMessageData> pdata( static_cast<IdentityResultMessageData*>(msg->pdata)); OnIdentityGenerated(pdata->data()->key_type_, - pdata->data()->identity_.Pass()); + std::move(pdata->data()->identity_)); break; } } @@ -178,9 +180,9 @@ // Return identity async - post even though we are on |signaling_thread_|. LOG(LS_VERBOSE) << "Using a free DTLS identity."; ++request_info_[key_type].gen_in_progress_counts_; - IdentityResultMessageData* msg = new IdentityResultMessageData( - new IdentityResult(key_type, - request_info_[key_type].free_identity_.Pass())); + IdentityResultMessageData* msg = + new IdentityResultMessageData(new IdentityResult( + key_type, std::move(request_info_[key_type].free_identity_))); signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg); return; } @@ -228,7 +230,7 @@ // Return the result to the observer. if (identity.get()) { LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer."; - observer->OnSuccess(identity.Pass()); + observer->OnSuccess(std::move(identity)); } else { LOG(LS_WARNING) << "Failed to generate DTLS identity."; observer->OnFailure(0);
diff --git a/talk/app/webrtc/dtlsidentitystore.h b/talk/app/webrtc/dtlsidentitystore.h index a0eef98..2a5309d 100644 --- a/talk/app/webrtc/dtlsidentitystore.h +++ b/talk/app/webrtc/dtlsidentitystore.h
@@ -30,6 +30,7 @@ #include <queue> #include <string> +#include <utility> #include "webrtc/base/messagehandler.h" #include "webrtc/base/messagequeue.h" @@ -129,7 +130,7 @@ struct IdentityResult { IdentityResult(rtc::KeyType key_type, rtc::scoped_ptr<rtc::SSLIdentity> identity) - : key_type_(key_type), identity_(identity.Pass()) {} + : key_type_(key_type), identity_(std::move(identity)) {} rtc::KeyType key_type_; rtc::scoped_ptr<rtc::SSLIdentity> identity_;
diff --git a/talk/app/webrtc/fakeportallocatorfactory.h b/talk/app/webrtc/fakeportallocatorfactory.h deleted file mode 100644 index f326b62..0000000 --- a/talk/app/webrtc/fakeportallocatorfactory.h +++ /dev/null
@@ -1,76 +0,0 @@ -/* - * libjingle - * Copyright 2011 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// This file defines a fake port allocator factory used for testing. -// This implementation creates instances of cricket::FakePortAllocator. - -#ifndef TALK_APP_WEBRTC_FAKEPORTALLOCATORFACTORY_H_ -#define TALK_APP_WEBRTC_FAKEPORTALLOCATORFACTORY_H_ - -#include "talk/app/webrtc/peerconnectioninterface.h" -#include "webrtc/p2p/client/fakeportallocator.h" - -namespace webrtc { - -class FakePortAllocatorFactory : public PortAllocatorFactoryInterface { - public: - static FakePortAllocatorFactory* Create() { - rtc::RefCountedObject<FakePortAllocatorFactory>* allocator = - new rtc::RefCountedObject<FakePortAllocatorFactory>(); - return allocator; - } - - virtual cricket::PortAllocator* CreatePortAllocator( - const std::vector<StunConfiguration>& stun_configurations, - const std::vector<TurnConfiguration>& turn_configurations) { - stun_configs_ = stun_configurations; - turn_configs_ = turn_configurations; - return new cricket::FakePortAllocator(rtc::Thread::Current(), NULL); - } - - const std::vector<StunConfiguration>& stun_configs() const { - return stun_configs_; - } - - const std::vector<TurnConfiguration>& turn_configs() const { - return turn_configs_; - } - - void SetNetworkIgnoreMask(int network_ignore_mask) {} - - protected: - FakePortAllocatorFactory() {} - ~FakePortAllocatorFactory() {} - - private: - std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_configs_; - std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_configs_; -}; - -} // namespace webrtc - -#endif // TALK_APP_WEBRTC_FAKEPORTALLOCATORFACTORY_H_
diff --git a/talk/app/webrtc/java/android/org/webrtc/Camera2Enumerator.java b/talk/app/webrtc/java/android/org/webrtc/Camera2Enumerator.java index 097d1cd..3444529 100644 --- a/talk/app/webrtc/java/android/org/webrtc/Camera2Enumerator.java +++ b/talk/app/webrtc/java/android/org/webrtc/Camera2Enumerator.java
@@ -27,7 +27,9 @@ package org.webrtc; +import android.annotation.TargetApi; import android.content.Context; + import android.graphics.ImageFormat; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; @@ -45,6 +47,7 @@ import java.util.List; import java.util.Map; +@TargetApi(21) public class Camera2Enumerator implements CameraEnumerationAndroid.Enumerator { private final static String TAG = "Camera2Enumerator"; private final static double NANO_SECONDS_PER_SECOND = 1.0e9;
diff --git a/talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java b/talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java index 3e37f6a..5f68c37 100644 --- a/talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java +++ b/talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java
@@ -29,7 +29,6 @@ import static java.lang.Math.abs; import static java.lang.Math.ceil; -import android.hardware.Camera; import android.graphics.ImageFormat; import org.json.JSONArray; @@ -72,7 +71,7 @@ // other image formats then this needs to be updated and // VideoCapturerAndroid.getSupportedFormats need to return CaptureFormats of // all imageFormats. - public final int imageFormat = ImageFormat.YV12; + public final int imageFormat = ImageFormat.NV21; public CaptureFormat(int width, int height, int minFramerate, int maxFramerate) { @@ -88,25 +87,15 @@ } // Calculates the frame size of the specified image format. Currently only - // supporting ImageFormat.YV12. The YV12's stride is the closest rounded up - // multiple of 16 of the width and width and height are always even. - // Android guarantees this: - // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29 + // supporting ImageFormat.NV21. + // The size is width * height * number of bytes per pixel. + // http://developer.android.com/reference/android/hardware/Camera.html#addCallbackBuffer(byte[]) public static int frameSize(int width, int height, int imageFormat) { - if (imageFormat != ImageFormat.YV12) { + if (imageFormat != ImageFormat.NV21) { throw new UnsupportedOperationException("Don't know how to calculate " - + "the frame size of non-YV12 image formats."); + + "the frame size of non-NV21 image formats."); } - int yStride = roundUp(width, 16); - int uvStride = roundUp(yStride / 2, 16); - int ySize = yStride * height; - int uvSize = uvStride * height / 2; - return ySize + uvSize * 2; - } - - // Rounds up |x| to the closest value that is a multiple of |alignment|. - private static int roundUp(int x, int alignment) { - return (int)ceil(x / (double)alignment) * alignment; + return (width * height * ImageFormat.getBitsPerPixel(imageFormat)) / 8; } @Override @@ -114,21 +103,19 @@ return width + "x" + height + "@[" + minFramerate + ":" + maxFramerate + "]"; } - @Override - public boolean equals(Object that) { - if (!(that instanceof CaptureFormat)) { + public boolean isSameFormat(final CaptureFormat that) { + if (that == null) { return false; } - final CaptureFormat c = (CaptureFormat) that; - return width == c.width && height == c.height && maxFramerate == c.maxFramerate - && minFramerate == c.minFramerate; + return width == that.width && height == that.height && maxFramerate == that.maxFramerate + && minFramerate == that.minFramerate; } } // Returns device names that can be used to create a new VideoCapturerAndroid. public static String[] getDeviceNames() { - String[] names = new String[Camera.getNumberOfCameras()]; - for (int i = 0; i < Camera.getNumberOfCameras(); ++i) { + String[] names = new String[android.hardware.Camera.getNumberOfCameras()]; + for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) { names[i] = getDeviceName(i); } return names; @@ -136,22 +123,22 @@ // Returns number of cameras on device. public static int getDeviceCount() { - return Camera.getNumberOfCameras(); + return android.hardware.Camera.getNumberOfCameras(); } // Returns the name of the camera with camera index. Returns null if the // camera can not be used. public static String getDeviceName(int index) { - Camera.CameraInfo info = new Camera.CameraInfo(); + android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); try { - Camera.getCameraInfo(index, info); + android.hardware.Camera.getCameraInfo(index, info); } catch (Exception e) { Logging.e(TAG, "getCameraInfo failed on index " + index,e); return null; } String facing = - (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) ? "front" : "back"; + (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT) ? "front" : "back"; return "Camera " + index + ", Facing " + facing + ", Orientation " + info.orientation; } @@ -159,13 +146,13 @@ // Returns the name of the front facing camera. Returns null if the // camera can not be used or does not exist. public static String getNameOfFrontFacingDevice() { - return getNameOfDevice(Camera.CameraInfo.CAMERA_FACING_FRONT); + return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT); } // Returns the name of the back facing camera. Returns null if the // camera can not be used or does not exist. public static String getNameOfBackFacingDevice() { - return getNameOfDevice(Camera.CameraInfo.CAMERA_FACING_BACK); + return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK); } public static String getSupportedFormatsAsJson(int id) throws JSONException { @@ -194,7 +181,8 @@ } } - public static int[] getFramerateRange(Camera.Parameters parameters, final int framerate) { + public static int[] getFramerateRange(android.hardware.Camera.Parameters parameters, + final int framerate) { List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange(); if (listFpsRange.isEmpty()) { Logging.w(TAG, "No supported preview fps range"); @@ -203,27 +191,30 @@ return Collections.min(listFpsRange, new ClosestComparator<int[]>() { @Override int diff(int[] range) { - return abs(framerate - range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX]) - + abs(framerate - range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); + final int maxFpsWeight = 10; + return range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + + maxFpsWeight * abs(framerate + - range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); } }); } - public static Camera.Size getClosestSupportedSize( - List<Camera.Size> supportedSizes, final int requestedWidth, final int requestedHeight) { + public static android.hardware.Camera.Size getClosestSupportedSize( + List<android.hardware.Camera.Size> supportedSizes, final int requestedWidth, + final int requestedHeight) { return Collections.min(supportedSizes, - new ClosestComparator<Camera.Size>() { - @Override int diff(Camera.Size size) { + new ClosestComparator<android.hardware.Camera.Size>() { + @Override int diff(android.hardware.Camera.Size size) { return abs(requestedWidth - size.width) + abs(requestedHeight - size.height); } }); } private static String getNameOfDevice(int facing) { - final Camera.CameraInfo info = new Camera.CameraInfo(); - for (int i = 0; i < Camera.getNumberOfCameras(); ++i) { + final android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); + for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) { try { - Camera.getCameraInfo(i, info); + android.hardware.Camera.getCameraInfo(i, info); if (info.facing == facing) { return getDeviceName(i); }
diff --git a/talk/app/webrtc/java/android/org/webrtc/CameraEnumerator.java b/talk/app/webrtc/java/android/org/webrtc/CameraEnumerator.java index 2f35dc3..54469cc 100644 --- a/talk/app/webrtc/java/android/org/webrtc/CameraEnumerator.java +++ b/talk/app/webrtc/java/android/org/webrtc/CameraEnumerator.java
@@ -27,7 +27,6 @@ package org.webrtc; -import android.hardware.Camera; import android.os.SystemClock; import org.webrtc.CameraEnumerationAndroid.CaptureFormat; @@ -60,11 +59,11 @@ private List<CaptureFormat> enumerateFormats(int cameraId) { Logging.d(TAG, "Get supported formats for camera index " + cameraId + "."); final long startTimeMs = SystemClock.elapsedRealtime(); - final Camera.Parameters parameters; - Camera camera = null; + final android.hardware.Camera.Parameters parameters; + android.hardware.Camera camera = null; try { Logging.d(TAG, "Opening camera with index " + cameraId); - camera = Camera.open(cameraId); + camera = android.hardware.Camera.open(cameraId); parameters = camera.getParameters(); } catch (RuntimeException e) { Logging.e(TAG, "Open camera failed on camera index " + cameraId, e); @@ -84,10 +83,10 @@ // getSupportedPreviewFpsRange() returns a sorted list. Take the fps range // corresponding to the highest fps. final int[] range = listFpsRange.get(listFpsRange.size() - 1); - minFps = range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX]; - maxFps = range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]; + minFps = range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX]; + maxFps = range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]; } - for (Camera.Size size : parameters.getSupportedPreviewSizes()) { + for (android.hardware.Camera.Size size : parameters.getSupportedPreviewSizes()) { formatList.add(new CaptureFormat(size.width, size.height, minFps, maxFps)); } } catch (Exception e) {
diff --git a/talk/app/webrtc/java/android/org/webrtc/EglBase.java b/talk/app/webrtc/java/android/org/webrtc/EglBase.java index 2ee3688..035645b 100644 --- a/talk/app/webrtc/java/android/org/webrtc/EglBase.java +++ b/talk/app/webrtc/java/android/org/webrtc/EglBase.java
@@ -28,244 +28,108 @@ package org.webrtc; import android.graphics.SurfaceTexture; -import android.view.SurfaceHolder; - -import org.webrtc.Logging; +import android.view.Surface; import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.egl.EGLSurface; + /** - * Holds EGL state and utility methods for handling an EGLContext, an EGLDisplay, and an EGLSurface. + * Holds EGL state and utility methods for handling an egl 1.0 EGLContext, an EGLDisplay, + * and an EGLSurface. */ -public final class EglBase { - private static final String TAG = "EglBase"; +public abstract class EglBase { + // EGL wrapper for an actual EGLContext. + public static class Context { + } + // These constants are taken from EGL14.EGL_OPENGL_ES2_BIT and EGL14.EGL_CONTEXT_CLIENT_VERSION. // https://android.googlesource.com/platform/frameworks/base/+/master/opengl/java/android/opengl/EGL14.java // This is similar to how GlSurfaceView does: // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/opengl/GLSurfaceView.java#760 private static final int EGL_OPENGL_ES2_BIT = 4; - private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; // Android-specific extension. private static final int EGL_RECORDABLE_ANDROID = 0x3142; - private final EGL10 egl; - private EGLContext eglContext; - private ConfigType configType; - private EGLConfig eglConfig; - private EGLDisplay eglDisplay; - private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; + public static final int[] CONFIG_PLAIN = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_NONE + }; + public static final int[] CONFIG_RGBA = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_NONE + }; + public static final int[] CONFIG_PIXEL_BUFFER = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, + EGL10.EGL_NONE + }; + public static final int[] CONFIG_PIXEL_RGBA_BUFFER = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, + EGL10.EGL_NONE + }; + public static final int[] CONFIG_RECORDABLE = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RECORDABLE_ANDROID, 1, + EGL10.EGL_NONE + }; - // EGLConfig constructor type. Influences eglChooseConfig arguments. - public static enum ConfigType { - // No special parameters. - PLAIN, - // Configures with EGL_SURFACE_TYPE = EGL_PBUFFER_BIT. - PIXEL_BUFFER, - // Configures with EGL_RECORDABLE_ANDROID = 1. - // Discourages EGL from using pixel formats that cannot efficiently be - // converted to something usable by the video encoder. - RECORDABLE + // Create a new context with the specified config attributes, sharing data with sharedContext. + // |sharedContext| can be null. + public static EglBase create(Context sharedContext, int[] configAttributes) { + return (EglBase14.isEGL14Supported() + && (sharedContext == null || sharedContext instanceof EglBase14.Context)) + ? new EglBase14((EglBase14.Context) sharedContext, configAttributes) + : new EglBase10((EglBase10.Context) sharedContext, configAttributes); } - // Create root context without any EGLSurface or parent EGLContext. This can be used for branching - // new contexts that share data. - public EglBase() { - this(EGL10.EGL_NO_CONTEXT, ConfigType.PLAIN); + public static EglBase create() { + return create(null, CONFIG_PLAIN); } - // Create a new context with the specified config type, sharing data with sharedContext. - public EglBase(EGLContext sharedContext, ConfigType configType) { - this.egl = (EGL10) EGLContext.getEGL(); - this.configType = configType; - eglDisplay = getEglDisplay(); - eglConfig = getEglConfig(eglDisplay, configType); - eglContext = createEglContext(sharedContext, eglDisplay, eglConfig); - } - - // Create EGLSurface from the Android SurfaceHolder. - public void createSurface(SurfaceHolder surfaceHolder) { - createSurfaceInternal(surfaceHolder); - } + public abstract void createSurface(Surface surface); // Create EGLSurface from the Android SurfaceTexture. - public void createSurface(SurfaceTexture surfaceTexture) { - createSurfaceInternal(surfaceTexture); - } - - // Create EGLSurface from either a SurfaceHolder or a SurfaceTexture. - private void createSurfaceInternal(Object nativeWindow) { - if (!(nativeWindow instanceof SurfaceHolder) && !(nativeWindow instanceof SurfaceTexture)) { - throw new IllegalStateException("Input must be either a SurfaceHolder or SurfaceTexture"); - } - checkIsNotReleased(); - if (configType == ConfigType.PIXEL_BUFFER) { - Logging.w(TAG, "This EGL context is configured for PIXEL_BUFFER, but uses regular Surface"); - } - if (eglSurface != EGL10.EGL_NO_SURFACE) { - throw new RuntimeException("Already has an EGLSurface"); - } - int[] surfaceAttribs = {EGL10.EGL_NONE}; - eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, nativeWindow, surfaceAttribs); - if (eglSurface == EGL10.EGL_NO_SURFACE) { - throw new RuntimeException("Failed to create window surface"); - } - } + public abstract void createSurface(SurfaceTexture surfaceTexture); // Create dummy 1x1 pixel buffer surface so the context can be made current. - public void createDummyPbufferSurface() { - createPbufferSurface(1, 1); - } + public abstract void createDummyPbufferSurface(); - public void createPbufferSurface(int width, int height) { - checkIsNotReleased(); - if (configType != ConfigType.PIXEL_BUFFER) { - throw new RuntimeException( - "This EGL context is not configured to use a pixel buffer: " + configType); - } - if (eglSurface != EGL10.EGL_NO_SURFACE) { - throw new RuntimeException("Already has an EGLSurface"); - } - int[] surfaceAttribs = {EGL10.EGL_WIDTH, width, EGL10.EGL_HEIGHT, height, EGL10.EGL_NONE}; - eglSurface = egl.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs); - if (eglSurface == EGL10.EGL_NO_SURFACE) { - throw new RuntimeException("Failed to create pixel buffer surface"); - } - } + public abstract void createPbufferSurface(int width, int height); - public EGLContext getContext() { - return eglContext; - } + public abstract Context getEglBaseContext(); - public boolean hasSurface() { - return eglSurface != EGL10.EGL_NO_SURFACE; - } + public abstract boolean hasSurface(); - public int surfaceWidth() { - final int widthArray[] = new int[1]; - egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, widthArray); - return widthArray[0]; - } + public abstract int surfaceWidth(); - public int surfaceHeight() { - final int heightArray[] = new int[1]; - egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, heightArray); - return heightArray[0]; - } + public abstract int surfaceHeight(); - public void releaseSurface() { - if (eglSurface != EGL10.EGL_NO_SURFACE) { - egl.eglDestroySurface(eglDisplay, eglSurface); - eglSurface = EGL10.EGL_NO_SURFACE; - } - } + public abstract void releaseSurface(); - private void checkIsNotReleased() { - if (eglDisplay == EGL10.EGL_NO_DISPLAY || eglContext == EGL10.EGL_NO_CONTEXT - || eglConfig == null) { - throw new RuntimeException("This object has been released"); - } - } + public abstract void release(); - public void release() { - checkIsNotReleased(); - releaseSurface(); - detachCurrent(); - egl.eglDestroyContext(eglDisplay, eglContext); - egl.eglTerminate(eglDisplay); - eglContext = EGL10.EGL_NO_CONTEXT; - eglDisplay = EGL10.EGL_NO_DISPLAY; - eglConfig = null; - } - - public void makeCurrent() { - checkIsNotReleased(); - if (eglSurface == EGL10.EGL_NO_SURFACE) { - throw new RuntimeException("No EGLSurface - can't make current"); - } - if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { - throw new RuntimeException("eglMakeCurrent failed"); - } - } + public abstract void makeCurrent(); // Detach the current EGL context, so that it can be made current on another thread. - public void detachCurrent() { - if (!egl.eglMakeCurrent( - eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { - throw new RuntimeException("eglMakeCurrent failed"); - } - } + public abstract void detachCurrent(); - public void swapBuffers() { - checkIsNotReleased(); - if (eglSurface == EGL10.EGL_NO_SURFACE) { - throw new RuntimeException("No EGLSurface - can't swap buffers"); - } - egl.eglSwapBuffers(eglDisplay, eglSurface); - } - - // Return an EGLDisplay, or die trying. - private EGLDisplay getEglDisplay() { - EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - if (eglDisplay == EGL10.EGL_NO_DISPLAY) { - throw new RuntimeException("Unable to get EGL10 display"); - } - int[] version = new int[2]; - if (!egl.eglInitialize(eglDisplay, version)) { - throw new RuntimeException("Unable to initialize EGL10"); - } - return eglDisplay; - } - - // Return an EGLConfig, or die trying. - private EGLConfig getEglConfig(EGLDisplay eglDisplay, ConfigType configType) { - // Always RGB888, GLES2. - int[] configAttributes = { - EGL10.EGL_RED_SIZE, 8, - EGL10.EGL_GREEN_SIZE, 8, - EGL10.EGL_BLUE_SIZE, 8, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL10.EGL_NONE, 0, // Allocate dummy fields for specific options. - EGL10.EGL_NONE - }; - - // Fill in dummy fields based on configType. - switch (configType) { - case PLAIN: - break; - case PIXEL_BUFFER: - configAttributes[configAttributes.length - 3] = EGL10.EGL_SURFACE_TYPE; - configAttributes[configAttributes.length - 2] = EGL10.EGL_PBUFFER_BIT; - break; - case RECORDABLE: - configAttributes[configAttributes.length - 3] = EGL_RECORDABLE_ANDROID; - configAttributes[configAttributes.length - 2] = 1; - break; - default: - throw new IllegalArgumentException(); - } - - EGLConfig[] configs = new EGLConfig[1]; - int[] numConfigs = new int[1]; - if (!egl.eglChooseConfig( - eglDisplay, configAttributes, configs, configs.length, numConfigs)) { - throw new RuntimeException("Unable to find RGB888 " + configType + " EGL config"); - } - return configs[0]; - } - - // Return an EGLConfig, or die trying. - private EGLContext createEglContext( - EGLContext sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) { - int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; - EGLContext eglContext = - egl.eglCreateContext(eglDisplay, eglConfig, sharedContext, contextAttributes); - if (eglContext == EGL10.EGL_NO_CONTEXT) { - throw new RuntimeException("Failed to create EGL context"); - } - return eglContext; - } + public abstract void swapBuffers(); }
diff --git a/talk/app/webrtc/java/android/org/webrtc/EglBase10.java b/talk/app/webrtc/java/android/org/webrtc/EglBase10.java new file mode 100644 index 0000000..f2aa985 --- /dev/null +++ b/talk/app/webrtc/java/android/org/webrtc/EglBase10.java
@@ -0,0 +1,299 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.webrtc; + +import android.graphics.Canvas; +import android.graphics.SurfaceTexture; +import android.graphics.Rect; +import android.view.Surface; +import android.view.SurfaceHolder; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + +/** + * Holds EGL state and utility methods for handling an egl 1.0 EGLContext, an EGLDisplay, + * and an EGLSurface. + */ +final class EglBase10 extends EglBase { + // This constant is taken from EGL14.EGL_CONTEXT_CLIENT_VERSION. + private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + + private final EGL10 egl; + private EGLContext eglContext; + private EGLConfig eglConfig; + private EGLDisplay eglDisplay; + private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; + + // EGL wrapper for an actual EGLContext. + public static class Context extends EglBase.Context { + private final EGLContext eglContext; + + public Context(EGLContext eglContext) { + this.eglContext = eglContext; + } + } + + // Create a new context with the specified config type, sharing data with sharedContext. + EglBase10(Context sharedContext, int[] configAttributes) { + this.egl = (EGL10) EGLContext.getEGL(); + eglDisplay = getEglDisplay(); + eglConfig = getEglConfig(eglDisplay, configAttributes); + eglContext = createEglContext(sharedContext, eglDisplay, eglConfig); + } + + @Override + public void createSurface(Surface surface) { + /** + * We have to wrap Surface in a SurfaceHolder because for some reason eglCreateWindowSurface + * couldn't actually take a Surface object until API 17. Older versions fortunately just call + * SurfaceHolder.getSurface(), so we'll do that. No other methods are relevant. + */ + class FakeSurfaceHolder implements SurfaceHolder { + private final Surface surface; + + FakeSurfaceHolder(Surface surface) { + this.surface = surface; + } + + @Override + public void addCallback(Callback callback) {} + + @Override + public void removeCallback(Callback callback) {} + + @Override + public boolean isCreating() { + return false; + } + + @Deprecated + @Override + public void setType(int i) {} + + @Override + public void setFixedSize(int i, int i2) {} + + @Override + public void setSizeFromLayout() {} + + @Override + public void setFormat(int i) {} + + @Override + public void setKeepScreenOn(boolean b) {} + + @Override + public Canvas lockCanvas() { + return null; + } + + @Override + public Canvas lockCanvas(Rect rect) { + return null; + } + + @Override + public void unlockCanvasAndPost(Canvas canvas) {} + + @Override + public Rect getSurfaceFrame() { + return null; + } + + @Override + public Surface getSurface() { + return surface; + } + } + + createSurfaceInternal(new FakeSurfaceHolder(surface)); + } + + // Create EGLSurface from the Android SurfaceTexture. + @Override + public void createSurface(SurfaceTexture surfaceTexture) { + createSurfaceInternal(surfaceTexture); + } + + // Create EGLSurface from either a SurfaceHolder or a SurfaceTexture. + private void createSurfaceInternal(Object nativeWindow) { + if (!(nativeWindow instanceof SurfaceHolder) && !(nativeWindow instanceof SurfaceTexture)) { + throw new IllegalStateException("Input must be either a SurfaceHolder or SurfaceTexture"); + } + checkIsNotReleased(); + if (eglSurface != EGL10.EGL_NO_SURFACE) { + throw new RuntimeException("Already has an EGLSurface"); + } + int[] surfaceAttribs = {EGL10.EGL_NONE}; + eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, nativeWindow, surfaceAttribs); + if (eglSurface == EGL10.EGL_NO_SURFACE) { + throw new RuntimeException("Failed to create window surface"); + } + } + + // Create dummy 1x1 pixel buffer surface so the context can be made current. + @Override + public void createDummyPbufferSurface() { + createPbufferSurface(1, 1); + } + + @Override + public void createPbufferSurface(int width, int height) { + checkIsNotReleased(); + if (eglSurface != EGL10.EGL_NO_SURFACE) { + throw new RuntimeException("Already has an EGLSurface"); + } + int[] surfaceAttribs = {EGL10.EGL_WIDTH, width, EGL10.EGL_HEIGHT, height, EGL10.EGL_NONE}; + eglSurface = egl.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs); + if (eglSurface == EGL10.EGL_NO_SURFACE) { + throw new RuntimeException("Failed to create pixel buffer surface"); + } + } + + @Override + public org.webrtc.EglBase.Context getEglBaseContext() { + return new EglBase10.Context(eglContext); + } + + @Override + public boolean hasSurface() { + return eglSurface != EGL10.EGL_NO_SURFACE; + } + + @Override + public int surfaceWidth() { + final int widthArray[] = new int[1]; + egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, widthArray); + return widthArray[0]; + } + + @Override + public int surfaceHeight() { + final int heightArray[] = new int[1]; + egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, heightArray); + return heightArray[0]; + } + + @Override + public void releaseSurface() { + if (eglSurface != EGL10.EGL_NO_SURFACE) { + egl.eglDestroySurface(eglDisplay, eglSurface); + eglSurface = EGL10.EGL_NO_SURFACE; + } + } + + private void checkIsNotReleased() { + if (eglDisplay == EGL10.EGL_NO_DISPLAY || eglContext == EGL10.EGL_NO_CONTEXT + || eglConfig == null) { + throw new RuntimeException("This object has been released"); + } + } + + @Override + public void release() { + checkIsNotReleased(); + releaseSurface(); + detachCurrent(); + egl.eglDestroyContext(eglDisplay, eglContext); + egl.eglTerminate(eglDisplay); + eglContext = EGL10.EGL_NO_CONTEXT; + eglDisplay = EGL10.EGL_NO_DISPLAY; + eglConfig = null; + } + + @Override + public void makeCurrent() { + checkIsNotReleased(); + if (eglSurface == EGL10.EGL_NO_SURFACE) { + throw new RuntimeException("No EGLSurface - can't make current"); + } + if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + + // Detach the current EGL context, so that it can be made current on another thread. + @Override + public void detachCurrent() { + if (!egl.eglMakeCurrent( + eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + + @Override + public void swapBuffers() { + checkIsNotReleased(); + if (eglSurface == EGL10.EGL_NO_SURFACE) { + throw new RuntimeException("No EGLSurface - can't swap buffers"); + } + egl.eglSwapBuffers(eglDisplay, eglSurface); + } + + // Return an EGLDisplay, or die trying. + private EGLDisplay getEglDisplay() { + EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + if (eglDisplay == EGL10.EGL_NO_DISPLAY) { + throw new RuntimeException("Unable to get EGL10 display"); + } + int[] version = new int[2]; + if (!egl.eglInitialize(eglDisplay, version)) { + throw new RuntimeException("Unable to initialize EGL10"); + } + return eglDisplay; + } + + // Return an EGLConfig, or die trying. + private EGLConfig getEglConfig(EGLDisplay eglDisplay, int[] configAttributes) { + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + if (!egl.eglChooseConfig( + eglDisplay, configAttributes, configs, configs.length, numConfigs)) { + throw new RuntimeException("Unable to find any matching EGL config"); + } + return configs[0]; + } + + // Return an EGLConfig, or die trying. + private EGLContext createEglContext( + Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) { + int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; + EGLContext rootContext = + sharedContext == null ? EGL10.EGL_NO_CONTEXT : sharedContext.eglContext; + EGLContext eglContext = + egl.eglCreateContext(eglDisplay, eglConfig, rootContext, contextAttributes); + if (eglContext == EGL10.EGL_NO_CONTEXT) { + throw new RuntimeException("Failed to create EGL context"); + } + return eglContext; + } +}
diff --git a/talk/app/webrtc/java/android/org/webrtc/EglBase14.java b/talk/app/webrtc/java/android/org/webrtc/EglBase14.java new file mode 100644 index 0000000..c6f98c3 --- /dev/null +++ b/talk/app/webrtc/java/android/org/webrtc/EglBase14.java
@@ -0,0 +1,254 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.webrtc; + +import android.annotation.TargetApi; +import android.graphics.SurfaceTexture; +import android.opengl.EGL14; +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLExt; +import android.opengl.EGLSurface; +import android.view.Surface; + +import org.webrtc.Logging; + +/** + * Holds EGL state and utility methods for handling an EGL14 EGLContext, an EGLDisplay, + * and an EGLSurface. + */ +@TargetApi(18) +final class EglBase14 extends EglBase { + private static final String TAG = "EglBase14"; + private static final int EGLExt_SDK_VERSION = android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; + private static final int CURRENT_SDK_VERSION = android.os.Build.VERSION.SDK_INT; + private EGLContext eglContext; + private EGLConfig eglConfig; + private EGLDisplay eglDisplay; + private EGLSurface eglSurface = EGL14.EGL_NO_SURFACE; + + // EGL 1.4 is supported from API 17. But EGLExt that is used for setting presentation + // time stamp on a surface is supported from 18 so we require 18. + public static boolean isEGL14Supported() { + Logging.d(TAG, "SDK version: " + CURRENT_SDK_VERSION + + ". isEGL14Supported: " + (CURRENT_SDK_VERSION >= EGLExt_SDK_VERSION)); + return (CURRENT_SDK_VERSION >= EGLExt_SDK_VERSION); + } + + public static class Context extends EglBase.Context { + private final android.opengl.EGLContext egl14Context; + + Context(android.opengl.EGLContext eglContext) { + this.egl14Context = eglContext; + } + } + + // Create a new context with the specified config type, sharing data with sharedContext. + // |sharedContext| may be null. + EglBase14(EglBase14.Context sharedContext, int[] configAttributes) { + eglDisplay = getEglDisplay(); + eglConfig = getEglConfig(eglDisplay, configAttributes); + eglContext = createEglContext(sharedContext, eglDisplay, eglConfig); + } + + // Create EGLSurface from the Android Surface. + @Override + public void createSurface(Surface surface) { + createSurfaceInternal(surface); + } + + // Create EGLSurface from the Android SurfaceTexture. + @Override + public void createSurface(SurfaceTexture surfaceTexture) { + createSurfaceInternal(surfaceTexture); + } + + // Create EGLSurface from either Surface or SurfaceTexture. + private void createSurfaceInternal(Object surface) { + if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) { + throw new IllegalStateException("Input must be either a Surface or SurfaceTexture"); + } + checkIsNotReleased(); + if (eglSurface != EGL14.EGL_NO_SURFACE) { + throw new RuntimeException("Already has an EGLSurface"); + } + int[] surfaceAttribs = {EGL14.EGL_NONE}; + eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, surfaceAttribs, 0); + if (eglSurface == EGL14.EGL_NO_SURFACE) { + throw new RuntimeException("Failed to create window surface"); + } + } + + @Override + public void createDummyPbufferSurface() { + createPbufferSurface(1, 1); + } + + @Override + public void createPbufferSurface(int width, int height) { + checkIsNotReleased(); + if (eglSurface != EGL14.EGL_NO_SURFACE) { + throw new RuntimeException("Already has an EGLSurface"); + } + int[] surfaceAttribs = {EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE}; + eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs, 0); + if (eglSurface == EGL14.EGL_NO_SURFACE) { + throw new RuntimeException("Failed to create pixel buffer surface"); + } + } + + @Override + public Context getEglBaseContext() { + return new EglBase14.Context(eglContext); + } + + @Override + public boolean hasSurface() { + return eglSurface != EGL14.EGL_NO_SURFACE; + } + + @Override + public int surfaceWidth() { + final int widthArray[] = new int[1]; + EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_WIDTH, widthArray, 0); + return widthArray[0]; + } + + @Override + public int surfaceHeight() { + final int heightArray[] = new int[1]; + EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_HEIGHT, heightArray, 0); + return heightArray[0]; + } + + @Override + public void releaseSurface() { + if (eglSurface != EGL14.EGL_NO_SURFACE) { + EGL14.eglDestroySurface(eglDisplay, eglSurface); + eglSurface = EGL14.EGL_NO_SURFACE; + } + } + + private void checkIsNotReleased() { + if (eglDisplay == EGL14.EGL_NO_DISPLAY || eglContext == EGL14.EGL_NO_CONTEXT + || eglConfig == null) { + throw new RuntimeException("This object has been released"); + } + } + + @Override + public void release() { + checkIsNotReleased(); + releaseSurface(); + detachCurrent(); + EGL14.eglDestroyContext(eglDisplay, eglContext); + EGL14.eglReleaseThread(); + EGL14.eglTerminate(eglDisplay); + eglContext = EGL14.EGL_NO_CONTEXT; + eglDisplay = EGL14.EGL_NO_DISPLAY; + eglConfig = null; + } + + @Override + public void makeCurrent() { + checkIsNotReleased(); + if (eglSurface == EGL14.EGL_NO_SURFACE) { + throw new RuntimeException("No EGLSurface - can't make current"); + } + if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + + // Detach the current EGL context, so that it can be made current on another thread. + @Override + public void detachCurrent() { + if (!EGL14.eglMakeCurrent( + eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + + @Override + public void swapBuffers() { + checkIsNotReleased(); + if (eglSurface == EGL14.EGL_NO_SURFACE) { + throw new RuntimeException("No EGLSurface - can't swap buffers"); + } + EGL14.eglSwapBuffers(eglDisplay, eglSurface); + } + + public void swapBuffers(long timeStampNs) { + checkIsNotReleased(); + if (eglSurface == EGL14.EGL_NO_SURFACE) { + throw new RuntimeException("No EGLSurface - can't swap buffers"); + } + // See https://android.googlesource.com/platform/frameworks/native/+/tools_r22.2/opengl/specs/EGL_ANDROID_presentation_time.txt + EGLExt.eglPresentationTimeANDROID(eglDisplay, eglSurface, timeStampNs); + EGL14.eglSwapBuffers(eglDisplay, eglSurface); + } + + // Return an EGLDisplay, or die trying. + private static EGLDisplay getEglDisplay() { + EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + if (eglDisplay == EGL14.EGL_NO_DISPLAY) { + throw new RuntimeException("Unable to get EGL14 display"); + } + int[] version = new int[2]; + if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) { + throw new RuntimeException("Unable to initialize EGL14"); + } + return eglDisplay; + } + + // Return an EGLConfig, or die trying. + private static EGLConfig getEglConfig(EGLDisplay eglDisplay, int[] configAttributes) { + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + if (!EGL14.eglChooseConfig( + eglDisplay, configAttributes, 0, configs, 0, configs.length, numConfigs, 0)) { + throw new RuntimeException("Unable to find any matching EGL config"); + } + return configs[0]; + } + + // Return an EGLConfig, or die trying. + private static EGLContext createEglContext( + EglBase14.Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) { + int[] contextAttributes = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}; + EGLContext rootContext = + sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext.egl14Context; + EGLContext eglContext = + EGL14.eglCreateContext(eglDisplay, eglConfig, rootContext, contextAttributes, 0); + if (eglContext == EGL14.EGL_NO_CONTEXT) { + throw new RuntimeException("Failed to create EGL context"); + } + return eglContext; + } +}
diff --git a/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java b/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java index 2cb8af7..6d3d5d2 100644 --- a/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java +++ b/talk/app/webrtc/java/android/org/webrtc/GlRectDrawer.java
@@ -40,13 +40,13 @@ import java.util.Map; /** - * Helper class to draw a quad that covers the entire viewport. Rotation, mirror, and cropping is - * specified using a 4x4 texture coordinate transform matrix. The frame input can either be an OES - * texture or YUV textures in I420 format. The GL state must be preserved between draw calls, this - * is intentional to maximize performance. The function release() must be called manually to free - * the resources held by this object. + * Helper class to draw an opaque quad on the target viewport location. Rotation, mirror, and + * cropping is specified using a 4x4 texture coordinate transform matrix. The frame input can either + * be an OES texture or YUV textures in I420 format. The GL state must be preserved between draw + * calls, this is intentional to maximize performance. The function release() must be called + * manually to free the resources held by this object. */ -public class GlRectDrawer { +public class GlRectDrawer implements RendererCommon.GlDrawer { // Simple vertex shader, used for both YUV and OES. private static final String VERTEX_SHADER_STRING = "varying vec2 interp_tc;\n" @@ -118,67 +118,31 @@ 1.0f, 1.0f // Top right. }); - // The keys are one of the fragments shaders above. - private final Map<String, GlShader> shaders = new IdentityHashMap<String, GlShader>(); - private GlShader currentShader; - private float[] currentTexMatrix; - private int texMatrixLocation; - // Intermediate copy buffer for uploading yuv frames that are not packed, i.e. stride > width. - // TODO(magjed): Investigate when GL_UNPACK_ROW_LENGTH is available, or make a custom shader that - // handles stride and compare performance with intermediate copy. - private ByteBuffer copyBuffer; + private static class Shader { + public final GlShader glShader; + public final int texMatrixLocation; - /** - * Upload |planes| into |outputYuvTextures|, taking stride into consideration. |outputYuvTextures| - * must have been generated in advance. - */ - public void uploadYuvData( - int[] outputYuvTextures, int width, int height, int[] strides, ByteBuffer[] planes) { - // Make a first pass to see if we need a temporary copy buffer. - int copyCapacityNeeded = 0; - for (int i = 0; i < 3; ++i) { - final int planeWidth = (i == 0) ? width : width / 2; - final int planeHeight = (i == 0) ? height : height / 2; - if (strides[i] > planeWidth) { - copyCapacityNeeded = Math.max(copyCapacityNeeded, planeWidth * planeHeight); - } - } - // Allocate copy buffer if necessary. - if (copyCapacityNeeded > 0 - && (copyBuffer == null || copyBuffer.capacity() < copyCapacityNeeded)) { - copyBuffer = ByteBuffer.allocateDirect(copyCapacityNeeded); - } - // Upload each plane. - for (int i = 0; i < 3; ++i) { - GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, outputYuvTextures[i]); - final int planeWidth = (i == 0) ? width : width / 2; - final int planeHeight = (i == 0) ? height : height / 2; - // GLES only accepts packed data, i.e. stride == planeWidth. - final ByteBuffer packedByteBuffer; - if (strides[i] == planeWidth) { - // Input is packed already. - packedByteBuffer = planes[i]; - } else { - VideoRenderer.nativeCopyPlane( - planes[i], planeWidth, planeHeight, strides[i], copyBuffer, planeWidth); - packedByteBuffer = copyBuffer; - } - GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, planeWidth, planeHeight, 0, - GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, packedByteBuffer); + public Shader(String fragmentShader) { + this.glShader = new GlShader(VERTEX_SHADER_STRING, fragmentShader); + this.texMatrixLocation = glShader.getUniformLocation("texMatrix"); } } + // The keys are one of the fragments shaders above. + private final Map<String, Shader> shaders = new IdentityHashMap<String, Shader>(); + /** * Draw an OES texture frame with specified texture transformation matrix. Required resources are * allocated at the first call to this function. */ - public void drawOes(int oesTextureId, float[] texMatrix) { - prepareShader(OES_FRAGMENT_SHADER_STRING); + @Override + public void drawOes(int oesTextureId, float[] texMatrix, int x, int y, int width, int height) { + prepareShader(OES_FRAGMENT_SHADER_STRING, texMatrix); + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); // updateTexImage() may be called from another thread in another EGL context, so we need to // bind/unbind the texture in each draw call so that GLES understads it's a new texture. GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, oesTextureId); - drawRectangle(texMatrix); + drawRectangle(x, y, width, height); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); } @@ -186,10 +150,12 @@ * Draw a RGB(A) texture frame with specified texture transformation matrix. Required resources * are allocated at the first call to this function. */ - public void drawRgb(int textureId, float[] texMatrix) { - prepareShader(RGB_FRAGMENT_SHADER_STRING); + @Override + public void drawRgb(int textureId, float[] texMatrix, int x, int y, int width, int height) { + prepareShader(RGB_FRAGMENT_SHADER_STRING, texMatrix); + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); - drawRectangle(texMatrix); + drawRectangle(x, y, width, height); // Unbind the texture as a precaution. GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); } @@ -198,14 +164,15 @@ * Draw a YUV frame with specified texture transformation matrix. Required resources are * allocated at the first call to this function. */ - public void drawYuv(int[] yuvTextures, float[] texMatrix) { - prepareShader(YUV_FRAGMENT_SHADER_STRING); + @Override + public void drawYuv(int[] yuvTextures, float[] texMatrix, int x, int y, int width, int height) { + prepareShader(YUV_FRAGMENT_SHADER_STRING, texMatrix); // Bind the textures. for (int i = 0; i < 3; ++i) { GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]); } - drawRectangle(texMatrix); + drawRectangle(x, y, width, height); // Unbind the textures as a precaution.. for (int i = 0; i < 3; ++i) { GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); @@ -213,60 +180,51 @@ } } - private void drawRectangle(float[] texMatrix) { - // Try avoid uploading the texture if possible. - if (!Arrays.equals(currentTexMatrix, texMatrix)) { - currentTexMatrix = texMatrix.clone(); - // Copy the texture transformation matrix over. - GLES20.glUniformMatrix4fv(texMatrixLocation, 1, false, texMatrix, 0); - } + private void drawRectangle(int x, int y, int width, int height) { // Draw quad. + GLES20.glViewport(x, y, width, height); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } - private void prepareShader(String fragmentShader) { - // Lazy allocation. - if (!shaders.containsKey(fragmentShader)) { - final GlShader shader = new GlShader(VERTEX_SHADER_STRING, fragmentShader); + private void prepareShader(String fragmentShader, float[] texMatrix) { + final Shader shader; + if (shaders.containsKey(fragmentShader)) { + shader = shaders.get(fragmentShader); + } else { + // Lazy allocation. + shader = new Shader(fragmentShader); shaders.put(fragmentShader, shader); - shader.useProgram(); + shader.glShader.useProgram(); // Initialize fragment shader uniform values. if (fragmentShader == YUV_FRAGMENT_SHADER_STRING) { - GLES20.glUniform1i(shader.getUniformLocation("y_tex"), 0); - GLES20.glUniform1i(shader.getUniformLocation("u_tex"), 1); - GLES20.glUniform1i(shader.getUniformLocation("v_tex"), 2); + GLES20.glUniform1i(shader.glShader.getUniformLocation("y_tex"), 0); + GLES20.glUniform1i(shader.glShader.getUniformLocation("u_tex"), 1); + GLES20.glUniform1i(shader.glShader.getUniformLocation("v_tex"), 2); } else if (fragmentShader == RGB_FRAGMENT_SHADER_STRING) { - GLES20.glUniform1i(shader.getUniformLocation("rgb_tex"), 0); + GLES20.glUniform1i(shader.glShader.getUniformLocation("rgb_tex"), 0); } else if (fragmentShader == OES_FRAGMENT_SHADER_STRING) { - GLES20.glUniform1i(shader.getUniformLocation("oes_tex"), 0); + GLES20.glUniform1i(shader.glShader.getUniformLocation("oes_tex"), 0); } else { throw new IllegalStateException("Unknown fragment shader: " + fragmentShader); } GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values."); // Initialize vertex shader attributes. - shader.setVertexAttribArray("in_pos", 2, FULL_RECTANGLE_BUF); - shader.setVertexAttribArray("in_tc", 2, FULL_RECTANGLE_TEX_BUF); + shader.glShader.setVertexAttribArray("in_pos", 2, FULL_RECTANGLE_BUF); + shader.glShader.setVertexAttribArray("in_tc", 2, FULL_RECTANGLE_TEX_BUF); } - - // Update GLES state if shader is not already current. - final GlShader shader = shaders.get(fragmentShader); - if (currentShader != shader) { - currentShader = shader; - shader.useProgram(); - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - currentTexMatrix = null; - texMatrixLocation = shader.getUniformLocation("texMatrix"); - } + shader.glShader.useProgram(); + // Copy the texture transformation matrix over. + GLES20.glUniformMatrix4fv(shader.texMatrixLocation, 1, false, texMatrix, 0); } /** * Release all GLES resources. This needs to be done manually, otherwise the resources are leaked. */ + @Override public void release() { - for (GlShader shader : shaders.values()) { - shader.release(); + for (Shader shader : shaders.values()) { + shader.glShader.release(); } shaders.clear(); - copyBuffer = null; } }
diff --git a/talk/app/webrtc/java/android/org/webrtc/NetworkMonitorAutoDetect.java b/talk/app/webrtc/java/android/org/webrtc/NetworkMonitorAutoDetect.java index e3a7850..950dcdf 100644 --- a/talk/app/webrtc/java/android/org/webrtc/NetworkMonitorAutoDetect.java +++ b/talk/app/webrtc/java/android/org/webrtc/NetworkMonitorAutoDetect.java
@@ -55,7 +55,7 @@ * ACCESS_NETWORK_STATE permission. */ public class NetworkMonitorAutoDetect extends BroadcastReceiver { - static enum ConnectionType { + public static enum ConnectionType { CONNECTION_UNKNOWN, CONNECTION_ETHERNET, CONNECTION_WIFI, @@ -96,6 +96,10 @@ /** Queries the ConnectivityManager for information about the current connection. */ static class ConnectivityManagerDelegate { + /** + * Note: In some rare Android systems connectivityManager is null. We handle that + * gracefully below. + */ private final ConnectivityManager connectivityManager; ConnectivityManagerDelegate(Context context) { @@ -114,6 +118,9 @@ * default network. */ NetworkState getNetworkState() { + if (connectivityManager == null) { + return new NetworkState(false, -1, -1); + } return getNetworkState(connectivityManager.getActiveNetworkInfo()); } @@ -123,6 +130,9 @@ */ @SuppressLint("NewApi") NetworkState getNetworkState(Network network) { + if (connectivityManager == null) { + return new NetworkState(false, -1, -1); + } return getNetworkState(connectivityManager.getNetworkInfo(network)); } @@ -142,6 +152,9 @@ */ @SuppressLint("NewApi") Network[] getAllNetworks() { + if (connectivityManager == null) { + return new Network[0]; + } return connectivityManager.getAllNetworks(); } @@ -152,6 +165,9 @@ */ @SuppressLint("NewApi") int getDefaultNetId() { + if (connectivityManager == null) { + return INVALID_NET_ID; + } // Android Lollipop had no API to get the default network; only an // API to return the NetworkInfo for the default network. To // determine the default network one can find the network with @@ -188,6 +204,9 @@ */ @SuppressLint("NewApi") boolean hasInternetCapability(Network network) { + if (connectivityManager == null) { + return false; + } final NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network); return capabilities != null && capabilities.hasCapability(NET_CAPABILITY_INTERNET); @@ -240,7 +259,6 @@ static final int INVALID_NET_ID = -1; private static final String TAG = "NetworkMonitorAutoDetect"; - private static final int UNKNOWN_LINK_SPEED = -1; private final IntentFilter intentFilter; // Observer for the connection type change.
diff --git a/talk/app/webrtc/java/android/org/webrtc/RendererCommon.java b/talk/app/webrtc/java/android/org/webrtc/RendererCommon.java index 94d180d..5ada4cc 100644 --- a/talk/app/webrtc/java/android/org/webrtc/RendererCommon.java +++ b/talk/app/webrtc/java/android/org/webrtc/RendererCommon.java
@@ -28,8 +28,11 @@ package org.webrtc; import android.graphics.Point; +import android.opengl.GLES20; import android.opengl.Matrix; +import java.nio.ByteBuffer; + /** * Static helper functions for renderer implementations. */ @@ -47,6 +50,73 @@ public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation); } + /** Interface for rendering frames on an EGLSurface. */ + public static interface GlDrawer { + /** + * Functions for drawing frames with different sources. The rendering surface target is + * implied by the current EGL context of the calling thread and requires no explicit argument. + * The coordinates specify the viewport location on the surface target. + */ + void drawOes(int oesTextureId, float[] texMatrix, int x, int y, int width, int height); + void drawRgb(int textureId, float[] texMatrix, int x, int y, int width, int height); + void drawYuv(int[] yuvTextures, float[] texMatrix, int x, int y, int width, int height); + + /** + * Release all GL resources. This needs to be done manually, otherwise resources may leak. + */ + void release(); + } + + /** + * Helper class for uploading YUV bytebuffer frames to textures that handles stride > width. This + * class keeps an internal ByteBuffer to avoid unnecessary allocations for intermediate copies. + */ + public static class YuvUploader { + // Intermediate copy buffer for uploading yuv frames that are not packed, i.e. stride > width. + // TODO(magjed): Investigate when GL_UNPACK_ROW_LENGTH is available, or make a custom shader + // that handles stride and compare performance with intermediate copy. + private ByteBuffer copyBuffer; + + /** + * Upload |planes| into |outputYuvTextures|, taking stride into consideration. + * |outputYuvTextures| must have been generated in advance. + */ + public void uploadYuvData( + int[] outputYuvTextures, int width, int height, int[] strides, ByteBuffer[] planes) { + final int[] planeWidths = new int[] {width, width / 2, width / 2}; + final int[] planeHeights = new int[] {height, height / 2, height / 2}; + // Make a first pass to see if we need a temporary copy buffer. + int copyCapacityNeeded = 0; + for (int i = 0; i < 3; ++i) { + if (strides[i] > planeWidths[i]) { + copyCapacityNeeded = Math.max(copyCapacityNeeded, planeWidths[i] * planeHeights[i]); + } + } + // Allocate copy buffer if necessary. + if (copyCapacityNeeded > 0 + && (copyBuffer == null || copyBuffer.capacity() < copyCapacityNeeded)) { + copyBuffer = ByteBuffer.allocateDirect(copyCapacityNeeded); + } + // Upload each plane. + for (int i = 0; i < 3; ++i) { + GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, outputYuvTextures[i]); + // GLES only accepts packed data, i.e. stride == planeWidth. + final ByteBuffer packedByteBuffer; + if (strides[i] == planeWidths[i]) { + // Input is packed already. + packedByteBuffer = planes[i]; + } else { + VideoRenderer.nativeCopyPlane( + planes[i], planeWidths[i], planeHeights[i], strides[i], copyBuffer, planeWidths[i]); + packedByteBuffer = copyBuffer; + } + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, planeWidths[i], + planeHeights[i], 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, packedByteBuffer); + } + } + } + // Types of video scaling: // SCALE_ASPECT_FIT - video frame is scaled to fit the size of the view by // maintaining the aspect ratio (black borders may be displayed). @@ -182,9 +252,9 @@ } // Each dimension is constrained on max display size and how much we are allowed to crop. final int width = Math.min(maxDisplayWidth, - (int) (maxDisplayHeight / minVisibleFraction * videoAspectRatio)); + Math.round(maxDisplayHeight / minVisibleFraction * videoAspectRatio)); final int height = Math.min(maxDisplayHeight, - (int) (maxDisplayWidth / minVisibleFraction / videoAspectRatio)); + Math.round(maxDisplayWidth / minVisibleFraction / videoAspectRatio)); return new Point(width, height); } }
diff --git a/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java b/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java index b9c158f..b001d2a 100644 --- a/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java +++ b/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java
@@ -35,12 +35,12 @@ import android.os.HandlerThread; import android.os.SystemClock; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import javax.microedition.khronos.egl.EGLContext; - /** * Helper class to create and synchronize access to a SurfaceTexture. The caller will get notified * of new frames in onTextureFrameAvailable(), and should call returnTextureFrame() when done with @@ -51,7 +51,7 @@ * wrapping texture frames into webrtc::VideoFrames and also handles calling returnTextureFrame() * when the webrtc::VideoFrame is no longer used. */ -final class SurfaceTextureHelper { +class SurfaceTextureHelper { private static final String TAG = "SurfaceTextureHelper"; /** * Callback interface for being notified that a new texture frame is available. The calls will be @@ -65,7 +65,7 @@ int oesTextureId, float[] transformMatrix, long timestampNs); } - public static SurfaceTextureHelper create(EGLContext sharedContext) { + public static SurfaceTextureHelper create(EglBase.Context sharedContext) { return create(sharedContext, null); } @@ -74,7 +74,8 @@ * |handler| is non-null, the callback will be executed on that handler's thread. If |handler| is * null, a dedicated private thread is created for the callbacks. */ - public static SurfaceTextureHelper create(final EGLContext sharedContext, final Handler handler) { + public static SurfaceTextureHelper create(final EglBase.Context sharedContext, + final Handler handler) { final Handler finalHandler; if (handler != null) { finalHandler = handler; @@ -94,25 +95,240 @@ }); } + // State for YUV conversion, instantiated on demand. + static private class YuvConverter { + private final EglBase eglBase; + private final GlShader shader; + private boolean released = false; + + // Vertex coordinates in Normalized Device Coordinates, i.e. + // (-1, -1) is bottom-left and (1, 1) is top-right. + private static final FloatBuffer DEVICE_RECTANGLE = + GlUtil.createFloatBuffer(new float[] { + -1.0f, -1.0f, // Bottom left. + 1.0f, -1.0f, // Bottom right. + -1.0f, 1.0f, // Top left. + 1.0f, 1.0f, // Top right. + }); + + // Texture coordinates - (0, 0) is bottom-left and (1, 1) is top-right. + private static final FloatBuffer TEXTURE_RECTANGLE = + GlUtil.createFloatBuffer(new float[] { + 0.0f, 0.0f, // Bottom left. + 1.0f, 0.0f, // Bottom right. + 0.0f, 1.0f, // Top left. + 1.0f, 1.0f // Top right. + }); + + private static final String VERTEX_SHADER = + "varying vec2 interp_tc;\n" + + "attribute vec4 in_pos;\n" + + "attribute vec4 in_tc;\n" + + "\n" + + "uniform mat4 texMatrix;\n" + + "\n" + + "void main() {\n" + + " gl_Position = in_pos;\n" + + " interp_tc = (texMatrix * in_tc).xy;\n" + + "}\n"; + + private static final String FRAGMENT_SHADER = + "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "varying vec2 interp_tc;\n" + + "\n" + + "uniform samplerExternalOES oesTex;\n" + // Difference in texture coordinate corresponding to one + // sub-pixel in the x direction. + + "uniform vec2 xUnit;\n" + // Color conversion coefficients, including constant term + + "uniform vec4 coeffs;\n" + + "\n" + + "void main() {\n" + // Since the alpha read from the texture is always 1, this could + // be written as a mat4 x vec4 multiply. However, that seems to + // give a worse framerate, possibly because the additional + // multiplies by 1.0 consume resources. TODO(nisse): Could also + // try to do it as a vec3 x mat3x4, followed by an add in of a + // constant vector. + + " gl_FragColor.r = coeffs.a + dot(coeffs.rgb,\n" + + " texture2D(oesTex, interp_tc - 1.5 * xUnit).rgb);\n" + + " gl_FragColor.g = coeffs.a + dot(coeffs.rgb,\n" + + " texture2D(oesTex, interp_tc - 0.5 * xUnit).rgb);\n" + + " gl_FragColor.b = coeffs.a + dot(coeffs.rgb,\n" + + " texture2D(oesTex, interp_tc + 0.5 * xUnit).rgb);\n" + + " gl_FragColor.a = coeffs.a + dot(coeffs.rgb,\n" + + " texture2D(oesTex, interp_tc + 1.5 * xUnit).rgb);\n" + + "}\n"; + + private int texMatrixLoc; + private int xUnitLoc; + private int coeffsLoc;; + + YuvConverter (EglBase.Context sharedContext) { + eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PIXEL_RGBA_BUFFER); + eglBase.createDummyPbufferSurface(); + eglBase.makeCurrent(); + + shader = new GlShader(VERTEX_SHADER, FRAGMENT_SHADER); + shader.useProgram(); + texMatrixLoc = shader.getUniformLocation("texMatrix"); + xUnitLoc = shader.getUniformLocation("xUnit"); + coeffsLoc = shader.getUniformLocation("coeffs"); + GLES20.glUniform1i(shader.getUniformLocation("oesTex"), 0); + GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values."); + // Initialize vertex shader attributes. + shader.setVertexAttribArray("in_pos", 2, DEVICE_RECTANGLE); + // If the width is not a multiple of 4 pixels, the texture + // will be scaled up slightly and clipped at the right border. + shader.setVertexAttribArray("in_tc", 2, TEXTURE_RECTANGLE); + eglBase.detachCurrent(); + } + + synchronized void convert(ByteBuffer buf, + int width, int height, int stride, int textureId, float [] transformMatrix) { + if (released) { + throw new IllegalStateException( + "YuvConverter.convert called on released object"); + } + + // We draw into a buffer laid out like + // + // +---------+ + // | | + // | Y | + // | | + // | | + // +----+----+ + // | U | V | + // | | | + // +----+----+ + // + // In memory, we use the same stride for all of Y, U and V. The + // U data starts at offset |height| * |stride| from the Y data, + // and the V data starts at at offset |stride/2| from the U + // data, with rows of U and V data alternating. + // + // Now, it would have made sense to allocate a pixel buffer with + // a single byte per pixel (EGL10.EGL_COLOR_BUFFER_TYPE, + // EGL10.EGL_LUMINANCE_BUFFER,), but that seems to be + // unsupported by devices. So do the following hack: Allocate an + // RGBA buffer, of width |stride|/4. To render each of these + // large pixels, sample the texture at 4 different x coordinates + // and store the results in the four components. + // + // Since the V data needs to start on a boundary of such a + // larger pixel, it is not sufficient that |stride| is even, it + // has to be a multiple of 8 pixels. + + if (stride % 8 != 0) { + throw new IllegalArgumentException( + "Invalid stride, must be a multiple of 8"); + } + if (stride < width){ + throw new IllegalArgumentException( + "Invalid stride, must >= width"); + } + + int y_width = (width+3) / 4; + int uv_width = (width+7) / 8; + int uv_height = (height+1)/2; + int total_height = height + uv_height; + int size = stride * total_height; + + if (buf.capacity() < size) { + throw new IllegalArgumentException("YuvConverter.convert called with too small buffer"); + } + // Produce a frame buffer starting at top-left corner, not + // bottom-left. + transformMatrix = + RendererCommon.multiplyMatrices(transformMatrix, + RendererCommon.verticalFlipMatrix()); + + // Create new pBuffferSurface with the correct size if needed. + if (eglBase.hasSurface()) { + if (eglBase.surfaceWidth() != stride/4 || + eglBase.surfaceHeight() != total_height){ + eglBase.releaseSurface(); + eglBase.createPbufferSurface(stride/4, total_height); + } + } else { + eglBase.createPbufferSurface(stride/4, total_height); + } + + eglBase.makeCurrent(); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId); + GLES20.glUniformMatrix4fv(texMatrixLoc, 1, false, transformMatrix, 0); + + // Draw Y + GLES20.glViewport(0, 0, y_width, height); + // Matrix * (1;0;0;0) / width. Note that opengl uses column major order. + GLES20.glUniform2f(xUnitLoc, + transformMatrix[0] / width, + transformMatrix[1] / width); + // Y'UV444 to RGB888, see + // https://en.wikipedia.org/wiki/YUV#Y.27UV444_to_RGB888_conversion. + // We use the ITU-R coefficients for U and V */ + GLES20.glUniform4f(coeffsLoc, 0.299f, 0.587f, 0.114f, 0.0f); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + + // Draw U + GLES20.glViewport(0, height, uv_width, uv_height); + // Matrix * (1;0;0;0) / (2*width). Note that opengl uses column major order. + GLES20.glUniform2f(xUnitLoc, + transformMatrix[0] / (2.0f*width), + transformMatrix[1] / (2.0f*width)); + GLES20.glUniform4f(coeffsLoc, -0.169f, -0.331f, 0.499f, 0.5f); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + + // Draw V + GLES20.glViewport(stride/8, height, uv_width, uv_height); + GLES20.glUniform4f(coeffsLoc, 0.499f, -0.418f, -0.0813f, 0.5f); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + + GLES20.glReadPixels(0, 0, stride/4, total_height, GLES20.GL_RGBA, + GLES20.GL_UNSIGNED_BYTE, buf); + + GlUtil.checkNoGLES2Error("YuvConverter.convert"); + + // Unbind texture. Reportedly needed on some devices to get + // the texture updated from the camera. + GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); + eglBase.detachCurrent(); + } + + synchronized void release() { + released = true; + eglBase.makeCurrent(); + shader.release(); + eglBase.release(); + } + } + private final Handler handler; - private final boolean isOwningThread; + private boolean isOwningThread; private final EglBase eglBase; private final SurfaceTexture surfaceTexture; private final int oesTextureId; + private YuvConverter yuvConverter; + private OnTextureFrameAvailableListener listener; // The possible states of this class. private boolean hasPendingTexture = false; - private boolean isTextureInUse = false; + private volatile boolean isTextureInUse = false; private boolean isQuitting = false; - private SurfaceTextureHelper(EGLContext sharedContext, Handler handler, boolean isOwningThread) { + private SurfaceTextureHelper(EglBase.Context sharedContext, + Handler handler, boolean isOwningThread) { if (handler.getLooper().getThread() != Thread.currentThread()) { throw new IllegalStateException("SurfaceTextureHelper must be created on the handler thread"); } this.handler = handler; this.isOwningThread = isOwningThread; - eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER); + eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PIXEL_BUFFER); eglBase.createDummyPbufferSurface(); eglBase.makeCurrent(); @@ -120,6 +336,18 @@ surfaceTexture = new SurfaceTexture(oesTextureId); } + private YuvConverter getYuvConverter() { + // yuvConverter is assigned once + if (yuvConverter != null) + return yuvConverter; + + synchronized(this) { + if (yuvConverter == null) + yuvConverter = new YuvConverter(eglBase.getEglBaseContext()); + return yuvConverter; + } + } + /** * Start to stream textures to the given |listener|. * A Listener can only be set once. @@ -164,12 +392,19 @@ }); } + public boolean isTextureInUse() { + return isTextureInUse; + } + /** * Call disconnect() to stop receiving frames. Resources are released when the texture frame has * been returned by a call to returnTextureFrame(). You are guaranteed to not receive any more * onTextureFrameAvailable() after this function returns. */ public void disconnect() { + if (!isOwningThread) { + throw new IllegalStateException("Must call disconnect(handler)."); + } if (handler.getLooper().getThread() == Thread.currentThread()) { isQuitting = true; if (!isTextureInUse) { @@ -190,6 +425,28 @@ ThreadUtils.awaitUninterruptibly(barrier); } + /** + * Call disconnect() to stop receiving frames and quit the looper used by |handler|. + * Resources are released when the texture frame has been returned by a call to + * returnTextureFrame(). You are guaranteed to not receive any more + * onTextureFrameAvailable() after this function returns. + */ + public void disconnect(Handler handler) { + if (this.handler != handler) { + throw new IllegalStateException("Wrong handler."); + } + isOwningThread = true; + disconnect(); + } + + public void textureToYUV(ByteBuffer buf, + int width, int height, int stride, int textureId, float [] transformMatrix) { + if (textureId != oesTextureId) + throw new IllegalStateException("textureToByteBuffer called with unexpected textureId"); + + getYuvConverter().convert(buf, width, height, stride, textureId, transformMatrix); + } + private void tryDeliverTextureFrame() { if (handler.getLooper().getThread() != Thread.currentThread()) { throw new IllegalStateException("Wrong thread."); @@ -218,12 +475,14 @@ if (isTextureInUse || !isQuitting) { throw new IllegalStateException("Unexpected release."); } + synchronized (this) { + if (yuvConverter != null) + yuvConverter.release(); + } eglBase.makeCurrent(); GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0); surfaceTexture.release(); eglBase.release(); - if (isOwningThread) { - handler.getLooper().quit(); - } + handler.getLooper().quit(); } }
diff --git a/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java b/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java index d7c9e2a..fa199b3 100644 --- a/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java +++ b/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java
@@ -28,10 +28,9 @@ package org.webrtc; import android.content.Context; +import android.content.res.Resources.NotFoundException; import android.graphics.Point; -import android.graphics.SurfaceTexture; import android.opengl.GLES20; -import android.opengl.Matrix; import android.os.Handler; import android.os.HandlerThread; import android.util.AttributeSet; @@ -67,7 +66,8 @@ // EGL and GL resources for drawing YUV/OES textures. After initilization, these are only accessed // from the render thread. private EglBase eglBase; - private GlRectDrawer drawer; + private final RendererCommon.YuvUploader yuvUploader = new RendererCommon.YuvUploader(); + private RendererCommon.GlDrawer drawer; // Texture ids for YUV frames. Allocated on first arrival of a YUV frame. private int[] yuvTextures = null; @@ -77,23 +77,22 @@ // These variables are synchronized on |layoutLock|. private final Object layoutLock = new Object(); - // These three different dimension values are used to keep track of the state in these functions: - // requestLayout() -> onMeasure() -> onLayout() -> surfaceChanged(). - // requestLayout() is triggered internally by frame size changes, but can also be triggered - // externally by layout update requests. - // Most recent measurement specification from onMeasure(). - private int widthSpec; - private int heightSpec; - // Current size on screen in pixels. Updated in onLayout(), and should be consistent with - // |widthSpec|/|heightSpec| after that. - private int layoutWidth; - private int layoutHeight; - // Current surface size of the underlying Surface. Updated in surfaceChanged(), and should be - // consistent with |layoutWidth|/|layoutHeight| after that. + // These dimension values are used to keep track of the state in these functions: onMeasure(), + // onLayout(), and surfaceChanged(). A new layout is triggered with requestLayout(). This happens + // internally when the incoming frame size changes. requestLayout() can also be triggered + // externally. The layout change is a two pass process: first onMeasure() is called in a top-down + // traversal of the View tree, followed by an onLayout() pass that is also top-down. During the + // onLayout() pass, each parent is responsible for positioning its children using the sizes + // computed in the measure pass. + // |desiredLayoutsize| is the layout size we have requested in onMeasure() and are waiting for to + // take effect. + private Point desiredLayoutSize = new Point(); + // |layoutSize|/|surfaceSize| is the actual current layout/surface size. They are updated in + // onLayout() and surfaceChanged() respectively. + private final Point layoutSize = new Point(); // TODO(magjed): Enable hardware scaler with SurfaceHolder.setFixedSize(). This will decouple // layout and surface size. - private int surfaceWidth; - private int surfaceHeight; + private final Point surfaceSize = new Point(); // |isSurfaceCreated| keeps track of the current status in surfaceCreated()/surfaceDestroyed(). private boolean isSurfaceCreated; // Last rendered frame dimensions, or 0 if no frame has been rendered yet. @@ -121,12 +120,18 @@ // Time in ns spent in renderFrameOnRenderThread() function. private long renderTimeNs; - // Runnable for posting frames to render thread.. + // Runnable for posting frames to render thread. private final Runnable renderFrameRunnable = new Runnable() { @Override public void run() { renderFrameOnRenderThread(); } }; + // Runnable for clearing Surface to black. + private final Runnable makeBlackRunnable = new Runnable() { + @Override public void run() { + makeBlack(); + } + }; /** * Standard View constructor. In order to render something, you must first call init(). @@ -149,17 +154,28 @@ * reinitialize the renderer after a previous init()/release() cycle. */ public void init( - EGLContext sharedContext, RendererCommon.RendererEvents rendererEvents) { + EglBase.Context sharedContext, RendererCommon.RendererEvents rendererEvents) { + init(sharedContext, rendererEvents, EglBase.CONFIG_PLAIN, new GlRectDrawer()); + } + + /** + * Initialize this class, sharing resources with |sharedContext|. The custom |drawer| will be used + * for drawing frames on the EGLSurface. This class is responsible for calling release() on + * |drawer|. It is allowed to call init() to reinitialize the renderer after a previous + * init()/release() cycle. + */ + public void init(EglBase.Context sharedContext, RendererCommon.RendererEvents rendererEvents, + int[] configAttributes, RendererCommon.GlDrawer drawer) { synchronized (handlerLock) { if (renderThreadHandler != null) { - throw new IllegalStateException("Already initialized"); + throw new IllegalStateException(getResourceName() + "Already initialized"); } - Logging.d(TAG, "Initializing"); + Logging.d(TAG, getResourceName() + "Initializing."); this.rendererEvents = rendererEvents; + this.drawer = drawer; renderThread = new HandlerThread(TAG); renderThread.start(); - drawer = new GlRectDrawer(); - eglBase = new EglBase(sharedContext, EglBase.ConfigType.PLAIN); + eglBase = EglBase.create(sharedContext, configAttributes); renderThreadHandler = new Handler(renderThread.getLooper()); } tryCreateEglSurface(); @@ -174,8 +190,8 @@ runOnRenderThread(new Runnable() { @Override public void run() { synchronized (layoutLock) { - if (isSurfaceCreated) { - eglBase.createSurface(getHolder()); + if (isSurfaceCreated && !eglBase.hasSurface()) { + eglBase.createSurface(getHolder().getSurface()); eglBase.makeCurrent(); // Necessary for YUV frames with odd width. GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); @@ -195,7 +211,7 @@ final CountDownLatch eglCleanupBarrier = new CountDownLatch(1); synchronized (handlerLock) { if (renderThreadHandler == null) { - Logging.d(TAG, "Already released"); + Logging.d(TAG, getResourceName() + "Already released"); return; } // Release EGL and GL resources on render thread. @@ -210,11 +226,8 @@ GLES20.glDeleteTextures(3, yuvTextures, 0); yuvTextures = null; } - if (eglBase.hasSurface()) { - // Clear last rendered image to black. - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - eglBase.swapBuffers(); - } + // Clear last rendered image to black. + makeBlack(); eglBase.release(); eglBase = null; eglCleanupBarrier.countDown(); @@ -242,6 +255,14 @@ frameRotation = 0; rendererEvents = null; } + resetStatistics(); + } + + /** + * Reset statistics. This will reset the logged statistics in logStatistics(), and + * RendererEvents.onFirstFrameRendered() will be called for the next frame. + */ + public void resetStatistics() { synchronized (statisticsLock) { framesReceived = 0; framesDropped = 0; @@ -277,27 +298,28 @@ } synchronized (handlerLock) { if (renderThreadHandler == null) { - Logging.d(TAG, "Dropping frame - SurfaceViewRenderer not initialized or already released."); - } else { - synchronized (frameLock) { - if (pendingFrame == null) { - updateFrameDimensionsAndReportEvents(frame); - pendingFrame = frame; - renderThreadHandler.post(renderFrameRunnable); - return; + Logging.d(TAG, getResourceName() + + "Dropping frame - Not initialized or already released."); + VideoRenderer.renderFrameDone(frame); + return; + } + synchronized (frameLock) { + if (pendingFrame != null) { + // Drop old frame. + synchronized (statisticsLock) { + ++framesDropped; } + VideoRenderer.renderFrameDone(pendingFrame); } + pendingFrame = frame; + updateFrameDimensionsAndReportEvents(frame); + renderThreadHandler.post(renderFrameRunnable); } } - // Drop frame. - synchronized (statisticsLock) { - ++framesDropped; - } - VideoRenderer.renderFrameDone(frame); } // Returns desired layout size given current measure specification and video aspect ratio. - private Point getDesiredLayoutSize() { + private Point getDesiredLayoutSize(int widthSpec, int heightSpec) { synchronized (layoutLock) { final int maxWidth = getDefaultSize(Integer.MAX_VALUE, widthSpec); final int maxHeight = getDefaultSize(Integer.MAX_VALUE, heightSpec); @@ -317,18 +339,30 @@ @Override protected void onMeasure(int widthSpec, int heightSpec) { synchronized (layoutLock) { - this.widthSpec = widthSpec; - this.heightSpec = heightSpec; - final Point size = getDesiredLayoutSize(); - setMeasuredDimension(size.x, size.y); + if (frameWidth == 0 || frameHeight == 0) { + super.onMeasure(widthSpec, heightSpec); + return; + } + desiredLayoutSize = getDesiredLayoutSize(widthSpec, heightSpec); + if (desiredLayoutSize.x != getMeasuredWidth() || desiredLayoutSize.y != getMeasuredHeight()) { + // Clear the surface asap before the layout change to avoid stretched video and other + // render artifacs. Don't wait for it to finish because the IO thread should never be + // blocked, so it's a best-effort attempt. + synchronized (handlerLock) { + if (renderThreadHandler != null) { + renderThreadHandler.postAtFrontOfQueue(makeBlackRunnable); + } + } + } + setMeasuredDimension(desiredLayoutSize.x, desiredLayoutSize.y); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { synchronized (layoutLock) { - layoutWidth = right - left; - layoutHeight = bottom - top; + layoutSize.x = right - left; + layoutSize.y = bottom - top; } // Might have a pending frame waiting for a layout of correct size. runOnRenderThread(renderFrameRunnable); @@ -337,7 +371,7 @@ // SurfaceHolder.Callback interface. @Override public void surfaceCreated(final SurfaceHolder holder) { - Logging.d(TAG, "Surface created"); + Logging.d(TAG, getResourceName() + "Surface created."); synchronized (layoutLock) { isSurfaceCreated = true; } @@ -346,11 +380,11 @@ @Override public void surfaceDestroyed(SurfaceHolder holder) { - Logging.d(TAG, "Surface destroyed"); + Logging.d(TAG, getResourceName() + "Surface destroyed."); synchronized (layoutLock) { isSurfaceCreated = false; - surfaceWidth = 0; - surfaceHeight = 0; + surfaceSize.x = 0; + surfaceSize.y = 0; } runOnRenderThread(new Runnable() { @Override public void run() { @@ -361,10 +395,10 @@ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Logging.d(TAG, "Surface changed: " + width + "x" + height); + Logging.d(TAG, getResourceName() + "Surface changed: " + width + "x" + height); synchronized (layoutLock) { - surfaceWidth = width; - surfaceHeight = height; + surfaceSize.x = width; + surfaceSize.y = height; } // Might have a pending frame waiting for a surface of correct size. runOnRenderThread(renderFrameRunnable); @@ -381,26 +415,35 @@ } } + private String getResourceName() { + try { + return getResources().getResourceEntryName(getId()) + ": "; + } catch (NotFoundException e) { + return ""; + } + } + + private void makeBlack() { + if (Thread.currentThread() != renderThread) { + throw new IllegalStateException(getResourceName() + "Wrong thread."); + } + if (eglBase != null && eglBase.hasSurface()) { + GLES20.glClearColor(0, 0, 0, 0); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + eglBase.swapBuffers(); + } + } + /** * Requests new layout if necessary. Returns true if layout and surface size are consistent. */ private boolean checkConsistentLayout() { + if (Thread.currentThread() != renderThread) { + throw new IllegalStateException(getResourceName() + "Wrong thread."); + } synchronized (layoutLock) { - final Point desiredLayoutSize = getDesiredLayoutSize(); - if (desiredLayoutSize.x != layoutWidth || desiredLayoutSize.y != layoutHeight) { - Logging.d(TAG, "Requesting new layout with size: " - + desiredLayoutSize.x + "x" + desiredLayoutSize.y); - // Request layout update on UI thread. - post(new Runnable() { - @Override public void run() { - requestLayout(); - } - }); - return false; - } - // Wait for requestLayout() to propagate through this sequence before returning true: - // requestLayout() -> onMeasure() -> onLayout() -> surfaceChanged(). - return surfaceWidth == layoutWidth && surfaceHeight == layoutHeight; + // Return false while we are in the middle of a layout change. + return layoutSize.equals(desiredLayoutSize) && surfaceSize.equals(layoutSize); } } @@ -408,24 +451,8 @@ * Renders and releases |pendingFrame|. */ private void renderFrameOnRenderThread() { - if (eglBase == null || !eglBase.hasSurface()) { - Logging.d(TAG, "No surface to draw on"); - return; - } - if (!checkConsistentLayout()) { - // Output intermediate black frames while the layout is updated. - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - eglBase.swapBuffers(); - return; - } - // After a surface size change, the EGLSurface might still have a buffer of the old size in the - // pipeline. Querying the EGLSurface will show if the underlying buffer dimensions haven't yet - // changed. Such a buffer will be rendered incorrectly, so flush it with a black frame. - synchronized (layoutLock) { - if (eglBase.surfaceWidth() != surfaceWidth || eglBase.surfaceHeight() != surfaceHeight) { - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - eglBase.swapBuffers(); - } + if (Thread.currentThread() != renderThread) { + throw new IllegalStateException(getResourceName() + "Wrong thread."); } // Fetch and render |pendingFrame|. final VideoRenderer.I420Frame frame; @@ -436,33 +463,39 @@ frame = pendingFrame; pendingFrame = null; } - - final long startTimeNs = System.nanoTime(); - final float[] samplingMatrix; - if (frame.yuvFrame) { - // The convention in WebRTC is that the first element in a ByteBuffer corresponds to the - // top-left corner of the image, but in glTexImage2D() the first element corresponds to the - // bottom-left corner. We correct this discrepancy by setting a vertical flip as sampling - // matrix. - samplingMatrix = RendererCommon.verticalFlipMatrix(); - } else { - // TODO(magjed): Move updateTexImage() to the video source instead. - SurfaceTexture surfaceTexture = (SurfaceTexture) frame.textureObject; - surfaceTexture.updateTexImage(); - samplingMatrix = new float[16]; - surfaceTexture.getTransformMatrix(samplingMatrix); + if (eglBase == null || !eglBase.hasSurface()) { + Logging.d(TAG, getResourceName() + "No surface to draw on"); + VideoRenderer.renderFrameDone(frame); + return; + } + if (!checkConsistentLayout()) { + // Output intermediate black frames while the layout is updated. + makeBlack(); + VideoRenderer.renderFrameDone(frame); + return; + } + // After a surface size change, the EGLSurface might still have a buffer of the old size in the + // pipeline. Querying the EGLSurface will show if the underlying buffer dimensions haven't yet + // changed. Such a buffer will be rendered incorrectly, so flush it with a black frame. + synchronized (layoutLock) { + if (eglBase.surfaceWidth() != surfaceSize.x || eglBase.surfaceHeight() != surfaceSize.y) { + makeBlack(); + } } + final long startTimeNs = System.nanoTime(); final float[] texMatrix; synchronized (layoutLock) { final float[] rotatedSamplingMatrix = - RendererCommon.rotateTextureMatrix(samplingMatrix, frame.rotationDegree); + RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotationDegree); final float[] layoutMatrix = RendererCommon.getLayoutMatrix( - mirror, frameAspectRatio(), (float) layoutWidth / layoutHeight); + mirror, frameAspectRatio(), (float) layoutSize.x / layoutSize.y); texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutMatrix); } - GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight); + // TODO(magjed): glClear() shouldn't be necessary since every pixel is covered anyway, but it's + // a workaround for bug 5147. Performance will be slightly worse. + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); if (frame.yuvFrame) { // Make sure YUV textures are allocated. if (yuvTextures == null) { @@ -471,11 +504,11 @@ yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); } } - drawer.uploadYuvData( + yuvUploader.uploadYuvData( yuvTextures, frame.width, frame.height, frame.yuvStrides, frame.yuvPlanes); - drawer.drawYuv(yuvTextures, texMatrix); + drawer.drawYuv(yuvTextures, texMatrix, 0, 0, surfaceSize.x, surfaceSize.y); } else { - drawer.drawOes(frame.textureId, texMatrix); + drawer.drawOes(frame.textureId, texMatrix, 0, 0, surfaceSize.x, surfaceSize.y); } eglBase.swapBuffers(); @@ -483,6 +516,12 @@ synchronized (statisticsLock) { if (framesRendered == 0) { firstFrameTimeNs = startTimeNs; + synchronized (layoutLock) { + Logging.d(TAG, getResourceName() + "Reporting first rendered frame."); + if (rendererEvents != null) { + rendererEvents.onFirstFrameRendered(); + } + } } ++framesRendered; renderTimeNs += (System.nanoTime() - startTimeNs); @@ -508,32 +547,32 @@ synchronized (layoutLock) { if (frameWidth != frame.width || frameHeight != frame.height || frameRotation != frame.rotationDegree) { + Logging.d(TAG, getResourceName() + "Reporting frame resolution changed to " + + frame.width + "x" + frame.height + " with rotation " + frame.rotationDegree); if (rendererEvents != null) { - final String id = getResources().getResourceEntryName(getId()); - if (frameWidth == 0 || frameHeight == 0) { - Logging.d(TAG, "ID: " + id + ". Reporting first rendered frame."); - rendererEvents.onFirstFrameRendered(); - } - Logging.d(TAG, "ID: " + id + ". Reporting frame resolution changed to " - + frame.width + "x" + frame.height + " with rotation " + frame.rotationDegree); rendererEvents.onFrameResolutionChanged(frame.width, frame.height, frame.rotationDegree); } frameWidth = frame.width; frameHeight = frame.height; frameRotation = frame.rotationDegree; + post(new Runnable() { + @Override public void run() { + requestLayout(); + } + }); } } } private void logStatistics() { synchronized (statisticsLock) { - Logging.d(TAG, "ID: " + getResources().getResourceEntryName(getId()) + ". Frames received: " + Logging.d(TAG, getResourceName() + "Frames received: " + framesReceived + ". Dropped: " + framesDropped + ". Rendered: " + framesRendered); if (framesReceived > 0 && framesRendered > 0) { final long timeSinceFirstFrameNs = System.nanoTime() - firstFrameTimeNs; - Logging.d(TAG, "Duration: " + (int) (timeSinceFirstFrameNs / 1e6) + - " ms. FPS: " + (float) framesRendered * 1e9 / timeSinceFirstFrameNs); - Logging.d(TAG, "Average render time: " + Logging.d(TAG, getResourceName() + "Duration: " + (int) (timeSinceFirstFrameNs / 1e6) + + " ms. FPS: " + framesRendered * 1e9 / timeSinceFirstFrameNs); + Logging.d(TAG, getResourceName() + "Average render time: " + (int) (renderTimeNs / (1000 * framesRendered)) + " us."); } }
diff --git a/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java b/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java index 0d8968a..e60ead9 100644 --- a/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java +++ b/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java
@@ -28,11 +28,13 @@ package org.webrtc; import android.os.Handler; +import android.os.SystemClock; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; -final class ThreadUtils { +public class ThreadUtils { /** * Utility class to be used for checking that a method is called on the correct thread. */ @@ -86,6 +88,29 @@ } } + public static boolean joinUninterruptibly(final Thread thread, long timeoutMs) { + final long startTimeMs = SystemClock.elapsedRealtime(); + long timeRemainingMs = timeoutMs; + boolean wasInterrupted = false; + while (timeRemainingMs > 0) { + try { + thread.join(timeRemainingMs); + break; + } catch (InterruptedException e) { + // Someone is asking us to return early at our convenience. We can't cancel this operation, + // but we should preserve the information and pass it along. + wasInterrupted = true; + final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; + timeRemainingMs = timeoutMs - elapsedTimeMs; + } + } + // Pass interruption information along. + if (wasInterrupted) { + Thread.currentThread().interrupt(); + } + return !thread.isAlive(); + } + public static void joinUninterruptibly(final Thread thread) { executeUninterruptibly(new BlockingOperation() { @Override @@ -104,6 +129,30 @@ }); } + public static boolean awaitUninterruptibly(CountDownLatch barrier, long timeoutMs) { + final long startTimeMs = SystemClock.elapsedRealtime(); + long timeRemainingMs = timeoutMs; + boolean wasInterrupted = false; + boolean result = false; + do { + try { + result = barrier.await(timeRemainingMs, TimeUnit.MILLISECONDS); + break; + } catch (InterruptedException e) { + // Someone is asking us to return early at our convenience. We can't cancel this operation, + // but we should preserve the information and pass it along. + wasInterrupted = true; + final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; + timeRemainingMs = timeoutMs - elapsedTimeMs; + } + } while (timeRemainingMs > 0); + // Pass interruption information along. + if (wasInterrupted) { + Thread.currentThread().interrupt(); + } + return result; + } + /** * Post |callable| to |handler| and wait for the result. */
diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java index 4caefc5..36f60ed 100644 --- a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java +++ b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java
@@ -28,9 +28,6 @@ package org.webrtc; import android.content.Context; -import android.graphics.SurfaceTexture; -import android.hardware.Camera; -import android.hardware.Camera.PreviewCallback; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; @@ -53,9 +50,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGL10; - // Android specific implementation of VideoCapturer. // An instance of this class can be created by an application using // VideoCapturerAndroid.create(); @@ -68,21 +62,22 @@ // camera thread. The internal *OnCameraThread() methods must check |camera| for null to check if // the camera has been stopped. @SuppressWarnings("deprecation") -public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallback, +public class VideoCapturerAndroid extends VideoCapturer implements + android.hardware.Camera.PreviewCallback, SurfaceTextureHelper.OnTextureFrameAvailableListener { private final static String TAG = "VideoCapturerAndroid"; private final static int CAMERA_OBSERVER_PERIOD_MS = 2000; + private final static int CAMERA_FREEZE_REPORT_TIMOUT_MS = 6000; - private Camera camera; // Only non-null while capturing. + private android.hardware.Camera camera; // Only non-null while capturing. private HandlerThread cameraThread; private final Handler cameraThreadHandler; private Context applicationContext; // Synchronization lock for |id|. private final Object cameraIdLock = new Object(); private int id; - private Camera.CameraInfo info; - private final FramePool videoBuffers; - private final CameraStatistics cameraStatistics = new CameraStatistics(); + private android.hardware.Camera.CameraInfo info; + private final CameraStatistics cameraStatistics; // Remember the requested format in case we want to switch cameras. private int requestedWidth; private int requestedHeight; @@ -94,17 +89,28 @@ private CapturerObserver frameObserver = null; private final CameraEventsHandler eventsHandler; private boolean firstFrameReported; + // Arbitrary queue depth. Higher number means more memory allocated & held, + // lower number means more sensitivity to processing time in the client (and + // potentially stalling the capturer if it runs out of buffers to write to). + private static final int NUMBER_OF_CAPTURE_BUFFERS = 3; + private final Set<byte[]> queuedBuffers = new HashSet<byte[]>(); private final boolean isCapturingToTexture; - private final SurfaceTextureHelper surfaceHelper; + final SurfaceTextureHelper surfaceHelper; // Package visible for testing purposes. // The camera API can output one old frame after the camera has been switched or the resolution // has been changed. This flag is used for dropping the first frame after camera restart. private boolean dropNextFrame = false; + // |openCameraOnCodecThreadRunner| is used for retrying to open the camera if it is in use by + // another application when startCaptureOnCameraThread is called. + private Runnable openCameraOnCodecThreadRunner; + private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; + private final static int OPEN_CAMERA_DELAY_MS = 500; + private int openCameraAttempts; // Camera error callback. - private final Camera.ErrorCallback cameraErrorCallback = - new Camera.ErrorCallback() { + private final android.hardware.Camera.ErrorCallback cameraErrorCallback = + new android.hardware.Camera.ErrorCallback() { @Override - public void onError(int error, Camera camera) { + public void onError(int error, android.hardware.Camera camera) { String errorMessage; if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { errorMessage = "Camera server died!"; @@ -120,47 +126,45 @@ // Camera observer - monitors camera framerate. Observer is executed on camera thread. private final Runnable cameraObserver = new Runnable() { + private int freezePeriodCount; @Override public void run() { int cameraFramesCount = cameraStatistics.getAndResetFrameCount(); int cameraFps = (cameraFramesCount * 1000 + CAMERA_OBSERVER_PERIOD_MS / 2) / CAMERA_OBSERVER_PERIOD_MS; - Logging.d(TAG, "Camera fps: " + cameraFps + - ". Pending buffers: " + cameraStatistics.pendingFramesTimeStamps()); + Logging.d(TAG, "Camera fps: " + cameraFps +"."); if (cameraFramesCount == 0) { - Logging.e(TAG, "Camera freezed."); - if (eventsHandler != null) { - eventsHandler.onCameraError("Camera failure."); + ++freezePeriodCount; + if (CAMERA_OBSERVER_PERIOD_MS * freezePeriodCount > CAMERA_FREEZE_REPORT_TIMOUT_MS + && eventsHandler != null) { + Logging.e(TAG, "Camera freezed."); + if (surfaceHelper.isTextureInUse()) { + // This can only happen if we are capturing to textures. + eventsHandler.onCameraFreezed("Camera failure. Client must return video buffers."); + } else { + eventsHandler.onCameraFreezed("Camera failure."); + } + return; } } else { - cameraThreadHandler.postDelayed(this, CAMERA_OBSERVER_PERIOD_MS); + freezePeriodCount = 0; } + cameraThreadHandler.postDelayed(this, CAMERA_OBSERVER_PERIOD_MS); } }; private static class CameraStatistics { private int frameCount = 0; private final ThreadUtils.ThreadChecker threadChecker = new ThreadUtils.ThreadChecker(); - private final Set<Long> timeStampsNs = new HashSet<Long>(); CameraStatistics() { threadChecker.detachThread(); } - public void addPendingFrame(long timestamp) { + public void addFrame() { threadChecker.checkIsOnValidThread(); ++frameCount; - timeStampsNs.add(timestamp); - } - - public void frameReturned(long timestamp) { - threadChecker.checkIsOnValidThread(); - if (!timeStampsNs.contains(timestamp)) { - throw new IllegalStateException( - "CameraStatistics.frameReturned called with unknown timestamp " + timestamp); - } - timeStampsNs.remove(timestamp); } public int getAndResetFrameCount() { @@ -169,28 +173,16 @@ frameCount = 0; return count; } - - // Return number of pending frames that have not been returned. - public int pendingFramesCount() { - threadChecker.checkIsOnValidThread(); - return timeStampsNs.size(); - } - - public String pendingFramesTimeStamps() { - threadChecker.checkIsOnValidThread(); - List<Long> timeStampsMs = new ArrayList<Long>(); - for (long ts : timeStampsNs) { - timeStampsMs.add(TimeUnit.NANOSECONDS.toMillis(ts)); - } - return timeStampsMs.toString(); - } } public static interface CameraEventsHandler { - // Camera error handler - invoked when camera stops receiving frames + // Camera error handler - invoked when camera can not be opened // or any camera exception happens on camera thread. void onCameraError(String errorDescription); + // Invoked when camera stops receiving frames + void onCameraFreezed(String errorDescription); + // Callback invoked when camera is opening. void onCameraOpening(int cameraId); @@ -216,7 +208,7 @@ } public static VideoCapturerAndroid create(String name, - CameraEventsHandler eventsHandler, EGLContext sharedEglContext) { + CameraEventsHandler eventsHandler, EglBase.Context sharedEglContext) { final int cameraId = lookupDeviceName(name); if (cameraId == -1) { return null; @@ -224,7 +216,8 @@ final VideoCapturerAndroid capturer = new VideoCapturerAndroid(cameraId, eventsHandler, sharedEglContext); - capturer.setNativeCapturer(nativeCreateVideoCapturer(capturer)); + capturer.setNativeCapturer( + nativeCreateVideoCapturer(capturer, capturer.surfaceHelper)); return capturer; } @@ -243,7 +236,7 @@ // Switch camera to the next valid camera id. This can only be called while // the camera is running. public void switchCamera(final CameraSwitchHandler handler) { - if (Camera.getNumberOfCameras() < 2) { + if (android.hardware.Camera.getNumberOfCameras() < 2) { if (handler != null) { handler.onCameraSwitchError("No camera to switch to."); } @@ -274,7 +267,8 @@ pendingCameraSwitch = false; } if (handler != null) { - handler.onCameraSwitchDone(info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT); + handler.onCameraSwitchDone( + info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT); } } }); @@ -282,6 +276,8 @@ // Requests a new output format from the video capturer. Captured frames // by the camera will be scaled/or dropped by the video capturer. + // It does not matter if width and height are flipped. I.E, |width| = 640, |height| = 480 produce + // the same result as |width| = 480, |height| = 640. // TODO(magjed/perkj): Document what this function does. Change name? public void onOutputFormatRequest(final int width, final int height, final int framerate) { cameraThreadHandler.post(new Runnable() { @@ -303,7 +299,7 @@ // Helper function to retrieve the current camera id synchronously. Note that the camera id might // change at any point by switchCamera() calls. - private int getCurrentCameraId() { + int getCurrentCameraId() { synchronized (cameraIdLock) { return id; } @@ -329,20 +325,19 @@ } private VideoCapturerAndroid(int cameraId, CameraEventsHandler eventsHandler, - EGLContext sharedContext) { - Logging.d(TAG, "VideoCapturerAndroid"); + EglBase.Context sharedContext) { this.id = cameraId; this.eventsHandler = eventsHandler; cameraThread = new HandlerThread(TAG); cameraThread.start(); cameraThreadHandler = new Handler(cameraThread.getLooper()); - videoBuffers = new FramePool(cameraThread); isCapturingToTexture = (sharedContext != null); - surfaceHelper = SurfaceTextureHelper.create( - isCapturingToTexture ? sharedContext : EGL10.EGL_NO_CONTEXT, cameraThreadHandler); + cameraStatistics = new CameraStatistics(); + surfaceHelper = SurfaceTextureHelper.create(sharedContext, cameraThreadHandler); if (isCapturingToTexture) { surfaceHelper.setListener(this); } + Logging.d(TAG, "VideoCapturerAndroid isCapturingToTexture : " + isCapturingToTexture); } private void checkIsOnCameraThread() { @@ -355,13 +350,13 @@ // found. If |deviceName| is empty, the first available device is used. private static int lookupDeviceName(String deviceName) { Logging.d(TAG, "lookupDeviceName: " + deviceName); - if (deviceName == null || Camera.getNumberOfCameras() == 0) { + if (deviceName == null || android.hardware.Camera.getNumberOfCameras() == 0) { return -1; } if (deviceName.isEmpty()) { return 0; } - for (int i = 0; i < Camera.getNumberOfCameras(); ++i) { + for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) { if (deviceName.equals(CameraEnumerationAndroid.getDeviceName(i))) { return i; } @@ -382,14 +377,9 @@ if (camera != null) { throw new IllegalStateException("Release called while camera is running"); } - if (cameraStatistics.pendingFramesCount() != 0) { - throw new IllegalStateException("Release called with pending frames left"); - } } }); - surfaceHelper.disconnect(); - cameraThread.quit(); - ThreadUtils.joinUninterruptibly(cameraThread); + surfaceHelper.disconnect(cameraThreadHandler); cameraThread = null; } @@ -413,6 +403,7 @@ if (frameObserver == null) { throw new RuntimeException("frameObserver not set."); } + cameraThreadHandler.post(new Runnable() { @Override public void run() { startCaptureOnCameraThread(width, height, framerate, frameObserver, @@ -422,8 +413,8 @@ } private void startCaptureOnCameraThread( - int width, int height, int framerate, CapturerObserver frameObserver, - Context applicationContext) { + final int width, final int height, final int framerate, final CapturerObserver frameObserver, + final Context applicationContext) { Throwable error = null; checkIsOnCameraThread(); if (camera != null) { @@ -431,17 +422,36 @@ } this.applicationContext = applicationContext; this.frameObserver = frameObserver; + this.firstFrameReported = false; + try { - synchronized (cameraIdLock) { - Logging.d(TAG, "Opening camera " + id); - firstFrameReported = false; - if (eventsHandler != null) { - eventsHandler.onCameraOpening(id); + try { + synchronized (cameraIdLock) { + Logging.d(TAG, "Opening camera " + id); + if (eventsHandler != null) { + eventsHandler.onCameraOpening(id); + } + camera = android.hardware.Camera.open(id); + info = new android.hardware.Camera.CameraInfo(); + android.hardware.Camera.getCameraInfo(id, info); } - camera = Camera.open(id); - info = new Camera.CameraInfo(); - Camera.getCameraInfo(id, info); + } catch (RuntimeException e) { + openCameraAttempts++; + if (openCameraAttempts < MAX_OPEN_CAMERA_ATTEMPTS) { + Logging.e(TAG, "Camera.open failed, retrying", e); + openCameraOnCodecThreadRunner = new Runnable() { + @Override public void run() { + startCaptureOnCameraThread(width, height, framerate, frameObserver, + applicationContext); + } + }; + cameraThreadHandler.postDelayed(openCameraOnCodecThreadRunner, OPEN_CAMERA_DELAY_MS); + return; + } + openCameraAttempts = 0; + throw e; } + try { camera.setPreviewTexture(surfaceHelper.getSurfaceTexture()); } catch (IOException e) { @@ -485,17 +495,18 @@ requestedFramerate = framerate; // Find closest supported format for |width| x |height| @ |framerate|. - final Camera.Parameters parameters = camera.getParameters(); + final android.hardware.Camera.Parameters parameters = camera.getParameters(); final int[] range = CameraEnumerationAndroid.getFramerateRange(parameters, framerate * 1000); - final Camera.Size previewSize = CameraEnumerationAndroid.getClosestSupportedSize( - parameters.getSupportedPreviewSizes(), width, height); + final android.hardware.Camera.Size previewSize = + CameraEnumerationAndroid.getClosestSupportedSize( + parameters.getSupportedPreviewSizes(), width, height); final CaptureFormat captureFormat = new CaptureFormat( previewSize.width, previewSize.height, - range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], - range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); + range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX], + range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); // Check if we are already using this capture format, then we don't need to do anything. - if (captureFormat.equals(this.captureFormat)) { + if (captureFormat.isSameFormat(this.captureFormat)) { return; } @@ -511,11 +522,15 @@ parameters.setPreviewFpsRange(captureFormat.minFramerate, captureFormat.maxFramerate); } parameters.setPreviewSize(captureFormat.width, captureFormat.height); - parameters.setPreviewFormat(captureFormat.imageFormat); + + if (!isCapturingToTexture) { + parameters.setPreviewFormat(captureFormat.imageFormat); + } // Picture size is for taking pictures and not for preview/video, but we need to set it anyway // as a workaround for an aspect ratio problem on Nexus 7. - final Camera.Size pictureSize = CameraEnumerationAndroid.getClosestSupportedSize( - parameters.getSupportedPictureSizes(), width, height); + final android.hardware.Camera.Size pictureSize = + CameraEnumerationAndroid.getClosestSupportedSize( + parameters.getSupportedPictureSizes(), width, height); parameters.setPictureSize(pictureSize.width, pictureSize.height); // Temporarily stop preview if it's already running. @@ -532,13 +547,19 @@ this.captureFormat = captureFormat; List<String> focusModes = parameters.getSupportedFocusModes(); - if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { - parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); + if (focusModes.contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { + parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); } camera.setParameters(parameters); if (!isCapturingToTexture) { - videoBuffers.queueCameraBuffers(captureFormat.frameSize(), camera); + queuedBuffers.clear(); + final int frameSize = captureFormat.frameSize(); + for (int i = 0; i < NUMBER_OF_CAPTURE_BUFFERS; ++i) { + final ByteBuffer buffer = ByteBuffer.allocateDirect(frameSize); + queuedBuffers.add(buffer.array()); + camera.addCallbackBuffer(buffer.array()); + } camera.setPreviewCallbackWithBuffer(this); } camera.startPreview(); @@ -561,6 +582,10 @@ private void stopCaptureOnCameraThread() { checkIsOnCameraThread(); Logging.d(TAG, "stopCaptureOnCameraThread"); + if (openCameraOnCodecThreadRunner != null) { + cameraThreadHandler.removeCallbacks(openCameraOnCodecThreadRunner); + } + openCameraAttempts = 0; if (camera == null) { Logging.e(TAG, "Calling stopCapture() for already stopped camera."); return; @@ -571,13 +596,7 @@ Logging.d(TAG, "Stop preview."); camera.stopPreview(); camera.setPreviewCallbackWithBuffer(null); - if (!isCapturingToTexture()) { - videoBuffers.stopReturnBuffersToCamera(); - Logging.d(TAG, "stopReturnBuffersToCamera called." - + (cameraStatistics.pendingFramesCount() == 0? - " All buffers have been returned." - : " Pending buffers: " + cameraStatistics.pendingFramesTimeStamps() + ".")); - } + queuedBuffers.clear(); captureFormat = null; Logging.d(TAG, "Release camera."); @@ -593,7 +612,7 @@ Logging.d(TAG, "switchCameraOnCameraThread"); stopCaptureOnCameraThread(); synchronized (cameraIdLock) { - id = (id + 1) % Camera.getNumberOfCameras(); + id = (id + 1) % android.hardware.Camera.getNumberOfCameras(); } dropNextFrame = true; startCaptureOnCameraThread(requestedWidth, requestedHeight, requestedFramerate, frameObserver, @@ -612,17 +631,9 @@ frameObserver.onOutputFormatRequest(width, height, framerate); } - public void returnBuffer(final long timeStamp) { - cameraThreadHandler.post(new Runnable() { - @Override public void run() { - cameraStatistics.frameReturned(timeStamp); - if (isCapturingToTexture) { - surfaceHelper.returnTextureFrame(); - } else { - videoBuffers.returnBuffer(timeStamp); - } - } - }); + // Exposed for testing purposes only. + Handler getCameraThreadHandler() { + return cameraThreadHandler; } private int getDeviceOrientation() { @@ -650,7 +661,7 @@ private int getFrameOrientation() { int rotation = getDeviceOrientation(); - if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { + if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) { rotation = 360 - rotation; } return (info.orientation + rotation) % 360; @@ -658,9 +669,10 @@ // Called on cameraThread so must not "synchronized". @Override - public void onPreviewFrame(byte[] data, Camera callbackCamera) { + public void onPreviewFrame(byte[] data, android.hardware.Camera callbackCamera) { checkIsOnCameraThread(); - if (camera == null) { + if (camera == null || !queuedBuffers.contains(data)) { + // The camera has been stopped or |data| is an old invalid buffer. return; } if (camera != callbackCamera) { @@ -675,16 +687,10 @@ firstFrameReported = true; } - // Mark the frame owning |data| as used. - // Note that since data is directBuffer, - // data.length >= videoBuffers.frameSize. - if (videoBuffers.reserveByteBuffer(data, captureTimeNs)) { - cameraStatistics.addPendingFrame(captureTimeNs); - frameObserver.onByteBufferFrameCaptured(data, videoBuffers.frameSize, captureFormat.width, - captureFormat.height, getFrameOrientation(), captureTimeNs); - } else { - Logging.w(TAG, "reserveByteBuffer failed - dropping frame."); - } + cameraStatistics.addFrame(); + frameObserver.onByteBufferFrameCaptured(data, captureFormat.width, captureFormat.height, + getFrameOrientation(), captureTimeNs); + camera.addCallbackBuffer(data); } @Override @@ -696,135 +702,22 @@ surfaceHelper.returnTextureFrame(); return; } - if (!dropNextFrame) { + if (dropNextFrame) { surfaceHelper.returnTextureFrame(); - dropNextFrame = true; + dropNextFrame = false; return; } int rotation = getFrameOrientation(); - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT) { // Undo the mirror that the OS "helps" us with. // http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int) transformMatrix = RendererCommon.multiplyMatrices(transformMatrix, RendererCommon.horizontalFlipMatrix()); } - transformMatrix = RendererCommon.rotateTextureMatrix(transformMatrix, rotation); - - final int rotatedWidth = (rotation % 180 == 0) ? captureFormat.width : captureFormat.height; - final int rotatedHeight = (rotation % 180 == 0) ? captureFormat.height : captureFormat.width; - cameraStatistics.addPendingFrame(timestampNs); - frameObserver.onTextureFrameCaptured(rotatedWidth, rotatedHeight, oesTextureId, - transformMatrix, timestampNs); - } - - // Class used for allocating and bookkeeping video frames. All buffers are - // direct allocated so that they can be directly used from native code. This class is - // not thread-safe, and enforces single thread use. - private static class FramePool { - // Thread that all calls should be made on. - private final Thread thread; - // Arbitrary queue depth. Higher number means more memory allocated & held, - // lower number means more sensitivity to processing time in the client (and - // potentially stalling the capturer if it runs out of buffers to write to). - private static final int numCaptureBuffers = 3; - // This container tracks the buffers added as camera callback buffers. It is needed for finding - // the corresponding ByteBuffer given a byte[]. - private final Map<byte[], ByteBuffer> queuedBuffers = new IdentityHashMap<byte[], ByteBuffer>(); - // This container tracks the frames that have been sent but not returned. It is needed for - // keeping the buffers alive and for finding the corresponding ByteBuffer given a timestamp. - private final Map<Long, ByteBuffer> pendingBuffers = new HashMap<Long, ByteBuffer>(); - private int frameSize = 0; - private Camera camera; - - public FramePool(Thread thread) { - this.thread = thread; - } - - private void checkIsOnValidThread() { - if (Thread.currentThread() != thread) { - throw new IllegalStateException("Wrong thread"); - } - } - - // Discards previous queued buffers and adds new callback buffers to camera. - public void queueCameraBuffers(int frameSize, Camera camera) { - checkIsOnValidThread(); - this.camera = camera; - this.frameSize = frameSize; - - queuedBuffers.clear(); - for (int i = 0; i < numCaptureBuffers; ++i) { - final ByteBuffer buffer = ByteBuffer.allocateDirect(frameSize); - camera.addCallbackBuffer(buffer.array()); - queuedBuffers.put(buffer.array(), buffer); - } - Logging.d(TAG, "queueCameraBuffers enqueued " + numCaptureBuffers - + " buffers of size " + frameSize + "."); - } - - public void stopReturnBuffersToCamera() { - checkIsOnValidThread(); - this.camera = null; - queuedBuffers.clear(); - // Frames in |pendingBuffers| need to be kept alive until they are returned. - } - - public boolean reserveByteBuffer(byte[] data, long timeStamp) { - checkIsOnValidThread(); - final ByteBuffer buffer = queuedBuffers.remove(data); - if (buffer == null) { - // Frames might be posted to |onPreviewFrame| with the previous format while changing - // capture format in |startPreviewOnCameraThread|. Drop these old frames. - Logging.w(TAG, "Received callback buffer from previous configuration with length: " - + (data == null ? "null" : data.length)); - return false; - } - if (buffer.capacity() != frameSize) { - throw new IllegalStateException("Callback buffer has unexpected frame size"); - } - if (pendingBuffers.containsKey(timeStamp)) { - Logging.e(TAG, "Timestamp already present in pending buffers - they need to be unique"); - return false; - } - pendingBuffers.put(timeStamp, buffer); - if (queuedBuffers.isEmpty()) { - Logging.d(TAG, "Camera is running out of capture buffers."); - } - return true; - } - - public void returnBuffer(long timeStamp) { - checkIsOnValidThread(); - final ByteBuffer returnedFrame = pendingBuffers.remove(timeStamp); - if (returnedFrame == null) { - throw new RuntimeException("unknown data buffer with time stamp " - + timeStamp + "returned?!?"); - } - - if (camera != null && returnedFrame.capacity() == frameSize) { - camera.addCallbackBuffer(returnedFrame.array()); - if (queuedBuffers.isEmpty()) { - Logging.d(TAG, "Frame returned when camera is running out of capture" - + " buffers for TS " + TimeUnit.NANOSECONDS.toMillis(timeStamp)); - } - queuedBuffers.put(returnedFrame.array(), returnedFrame); - return; - } - - if (returnedFrame.capacity() != frameSize) { - Logging.d(TAG, "returnBuffer with time stamp " - + TimeUnit.NANOSECONDS.toMillis(timeStamp) - + " called with old frame size, " + returnedFrame.capacity() + "."); - // Since this frame has the wrong size, don't requeue it. Frames with the correct size are - // created in queueCameraBuffers so this must be an old buffer. - return; - } - - Logging.d(TAG, "returnBuffer with time stamp " - + TimeUnit.NANOSECONDS.toMillis(timeStamp) - + " called after camera has been stopped."); - } + cameraStatistics.addFrame(); + frameObserver.onTextureFrameCaptured(captureFormat.width, captureFormat.height, oesTextureId, + transformMatrix, rotation, timestampNs); } // Interface used for providing callbacks to an observer. @@ -835,13 +728,14 @@ // Delivers a captured frame. Called on a Java thread owned by // VideoCapturerAndroid. - abstract void onByteBufferFrameCaptured(byte[] data, int length, int width, int height, - int rotation, long timeStamp); + abstract void onByteBufferFrameCaptured(byte[] data, int width, int height, int rotation, + long timeStamp); // Delivers a captured frame in a texture with id |oesTextureId|. Called on a Java thread // owned by VideoCapturerAndroid. abstract void onTextureFrameCaptured( - int width, int height, int oesTextureId, float[] transformMatrix, long timestamp); + int width, int height, int oesTextureId, float[] transformMatrix, int rotation, + long timestamp); // Requests an output format from the video capturer. Captured frames // by the camera will be scaled/or dropped by the video capturer. @@ -864,17 +758,18 @@ } @Override - public void onByteBufferFrameCaptured(byte[] data, int length, int width, int height, + public void onByteBufferFrameCaptured(byte[] data, int width, int height, int rotation, long timeStamp) { - nativeOnByteBufferFrameCaptured(nativeCapturer, data, length, width, height, rotation, + nativeOnByteBufferFrameCaptured(nativeCapturer, data, data.length, width, height, rotation, timeStamp); } @Override public void onTextureFrameCaptured( - int width, int height, int oesTextureId, float[] transformMatrix, long timestamp) { + int width, int height, int oesTextureId, float[] transformMatrix, int rotation, + long timestamp) { nativeOnTextureFrameCaptured(nativeCapturer, width, height, oesTextureId, transformMatrix, - timestamp); + rotation, timestamp); } @Override @@ -887,10 +782,12 @@ private native void nativeOnByteBufferFrameCaptured(long nativeCapturer, byte[] data, int length, int width, int height, int rotation, long timeStamp); private native void nativeOnTextureFrameCaptured(long nativeCapturer, int width, int height, - int oesTextureId, float[] transformMatrix, long timestamp); + int oesTextureId, float[] transformMatrix, int rotation, long timestamp); private native void nativeOnOutputFormatRequest(long nativeCapturer, int width, int height, int framerate); } - private static native long nativeCreateVideoCapturer(VideoCapturerAndroid videoCapturer); + private static native long nativeCreateVideoCapturer( + VideoCapturerAndroid videoCapturer, + SurfaceTextureHelper surfaceHelper); }
diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java index bacd0cf..bb6f01c 100644 --- a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java +++ b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
@@ -38,7 +38,7 @@ import android.annotation.SuppressLint; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.SurfaceTexture; +import android.opengl.EGL14; import android.opengl.GLES20; import android.opengl.GLSurfaceView; @@ -59,7 +59,7 @@ private static Runnable eglContextReady = null; private static final String TAG = "VideoRendererGui"; private GLSurfaceView surface; - private static EGLContext eglContext = null; + private static EglBase.Context eglContext = null; // Indicates if SurfaceView.Renderer.onSurfaceCreated was called. // If true then for every newly created yuv image renderer createTexture() // should be called. The variable is accessed on multiple threads and @@ -69,8 +69,6 @@ private int screenHeight; // List of yuv renderers. private final ArrayList<YuvImageRenderer> yuvImageRenderers; - // |drawer| is synchronized on |yuvImageRenderers|. - private GlRectDrawer drawer; // Render and draw threads. private static Thread renderFrameThread; private static Thread drawThread; @@ -99,6 +97,8 @@ // currently leaking resources to avoid a rare crash in release() where the EGLContext has // become invalid beforehand. private int[] yuvTextures = { 0, 0, 0 }; + private final RendererCommon.YuvUploader yuvUploader = new RendererCommon.YuvUploader(); + private final RendererCommon.GlDrawer drawer; // Resources for making a deep copy of incoming OES texture frame. private GlTextureFrameBuffer textureCopy; @@ -157,12 +157,13 @@ private YuvImageRenderer( GLSurfaceView surface, int id, int x, int y, int width, int height, - RendererCommon.ScalingType scalingType, boolean mirror) { + RendererCommon.ScalingType scalingType, boolean mirror, RendererCommon.GlDrawer drawer) { Logging.d(TAG, "YuvImageRenderer.Create id: " + id); this.surface = surface; this.id = id; this.scalingType = scalingType; this.mirror = mirror; + this.drawer = drawer; layoutInPercentage = new Rect(x, y, Math.min(100, x + width), Math.min(100, y + height)); updateLayoutProperties = false; rotationDegree = 0; @@ -174,6 +175,7 @@ private synchronized void release() { surface = null; + drawer.release(); synchronized (pendingFrameLock) { if (pendingFrame != null) { VideoRenderer.renderFrameDone(pendingFrame); @@ -226,7 +228,7 @@ } } - private void draw(GlRectDrawer drawer) { + private void draw() { if (!seenFrame) { // No frame received yet - nothing to render. return; @@ -241,29 +243,15 @@ } if (isNewFrame) { + rotatedSamplingMatrix = RendererCommon.rotateTextureMatrix( + pendingFrame.samplingMatrix, pendingFrame.rotationDegree); if (pendingFrame.yuvFrame) { rendererType = RendererType.RENDERER_YUV; - drawer.uploadYuvData(yuvTextures, pendingFrame.width, pendingFrame.height, + yuvUploader.uploadYuvData(yuvTextures, pendingFrame.width, pendingFrame.height, pendingFrame.yuvStrides, pendingFrame.yuvPlanes); - // The convention in WebRTC is that the first element in a ByteBuffer corresponds to the - // top-left corner of the image, but in glTexImage2D() the first element corresponds to - // the bottom-left corner. We correct this discrepancy by setting a vertical flip as - // sampling matrix. - final float[] samplingMatrix = RendererCommon.verticalFlipMatrix(); - rotatedSamplingMatrix = - RendererCommon.rotateTextureMatrix(samplingMatrix, pendingFrame.rotationDegree); } else { rendererType = RendererType.RENDERER_TEXTURE; - // External texture rendering. Update texture image to latest and make a deep copy of - // the external texture. - // TODO(magjed): Move updateTexImage() to the video source instead. - final SurfaceTexture surfaceTexture = (SurfaceTexture) pendingFrame.textureObject; - surfaceTexture.updateTexImage(); - final float[] samplingMatrix = new float[16]; - surfaceTexture.getTransformMatrix(samplingMatrix); - rotatedSamplingMatrix = - RendererCommon.rotateTextureMatrix(samplingMatrix, pendingFrame.rotationDegree); - + // External texture rendering. Make a deep copy of the external texture. // Reallocate offscreen texture if necessary. textureCopy.setSize(pendingFrame.rotatedWidth(), pendingFrame.rotatedHeight()); @@ -272,12 +260,13 @@ GlUtil.checkNoGLES2Error("glBindFramebuffer"); // Copy the OES texture content. This will also normalize the sampling matrix. - GLES20.glViewport(0, 0, textureCopy.getWidth(), textureCopy.getHeight()); - drawer.drawOes(pendingFrame.textureId, rotatedSamplingMatrix); + drawer.drawOes(pendingFrame.textureId, rotatedSamplingMatrix, + 0, 0, textureCopy.getWidth(), textureCopy.getHeight()); rotatedSamplingMatrix = RendererCommon.identityMatrix(); // Restore normal framebuffer. GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); + GLES20.glFinish(); } copyTimeNs += (System.nanoTime() - now); VideoRenderer.renderFrameDone(pendingFrame); @@ -285,17 +274,17 @@ } } - // OpenGL defaults to lower left origin - flip vertically. - GLES20.glViewport(displayLayout.left, screenHeight - displayLayout.bottom, - displayLayout.width(), displayLayout.height()); - updateLayoutMatrix(); final float[] texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutMatrix); + // OpenGL defaults to lower left origin - flip viewport position vertically. + final int viewportY = screenHeight - displayLayout.bottom; if (rendererType == RendererType.RENDERER_YUV) { - drawer.drawYuv(yuvTextures, texMatrix); + drawer.drawYuv(yuvTextures, texMatrix, + displayLayout.left, viewportY, displayLayout.width(), displayLayout.height()); } else { - drawer.drawRgb(textureCopy.getTextureId(), texMatrix); + drawer.drawRgb(textureCopy.getTextureId(), texMatrix, + displayLayout.left, viewportY, displayLayout.width(), displayLayout.height()); } if (isNewFrame) { @@ -314,7 +303,7 @@ ". Dropped: " + framesDropped + ". Rendered: " + framesRendered); if (framesReceived > 0 && framesRendered > 0) { Logging.d(TAG, "Duration: " + (int)(timeSinceFirstFrameNs / 1e6) + - " ms. FPS: " + (float)framesRendered * 1e9 / timeSinceFirstFrameNs); + " ms. FPS: " + framesRendered * 1e9 / timeSinceFirstFrameNs); Logging.d(TAG, "Draw time: " + (int) (drawTimeNs / (1000 * framesRendered)) + " us. Copy time: " + (int) (copyTimeNs / (1000 * framesReceived)) + " us"); @@ -429,7 +418,7 @@ eglContextReady = eglContextReadyCallback; } - public static synchronized EGLContext getEGLContext() { + public static synchronized EglBase.Context getEglBaseContext() { return eglContext; } @@ -477,6 +466,16 @@ */ public static synchronized YuvImageRenderer create(int x, int y, int width, int height, RendererCommon.ScalingType scalingType, boolean mirror) { + return create(x, y, width, height, scalingType, mirror, new GlRectDrawer()); + } + + /** + * Creates VideoRenderer.Callbacks with top left corner at (x, y) and resolution (width, height). + * All parameters are in percentage of screen resolution. The custom |drawer| will be used for + * drawing frames on the EGLSurface. This class is responsible for calling release() on |drawer|. + */ + public static synchronized YuvImageRenderer create(int x, int y, int width, int height, + RendererCommon.ScalingType scalingType, boolean mirror, RendererCommon.GlDrawer drawer) { // Check display region parameters. if (x < 0 || x > 100 || y < 0 || y > 100 || width < 0 || width > 100 || height < 0 || height > 100 || @@ -490,7 +489,7 @@ } final YuvImageRenderer yuvImageRenderer = new YuvImageRenderer( instance.surface, instance.yuvImageRenderers.size(), - x, y, width, height, scalingType, mirror); + x, y, width, height, scalingType, mirror, drawer); synchronized (instance.yuvImageRenderers) { if (instance.onSurfaceCreatedCalled) { // onSurfaceCreated has already been called for VideoRendererGui - @@ -498,6 +497,7 @@ // rendering list. final CountDownLatch countDownLatch = new CountDownLatch(1); instance.surface.queueEvent(new Runnable() { + @Override public void run() { yuvImageRenderer.createTextures(); yuvImageRenderer.setScreenSize( @@ -608,13 +608,16 @@ Logging.d(TAG, "VideoRendererGui.onSurfaceCreated"); // Store render EGL context. synchronized (VideoRendererGui.class) { - eglContext = ((EGL10) EGLContext.getEGL()).eglGetCurrentContext(); + if (EglBase14.isEGL14Supported()) { + eglContext = new EglBase14.Context(EGL14.eglGetCurrentContext()); + } else { + eglContext = new EglBase10.Context(((EGL10) EGLContext.getEGL()).eglGetCurrentContext()); + } + Logging.d(TAG, "VideoRendererGui EGL Context: " + eglContext); } synchronized (yuvImageRenderers) { - // Create drawer for YUV/OES frames. - drawer = new GlRectDrawer(); // Create textures for all images. for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { yuvImageRenderer.createTextures(); @@ -655,7 +658,7 @@ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); synchronized (yuvImageRenderers) { for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { - yuvImageRenderer.draw(drawer); + yuvImageRenderer.draw(); } } }
diff --git a/talk/app/webrtc/java/jni/androidmediacodeccommon.h b/talk/app/webrtc/java/jni/androidmediacodeccommon.h index 348a716..92ea135 100644 --- a/talk/app/webrtc/java/jni/androidmediacodeccommon.h +++ b/talk/app/webrtc/java/jni/androidmediacodeccommon.h
@@ -72,6 +72,8 @@ enum { kMediaCodecStatisticsIntervalMs = 3000 }; // Maximum amount of pending frames for VP8 decoder. enum { kMaxPendingFramesVp8 = 1 }; +// Maximum amount of pending frames for VP9 decoder. +enum { kMaxPendingFramesVp9 = 1 }; // Maximum amount of pending frames for H.264 decoder. enum { kMaxPendingFramesH264 = 30 }; // Maximum amount of decoded frames for which per-frame logging is enabled.
diff --git a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc index b664f16..c3d287c 100644 --- a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc +++ b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
@@ -33,14 +33,15 @@ #include "talk/app/webrtc/java/jni/androidmediacodeccommon.h" #include "talk/app/webrtc/java/jni/classreferenceholder.h" #include "talk/app/webrtc/java/jni/native_handle_impl.h" +#include "talk/app/webrtc/java/jni/surfacetexturehelper_jni.h" #include "webrtc/base/bind.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/base/thread.h" #include "webrtc/base/timeutils.h" -#include "webrtc/common_video/interface/i420_buffer_pool.h" -#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" +#include "webrtc/common_video/include/i420_buffer_pool.h" +#include "webrtc/modules/video_coding/include/video_codec_interface.h" #include "webrtc/system_wrappers/include/logcat_trace_context.h" #include "webrtc/system_wrappers/include/tick_util.h" #include "third_party/libyuv/include/libyuv/convert.h" @@ -62,6 +63,7 @@ using webrtc::VideoCodecType; using webrtc::kVideoCodecH264; using webrtc::kVideoCodecVP8; +using webrtc::kVideoCodecVP9; namespace webrtc_jni { @@ -87,9 +89,14 @@ int32_t Release() override; int32_t Reset() override; + + bool PrefersLateDecoding() const override { return true; } + // rtc::MessageHandler implementation. void OnMessage(rtc::Message* msg) override; + const char* ImplementationName() const override; + private: // CHECK-fail if not running on |codec_thread_|. void CheckOnCodecThread(); @@ -105,13 +112,17 @@ // Type of video codec. VideoCodecType codecType_; + // Render EGL context - owned by factory, should not be allocated/destroyed + // by VideoDecoder. + jobject render_egl_context_; + bool key_frame_required_; bool inited_; bool sw_fallback_required_; bool use_surface_; VideoCodec codec_; webrtc::I420BufferPool decoded_frame_pool_; - NativeHandleImpl native_handle_; + rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_; DecodedImageCallback* callback_; int frames_received_; // Number of frames received by decoder. int frames_decoded_; // Number of frames decoded by decoder. @@ -120,10 +131,6 @@ int current_bytes_; // Encoded bytes in the current statistics interval. int current_decoding_time_ms_; // Overall decoding time in the current second uint32_t max_pending_frames_; // Maximum number of pending input frames - std::vector<int32_t> timestamps_; - std::vector<int64_t> ntp_times_ms_; - std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to - // decoder input. // State that is constant for the lifetime of this object once the ctor // returns. @@ -134,7 +141,8 @@ jmethodID j_release_method_; jmethodID j_dequeue_input_buffer_method_; jmethodID j_queue_input_buffer_method_; - jmethodID j_dequeue_output_buffer_method_; + jmethodID j_dequeue_byte_buffer_method_; + jmethodID j_dequeue_texture_buffer_method_; jmethodID j_return_decoded_byte_buffer_method_; // MediaCodecVideoDecoder fields. jfieldID j_input_buffers_field_; @@ -144,24 +152,23 @@ jfieldID j_height_field_; jfieldID j_stride_field_; jfieldID j_slice_height_field_; - jfieldID j_surface_texture_field_; // MediaCodecVideoDecoder.DecodedTextureBuffer fields. - jfieldID j_textureID_field_; - jfieldID j_texture_presentation_timestamp_us_field_; - // MediaCodecVideoDecoder.DecodedByteBuffer fields. + jfieldID j_texture_id_field_; + jfieldID j_transform_matrix_field_; + jfieldID j_texture_timestamp_ms_field_; + jfieldID j_texture_ntp_timestamp_ms_field_; + jfieldID j_texture_decode_time_ms_field_; + jfieldID j_texture_frame_delay_ms_field_; + // MediaCodecVideoDecoder.DecodedOutputBuffer fields. jfieldID j_info_index_field_; jfieldID j_info_offset_field_; jfieldID j_info_size_field_; - jfieldID j_info_presentation_timestamp_us_field_; + jfieldID j_info_timestamp_ms_field_; + jfieldID j_info_ntp_timestamp_ms_field_; + jfieldID j_byte_buffer_decode_time_ms_field_; // Global references; must be deleted in Release(). std::vector<jobject> input_buffers_; - jobject surface_texture_; - jobject previous_surface_texture_; - - // Render EGL context - owned by factory, should not be allocated/destroyed - // by VideoDecoder. - jobject render_egl_context_; }; MediaCodecVideoDecoder::MediaCodecVideoDecoder( @@ -171,8 +178,6 @@ key_frame_required_(true), inited_(false), sw_fallback_required_(false), - surface_texture_(NULL), - previous_surface_texture_(NULL), codec_thread_(new Thread()), j_media_codec_video_decoder_class_( jni, @@ -191,19 +196,22 @@ j_init_decode_method_ = GetMethodID( jni, *j_media_codec_video_decoder_class_, "initDecode", "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;" - "IILjavax/microedition/khronos/egl/EGLContext;)Z"); + "IILorg/webrtc/SurfaceTextureHelper;)Z"); j_release_method_ = GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V"); j_dequeue_input_buffer_method_ = GetMethodID( jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I"); j_queue_input_buffer_method_ = GetMethodID( - jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z"); - j_dequeue_output_buffer_method_ = GetMethodID( + jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z"); + j_dequeue_byte_buffer_method_ = GetMethodID( jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer", - "(I)Ljava/lang/Object;"); + "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;"); + j_dequeue_texture_buffer_method_ = GetMethodID( + jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer", + "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;"); j_return_decoded_byte_buffer_method_ = GetMethodID(jni, *j_media_codec_video_decoder_class_, - "returnDecodedByteBuffer", "(I)V"); + "returnDecodedOutputBuffer", "(I)V"); j_input_buffers_field_ = GetFieldID( jni, *j_media_codec_video_decoder_class_, @@ -221,28 +229,36 @@ jni, *j_media_codec_video_decoder_class_, "stride", "I"); j_slice_height_field_ = GetFieldID( jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I"); - j_surface_texture_field_ = GetFieldID( - jni, *j_media_codec_video_decoder_class_, "surfaceTexture", - "Landroid/graphics/SurfaceTexture;"); - jclass j_decoder_decoded_texture_buffer_class = FindClass(jni, + jclass j_decoded_texture_buffer_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer"); - j_textureID_field_ = GetFieldID( - jni, j_decoder_decoded_texture_buffer_class, "textureID", "I"); - j_texture_presentation_timestamp_us_field_ = - GetFieldID(jni, j_decoder_decoded_texture_buffer_class, - "presentationTimestampUs", "J"); + j_texture_id_field_ = GetFieldID( + jni, j_decoded_texture_buffer_class, "textureID", "I"); + j_transform_matrix_field_ = GetFieldID( + jni, j_decoded_texture_buffer_class, "transformMatrix", "[F"); + j_texture_timestamp_ms_field_ = GetFieldID( + jni, j_decoded_texture_buffer_class, "timeStampMs", "J"); + j_texture_ntp_timestamp_ms_field_ = GetFieldID( + jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J"); + j_texture_decode_time_ms_field_ = GetFieldID( + jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J"); + j_texture_frame_delay_ms_field_ = GetFieldID( + jni, j_decoded_texture_buffer_class, "frameDelayMs", "J"); - jclass j_decoder_decoded_byte_buffer_class = FindClass(jni, - "org/webrtc/MediaCodecVideoDecoder$DecodedByteBuffer"); + jclass j_decoded_output_buffer_class = FindClass(jni, + "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer"); j_info_index_field_ = GetFieldID( - jni, j_decoder_decoded_byte_buffer_class, "index", "I"); + jni, j_decoded_output_buffer_class, "index", "I"); j_info_offset_field_ = GetFieldID( - jni, j_decoder_decoded_byte_buffer_class, "offset", "I"); + jni, j_decoded_output_buffer_class, "offset", "I"); j_info_size_field_ = GetFieldID( - jni, j_decoder_decoded_byte_buffer_class, "size", "I"); - j_info_presentation_timestamp_us_field_ = GetFieldID( - jni, j_decoder_decoded_byte_buffer_class, "presentationTimestampUs", "J"); + jni, j_decoded_output_buffer_class, "size", "I"); + j_info_timestamp_ms_field_ = GetFieldID( + jni, j_decoded_output_buffer_class, "timeStampMs", "J"); + j_info_ntp_timestamp_ms_field_ = GetFieldID( + jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J"); + j_byte_buffer_decode_time_ms_field_ = GetFieldID( + jni, j_decoded_output_buffer_class, "decodeTimeMs", "J"); CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed"; use_surface_ = (render_egl_context_ != NULL); @@ -254,14 +270,6 @@ MediaCodecVideoDecoder::~MediaCodecVideoDecoder() { // Call Release() to ensure no more callbacks to us after we are deleted. Release(); - // Delete global references. - JNIEnv* jni = AttachCurrentThreadIfNeeded(); - if (previous_surface_texture_ != NULL) { - jni->DeleteGlobalRef(previous_surface_texture_); - } - if (surface_texture_ != NULL) { - jni->DeleteGlobalRef(surface_texture_); - } } int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst, @@ -312,6 +320,21 @@ frames_received_ = 0; frames_decoded_ = 0; + jobject java_surface_texture_helper_ = nullptr; + if (use_surface_) { + java_surface_texture_helper_ = jni->CallStaticObjectMethod( + FindClass(jni, "org/webrtc/SurfaceTextureHelper"), + GetStaticMethodID(jni, + FindClass(jni, "org/webrtc/SurfaceTextureHelper"), + "create", + "(Lorg/webrtc/EglBase$Context;)" + "Lorg/webrtc/SurfaceTextureHelper;"), + render_egl_context_); + RTC_CHECK(java_surface_texture_helper_ != nullptr); + surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>( + jni, java_surface_texture_helper_); + } + jobject j_video_codec_enum = JavaEnumFromIndex( jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_); bool success = jni->CallBooleanMethod( @@ -320,7 +343,7 @@ j_video_codec_enum, codec_.width, codec_.height, - use_surface_ ? render_egl_context_ : nullptr); + java_surface_texture_helper_); if (CheckException(jni) || !success) { ALOGE << "Codec initialization error - fallback to SW codec."; sw_fallback_required_ = true; @@ -332,6 +355,9 @@ case kVideoCodecVP8: max_pending_frames_ = kMaxPendingFramesVp8; break; + case kVideoCodecVP9: + max_pending_frames_ = kMaxPendingFramesVp9; + break; case kVideoCodecH264: max_pending_frames_ = kMaxPendingFramesH264; break; @@ -342,9 +368,6 @@ current_frames_ = 0; current_bytes_ = 0; current_decoding_time_ms_ = 0; - timestamps_.clear(); - ntp_times_ms_.clear(); - frame_rtc_times_ms_.clear(); jobjectArray input_buffers = (jobjectArray)GetObjectField( jni, *j_media_codec_video_decoder_, j_input_buffers_field_); @@ -361,15 +384,6 @@ } } - if (use_surface_) { - jobject surface_texture = GetObjectField( - jni, *j_media_codec_video_decoder_, j_surface_texture_field_); - if (previous_surface_texture_ != NULL) { - jni->DeleteGlobalRef(previous_surface_texture_); - } - previous_surface_texture_ = surface_texture_; - surface_texture_ = jni->NewGlobalRef(surface_texture); - } codec_thread_->PostDelayed(kMediaCodecPollMs, this); return WEBRTC_VIDEO_CODEC_OK; @@ -395,6 +409,7 @@ } input_buffers_.clear(); jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_); + surface_texture_helper_ = nullptr; inited_ = false; rtc::MessageQueueManager::Clear(this); if (CheckException(jni)) { @@ -501,19 +516,21 @@ // Try to drain the decoder and wait until output is not too // much behind the input. - if (frames_received_ > frames_decoded_ + max_pending_frames_) { + const int64 drain_start = GetCurrentTimeMs(); + while ((frames_received_ > frames_decoded_ + max_pending_frames_) && + (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) { ALOGV("Received: %d. Decoded: %d. Wait for output...", frames_received_, frames_decoded_); - if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) { + if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) { ALOGE << "DeliverPendingOutputs error. Frames received: " << frames_received_ << ". Frames decoded: " << frames_decoded_; return ProcessHWErrorOnCodecThread(); } - if (frames_received_ > frames_decoded_ + max_pending_frames_) { - ALOGE << "Output buffer dequeue timeout. Frames received: " << - frames_received_ << ". Frames decoded: " << frames_decoded_; - return ProcessHWErrorOnCodecThread(); - } + } + if (frames_received_ > frames_decoded_ + max_pending_frames_) { + ALOGE << "Output buffer dequeue timeout. Frames received: " << + frames_received_ << ". Frames decoded: " << frames_decoded_; + return ProcessHWErrorOnCodecThread(); } // Get input buffer. @@ -535,11 +552,14 @@ " is bigger than buffer size " << buffer_capacity; return ProcessHWErrorOnCodecThread(); } - jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate; + jlong presentation_timestamp_us = + (frames_received_ * 1000000) / codec_.maxFramerate; if (frames_decoded_ < kMaxDecodedLogFrames) { ALOGD << "Decoder frame in # " << frames_received_ << ". Type: " << inputImage._frameType << ". Buffer # " << - j_input_buffer_index << ". TS: " << (int)(timestamp_us / 1000) + j_input_buffer_index << ". pTS: " + << (int)(presentation_timestamp_us / 1000) + << ". TS: " << inputImage._timeStamp << ". Size: " << inputImage._length; } memcpy(buffer, inputImage._buffer, inputImage._length); @@ -547,16 +567,16 @@ // Save input image timestamps for later output. frames_received_++; current_bytes_ += inputImage._length; - timestamps_.push_back(inputImage._timeStamp); - ntp_times_ms_.push_back(inputImage.ntp_time_ms_); - frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); // Feed input to decoder. - bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_, - j_queue_input_buffer_method_, - j_input_buffer_index, - inputImage._length, - timestamp_us); + bool success = jni->CallBooleanMethod( + *j_media_codec_video_decoder_, + j_queue_input_buffer_method_, + j_input_buffer_index, + inputImage._length, + presentation_timestamp_us, + static_cast<int64_t> (inputImage._timeStamp), + inputImage.ntp_time_ms_); if (CheckException(jni) || !success) { ALOGE << "queueInputBuffer error"; return ProcessHWErrorOnCodecThread(); @@ -572,16 +592,18 @@ } bool MediaCodecVideoDecoder::DeliverPendingOutputs( - JNIEnv* jni, int dequeue_timeout_us) { + JNIEnv* jni, int dequeue_timeout_ms) { if (frames_received_ <= frames_decoded_) { // No need to query for output buffers - decoder is drained. return true; } // Get decoder output. - jobject j_decoder_output_buffer = jni->CallObjectMethod( - *j_media_codec_video_decoder_, - j_dequeue_output_buffer_method_, - dequeue_timeout_us); + jobject j_decoder_output_buffer = + jni->CallObjectMethod(*j_media_codec_video_decoder_, + use_surface_ ? j_dequeue_texture_buffer_method_ + : j_dequeue_byte_buffer_method_, + dequeue_timeout_ms); + if (CheckException(jni)) { ALOGE << "dequeueOutputBuffer() error"; return false; @@ -601,19 +623,35 @@ j_slice_height_field_); rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer; - long output_timestamps_ms = 0; + int64_t output_timestamps_ms = 0; + int64_t output_ntp_timestamps_ms = 0; + int decode_time_ms = 0; + int64_t frame_delayed_ms = 0; if (use_surface_) { // Extract data from Java DecodedTextureBuffer. const int texture_id = - GetIntField(jni, j_decoder_output_buffer, j_textureID_field_); - const int64_t timestamp_us = - GetLongField(jni, j_decoder_output_buffer, - j_texture_presentation_timestamp_us_field_); - output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec; - // Create webrtc::VideoFrameBuffer with native texture handle. - native_handle_.SetTextureObject(surface_texture_, texture_id); - frame_buffer = new rtc::RefCountedObject<JniNativeHandleBuffer>( - &native_handle_, width, height); + GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_); + if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame. + const jfloatArray j_transform_matrix = + reinterpret_cast<jfloatArray>(GetObjectField( + jni, j_decoder_output_buffer, j_transform_matrix_field_)); + const int64_t timestamp_us = + GetLongField(jni, j_decoder_output_buffer, + j_texture_timestamp_ms_field_); + output_timestamps_ms = GetLongField(jni, j_decoder_output_buffer, + j_texture_timestamp_ms_field_); + output_ntp_timestamps_ms = + GetLongField(jni, j_decoder_output_buffer, + j_texture_ntp_timestamp_ms_field_); + decode_time_ms = GetLongField(jni, j_decoder_output_buffer, + j_texture_decode_time_ms_field_); + frame_delayed_ms = GetLongField(jni, j_decoder_output_buffer, + j_texture_frame_delay_ms_field_); + + // Create webrtc::VideoFrameBuffer with native texture handle. + frame_buffer = surface_texture_helper_->CreateTextureFrame( + width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix)); + } } else { // Extract data from Java ByteBuffer and create output yuv420 frame - // for non surface decoding only. @@ -623,9 +661,14 @@ GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_); const int output_buffer_size = GetIntField(jni, j_decoder_output_buffer, j_info_size_field_); - const int64_t timestamp_us = GetLongField( - jni, j_decoder_output_buffer, j_info_presentation_timestamp_us_field_); - output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec; + output_timestamps_ms = GetLongField(jni, j_decoder_output_buffer, + j_info_timestamp_ms_field_); + output_ntp_timestamps_ms = + GetLongField(jni, j_decoder_output_buffer, + j_info_ntp_timestamp_ms_field_); + + decode_time_ms = GetLongField(jni, j_decoder_output_buffer, + j_byte_buffer_decode_time_ms_field_); if (output_buffer_size < width * height * 3 / 2) { ALOGE << "Insufficient output buffer size: " << output_buffer_size; @@ -683,41 +726,31 @@ j_return_decoded_byte_buffer_method_, output_buffer_index); if (CheckException(jni)) { - ALOGE << "returnDecodedByteBuffer error"; + ALOGE << "returnDecodedOutputBuffer error"; return false; } } VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0); + decoded_frame.set_timestamp(output_timestamps_ms); + decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms); - // Get frame timestamps from a queue. - if (timestamps_.size() > 0) { - decoded_frame.set_timestamp(timestamps_.front()); - timestamps_.erase(timestamps_.begin()); - } - if (ntp_times_ms_.size() > 0) { - decoded_frame.set_ntp_time_ms(ntp_times_ms_.front()); - ntp_times_ms_.erase(ntp_times_ms_.begin()); - } - int64_t frame_decoding_time_ms = 0; - if (frame_rtc_times_ms_.size() > 0) { - frame_decoding_time_ms = GetCurrentTimeMs() - frame_rtc_times_ms_.front(); - frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin()); - } if (frames_decoded_ < kMaxDecodedLogFrames) { ALOGD << "Decoder frame out # " << frames_decoded_ << ". " << width << " x " << height << ". " << stride << " x " << slice_height << - ". Color: " << color_format << ". TS:" << (int)output_timestamps_ms << - ". DecTime: " << (int)frame_decoding_time_ms; + ". Color: " << color_format << ". TS:" << decoded_frame.timestamp() << + ". DecTime: " << (int)decode_time_ms << + ". DelayTime: " << (int)frame_delayed_ms; } // Calculate and print decoding statistics - every 3 seconds. frames_decoded_++; current_frames_++; - current_decoding_time_ms_ += frame_decoding_time_ms; + current_decoding_time_ms_ += decode_time_ms; int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_; if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs && current_frames_ > 0) { - ALOGD << "Decoded frames: " << frames_decoded_ << ". Bitrate: " << + ALOGD << "Decoded frames: " << frames_decoded_ << ". Received frames: " + << frames_received_ << ". Bitrate: " << (current_bytes_ * 8 / statistic_time_ms) << " kbps, fps: " << ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms) << ". decTime: " << (current_decoding_time_ms_ / current_frames_) << @@ -728,12 +761,15 @@ current_decoding_time_ms_ = 0; } - // Callback - output decoded frame. - const int32_t callback_status = callback_->Decoded(decoded_frame); - if (callback_status > 0) { - ALOGE << "callback error"; + // |.IsZeroSize())| returns true when a frame has been dropped. + if (!decoded_frame.IsZeroSize()) { + // Callback - output decoded frame. + const int32_t callback_status = + callback_->Decoded(decoded_frame, decode_time_ms); + if (callback_status > 0) { + ALOGE << "callback error"; + } } - return true; } @@ -790,6 +826,17 @@ supported_codec_types_.push_back(kVideoCodecVP8); } + bool is_vp9_hw_supported = jni->CallStaticBooleanMethod( + j_decoder_class, + GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z")); + if (CheckException(jni)) { + is_vp9_hw_supported = false; + } + if (is_vp9_hw_supported) { + ALOGD << "VP9 HW Decoder supported."; + supported_codec_types_.push_back(kVideoCodecVP9); + } + bool is_h264_hw_supported = jni->CallStaticBooleanMethod( j_decoder_class, GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z")); @@ -825,7 +872,7 @@ render_egl_context_ = NULL; } else { jclass j_egl_context_class = - FindClass(jni, "javax/microedition/khronos/egl/EGLContext"); + FindClass(jni, "org/webrtc/EglBase$Context"); if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) { ALOGE << "Wrong EGL Context."; jni->DeleteGlobalRef(render_egl_context_); @@ -841,7 +888,7 @@ webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder( VideoCodecType type) { if (supported_codec_types_.empty()) { - ALOGE << "No HW video decoder for type " << (int)type; + ALOGW << "No HW video decoder for type " << (int)type; return NULL; } for (VideoCodecType codec_type : supported_codec_types_) { @@ -851,7 +898,7 @@ AttachCurrentThreadIfNeeded(), type, render_egl_context_); } } - ALOGE << "Can not find HW video decoder for type " << (int)type; + ALOGW << "Can not find HW video decoder for type " << (int)type; return NULL; } @@ -861,5 +908,9 @@ delete decoder; } +const char* MediaCodecVideoDecoder::ImplementationName() const { + return "MediaCodec"; +} + } // namespace webrtc_jni
diff --git a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc index ac349e7..64831c3 100644 --- a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc +++ b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
@@ -29,14 +29,16 @@ #include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h" #include "talk/app/webrtc/java/jni/classreferenceholder.h" #include "talk/app/webrtc/java/jni/androidmediacodeccommon.h" +#include "talk/app/webrtc/java/jni/native_handle_impl.h" #include "webrtc/base/bind.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/base/thread.h" +#include "webrtc/base/thread_checker.h" #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h" -#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" -#include "webrtc/modules/video_coding/utility/include/quality_scaler.h" -#include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h" +#include "webrtc/modules/video_coding/include/video_codec_interface.h" +#include "webrtc/modules/video_coding/utility/quality_scaler.h" +#include "webrtc/modules/video_coding/utility/vp8_header_parser.h" #include "webrtc/system_wrappers/include/field_trial.h" #include "webrtc/system_wrappers/include/logcat_trace_context.h" #include "third_party/libyuv/include/libyuv/convert.h" @@ -56,6 +58,7 @@ using webrtc::VideoCodecType; using webrtc::kVideoCodecH264; using webrtc::kVideoCodecVP8; +using webrtc::kVideoCodecVP9; namespace webrtc_jni { @@ -79,7 +82,9 @@ public rtc::MessageHandler { public: virtual ~MediaCodecVideoEncoder(); - explicit MediaCodecVideoEncoder(JNIEnv* jni, VideoCodecType codecType); + MediaCodecVideoEncoder(JNIEnv* jni, + VideoCodecType codecType, + jobject egl_context); // webrtc::VideoEncoder implementation. Everything trampolines to // |codec_thread_| for execution. @@ -103,13 +108,18 @@ int GetTargetFramerate() override; + bool SupportsNativeHandle() const override { return true; } + const char* ImplementationName() const override; + private: // CHECK-fail if not running on |codec_thread_|. void CheckOnCodecThread(); - // Release() and InitEncode() in an attempt to restore the codec to an + private: + // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and + // InitEncodeOnCodecThread() in an attempt to restore the codec to an // operable state. Necessary after all manner of OMX-layer errors. - void ResetCodec(); + bool ResetCodecOnCodecThread(); // Implementation of webrtc::VideoEncoder methods above, all running on the // codec thread exclusively. @@ -117,10 +127,20 @@ // If width==0 then this is assumed to be a re-initialization and the // previously-current values are reused instead of the passed parameters // (makes it easier to reason about thread-safety). - int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps); + int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps, + bool use_surface); + // Reconfigure to match |frame| in width, height. Also reconfigures the + // encoder if |frame| is a texture/byte buffer and the encoder is initialized + // for byte buffer/texture. Returns false if reconfiguring fails. + bool MaybeReconfigureEncoderOnCodecThread(const webrtc::VideoFrame& frame); int32_t EncodeOnCodecThread( const webrtc::VideoFrame& input_image, const std::vector<webrtc::FrameType>* frame_types); + bool EncodeByteBufferOnCodecThread(JNIEnv* jni, + bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index); + bool EncodeTextureOnCodecThread(JNIEnv* jni, + bool key_frame, const webrtc::VideoFrame& frame); + int32_t RegisterEncodeCompleteCallbackOnCodecThread( webrtc::EncodedImageCallback* callback); int32_t ReleaseOnCodecThread(); @@ -150,11 +170,14 @@ // State that is constant for the lifetime of this object once the ctor // returns. scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. + rtc::ThreadChecker codec_thread_checker_; ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_; ScopedGlobalRef<jobject> j_media_codec_video_encoder_; jmethodID j_init_encode_method_; + jmethodID j_get_input_buffers_method_; jmethodID j_dequeue_input_buffer_method_; - jmethodID j_encode_method_; + jmethodID j_encode_buffer_method_; + jmethodID j_encode_texture_method_; jmethodID j_release_method_; jmethodID j_set_rates_method_; jmethodID j_dequeue_output_buffer_method_; @@ -170,6 +193,7 @@ int width_; // Frame width in pixels. int height_; // Frame height in pixels. bool inited_; + bool use_surface_; uint16_t picture_id_; enum libyuv::FourCC encoder_fourcc_; // Encoder color space format. int last_set_bitrate_kbps_; // Last-requested bitrate in kbps. @@ -205,6 +229,16 @@ // H264 bitstream parser, used to extract QP from encoded bitstreams. webrtc::H264BitstreamParser h264_bitstream_parser_; + + // VP9 variables to populate codec specific structure. + webrtc::GofInfoVP9 gof_; // Contains each frame's temporal information for + // non-flexible VP9 mode. + uint8_t tl0_pic_idx_; + size_t gof_idx_; + + // EGL context - owned by factory, should not be allocated/destroyed + // by MediaCodecVideoEncoder. + jobject egl_context_; }; MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { @@ -213,11 +247,9 @@ } MediaCodecVideoEncoder::MediaCodecVideoEncoder( - JNIEnv* jni, VideoCodecType codecType) : + JNIEnv* jni, VideoCodecType codecType, jobject egl_context) : codecType_(codecType), callback_(NULL), - inited_(false), - picture_id_(0), codec_thread_(new Thread()), j_media_codec_video_encoder_class_( jni, @@ -228,7 +260,11 @@ GetMethodID(jni, *j_media_codec_video_encoder_class_, "<init>", - "()V"))) { + "()V"))), + inited_(false), + use_surface_(false), + picture_id_(0), + egl_context_(egl_context) { ScopedLocalRefFrame local_ref_frame(jni); // It would be nice to avoid spinning up a new thread per MediaCodec, and // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug @@ -239,19 +275,27 @@ // thread. codec_thread_->SetName("MediaCodecVideoEncoder", NULL); RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; - + codec_thread_checker_.DetachFromThread(); jclass j_output_buffer_info_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo"); j_init_encode_method_ = GetMethodID( jni, *j_media_codec_video_encoder_class_, "initEncode", - "(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;IIII)" - "[Ljava/nio/ByteBuffer;"); + "(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;" + "IIIILorg/webrtc/EglBase14$Context;)Z"); + j_get_input_buffers_method_ = GetMethodID( + jni, + *j_media_codec_video_encoder_class_, + "getInputBuffers", + "()[Ljava/nio/ByteBuffer;"); j_dequeue_input_buffer_method_ = GetMethodID( jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I"); - j_encode_method_ = GetMethodID( - jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z"); + j_encode_buffer_method_ = GetMethodID( + jni, *j_media_codec_video_encoder_class_, "encodeBuffer", "(ZIIJ)Z"); + j_encode_texture_method_ = GetMethodID( + jni, *j_media_codec_video_encoder_class_, "encodeTexture", + "(ZI[FJ)Z"); j_release_method_ = GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V"); j_set_rates_method_ = GetMethodID( @@ -275,6 +319,7 @@ j_info_presentation_timestamp_us_field_ = GetFieldID( jni, j_output_buffer_info_class, "presentationTimestampUs", "J"); CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed"; + srand(time(NULL)); AllowBlockingCalls(); } @@ -295,8 +340,8 @@ << codecType_; ALOGD << "InitEncode request"; - scale_ = webrtc::field_trial::FindFullName( - "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled"; + scale_ = (codecType_ != kVideoCodecVP9) && (webrtc::field_trial::FindFullName( + "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled"); ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled"); if (scale_) { if (codecType_ == kVideoCodecVP8) { @@ -331,7 +376,8 @@ codec_settings->width, codec_settings->height, codec_settings->startBitrate, - codec_settings->maxFramerate)); + codec_settings->maxFramerate, + false /* use_surface */)); } int32_t MediaCodecVideoEncoder::Encode( @@ -374,6 +420,7 @@ } void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); @@ -381,7 +428,6 @@ // functor), so expect no ID/data. RTC_CHECK(!msg->message_id) << "Unexpected message!"; RTC_CHECK(!msg->pdata) << "Unexpected message!"; - CheckOnCodecThread(); if (!inited_) { return; } @@ -393,26 +439,24 @@ codec_thread_->PostDelayed(kMediaCodecPollMs, this); } -void MediaCodecVideoEncoder::CheckOnCodecThread() { - RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread()) - << "Running on wrong thread!"; -} - -void MediaCodecVideoEncoder::ResetCodec() { - ALOGE << "ResetCodec"; - if (Release() != WEBRTC_VIDEO_CODEC_OK || - codec_thread_->Invoke<int32_t>(Bind( - &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, - width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) { +bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); + ALOGE << "ResetOnCodecThread"; + if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || + InitEncodeOnCodecThread(width_, height_, 0, 0, false) != + WEBRTC_VIDEO_CODEC_OK) { // TODO(fischman): wouldn't it be nice if there was a way to gracefully // degrade to a SW encoder at this point? There isn't one AFAICT :( // https://code.google.com/p/webrtc/issues/detail?id=2920 + return false; } + return true; } int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( - int width, int height, int kbps, int fps) { - CheckOnCodecThread(); + int width, int height, int kbps, int fps, bool use_surface) { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); + RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set."; JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); @@ -448,52 +492,63 @@ render_times_ms_.clear(); frame_rtc_times_ms_.clear(); drop_next_input_frame_ = false; + use_surface_ = use_surface; picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; + gof_.SetGofInfoVP9(webrtc::TemporalStructureMode::kTemporalStructureMode1); + tl0_pic_idx_ = static_cast<uint8_t>(rand()); + gof_idx_ = 0; + // We enforce no extra stride/padding in the format creation step. jobject j_video_codec_enum = JavaEnumFromIndex( jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); - jobjectArray input_buffers = reinterpret_cast<jobjectArray>( - jni->CallObjectMethod(*j_media_codec_video_encoder_, - j_init_encode_method_, - j_video_codec_enum, - width_, - height_, - kbps, - fps)); - CHECK_EXCEPTION(jni); - if (IsNull(jni, input_buffers)) { + const bool encode_status = jni->CallBooleanMethod( + *j_media_codec_video_encoder_, j_init_encode_method_, + j_video_codec_enum, width, height, kbps, fps, + (use_surface ? egl_context_ : nullptr)); + if (!encode_status) { + ALOGE << "Failed to configure encoder."; return WEBRTC_VIDEO_CODEC_ERROR; } + CHECK_EXCEPTION(jni); + + if (!use_surface) { + jobjectArray input_buffers = reinterpret_cast<jobjectArray>( + jni->CallObjectMethod(*j_media_codec_video_encoder_, + j_get_input_buffers_method_)); + CHECK_EXCEPTION(jni); + if (IsNull(jni, input_buffers)) { + return WEBRTC_VIDEO_CODEC_ERROR; + } + + switch (GetIntField(jni, *j_media_codec_video_encoder_, + j_color_format_field_)) { + case COLOR_FormatYUV420Planar: + encoder_fourcc_ = libyuv::FOURCC_YU12; + break; + case COLOR_FormatYUV420SemiPlanar: + case COLOR_QCOM_FormatYUV420SemiPlanar: + case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: + encoder_fourcc_ = libyuv::FOURCC_NV12; + break; + default: + LOG(LS_ERROR) << "Wrong color format."; + return WEBRTC_VIDEO_CODEC_ERROR; + } + size_t num_input_buffers = jni->GetArrayLength(input_buffers); + RTC_CHECK(input_buffers_.empty()) + << "Unexpected double InitEncode without Release"; + input_buffers_.resize(num_input_buffers); + for (size_t i = 0; i < num_input_buffers; ++i) { + input_buffers_[i] = + jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); + int64_t yuv_buffer_capacity = + jni->GetDirectBufferCapacity(input_buffers_[i]); + CHECK_EXCEPTION(jni); + RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; + } + } inited_ = true; - switch (GetIntField(jni, *j_media_codec_video_encoder_, - j_color_format_field_)) { - case COLOR_FormatYUV420Planar: - encoder_fourcc_ = libyuv::FOURCC_YU12; - break; - case COLOR_FormatYUV420SemiPlanar: - case COLOR_QCOM_FormatYUV420SemiPlanar: - case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: - encoder_fourcc_ = libyuv::FOURCC_NV12; - break; - default: - LOG(LS_ERROR) << "Wrong color format."; - return WEBRTC_VIDEO_CODEC_ERROR; - } - size_t num_input_buffers = jni->GetArrayLength(input_buffers); - RTC_CHECK(input_buffers_.empty()) - << "Unexpected double InitEncode without Release"; - input_buffers_.resize(num_input_buffers); - for (size_t i = 0; i < num_input_buffers; ++i) { - input_buffers_[i] = - jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); - int64_t yuv_buffer_capacity = - jni->GetDirectBufferCapacity(input_buffers_[i]); - CHECK_EXCEPTION(jni); - RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; - } - CHECK_EXCEPTION(jni); - codec_thread_->PostDelayed(kMediaCodecPollMs, this); return WEBRTC_VIDEO_CODEC_OK; } @@ -501,40 +556,53 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( const webrtc::VideoFrame& frame, const std::vector<webrtc::FrameType>* frame_types) { - CheckOnCodecThread(); + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); if (!inited_) { return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } + frames_received_++; if (!DeliverPendingOutputs(jni)) { - ResetCodec(); - // Continue as if everything's fine. + if (!ResetCodecOnCodecThread()) + return WEBRTC_VIDEO_CODEC_ERROR; } if (drop_next_input_frame_) { - ALOGV("Encoder drop frame - failed callback."); + ALOGW << "Encoder drop frame - failed callback."; drop_next_input_frame_ = false; return WEBRTC_VIDEO_CODEC_OK; } RTC_CHECK(frame_types->size() == 1) << "Unexpected stream count"; - // Check framerate before spatial resolution change. - if (scale_) + + VideoFrame input_frame = frame; + if (scale_) { + // Check framerate before spatial resolution change. quality_scaler_.OnEncodeFrame(frame); + const webrtc::QualityScaler::Resolution scaled_resolution = + quality_scaler_.GetScaledResolution(); + if (scaled_resolution.width != frame.width() || + scaled_resolution.height != frame.height()) { + if (frame.native_handle() != nullptr) { + rtc::scoped_refptr<webrtc::VideoFrameBuffer> scaled_buffer( + static_cast<AndroidTextureBuffer*>( + frame.video_frame_buffer().get())->ScaleAndRotate( + scaled_resolution.width, + scaled_resolution.height, + webrtc::kVideoRotation_0)); + input_frame.set_video_frame_buffer(scaled_buffer); + } else { + input_frame = quality_scaler_.GetScaledFrame(frame); + } + } + } - const VideoFrame& input_frame = - scale_ ? quality_scaler_.GetScaledFrame(frame) : frame; - - if (input_frame.width() != width_ || input_frame.height() != height_) { - ALOGD << "Frame resolution change from " << width_ << " x " << height_ << - " to " << input_frame.width() << " x " << input_frame.height(); - width_ = input_frame.width(); - height_ = input_frame.height(); - ResetCodec(); - return WEBRTC_VIDEO_CODEC_OK; + if (!MaybeReconfigureEncoderOnCodecThread(input_frame)) { + ALOGE << "Failed to reconfigure encoder."; + return WEBRTC_VIDEO_CODEC_ERROR; } // Check if we accumulated too many frames in encoder input buffers @@ -552,65 +620,138 @@ } } - int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, - j_dequeue_input_buffer_method_); - CHECK_EXCEPTION(jni); - if (j_input_buffer_index == -1) { - // Video codec falls behind - no input buffer available. - ALOGV("Encoder drop frame - no input buffers available"); - frames_dropped_++; - // Report dropped frame to quality_scaler_. - OnDroppedFrame(); - return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887. + const bool key_frame = frame_types->front() != webrtc::kVideoFrameDelta; + bool encode_status = true; + if (!input_frame.native_handle()) { + int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, + j_dequeue_input_buffer_method_); + CHECK_EXCEPTION(jni); + if (j_input_buffer_index == -1) { + // Video codec falls behind - no input buffer available. + ALOGW << "Encoder drop frame - no input buffers available"; + frames_dropped_++; + // Report dropped frame to quality_scaler_. + OnDroppedFrame(); + return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887. + } + if (j_input_buffer_index == -2) { + ResetCodecOnCodecThread(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + encode_status = EncodeByteBufferOnCodecThread(jni, key_frame, input_frame, + j_input_buffer_index); + } else { + encode_status = EncodeTextureOnCodecThread(jni, key_frame, input_frame); } - if (j_input_buffer_index == -2) { - ResetCodec(); + + if (!encode_status) { + ALOGE << "Failed encode frame with timestamp: " << input_frame.timestamp(); + ResetCodecOnCodecThread(); return WEBRTC_VIDEO_CODEC_ERROR; } - ALOGV("Encoder frame in # %d. TS: %lld. Q: %d", - frames_received_ - 1, current_timestamp_us_ / 1000, frames_in_queue_); - - jobject j_input_buffer = input_buffers_[j_input_buffer_index]; - uint8_t* yuv_buffer = - reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); - CHECK_EXCEPTION(jni); - RTC_CHECK(yuv_buffer) << "Indirect buffer??"; - RTC_CHECK(!libyuv::ConvertFromI420( - input_frame.buffer(webrtc::kYPlane), input_frame.stride(webrtc::kYPlane), - input_frame.buffer(webrtc::kUPlane), input_frame.stride(webrtc::kUPlane), - input_frame.buffer(webrtc::kVPlane), input_frame.stride(webrtc::kVPlane), - yuv_buffer, width_, width_, height_, encoder_fourcc_)) - << "ConvertFromI420 failed"; - last_input_timestamp_ms_ = current_timestamp_us_ / 1000; + last_input_timestamp_ms_ = + current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; frames_in_queue_++; // Save input image timestamps for later output timestamps_.push_back(input_frame.timestamp()); render_times_ms_.push_back(input_frame.render_time_ms()); frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); + current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; - bool key_frame = frame_types->front() != webrtc::kVideoFrameDelta; + if (!DeliverPendingOutputs(jni)) { + ALOGE << "Failed deliver pending outputs."; + ResetCodecOnCodecThread(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + return WEBRTC_VIDEO_CODEC_OK; +} + +bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( + const webrtc::VideoFrame& frame) { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); + + const bool is_texture_frame = frame.native_handle() != nullptr; + const bool reconfigure_due_to_format = is_texture_frame != use_surface_; + const bool reconfigure_due_to_size = + frame.width() != width_ || frame.height() != height_; + + if (reconfigure_due_to_format) { + ALOGD << "Reconfigure encoder due to format change. " + << (use_surface_ ? + "Reconfiguring to encode from byte buffer." : + "Reconfiguring to encode from texture."); + } + if (reconfigure_due_to_size) { + ALOGD << "Reconfigure encoder due to frame resolution change from " + << width_ << " x " << height_ << " to " << frame.width() << " x " + << frame.height(); + width_ = frame.width(); + height_ = frame.height(); + } + + if (!reconfigure_due_to_format && !reconfigure_due_to_size) + return true; + + ReleaseOnCodecThread(); + + return InitEncodeOnCodecThread(width_, height_, 0, 0 , is_texture_frame) == + WEBRTC_VIDEO_CODEC_OK; +} + +bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni, + bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index) { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); + RTC_CHECK(!use_surface_); + + ALOGV("Encoder frame in # %d. TS: %lld. Q: %d", + frames_received_ - 1, current_timestamp_us_ / 1000, frames_in_queue_); + + jobject j_input_buffer = input_buffers_[input_buffer_index]; + uint8_t* yuv_buffer = + reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); + CHECK_EXCEPTION(jni); + RTC_CHECK(yuv_buffer) << "Indirect buffer??"; + RTC_CHECK(!libyuv::ConvertFromI420( + frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane), + frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane), + frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane), + yuv_buffer, width_, width_, height_, encoder_fourcc_)) + << "ConvertFromI420 failed"; + bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, - j_encode_method_, + j_encode_buffer_method_, key_frame, - j_input_buffer_index, + input_buffer_index, yuv_size_, current_timestamp_us_); CHECK_EXCEPTION(jni); - current_timestamp_us_ += 1000000 / last_set_fps_; + return encode_status; +} - if (!encode_status || !DeliverPendingOutputs(jni)) { - ResetCodec(); - return WEBRTC_VIDEO_CODEC_ERROR; - } +bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni, + bool key_frame, const webrtc::VideoFrame& frame) { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); + RTC_CHECK(use_surface_); + NativeHandleImpl* handle = + static_cast<NativeHandleImpl*>(frame.native_handle()); + jfloatArray sampling_matrix = jni->NewFloatArray(16); + jni->SetFloatArrayRegion(sampling_matrix, 0, 16, handle->sampling_matrix); - return WEBRTC_VIDEO_CODEC_OK; + bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, + j_encode_texture_method_, + key_frame, + handle->oes_texture_id, + sampling_matrix, + current_timestamp_us_); + CHECK_EXCEPTION(jni); + return encode_status; } int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( webrtc::EncodedImageCallback* callback) { - CheckOnCodecThread(); + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); callback_ = callback; @@ -618,10 +759,10 @@ } int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); if (!inited_) { return WEBRTC_VIDEO_CODEC_OK; } - CheckOnCodecThread(); JNIEnv* jni = AttachCurrentThreadIfNeeded(); ALOGD << "EncoderReleaseOnCodecThread: Frames received: " << frames_received_ << ". Encoded: " << frames_encoded_ << @@ -634,13 +775,14 @@ CHECK_EXCEPTION(jni); rtc::MessageQueueManager::Clear(this); inited_ = false; + use_surface_ = false; ALOGD << "EncoderReleaseOnCodecThread done."; return WEBRTC_VIDEO_CODEC_OK; } int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate) { - CheckOnCodecThread(); + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); if (last_set_bitrate_kbps_ == new_bit_rate && last_set_fps_ == frame_rate) { return WEBRTC_VIDEO_CODEC_OK; @@ -659,7 +801,7 @@ last_set_fps_); CHECK_EXCEPTION(jni); if (!ret) { - ResetCodec(); + ResetCodecOnCodecThread(); return WEBRTC_VIDEO_CODEC_ERROR; } return WEBRTC_VIDEO_CODEC_OK; @@ -691,6 +833,7 @@ } bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) { + RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); while (true) { jobject j_output_buffer_info = jni->CallObjectMethod( *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_); @@ -702,7 +845,7 @@ int output_buffer_index = GetOutputBufferInfoIndex(jni, j_output_buffer_info); if (output_buffer_index == -1) { - ResetCodec(); + ResetCodecOnCodecThread(); return false; } @@ -786,19 +929,42 @@ info.codecSpecific.VP8.layerSync = false; info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx; info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx; - picture_id_ = (picture_id_ + 1) & 0x7FFF; + } else if (codecType_ == kVideoCodecVP9) { + if (key_frame) { + gof_idx_ = 0; + } + info.codecSpecific.VP9.picture_id = picture_id_; + info.codecSpecific.VP9.inter_pic_predicted = key_frame ? false : true; + info.codecSpecific.VP9.flexible_mode = false; + info.codecSpecific.VP9.ss_data_available = key_frame ? true : false; + info.codecSpecific.VP9.tl0_pic_idx = tl0_pic_idx_++; + info.codecSpecific.VP9.temporal_idx = webrtc::kNoTemporalIdx; + info.codecSpecific.VP9.spatial_idx = webrtc::kNoSpatialIdx; + info.codecSpecific.VP9.temporal_up_switch = true; + info.codecSpecific.VP9.inter_layer_predicted = false; + info.codecSpecific.VP9.gof_idx = + static_cast<uint8_t>(gof_idx_++ % gof_.num_frames_in_gof); + info.codecSpecific.VP9.num_spatial_layers = 1; + info.codecSpecific.VP9.spatial_layer_resolution_present = false; + if (info.codecSpecific.VP9.ss_data_available) { + info.codecSpecific.VP9.spatial_layer_resolution_present = true; + info.codecSpecific.VP9.width[0] = width_; + info.codecSpecific.VP9.height[0] = height_; + info.codecSpecific.VP9.gof.CopyGofInfoVP9(gof_); + } } + picture_id_ = (picture_id_ + 1) & 0x7FFF; // Generate a header describing a single fragment. webrtc::RTPFragmentationHeader header; memset(&header, 0, sizeof(header)); - if (codecType_ == kVideoCodecVP8) { + if (codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecVP9) { header.VerifyAndAllocateFragmentationHeader(1); header.fragmentationOffset[0] = 0; header.fragmentationLength[0] = image->_length; header.fragmentationPlType[0] = 0; header.fragmentationTimeDiff[0] = 0; - if (scale_) { + if (codecType_ == kVideoCodecVP8 && scale_) { int qp; if (webrtc::vp8::GetQp(payload, payload_size, &qp)) quality_scaler_.ReportQP(qp); @@ -829,7 +995,7 @@ ALOGE << "Data:" << image->_buffer[0] << " " << image->_buffer[1] << " " << image->_buffer[2] << " " << image->_buffer[3] << " " << image->_buffer[4] << " " << image->_buffer[5]; - ResetCodec(); + ResetCodecOnCodecThread(); return false; } scPositions[scPositionsLength] = payload_size; @@ -852,7 +1018,7 @@ output_buffer_index); CHECK_EXCEPTION(jni); if (!success) { - ResetCodec(); + ResetCodecOnCodecThread(); return false; } @@ -907,7 +1073,12 @@ return scale_ ? quality_scaler_.GetTargetFramerate() : -1; } -MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() { +const char* MediaCodecVideoEncoder::ImplementationName() const { + return "MediaCodec"; +} + +MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() + : egl_context_(nullptr) { JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder"); @@ -923,6 +1094,16 @@ MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); } + bool is_vp9_hw_supported = jni->CallStaticBooleanMethod( + j_encoder_class, + GetStaticMethodID(jni, j_encoder_class, "isVp9HwSupported", "()Z")); + CHECK_EXCEPTION(jni); + if (is_vp9_hw_supported) { + ALOGD << "VP9 HW Encoder supported."; + supported_codecs_.push_back(VideoCodec(kVideoCodecVP9, "VP9", + MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT, MAX_VIDEO_FPS)); + } + bool is_h264_hw_supported = jni->CallStaticBooleanMethod( j_encoder_class, GetStaticMethodID(jni, j_encoder_class, "isH264HwSupported", "()Z")); @@ -936,9 +1117,37 @@ MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {} +void MediaCodecVideoEncoderFactory::SetEGLContext( + JNIEnv* jni, jobject render_egl_context) { + ALOGD << "MediaCodecVideoEncoderFactory::SetEGLContext"; + if (egl_context_) { + jni->DeleteGlobalRef(egl_context_); + egl_context_ = NULL; + } + if (!IsNull(jni, render_egl_context)) { + egl_context_ = jni->NewGlobalRef(render_egl_context); + if (CheckException(jni)) { + ALOGE << "error calling NewGlobalRef for EGL Context."; + egl_context_ = NULL; + } else { + jclass j_egl_context_class = + FindClass(jni, "org/webrtc/EglBase14$Context"); + if (!jni->IsInstanceOf(egl_context_, j_egl_context_class)) { + ALOGE << "Wrong EGL Context."; + jni->DeleteGlobalRef(egl_context_); + egl_context_ = NULL; + } + } + } + if (egl_context_ == NULL) { + ALOGW << "NULL VideoDecoder EGL context - HW surface encoding is disabled."; + } +} + webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder( VideoCodecType type) { if (supported_codecs_.empty()) { + ALOGW << "No HW video encoder for type " << (int)type; return NULL; } for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin(); @@ -946,9 +1155,11 @@ if (it->type == type) { ALOGD << "Create HW video encoder for type " << (int)type << " (" << it->name << ")."; - return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type); + return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type, + egl_context_); } } + ALOGW << "Can not find HW video encoder for type " << (int)type; return NULL; }
diff --git a/talk/app/webrtc/java/jni/androidmediaencoder_jni.h b/talk/app/webrtc/java/jni/androidmediaencoder_jni.h index ff124aa..8ff8164 100644 --- a/talk/app/webrtc/java/jni/androidmediaencoder_jni.h +++ b/talk/app/webrtc/java/jni/androidmediaencoder_jni.h
@@ -43,6 +43,8 @@ MediaCodecVideoEncoderFactory(); virtual ~MediaCodecVideoEncoderFactory(); + void SetEGLContext(JNIEnv* jni, jobject render_egl_context); + // WebRtcVideoEncoderFactory implementation. webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type) override; @@ -50,6 +52,7 @@ void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override; private: + jobject egl_context_; // Empty if platform support is lacking, const after ctor returns. std::vector<VideoCodec> supported_codecs_; };
diff --git a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc index 02b9f22..8813c89 100644 --- a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc +++ b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc
@@ -29,8 +29,9 @@ #include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h" #include "talk/app/webrtc/java/jni/classreferenceholder.h" #include "talk/app/webrtc/java/jni/native_handle_impl.h" +#include "talk/app/webrtc/java/jni/surfacetexturehelper_jni.h" +#include "third_party/libyuv/include/libyuv/convert.h" #include "webrtc/base/bind.h" -#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" namespace webrtc_jni { @@ -47,15 +48,19 @@ return 0; } -AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni, - jobject j_video_capturer) - : j_capturer_global_(jni, j_video_capturer), +AndroidVideoCapturerJni::AndroidVideoCapturerJni( + JNIEnv* jni, + jobject j_video_capturer, + jobject j_surface_texture_helper) + : j_video_capturer_(jni, j_video_capturer), j_video_capturer_class_( jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")), j_observer_class_( jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid$NativeObserver")), + surface_texture_helper_(new rtc::RefCountedObject<SurfaceTextureHelper>( + jni, j_surface_texture_helper)), capturer_(nullptr) { LOG(LS_INFO) << "AndroidVideoCapturerJni ctor"; thread_checker_.DetachFromThread(); @@ -64,7 +69,7 @@ AndroidVideoCapturerJni::~AndroidVideoCapturerJni() { LOG(LS_INFO) << "AndroidVideoCapturerJni dtor"; jni()->CallVoidMethod( - *j_capturer_global_, + *j_video_capturer_, GetMethodID(jni(), *j_video_capturer_class_, "release", "()V")); CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.release()"; } @@ -90,7 +95,7 @@ jni(), *j_video_capturer_class_, "startCapture", "(IIILandroid/content/Context;" "Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V"); - jni()->CallVoidMethod(*j_capturer_global_, + jni()->CallVoidMethod(*j_video_capturer_, m, width, height, framerate, application_context_, @@ -109,7 +114,7 @@ } jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, "stopCapture", "()V"); - jni()->CallVoidMethod(*j_capturer_global_, m); + jni()->CallVoidMethod(*j_video_capturer_, m); CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture"; LOG(LS_INFO) << "AndroidVideoCapturerJni stop done"; } @@ -127,19 +132,12 @@ invoker_->AsyncInvoke<void>(rtc::Bind(method, capturer_, args...)); } -void AndroidVideoCapturerJni::ReturnBuffer(int64_t time_stamp) { - jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, - "returnBuffer", "(J)V"); - jni()->CallVoidMethod(*j_capturer_global_, m, time_stamp); - CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.returnBuffer"; -} - std::string AndroidVideoCapturerJni::GetSupportedFormats() { jmethodID m = GetMethodID(jni(), *j_video_capturer_class_, "getSupportedFormatsAsJson", "()Ljava/lang/String;"); jstring j_json_caps = - (jstring) jni()->CallObjectMethod(*j_capturer_global_, m); + (jstring) jni()->CallObjectMethod(*j_video_capturer_, m); CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson"; return JavaToStdString(jni(), j_json_caps); } @@ -158,46 +156,33 @@ int rotation, int64_t timestamp_ns) { const uint8_t* y_plane = static_cast<uint8_t*>(video_frame); - // Android guarantees that the stride is a multiple of 16. - // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29 - int y_stride; - int uv_stride; - webrtc::Calc16ByteAlignedStride(width, &y_stride, &uv_stride); - const uint8_t* v_plane = y_plane + y_stride * height; - const uint8_t* u_plane = - v_plane + uv_stride * webrtc::AlignInt(height, 2) / 2; + const uint8_t* vu_plane = y_plane + width * height; - // Wrap the Java buffer, and call ReturnBuffer() in the wrapped - // VideoFrameBuffer destructor. - rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer( - new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( - width, height, y_plane, y_stride, u_plane, uv_stride, v_plane, - uv_stride, - rtc::Bind(&AndroidVideoCapturerJni::ReturnBuffer, this, - timestamp_ns))); + rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer = + buffer_pool_.CreateBuffer(width, height); + libyuv::NV21ToI420( + y_plane, width, + vu_plane, width, + buffer->MutableData(webrtc::kYPlane), buffer->stride(webrtc::kYPlane), + buffer->MutableData(webrtc::kUPlane), buffer->stride(webrtc::kUPlane), + buffer->MutableData(webrtc::kVPlane), buffer->stride(webrtc::kVPlane), + width, height); AsyncCapturerInvoke("OnIncomingFrame", &webrtc::AndroidVideoCapturer::OnIncomingFrame, buffer, rotation, timestamp_ns); } -void AndroidVideoCapturerJni::OnTextureFrame( - int width, - int height, - int64_t timestamp_ns, - const NativeTextureHandleImpl& handle) { - // TODO(magjed): Fix this. See bug webrtc:4993. - RTC_NOTREACHED() - << "The rest of the stack for Android expects the native " - "handle to be a NativeHandleImpl with a SurfaceTexture, not a " - "NativeTextureHandleImpl"; +void AndroidVideoCapturerJni::OnTextureFrame(int width, + int height, + int rotation, + int64_t timestamp_ns, + const NativeHandleImpl& handle) { rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer( - new rtc::RefCountedObject<AndroidTextureBuffer>( - width, height, handle, - rtc::Bind(&AndroidVideoCapturerJni::ReturnBuffer, this, - timestamp_ns))); + surface_texture_helper_->CreateTextureFrame(width, height, handle)); + AsyncCapturerInvoke("OnIncomingFrame", &webrtc::AndroidVideoCapturer::OnIncomingFrame, - buffer, 0, timestamp_ns); + buffer, rotation, timestamp_ns); } void AndroidVideoCapturerJni::OnOutputFormatRequest(int width, @@ -216,13 +201,6 @@ jint width, jint height, jint rotation, jlong timestamp) { jboolean is_copy = true; jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy); - // If this is a copy of the original frame, it means that the memory - // is not direct memory and thus VideoCapturerAndroid does not guarantee - // that the memory is valid when we have released |j_frame|. - // TODO(magjed): Move ReleaseByteArrayElements() into ReturnBuffer() and - // remove this check. - RTC_CHECK(!is_copy) - << "NativeObserver_nativeOnFrameCaptured: frame is a copy"; reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer) ->OnMemoryBufferFrame(bytes, length, width, height, rotation, timestamp); jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT); @@ -231,11 +209,11 @@ JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnTextureFrameCaptured) (JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height, jint j_oes_texture_id, jfloatArray j_transform_matrix, - jlong j_timestamp) { + jint j_rotation, jlong j_timestamp) { reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer) - ->OnTextureFrame(j_width, j_height, j_timestamp, - NativeTextureHandleImpl(jni, j_oes_texture_id, - j_transform_matrix)); + ->OnTextureFrame(j_width, j_height, j_rotation, j_timestamp, + NativeHandleImpl(jni, j_oes_texture_id, + j_transform_matrix)); } JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted) @@ -254,9 +232,11 @@ } JOW(jlong, VideoCapturerAndroid_nativeCreateVideoCapturer) - (JNIEnv* jni, jclass, jobject j_video_capturer) { + (JNIEnv* jni, jclass, + jobject j_video_capturer, jobject j_surface_texture_helper) { rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate = - new rtc::RefCountedObject<AndroidVideoCapturerJni>(jni, j_video_capturer); + new rtc::RefCountedObject<AndroidVideoCapturerJni>( + jni, j_video_capturer, j_surface_texture_helper); rtc::scoped_ptr<cricket::VideoCapturer> capturer( new webrtc::AndroidVideoCapturer(delegate)); // Caller takes ownership of the cricket::VideoCapturer* pointer.
diff --git a/talk/app/webrtc/java/jni/androidvideocapturer_jni.h b/talk/app/webrtc/java/jni/androidvideocapturer_jni.h index d1eb3a0..89ecacb 100644 --- a/talk/app/webrtc/java/jni/androidvideocapturer_jni.h +++ b/talk/app/webrtc/java/jni/androidvideocapturer_jni.h
@@ -36,10 +36,12 @@ #include "webrtc/base/asyncinvoker.h" #include "webrtc/base/criticalsection.h" #include "webrtc/base/thread_checker.h" +#include "webrtc/common_video/include/i420_buffer_pool.h" namespace webrtc_jni { -class NativeTextureHandleImpl; +struct NativeHandleImpl; +class SurfaceTextureHelper; // AndroidVideoCapturerJni implements AndroidVideoCapturerDelegate. // The purpose of the delegate is to hide the JNI specifics from the C++ only @@ -48,7 +50,9 @@ public: static int SetAndroidObjects(JNIEnv* jni, jobject appliction_context); - AndroidVideoCapturerJni(JNIEnv* jni, jobject j_video_capturer); + AndroidVideoCapturerJni(JNIEnv* jni, + jobject j_video_capturer, + jobject j_surface_texture_helper); void Start(int width, int height, int framerate, webrtc::AndroidVideoCapturer* capturer) override; @@ -60,15 +64,14 @@ void OnCapturerStarted(bool success); void OnMemoryBufferFrame(void* video_frame, int length, int width, int height, int rotation, int64_t timestamp_ns); - void OnTextureFrame(int width, int height, int64_t timestamp_ns, - const NativeTextureHandleImpl& handle); + void OnTextureFrame(int width, int height, int rotation, int64_t timestamp_ns, + const NativeHandleImpl& handle); void OnOutputFormatRequest(int width, int height, int fps); protected: ~AndroidVideoCapturerJni(); private: - void ReturnBuffer(int64_t time_stamp); JNIEnv* jni(); // To avoid deducing Args from the 3rd parameter of AsyncCapturerInvoke. @@ -85,10 +88,13 @@ void (webrtc::AndroidVideoCapturer::*method)(Args...), typename Identity<Args>::type... args); - const ScopedGlobalRef<jobject> j_capturer_global_; + const ScopedGlobalRef<jobject> j_video_capturer_; const ScopedGlobalRef<jclass> j_video_capturer_class_; const ScopedGlobalRef<jclass> j_observer_class_; + // Used on the Java thread running the camera. + webrtc::I420BufferPool buffer_pool_; + rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_; rtc::ThreadChecker thread_checker_; // |capturer| is a guaranteed to be a valid pointer between a call to
diff --git a/talk/app/webrtc/java/jni/classreferenceholder.cc b/talk/app/webrtc/java/jni/classreferenceholder.cc index 4c836f8..5fe8ec7 100644 --- a/talk/app/webrtc/java/jni/classreferenceholder.cc +++ b/talk/app/webrtc/java/jni/classreferenceholder.cc
@@ -72,20 +72,21 @@ LoadClass(jni, "org/webrtc/IceCandidate"); #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) LoadClass(jni, "android/graphics/SurfaceTexture"); - LoadClass(jni, "javax/microedition/khronos/egl/EGLContext"); LoadClass(jni, "org/webrtc/CameraEnumerator"); LoadClass(jni, "org/webrtc/Camera2Enumerator"); LoadClass(jni, "org/webrtc/CameraEnumerationAndroid"); LoadClass(jni, "org/webrtc/VideoCapturerAndroid"); LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeObserver"); LoadClass(jni, "org/webrtc/EglBase"); + LoadClass(jni, "org/webrtc/EglBase$Context"); + LoadClass(jni, "org/webrtc/EglBase14$Context"); LoadClass(jni, "org/webrtc/NetworkMonitor"); LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder"); LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo"); LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$VideoCodecType"); LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder"); LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer"); - LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecodedByteBuffer"); + LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer"); LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$VideoCodecType"); LoadClass(jni, "org/webrtc/SurfaceTextureHelper"); #endif
diff --git a/talk/app/webrtc/java/jni/jni_helpers.cc b/talk/app/webrtc/java/jni/jni_helpers.cc index 755698e..3a7ff21 100644 --- a/talk/app/webrtc/java/jni/jni_helpers.cc +++ b/talk/app/webrtc/java/jni/jni_helpers.cc
@@ -1,4 +1,3 @@ - /* * libjingle * Copyright 2015 Google Inc. @@ -33,8 +32,6 @@ #include <sys/syscall.h> #include <unistd.h> -#include "unicode/unistr.h" - namespace webrtc_jni { static JavaVM* g_jvm = nullptr; @@ -46,8 +43,6 @@ // were attached by the JVM because of a Java->native call. static pthread_key_t g_jni_ptr; -using icu::UnicodeString; - JavaVM *GetJVM() { RTC_CHECK(g_jvm) << "JNI_OnLoad failed to run?"; return g_jvm; @@ -232,22 +227,20 @@ // Given a UTF-8 encoded |native| string return a new (UTF-16) jstring. jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) { - UnicodeString ustr(UnicodeString::fromUTF8(native)); - jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length()); - CHECK_EXCEPTION(jni) << "error during NewString"; + jstring jstr = jni->NewStringUTF(native.c_str()); + CHECK_EXCEPTION(jni) << "error during NewStringUTF"; return jstr; } // Given a (UTF-16) jstring return a new UTF-8 native string. std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) { - const jchar* jchars = jni->GetStringChars(j_string, NULL); - CHECK_EXCEPTION(jni) << "Error during GetStringChars"; - UnicodeString ustr(jchars, jni->GetStringLength(j_string)); - CHECK_EXCEPTION(jni) << "Error during GetStringLength"; - jni->ReleaseStringChars(j_string, jchars); - CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars"; - std::string ret; - return ustr.toUTF8String(ret); + const char* chars = jni->GetStringUTFChars(j_string, NULL); + CHECK_EXCEPTION(jni) << "Error during GetStringUTFChars"; + std::string str(chars, jni->GetStringUTFLength(j_string)); + CHECK_EXCEPTION(jni) << "Error during GetStringUTFLength"; + jni->ReleaseStringUTFChars(j_string, chars); + CHECK_EXCEPTION(jni) << "Error during ReleaseStringUTFChars"; + return str; } // Return the (singleton) Java Enum object corresponding to |index|;
diff --git a/talk/app/webrtc/java/jni/jni_onload.cc b/talk/app/webrtc/java/jni/jni_onload.cc new file mode 100644 index 0000000..9664ecd --- /dev/null +++ b/talk/app/webrtc/java/jni/jni_onload.cc
@@ -0,0 +1,55 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <jni.h> +#undef JNIEXPORT +#define JNIEXPORT __attribute__((visibility("default"))) + +#include "talk/app/webrtc/java/jni/classreferenceholder.h" +#include "talk/app/webrtc/java/jni/jni_helpers.h" +#include "webrtc/base/ssladapter.h" + +namespace webrtc_jni { + +extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { + jint ret = InitGlobalJniVariables(jvm); + RTC_DCHECK_GE(ret, 0); + if (ret < 0) + return -1; + + RTC_CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()"; + LoadGlobalClassReferenceHolder(); + + return ret; +} + +extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) { + FreeGlobalClassReferenceHolder(); + RTC_CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()"; +} + +} // namespace webrtc_jni
diff --git a/talk/app/webrtc/java/jni/native_handle_impl.cc b/talk/app/webrtc/java/jni/native_handle_impl.cc index ac3e045..1757184 100644 --- a/talk/app/webrtc/java/jni/native_handle_impl.cc +++ b/talk/app/webrtc/java/jni/native_handle_impl.cc
@@ -27,14 +27,65 @@ #include "talk/app/webrtc/java/jni/native_handle_impl.h" +#include "talk/app/webrtc/java/jni/jni_helpers.h" +#include "webrtc/base/bind.h" #include "webrtc/base/checks.h" +#include "webrtc/base/keep_ref_until_done.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/base/logging.h" + +using webrtc::NativeHandleBuffer; + +namespace { + +void RotateMatrix(float a[16], webrtc::VideoRotation rotation) { + // Texture coordinates are in the range 0 to 1. The transformation of the last + // row in each rotation matrix is needed for proper translation, e.g, to + // mirror x, we don't replace x by -x, but by 1-x. + switch (rotation) { + case webrtc::kVideoRotation_0: + break; + case webrtc::kVideoRotation_90: { + const float ROTATE_90[16] = + { a[4], a[5], a[6], a[7], + -a[0], -a[1], -a[2], -a[3], + a[8], a[9], a[10], a[11], + a[0] + a[12], a[1] + a[13], a[2] + a[14], a[3] + a[15]}; + memcpy(a, ROTATE_90, sizeof(ROTATE_90)); + } break; + case webrtc::kVideoRotation_180: { + const float ROTATE_180[16] = + { -a[0], -a[1], -a[2], -a[3], + -a[4], -a[5], -a[6], -a[7], + a[8], a[9], a[10], a[11], + a[0] + a[4] + a[12], a[1] +a[5] + a[13], a[2] + a[6] + a[14], + a[3] + a[11]+ a[15]}; + memcpy(a, ROTATE_180, sizeof(ROTATE_180)); + } + break; + case webrtc::kVideoRotation_270: { + const float ROTATE_270[16] = + { -a[4], -a[5], -a[6], -a[7], + a[0], a[1], a[2], a[3], + a[8], a[9], a[10], a[11], + a[4] + a[12], a[5] + a[13], a[6] + a[14], a[7] + a[15]}; + memcpy(a, ROTATE_270, sizeof(ROTATE_270)); + } break; + } +} + +} // anonymouse namespace namespace webrtc_jni { -NativeTextureHandleImpl::NativeTextureHandleImpl(JNIEnv* jni, - jint j_oes_texture_id, - jfloatArray j_transform_matrix) - : oes_texture_id(j_oes_texture_id) { +// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. +static const int kBufferAlignment = 64; + +NativeHandleImpl::NativeHandleImpl(JNIEnv* jni, + jint j_oes_texture_id, + jfloatArray j_transform_matrix) + : oes_texture_id(j_oes_texture_id) { RTC_CHECK_EQ(16, jni->GetArrayLength(j_transform_matrix)); jfloat* transform_matrix_ptr = jni->GetFloatArrayElements(j_transform_matrix, nullptr); @@ -44,41 +95,15 @@ jni->ReleaseFloatArrayElements(j_transform_matrix, transform_matrix_ptr, 0); } -NativeHandleImpl::NativeHandleImpl() : texture_object_(NULL), texture_id_(-1) {} - -void* NativeHandleImpl::GetHandle() { - return texture_object_; -} - -int NativeHandleImpl::GetTextureId() { - return texture_id_; -} - -void NativeHandleImpl::SetTextureObject(void* texture_object, int texture_id) { - texture_object_ = reinterpret_cast<jobject>(texture_object); - texture_id_ = texture_id; -} - -JniNativeHandleBuffer::JniNativeHandleBuffer(void* native_handle, - int width, - int height) - : NativeHandleBuffer(native_handle, width, height) {} - -rtc::scoped_refptr<webrtc::VideoFrameBuffer> -JniNativeHandleBuffer::NativeToI420Buffer() { - // TODO(pbos): Implement before using this in the encoder pipeline (or - // remove the RTC_CHECK() in VideoCapture). - RTC_NOTREACHED(); - return nullptr; -} - AndroidTextureBuffer::AndroidTextureBuffer( int width, int height, - const NativeTextureHandleImpl& native_handle, + const NativeHandleImpl& native_handle, + jobject surface_texture_helper, const rtc::Callback0<void>& no_longer_used) : webrtc::NativeHandleBuffer(&native_handle_, width, height), native_handle_(native_handle), + surface_texture_helper_(surface_texture_helper), no_longer_used_cb_(no_longer_used) {} AndroidTextureBuffer::~AndroidTextureBuffer() { @@ -87,9 +112,75 @@ rtc::scoped_refptr<webrtc::VideoFrameBuffer> AndroidTextureBuffer::NativeToI420Buffer() { - RTC_NOTREACHED() - << "AndroidTextureBuffer::NativeToI420Buffer not implemented."; - return nullptr; + int uv_width = (width()+7) / 8; + int stride = 8 * uv_width; + int uv_height = (height()+1)/2; + size_t size = stride * (height() + uv_height); + // The data is owned by the frame, and the normal case is that the + // data is deleted by the frame's destructor callback. + // + // TODO(nisse): Use an I420BufferPool. We then need to extend that + // class, and I420Buffer, to support our memory layout. + rtc::scoped_ptr<uint8_t, webrtc::AlignedFreeDeleter> yuv_data( + static_cast<uint8_t*>(webrtc::AlignedMalloc(size, kBufferAlignment))); + // See SurfaceTextureHelper.java for the required layout. + uint8_t* y_data = yuv_data.get(); + uint8_t* u_data = y_data + height() * stride; + uint8_t* v_data = u_data + stride/2; + + rtc::scoped_refptr<webrtc::VideoFrameBuffer> copy = + new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( + width(), height(), + y_data, stride, + u_data, stride, + v_data, stride, + rtc::Bind(&webrtc::AlignedFree, yuv_data.release())); + + JNIEnv* jni = AttachCurrentThreadIfNeeded(); + ScopedLocalRefFrame local_ref_frame(jni); + + jmethodID transform_mid = GetMethodID( + jni, + GetObjectClass(jni, surface_texture_helper_), + "textureToYUV", + "(Ljava/nio/ByteBuffer;IIII[F)V"); + + jobject byte_buffer = jni->NewDirectByteBuffer(y_data, size); + + // TODO(nisse): Keep java transform matrix around. + jfloatArray sampling_matrix = jni->NewFloatArray(16); + jni->SetFloatArrayRegion(sampling_matrix, 0, 16, + native_handle_.sampling_matrix); + + jni->CallVoidMethod(surface_texture_helper_, + transform_mid, + byte_buffer, width(), height(), stride, + native_handle_.oes_texture_id, sampling_matrix); + CHECK_EXCEPTION(jni) << "textureToYUV throwed an exception"; + + return copy; +} + +rtc::scoped_refptr<AndroidTextureBuffer> +AndroidTextureBuffer::ScaleAndRotate(int dst_widht, + int dst_height, + webrtc::VideoRotation rotation) { + if (width() == dst_widht && height() == dst_height && + rotation == webrtc::kVideoRotation_0) { + return this; + } + int rotated_width = (rotation % 180 == 0) ? dst_widht : dst_height; + int rotated_height = (rotation % 180 == 0) ? dst_height : dst_widht; + + // Here we use Bind magic to add a reference count to |this| until the newly + // created AndroidTextureBuffer is destructed + rtc::scoped_refptr<AndroidTextureBuffer> buffer( + new rtc::RefCountedObject<AndroidTextureBuffer>( + rotated_width, rotated_height, native_handle_, + surface_texture_helper_, rtc::KeepRefUntilDone(this))); + + RotateMatrix(buffer->native_handle_.sampling_matrix, rotation); + return buffer; } } // namespace webrtc_jni
diff --git a/talk/app/webrtc/java/jni/native_handle_impl.h b/talk/app/webrtc/java/jni/native_handle_impl.h index dd04bc2..1d0f601 100644 --- a/talk/app/webrtc/java/jni/native_handle_impl.h +++ b/talk/app/webrtc/java/jni/native_handle_impl.h
@@ -31,56 +31,44 @@ #include <jni.h> -#include "webrtc/common_video/interface/video_frame_buffer.h" +#include "webrtc/common_video/include/video_frame_buffer.h" +#include "webrtc/common_video/rotation.h" namespace webrtc_jni { // Wrapper for texture object. -struct NativeTextureHandleImpl { - NativeTextureHandleImpl(JNIEnv* jni, - jint j_oes_texture_id, - jfloatArray j_transform_matrix); +struct NativeHandleImpl { + NativeHandleImpl(JNIEnv* jni, + jint j_oes_texture_id, + jfloatArray j_transform_matrix); const int oes_texture_id; float sampling_matrix[16]; }; -// Native handle for SurfaceTexture + texture id. -class NativeHandleImpl { - public: - NativeHandleImpl(); - - void* GetHandle(); - int GetTextureId(); - void SetTextureObject(void* texture_object, int texture_id); - - private: - jobject texture_object_; - int32_t texture_id_; -}; - -class JniNativeHandleBuffer : public webrtc::NativeHandleBuffer { - public: - JniNativeHandleBuffer(void* native_handle, int width, int height); - - // TODO(pbos): Override destructor to release native handle, at the moment the - // native handle is not released based on refcount. - - private: - rtc::scoped_refptr<webrtc::VideoFrameBuffer> NativeToI420Buffer() override; -}; - class AndroidTextureBuffer : public webrtc::NativeHandleBuffer { public: AndroidTextureBuffer(int width, int height, - const NativeTextureHandleImpl& native_handle, + const NativeHandleImpl& native_handle, + jobject surface_texture_helper, const rtc::Callback0<void>& no_longer_used); ~AndroidTextureBuffer(); rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() override; + rtc::scoped_refptr<AndroidTextureBuffer> ScaleAndRotate( + int dst_widht, + int dst_height, + webrtc::VideoRotation rotation); + private: - NativeTextureHandleImpl native_handle_; + NativeHandleImpl native_handle_; + // Raw object pointer, relying on the caller, i.e., + // AndroidVideoCapturerJni or the C++ SurfaceTextureHelper, to keep + // a global reference. TODO(nisse): Make this a reference to the C++ + // SurfaceTextureHelper instead, but that requires some refactoring + // of AndroidVideoCapturerJni. + jobject surface_texture_helper_; rtc::Callback0<void> no_longer_used_cb_; };
diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc index e75cd55..5ea63f7 100644 --- a/talk/app/webrtc/java/jni/peerconnection_jni.cc +++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc
@@ -57,6 +57,7 @@ #define JNIEXPORT __attribute__((visibility("default"))) #include <limits> +#include <utility> #include "talk/app/webrtc/java/jni/classreferenceholder.h" #include "talk/app/webrtc/java/jni/jni_helpers.h" @@ -74,10 +75,11 @@ #include "talk/media/webrtc/webrtcvideoencoderfactory.h" #include "webrtc/base/bind.h" #include "webrtc/base/checks.h" +#include "webrtc/base/event_tracer.h" #include "webrtc/base/logging.h" #include "webrtc/base/logsinks.h" -#include "webrtc/base/networkmonitor.h" #include "webrtc/base/messagequeue.h" +#include "webrtc/base/networkmonitor.h" #include "webrtc/base/ssladapter.h" #include "webrtc/base/stringutils.h" #include "webrtc/system_wrappers/include/field_trial_default.h" @@ -141,22 +143,6 @@ static bool video_hw_acceleration_enabled = true; #endif -extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { - jint ret = InitGlobalJniVariables(jvm); - if (ret < 0) - return -1; - - RTC_CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()"; - LoadGlobalClassReferenceHolder(); - - return ret; -} - -extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) { - FreeGlobalClassReferenceHolder(); - RTC_CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()"; -} - // Return the (singleton) Java Enum object corresponding to |index|; // |state_class_fragment| is something like "MediaSource$State". static jobject JavaEnumFromIndex( @@ -545,7 +531,7 @@ protected: // Common implementation for failure of Set & Create types, distinguished by // |op| being "Set" or "Create". - void OnFailure(const std::string& op, const std::string& error) { + void DoOnFailure(const std::string& op, const std::string& error) { jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure", "(Ljava/lang/String;)V"); jstring j_error_string = JavaStringFromStdString(jni(), error); @@ -572,7 +558,7 @@ void OnFailure(const std::string& error) override { ScopedLocalRefFrame local_ref_frame(jni()); - SdpObserverWrapper::OnFailure(std::string("Create"), error); + SdpObserverWrapper::DoOnFailure(std::string("Create"), error); } }; @@ -585,7 +571,7 @@ void OnFailure(const std::string& error) override { ScopedLocalRefFrame local_ref_frame(jni()); - SdpObserverWrapper::OnFailure(std::string("Set"), error); + SdpObserverWrapper::DoOnFailure(std::string("Set"), error); } }; @@ -773,7 +759,7 @@ jni, *j_frame_class_, "<init>", "(III[I[Ljava/nio/ByteBuffer;J)V")), j_texture_frame_ctor_id_(GetMethodID( jni, *j_frame_class_, "<init>", - "(IIILjava/lang/Object;IJ)V")), + "(IIII[FJ)V")), j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) { CHECK_EXCEPTION(jni); } @@ -829,13 +815,13 @@ jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) { NativeHandleImpl* handle = reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle()); - jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle()); - int texture_id = handle->GetTextureId(); + jfloatArray sampling_matrix = jni()->NewFloatArray(16); + jni()->SetFloatArrayRegion(sampling_matrix, 0, 16, handle->sampling_matrix); return jni()->NewObject( *j_frame_class_, j_texture_frame_ctor_id_, frame->GetWidth(), frame->GetHeight(), static_cast<int>(frame->GetVideoRotation()), - texture_object, texture_id, javaShallowCopy(frame)); + handle->oes_texture_id, sampling_matrix, javaShallowCopy(frame)); } JNIEnv* jni() { @@ -1054,6 +1040,32 @@ webrtc::field_trial::InitFieldTrialsFromString(field_trials_init_string); } +JOW(void, PeerConnectionFactory_initializeInternalTracer)(JNIEnv* jni, jclass) { + rtc::tracing::SetupInternalTracer(); +} + +JOW(jboolean, PeerConnectionFactory_startInternalTracingCapture)( + JNIEnv* jni, jclass, jstring j_event_tracing_filename) { + if (!j_event_tracing_filename) + return false; + + const char* init_string = + jni->GetStringUTFChars(j_event_tracing_filename, NULL); + LOG(LS_INFO) << "Starting internal tracing to: " << init_string; + bool ret = rtc::tracing::StartInternalCapture(init_string); + jni->ReleaseStringUTFChars(j_event_tracing_filename, init_string); + return ret; +} + +JOW(void, PeerConnectionFactory_stopInternalTracingCapture)( + JNIEnv* jni, jclass) { + rtc::tracing::StopInternalCapture(); +} + +JOW(void, PeerConnectionFactory_shutdownInternalTracer)(JNIEnv* jni, jclass) { + rtc::tracing::ShutdownInternalTracer(); +} + // Helper struct for working around the fact that CreatePeerConnectionFactory() // comes in two flavors: either entirely automagical (constructing its own // threads and deleting them on teardown, but no external codec factory support) @@ -1251,6 +1263,46 @@ return (jlong)track.release(); } +JOW(jboolean, PeerConnectionFactory_nativeStartAecDump)( + JNIEnv* jni, jclass, jlong native_factory, jint file) { +#if defined(ANDROID) + rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( + factoryFromJava(native_factory)); + return factory->StartAecDump(file); +#else + return false; +#endif +} + +JOW(void, PeerConnectionFactory_nativeStopAecDump)( + JNIEnv* jni, jclass, jlong native_factory) { +#if defined(ANDROID) + rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( + factoryFromJava(native_factory)); + factory->StopAecDump(); +#endif +} + +JOW(jboolean, PeerConnectionFactory_nativeStartRtcEventLog)( + JNIEnv* jni, jclass, jlong native_factory, jint file) { +#if defined(ANDROID) + rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( + factoryFromJava(native_factory)); + return factory->StartRtcEventLog(file); +#else + return false; +#endif +} + +JOW(void, PeerConnectionFactory_nativeStopRtcEventLog)( + JNIEnv* jni, jclass, jlong native_factory) { +#if defined(ANDROID) + rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( + factoryFromJava(native_factory)); + factory->StopRtcEventLog(); +#endif +} + JOW(void, PeerConnectionFactory_nativeSetOptions)( JNIEnv* jni, jclass, jlong native_factory, jobject options) { rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( @@ -1292,21 +1344,35 @@ } JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions)( - JNIEnv* jni, jclass, jlong native_factory, jobject render_egl_context) { + JNIEnv* jni, jclass, jlong native_factory, jobject local_egl_context, + jobject remote_egl_context) { #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) OwnedFactoryAndThreads* owned_factory = reinterpret_cast<OwnedFactoryAndThreads*>(native_factory); + + jclass j_eglbase14_context_class = + FindClass(jni, "org/webrtc/EglBase14$Context"); + + MediaCodecVideoEncoderFactory* encoder_factory = + static_cast<MediaCodecVideoEncoderFactory*> + (owned_factory->encoder_factory()); + if (encoder_factory && + jni->IsInstanceOf(local_egl_context, j_eglbase14_context_class)) { + LOG(LS_INFO) << "Set EGL context for HW encoding."; + encoder_factory->SetEGLContext(jni, local_egl_context); + } + MediaCodecVideoDecoderFactory* decoder_factory = static_cast<MediaCodecVideoDecoderFactory*> (owned_factory->decoder_factory()); - if (decoder_factory) { - LOG(LS_INFO) << "Set EGL context for HW acceleration."; - decoder_factory->SetEGLContext(jni, render_egl_context); + if (decoder_factory && + jni->IsInstanceOf(remote_egl_context, j_eglbase14_context_class)) { + LOG(LS_INFO) << "Set EGL context for HW decoding."; + decoder_factory->SetEGLContext(jni, remote_egl_context); } #endif } - static std::string GetJavaEnumName(JNIEnv* jni, const std::string& className, jobject j_enum) { jclass enumClass = FindClass(jni, className.c_str()); @@ -1503,6 +1569,9 @@ jfieldID j_ice_connection_receiving_timeout_id = GetFieldID(jni, j_rtc_config_class, "iceConnectionReceivingTimeout", "I"); + jfieldID j_ice_backup_candidate_pair_ping_interval_id = GetFieldID( + jni, j_rtc_config_class, "iceBackupCandidatePairPingInterval", "I"); + jfieldID j_continual_gathering_policy_id = GetFieldID(jni, j_rtc_config_class, "continualGatheringPolicy", "Lorg/webrtc/PeerConnection$ContinualGatheringPolicy;"); @@ -1524,6 +1593,8 @@ jni, j_rtc_config, j_audio_jitter_buffer_fast_accelerate_id); rtc_config->ice_connection_receiving_timeout = GetIntField(jni, j_rtc_config, j_ice_connection_receiving_timeout_id); + rtc_config->ice_backup_candidate_pair_ping_interval = GetIntField( + jni, j_rtc_config, j_ice_backup_candidate_pair_ping_interval_id); rtc_config->continual_gathering_policy = JavaContinualGatheringPolicyToNativeType( jni, j_continual_gathering_policy); @@ -1550,7 +1621,7 @@ rtc::SSLIdentity::Generate(webrtc::kIdentityName, rtc::KT_ECDSA)); if (ssl_identity.get()) { rtc_config.certificates.push_back( - rtc::RTCCertificate::Create(ssl_identity.Pass())); + rtc::RTCCertificate::Create(std::move(ssl_identity))); LOG(LS_INFO) << "ECDSA certificate created."; } else { // Failing to create certificate should not abort peer connection @@ -1704,6 +1775,29 @@ reinterpret_cast<MediaStreamInterface*>(native_stream)); } +JOW(jobject, PeerConnection_nativeCreateSender)( + JNIEnv* jni, jobject j_pc, jstring j_kind, jstring j_stream_id) { + jclass j_rtp_sender_class = FindClass(jni, "org/webrtc/RtpSender"); + jmethodID j_rtp_sender_ctor = + GetMethodID(jni, j_rtp_sender_class, "<init>", "(J)V"); + + std::string kind = JavaToStdString(jni, j_kind); + std::string stream_id = JavaToStdString(jni, j_stream_id); + rtc::scoped_refptr<RtpSenderInterface> sender = + ExtractNativePC(jni, j_pc)->CreateSender(kind, stream_id); + if (!sender.get()) { + return nullptr; + } + jlong nativeSenderPtr = jlongFromPointer(sender.get()); + jobject j_sender = + jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr); + CHECK_EXCEPTION(jni) << "error during NewObject"; + // Sender is now owned by the Java object, and will be freed from + // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders(). + sender->AddRef(); + return j_sender; +} + JOW(jobject, PeerConnection_nativeGetSenders)(JNIEnv* jni, jobject j_pc) { jclass j_array_list_class = FindClass(jni, "java/util/ArrayList"); jmethodID j_array_list_ctor = @@ -1723,7 +1817,8 @@ jobject j_sender = jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr); CHECK_EXCEPTION(jni) << "error during NewObject"; - // Sender is now owned by Java object, and will be freed from there. + // Sender is now owned by the Java object, and will be freed from + // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders(). sender->AddRef(); jni->CallBooleanMethod(j_senders, j_array_list_add, j_sender); CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; @@ -1802,6 +1897,7 @@ // Since we can't create platform specific java implementations in Java, we // defer the creation to C land. #if defined(ANDROID) + // TODO(nisse): This case is intended to be deleted. jclass j_video_capturer_class( FindClass(jni, "org/webrtc/VideoCapturerAndroid")); const int camera_id = jni->CallStaticIntMethod( @@ -1816,8 +1912,13 @@ j_video_capturer_class, GetMethodID(jni, j_video_capturer_class, "<init>", "(I)V"), camera_id); CHECK_EXCEPTION(jni) << "error during creation of VideoCapturerAndroid"; + jfieldID helper_fid = GetFieldID(jni, j_video_capturer_class, "surfaceHelper", + "Lorg/webrtc/SurfaceTextureHelper;"); + rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate = - new rtc::RefCountedObject<AndroidVideoCapturerJni>(jni, j_video_capturer); + new rtc::RefCountedObject<AndroidVideoCapturerJni>( + jni, j_video_capturer, + GetObjectField(jni, j_video_capturer, helper_fid)); rtc::scoped_ptr<cricket::VideoCapturer> capturer( new webrtc::AndroidVideoCapturer(delegate)); @@ -2003,11 +2104,11 @@ return result; } -JOW(void, RtpSender_nativeSetTrack)(JNIEnv* jni, +JOW(jboolean, RtpSender_nativeSetTrack)(JNIEnv* jni, jclass, jlong j_rtp_sender_pointer, jlong j_track_pointer) { - reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer) + return reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer) ->SetTrack(reinterpret_cast<MediaStreamTrackInterface*>(j_track_pointer)); }
diff --git a/talk/app/webrtc/java/jni/surfacetexturehelper_jni.cc b/talk/app/webrtc/java/jni/surfacetexturehelper_jni.cc index 05f1b23..3e32b9a 100644 --- a/talk/app/webrtc/java/jni/surfacetexturehelper_jni.cc +++ b/talk/app/webrtc/java/jni/surfacetexturehelper_jni.cc
@@ -35,25 +35,14 @@ namespace webrtc_jni { -SurfaceTextureHelper::SurfaceTextureHelper(JNIEnv* jni, - jobject egl_shared_context) - : j_surface_texture_helper_class_( - jni, - FindClass(jni, "org/webrtc/SurfaceTextureHelper")), - j_surface_texture_helper_( - jni, - jni->CallStaticObjectMethod( - *j_surface_texture_helper_class_, - GetStaticMethodID(jni, - *j_surface_texture_helper_class_, - "create", - "(Ljavax/microedition/khronos/egl/EGLContext;)" - "Lorg/webrtc/SurfaceTextureHelper;"), - egl_shared_context)), - j_return_texture_method_(GetMethodID(jni, - *j_surface_texture_helper_class_, - "returnTextureFrame", - "()V")) { +SurfaceTextureHelper::SurfaceTextureHelper( + JNIEnv* jni, jobject surface_texture_helper) + : j_surface_texture_helper_(jni, surface_texture_helper), + j_return_texture_method_( + GetMethodID(jni, + FindClass(jni, "org/webrtc/SurfaceTextureHelper"), + "returnTextureFrame", + "()V")) { CHECK_EXCEPTION(jni) << "error during initialization of SurfaceTextureHelper"; } @@ -70,9 +59,9 @@ rtc::scoped_refptr<webrtc::VideoFrameBuffer> SurfaceTextureHelper::CreateTextureFrame(int width, int height, - const NativeTextureHandleImpl& native_handle) { + const NativeHandleImpl& native_handle) { return new rtc::RefCountedObject<AndroidTextureBuffer>( - width, height, native_handle, + width, height, native_handle, *j_surface_texture_helper_, rtc::Bind(&SurfaceTextureHelper::ReturnTextureFrame, this)); }
diff --git a/talk/app/webrtc/java/jni/surfacetexturehelper_jni.h b/talk/app/webrtc/java/jni/surfacetexturehelper_jni.h index dc9d2b8..8dde2b5 100644 --- a/talk/app/webrtc/java/jni/surfacetexturehelper_jni.h +++ b/talk/app/webrtc/java/jni/surfacetexturehelper_jni.h
@@ -35,7 +35,7 @@ #include "talk/app/webrtc/java/jni/native_handle_impl.h" #include "webrtc/base/refcount.h" #include "webrtc/base/scoped_ref_ptr.h" -#include "webrtc/common_video/interface/video_frame_buffer.h" +#include "webrtc/common_video/include/video_frame_buffer.h" namespace webrtc_jni { @@ -49,24 +49,19 @@ // destroyed while a VideoFrameBuffer is in use. // This class is the C++ counterpart of the java class SurfaceTextureHelper. // Usage: -// 1. Create an instance of this class. -// 2. Call GetJavaSurfaceTextureHelper to get the Java SurfaceTextureHelper. +// 1. Create an java instance of SurfaceTextureHelper. +// 2. Create an instance of this class. // 3. Register a listener to the Java SurfaceListener and start producing // new buffers. -// 3. Call CreateTextureFrame to wrap the Java texture in a VideoFrameBuffer. +// 4. Call CreateTextureFrame to wrap the Java texture in a VideoFrameBuffer. class SurfaceTextureHelper : public rtc::RefCountInterface { public: - SurfaceTextureHelper(JNIEnv* jni, jobject shared_egl_context); - - // Returns the Java SurfaceTextureHelper. - jobject GetJavaSurfaceTextureHelper() const { - return *j_surface_texture_helper_; - } + SurfaceTextureHelper(JNIEnv* jni, jobject surface_texture_helper); rtc::scoped_refptr<webrtc::VideoFrameBuffer> CreateTextureFrame( int width, int height, - const NativeTextureHandleImpl& native_handle); + const NativeHandleImpl& native_handle); protected: ~SurfaceTextureHelper(); @@ -75,7 +70,6 @@ // May be called on arbitrary thread. void ReturnTextureFrame() const; - const ScopedGlobalRef<jclass> j_surface_texture_helper_class_; const ScopedGlobalRef<jobject> j_surface_texture_helper_; const jmethodID j_return_texture_method_; };
diff --git a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java index 42af9c7..19002f7 100644 --- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java +++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java
@@ -33,23 +33,23 @@ import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCodecList; import android.media.MediaFormat; -import android.opengl.GLES11Ext; -import android.opengl.GLES20; import android.os.Build; +import android.os.SystemClock; import android.view.Surface; import org.webrtc.Logging; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.LinkedList; import java.util.List; - -import javax.microedition.khronos.egl.EGLContext; +import java.util.concurrent.CountDownLatch; +import java.util.Queue; +import java.util.concurrent.TimeUnit; // Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder. // This class is an implementation detail of the Java PeerConnection API. -// MediaCodec is thread-hostile so this class must be operated on a single -// thread. +@SuppressWarnings("deprecation") public class MediaCodecVideoDecoder { // This class is constructed, operated, and destroyed by its C++ incarnation, // so the class and its methods have non-public visibility. The API this @@ -66,18 +66,26 @@ } private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout. + private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; // Timeout for codec releasing. // Active running decoder instance. Set in initDecode() (called from native code) // and reset to null in release() call. private static MediaCodecVideoDecoder runningInstance = null; + private static MediaCodecVideoDecoderErrorCallback errorCallback = null; + private static int codecErrors = 0; + private Thread mediaCodecThread; private MediaCodec mediaCodec; private ByteBuffer[] inputBuffers; private ByteBuffer[] outputBuffers; private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; + private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9"; private static final String H264_MIME_TYPE = "video/avc"; // List of supported HW VP8 decoders. private static final String[] supportedVp8HwCodecPrefixes = {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." }; + // List of supported HW VP9 decoders. + private static final String[] supportedVp9HwCodecPrefixes = + {"OMX.qcom.", "OMX.Exynos." }; // List of supported HW H.264 decoders. private static final String[] supportedH264HwCodecPrefixes = {"OMX.qcom.", "OMX.Intel." }; @@ -96,13 +104,29 @@ private int height; private int stride; private int sliceHeight; + private boolean hasDecodedFirstFrame; + private final Queue<TimeStamps> decodeStartTimeMs = new LinkedList<TimeStamps>(); private boolean useSurface; - private int textureID = 0; - private SurfaceTexture surfaceTexture = null; - private Surface surface = null; - private EglBase eglBase; - private MediaCodecVideoDecoder() { + // The below variables are only used when decoding to a Surface. + private TextureListener textureListener; + // Max number of output buffers queued before starting to drop decoded frames. + private static final int MAX_QUEUED_OUTPUTBUFFERS = 3; + private int droppedFrames; + private Surface surface = null; + private final Queue<DecodedOutputBuffer> + dequeuedSurfaceOutputBuffers = new LinkedList<DecodedOutputBuffer>(); + + // MediaCodec error handler - invoked when critical error happens which may prevent + // further use of media codec API. Now it means that one of media codec instances + // is hanging and can no longer be used in the next call. + public static interface MediaCodecVideoDecoderErrorCallback { + void onMediaCodecVideoDecoderCriticalError(int codecErrors); + } + + public static void setErrorCallback(MediaCodecVideoDecoderErrorCallback errorCallback) { + Logging.d(TAG, "Set error callback"); + MediaCodecVideoDecoder.errorCallback = errorCallback; } // Helper struct for findVp8Decoder() below. @@ -120,6 +144,7 @@ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { return null; // MediaCodec.setParameters is missing. } + Logging.d(TAG, "Trying to find HW decoder for mime " + mime); for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) { MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); if (info.isEncoder()) { @@ -135,7 +160,7 @@ if (name == null) { continue; // No HW support in this codec; try the next one. } - Logging.v(TAG, "Found candidate decoder " + name); + Logging.d(TAG, "Found candidate decoder " + name); // Check if this is supported decoder. boolean supportedCodec = false; @@ -166,6 +191,7 @@ } } } + Logging.d(TAG, "No HW decoder found for mime " + mime); return null; // No HW decoder. } @@ -173,6 +199,10 @@ return findDecoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes) != null; } + public static boolean isVp9HwSupported() { + return findDecoder(VP9_MIME_TYPE, supportedVp9HwCodecPrefixes) != null; + } + public static boolean isH264HwSupported() { return findDecoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null; } @@ -197,17 +227,21 @@ } } - // Pass null in |sharedContext| to configure the codec for ByteBuffer output. - private boolean initDecode(VideoCodecType type, int width, int height, EGLContext sharedContext) { + // Pass null in |surfaceTextureHelper| to configure the codec for ByteBuffer output. + private boolean initDecode( + VideoCodecType type, int width, int height, SurfaceTextureHelper surfaceTextureHelper) { if (mediaCodecThread != null) { throw new RuntimeException("Forgot to release()?"); } - useSurface = (sharedContext != null); + useSurface = (surfaceTextureHelper != null); String mime = null; String[] supportedCodecPrefixes = null; if (type == VideoCodecType.VIDEO_CODEC_VP8) { mime = VP8_MIME_TYPE; supportedCodecPrefixes = supportedVp8HwCodecPrefixes; + } else if (type == VideoCodecType.VIDEO_CODEC_VP9) { + mime = VP9_MIME_TYPE; + supportedCodecPrefixes = supportedVp9HwCodecPrefixes; } else if (type == VideoCodecType.VIDEO_CODEC_H264) { mime = H264_MIME_TYPE; supportedCodecPrefixes = supportedH264HwCodecPrefixes; @@ -221,9 +255,6 @@ Logging.d(TAG, "Java initDecode: " + type + " : "+ width + " x " + height + ". Color: 0x" + Integer.toHexString(properties.colorFormat) + ". Use Surface: " + useSurface); - if (sharedContext != null) { - Logging.d(TAG, "Decoder shared EGL Context: " + sharedContext); - } runningInstance = this; // Decoder is now running and can be queried for stack traces. mediaCodecThread = Thread.currentThread(); try { @@ -233,16 +264,8 @@ sliceHeight = height; if (useSurface) { - // Create shared EGL context. - eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER); - eglBase.createDummyPbufferSurface(); - eglBase.makeCurrent(); - - // Create output surface - textureID = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); - Logging.d(TAG, "Video decoder TextureID = " + textureID); - surfaceTexture = new SurfaceTexture(textureID); - surface = new Surface(surfaceTexture); + textureListener = new TextureListener(surfaceTextureHelper); + surface = new Surface(surfaceTextureHelper.getSurfaceTexture()); } MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); @@ -261,6 +284,10 @@ colorFormat = properties.colorFormat; outputBuffers = mediaCodec.getOutputBuffers(); inputBuffers = mediaCodec.getInputBuffers(); + decodeStartTimeMs.clear(); + hasDecodedFirstFrame = false; + dequeuedSurfaceOutputBuffers.clear(); + droppedFrames = 0; Logging.d(TAG, "Input buffers: " + inputBuffers.length + ". Output buffers: " + outputBuffers.length); return true; @@ -271,25 +298,45 @@ } private void release() { - Logging.d(TAG, "Java releaseDecoder"); + Logging.d(TAG, "Java releaseDecoder. Total number of dropped frames: " + droppedFrames); checkOnMediaCodecThread(); - try { - mediaCodec.stop(); - mediaCodec.release(); - } catch (IllegalStateException e) { - Logging.e(TAG, "release failed", e); + + // Run Mediacodec stop() and release() on separate thread since sometime + // Mediacodec.stop() may hang. + final CountDownLatch releaseDone = new CountDownLatch(1); + + Runnable runMediaCodecRelease = new Runnable() { + @Override + public void run() { + try { + Logging.d(TAG, "Java releaseDecoder on release thread"); + mediaCodec.stop(); + mediaCodec.release(); + Logging.d(TAG, "Java releaseDecoder on release thread done"); + } catch (Exception e) { + Logging.e(TAG, "Media decoder release failed", e); + } + releaseDone.countDown(); + } + }; + new Thread(runMediaCodecRelease).start(); + + if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIMEOUT_MS)) { + Logging.e(TAG, "Media decoder release timeout"); + codecErrors++; + if (errorCallback != null) { + Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors); + errorCallback.onMediaCodecVideoDecoderCriticalError(codecErrors); + } } + mediaCodec = null; mediaCodecThread = null; runningInstance = null; if (useSurface) { surface.release(); surface = null; - Logging.d(TAG, "Delete video decoder TextureID " + textureID); - GLES20.glDeleteTextures(1, new int[] {textureID}, 0); - textureID = 0; - eglBase.release(); - eglBase = null; + textureListener.release(); } Logging.d(TAG, "Java releaseDecoder done"); } @@ -306,13 +353,15 @@ } } - private boolean queueInputBuffer( - int inputBufferIndex, int size, long timestampUs) { + private boolean queueInputBuffer(int inputBufferIndex, int size, long presentationTimeStamUs, + long timeStampMs, long ntpTimeStamp) { checkOnMediaCodecThread(); try { inputBuffers[inputBufferIndex].position(0); inputBuffers[inputBufferIndex].limit(size); - mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, timestampUs, 0); + decodeStartTimeMs.add(new TimeStamps(SystemClock.elapsedRealtime(), timeStampMs, + ntpTimeStamp)); + mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, presentationTimeStamUs, 0); return true; } catch (IllegalStateException e) { @@ -321,56 +370,183 @@ } } - // Helper structs for dequeueOutputBuffer() below. - private static class DecodedByteBuffer { - public DecodedByteBuffer(int index, int offset, int size, long presentationTimestampUs) { + private static class TimeStamps { + public TimeStamps(long decodeStartTimeMs, long timeStampMs, long ntpTimeStampMs) { + this.decodeStartTimeMs = decodeStartTimeMs; + this.timeStampMs = timeStampMs; + this.ntpTimeStampMs = ntpTimeStampMs; + } + private final long decodeStartTimeMs; // Time when this frame was queued for decoding. + private final long timeStampMs; // Only used for bookkeeping in Java. Used in C++; + private final long ntpTimeStampMs; // Only used for bookkeeping in Java. Used in C++; + } + + // Helper struct for dequeueOutputBuffer() below. + private static class DecodedOutputBuffer { + public DecodedOutputBuffer(int index, int offset, int size, long timeStampMs, + long ntpTimeStampMs, long decodeTime, long endDecodeTime) { this.index = index; this.offset = offset; this.size = size; - this.presentationTimestampUs = presentationTimestampUs; + this.timeStampMs = timeStampMs; + this.ntpTimeStampMs = ntpTimeStampMs; + this.decodeTimeMs = decodeTime; + this.endDecodeTimeMs = endDecodeTime; } private final int index; private final int offset; private final int size; - private final long presentationTimestampUs; + private final long timeStampMs; + private final long ntpTimeStampMs; + // Number of ms it took to decode this frame. + private final long decodeTimeMs; + // System time when this frame finished decoding. + private final long endDecodeTimeMs; } + // Helper struct for dequeueTextureBuffer() below. private static class DecodedTextureBuffer { private final int textureID; - private final long presentationTimestampUs; + private final float[] transformMatrix; + private final long timeStampMs; + private final long ntpTimeStampMs; + private final long decodeTimeMs; + // Interval from when the frame finished decoding until this buffer has been created. + // Since there is only one texture, this interval depend on the time from when + // a frame is decoded and provided to C++ and until that frame is returned to the MediaCodec + // so that the texture can be updated with the next decoded frame. + private final long frameDelayMs; - public DecodedTextureBuffer(int textureID, long presentationTimestampUs) { + // A DecodedTextureBuffer with zero |textureID| has special meaning and represents a frame + // that was dropped. + public DecodedTextureBuffer(int textureID, float[] transformMatrix, long timeStampMs, + long ntpTimeStampMs, long decodeTimeMs, long frameDelay) { this.textureID = textureID; - this.presentationTimestampUs = presentationTimestampUs; + this.transformMatrix = transformMatrix; + this.timeStampMs = timeStampMs; + this.ntpTimeStampMs = ntpTimeStampMs; + this.decodeTimeMs = decodeTimeMs; + this.frameDelayMs = frameDelay; } } - // Returns null if no decoded buffer is available, and otherwise either a DecodedByteBuffer or - // DecodedTexturebuffer depending on |useSurface| configuration. + // Poll based texture listener. + private static class TextureListener + implements SurfaceTextureHelper.OnTextureFrameAvailableListener { + private final SurfaceTextureHelper surfaceTextureHelper; + // |newFrameLock| is used to synchronize arrival of new frames with wait()/notifyAll(). + private final Object newFrameLock = new Object(); + // |bufferToRender| is non-null when waiting for transition between addBufferToRender() to + // onTextureFrameAvailable(). + private DecodedOutputBuffer bufferToRender; + private DecodedTextureBuffer renderedBuffer; + + public TextureListener(SurfaceTextureHelper surfaceTextureHelper) { + this.surfaceTextureHelper = surfaceTextureHelper; + surfaceTextureHelper.setListener(this); + } + + public void addBufferToRender(DecodedOutputBuffer buffer) { + if (bufferToRender != null) { + Logging.e(TAG, + "Unexpected addBufferToRender() called while waiting for a texture."); + throw new IllegalStateException("Waiting for a texture."); + } + bufferToRender = buffer; + } + + public boolean isWaitingForTexture() { + synchronized (newFrameLock) { + return bufferToRender != null; + } + } + + // Callback from |surfaceTextureHelper|. May be called on an arbitrary thread. + @Override + public void onTextureFrameAvailable( + int oesTextureId, float[] transformMatrix, long timestampNs) { + synchronized (newFrameLock) { + if (renderedBuffer != null) { + Logging.e(TAG, + "Unexpected onTextureFrameAvailable() called while already holding a texture."); + throw new IllegalStateException("Already holding a texture."); + } + // |timestampNs| is always zero on some Android versions. + renderedBuffer = new DecodedTextureBuffer(oesTextureId, transformMatrix, + bufferToRender.timeStampMs, bufferToRender.ntpTimeStampMs, bufferToRender.decodeTimeMs, + SystemClock.elapsedRealtime() - bufferToRender.endDecodeTimeMs); + bufferToRender = null; + newFrameLock.notifyAll(); + } + } + + // Dequeues and returns a DecodedTextureBuffer if available, or null otherwise. + public DecodedTextureBuffer dequeueTextureBuffer(int timeoutMs) { + synchronized (newFrameLock) { + if (renderedBuffer == null && timeoutMs > 0 && isWaitingForTexture()) { + try { + newFrameLock.wait(timeoutMs); + } catch(InterruptedException e) { + // Restore the interrupted status by reinterrupting the thread. + Thread.currentThread().interrupt(); + } + } + DecodedTextureBuffer returnedBuffer = renderedBuffer; + renderedBuffer = null; + return returnedBuffer; + } + } + + public void release() { + // SurfaceTextureHelper.disconnect() will block until any onTextureFrameAvailable() in + // progress is done. Therefore, the call to disconnect() must be outside any synchronized + // statement that is also used in the onTextureFrameAvailable() above to avoid deadlocks. + surfaceTextureHelper.disconnect(); + synchronized (newFrameLock) { + if (renderedBuffer != null) { + surfaceTextureHelper.returnTextureFrame(); + renderedBuffer = null; + } + } + } + } + + // Returns null if no decoded buffer is available, and otherwise a DecodedByteBuffer. // Throws IllegalStateException if call is made on the wrong thread, if color format changes to an // unsupported format, or if |mediaCodec| is not in the Executing state. Throws CodecException // upon codec error. - private Object dequeueOutputBuffer(int dequeueTimeoutUs) - throws IllegalStateException, MediaCodec.CodecException { + private DecodedOutputBuffer dequeueOutputBuffer(int dequeueTimeoutMs) { checkOnMediaCodecThread(); + if (decodeStartTimeMs.isEmpty()) { + return null; + } // Drain the decoder until receiving a decoded buffer or hitting // MediaCodec.INFO_TRY_AGAIN_LATER. final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); while (true) { - final int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); + final int result = mediaCodec.dequeueOutputBuffer( + info, TimeUnit.MILLISECONDS.toMicros(dequeueTimeoutMs)); switch (result) { - case MediaCodec.INFO_TRY_AGAIN_LATER: - return null; case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: outputBuffers = mediaCodec.getOutputBuffers(); Logging.d(TAG, "Decoder output buffers changed: " + outputBuffers.length); + if (hasDecodedFirstFrame) { + throw new RuntimeException("Unexpected output buffer change event."); + } break; case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: MediaFormat format = mediaCodec.getOutputFormat(); Logging.d(TAG, "Decoder format changed: " + format.toString()); + int new_width = format.getInteger(MediaFormat.KEY_WIDTH); + int new_height = format.getInteger(MediaFormat.KEY_HEIGHT); + if (hasDecodedFirstFrame && (new_width != width || new_height != height)) { + throw new RuntimeException("Unexpected size change. Configured " + width + "*" + + height + ". New " + new_width + "*" + new_height); + } width = format.getInteger(MediaFormat.KEY_WIDTH); height = format.getInteger(MediaFormat.KEY_HEIGHT); + if (!useSurface && format.containsKey(MediaFormat.KEY_COLOR_FORMAT)) { colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT); Logging.d(TAG, "Color: 0x" + Integer.toHexString(colorFormat)); @@ -388,30 +564,88 @@ stride = Math.max(width, stride); sliceHeight = Math.max(height, sliceHeight); break; + case MediaCodec.INFO_TRY_AGAIN_LATER: + return null; default: - // Output buffer decoded. - if (useSurface) { - mediaCodec.releaseOutputBuffer(result, true /* render */); - // TODO(magjed): Wait for SurfaceTexture.onFrameAvailable() before returning a texture - // frame. - return new DecodedTextureBuffer(textureID, info.presentationTimeUs); - } else { - return new DecodedByteBuffer(result, info.offset, info.size, info.presentationTimeUs); - } - } + hasDecodedFirstFrame = true; + TimeStamps timeStamps = decodeStartTimeMs.remove(); + return new DecodedOutputBuffer(result, info.offset, info.size, timeStamps.timeStampMs, + timeStamps.ntpTimeStampMs, + SystemClock.elapsedRealtime() - timeStamps.decodeStartTimeMs, + SystemClock.elapsedRealtime()); + } } } + // Returns null if no decoded buffer is available, and otherwise a DecodedTextureBuffer. + // Throws IllegalStateException if call is made on the wrong thread, if color format changes to an + // unsupported format, or if |mediaCodec| is not in the Executing state. Throws CodecException + // upon codec error. If |dequeueTimeoutMs| > 0, the oldest decoded frame will be dropped if + // a frame can't be returned. + private DecodedTextureBuffer dequeueTextureBuffer(int dequeueTimeoutMs) { + checkOnMediaCodecThread(); + if (!useSurface) { + throw new IllegalStateException("dequeueTexture() called for byte buffer decoding."); + } + DecodedOutputBuffer outputBuffer = dequeueOutputBuffer(dequeueTimeoutMs); + if (outputBuffer != null) { + dequeuedSurfaceOutputBuffers.add(outputBuffer); + } + + MaybeRenderDecodedTextureBuffer(); + // Check if there is texture ready now by waiting max |dequeueTimeoutMs|. + DecodedTextureBuffer renderedBuffer = textureListener.dequeueTextureBuffer(dequeueTimeoutMs); + if (renderedBuffer != null) { + MaybeRenderDecodedTextureBuffer(); + return renderedBuffer; + } + + if ((dequeuedSurfaceOutputBuffers.size() + >= Math.min(MAX_QUEUED_OUTPUTBUFFERS, outputBuffers.length) + || (dequeueTimeoutMs > 0 && !dequeuedSurfaceOutputBuffers.isEmpty()))) { + ++droppedFrames; + // Drop the oldest frame still in dequeuedSurfaceOutputBuffers. + // The oldest frame is owned by |textureListener| and can't be dropped since + // mediaCodec.releaseOutputBuffer has already been called. + final DecodedOutputBuffer droppedFrame = dequeuedSurfaceOutputBuffers.remove(); + if (dequeueTimeoutMs > 0) { + // TODO(perkj): Re-add the below log when VideoRenderGUI has been removed or fixed to + // return the one and only texture even if it does not render. + // Logging.w(TAG, "Draining decoder. Dropping frame with TS: " + // + droppedFrame.timeStampMs + ". Total number of dropped frames: " + droppedFrames); + } else { + Logging.w(TAG, "Too many output buffers. Dropping frame with TS: " + + droppedFrame.timeStampMs + ". Total number of dropped frames: " + droppedFrames); + } + + mediaCodec.releaseOutputBuffer(droppedFrame.index, false /* render */); + return new DecodedTextureBuffer(0, null, droppedFrame.timeStampMs, + droppedFrame.ntpTimeStampMs, droppedFrame.decodeTimeMs, + SystemClock.elapsedRealtime() - droppedFrame.endDecodeTimeMs); + } + return null; + } + + private void MaybeRenderDecodedTextureBuffer() { + if (dequeuedSurfaceOutputBuffers.isEmpty() || textureListener.isWaitingForTexture()) { + return; + } + // Get the first frame in the queue and render to the decoder output surface. + final DecodedOutputBuffer buffer = dequeuedSurfaceOutputBuffers.remove(); + textureListener.addBufferToRender(buffer); + mediaCodec.releaseOutputBuffer(buffer.index, true /* render */); + } + // Release a dequeued output byte buffer back to the codec for re-use. Should only be called for // non-surface decoding. // Throws IllegalStateException if the call is made on the wrong thread, if codec is configured // for surface decoding, or if |mediaCodec| is not in the Executing state. Throws // MediaCodec.CodecException upon codec error. - private void returnDecodedByteBuffer(int index) + private void returnDecodedOutputBuffer(int index) throws IllegalStateException, MediaCodec.CodecException { checkOnMediaCodecThread(); if (useSurface) { - throw new IllegalStateException("returnDecodedByteBuffer() called for surface decoding."); + throw new IllegalStateException("returnDecodedOutputBuffer() called for surface decoding."); } mediaCodec.releaseOutputBuffer(index, false /* render */); }
diff --git a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java index f3f03c1..5c8f9dc 100644 --- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java +++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
@@ -27,24 +27,29 @@ package org.webrtc; +import android.annotation.TargetApi; import android.media.MediaCodec; import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.media.MediaFormat; +import android.opengl.GLES20; import android.os.Build; import android.os.Bundle; +import android.view.Surface; import org.webrtc.Logging; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; // Java-side of peerconnection_jni.cc:MediaCodecVideoEncoder. // This class is an implementation detail of the Java PeerConnection API. -// MediaCodec is thread-hostile so this class must be operated on a single -// thread. +@TargetApi(19) +@SuppressWarnings("deprecation") public class MediaCodecVideoEncoder { // This class is constructed, operated, and destroyed by its C++ incarnation, // so the class and its methods have non-public visibility. The API this @@ -60,18 +65,31 @@ VIDEO_CODEC_H264 } + private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; // Timeout for codec releasing. private static final int DEQUEUE_TIMEOUT = 0; // Non-blocking, no wait. - // Active running encoder instance. Set in initDecode() (called from native code) + // Active running encoder instance. Set in initEncode() (called from native code) // and reset to null in release() call. private static MediaCodecVideoEncoder runningInstance = null; + private static MediaCodecVideoEncoderErrorCallback errorCallback = null; + private static int codecErrors = 0; + private Thread mediaCodecThread; private MediaCodec mediaCodec; private ByteBuffer[] outputBuffers; + private EglBase14 eglBase; + private int width; + private int height; + private Surface inputSurface; + private GlRectDrawer drawer; private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; + private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9"; private static final String H264_MIME_TYPE = "video/avc"; // List of supported HW VP8 codecs. private static final String[] supportedVp8HwCodecPrefixes = {"OMX.qcom.", "OMX.Intel." }; + // List of supported HW VP9 decoders. + private static final String[] supportedVp9HwCodecPrefixes = + {"OMX.qcom."}; // List of supported HW H.264 codecs. private static final String[] supportedH264HwCodecPrefixes = {"OMX.qcom." }; @@ -99,13 +117,25 @@ CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m }; - private int colorFormat; - // Video encoder type. + private static final int[] supportedSurfaceColorList = { + CodecCapabilities.COLOR_FormatSurface + }; private VideoCodecType type; + private int colorFormat; // Used by native code. + // SPS and PPS NALs (Config frame) for H.264. private ByteBuffer configData = null; - private MediaCodecVideoEncoder() { + // MediaCodec error handler - invoked when critical error happens which may prevent + // further use of media codec API. Now it means that one of media codec instances + // is hanging and can no longer be used in the next call. + public static interface MediaCodecVideoEncoderErrorCallback { + void onMediaCodecVideoEncoderCriticalError(int codecErrors); + } + + public static void setErrorCallback(MediaCodecVideoEncoderErrorCallback errorCallback) { + Logging.d(TAG, "Set error callback"); + MediaCodecVideoEncoder.errorCallback = errorCallback; } // Helper struct for findHwEncoder() below. @@ -119,7 +149,7 @@ } private static EncoderProperties findHwEncoder( - String mime, String[] supportedHwCodecPrefixes) { + String mime, String[] supportedHwCodecPrefixes, int[] colorList) { // MediaCodec.setParameters is missing for JB and below, so bitrate // can not be adjusted dynamically. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { @@ -130,8 +160,7 @@ if (mime.equals(H264_MIME_TYPE)) { List<String> exceptionModels = Arrays.asList(H264_HW_EXCEPTION_MODELS); if (exceptionModels.contains(Build.MODEL)) { - Logging.w(TAG, "Model: " + Build.MODEL + - " has black listed H.264 encoder."); + Logging.w(TAG, "Model: " + Build.MODEL + " has black listed H.264 encoder."); return null; } } @@ -170,8 +199,7 @@ Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); } - // Check if codec supports either yuv420 or nv12. - for (int supportedColorFormat : supportedColorList) { + for (int supportedColorFormat : colorList) { for (int codecColorFormat : capabilities.colorFormats) { if (codecColorFormat == supportedColorFormat) { // Found supported HW encoder. @@ -182,15 +210,34 @@ } } } - return null; // No HW VP8 encoder. + return null; // No HW encoder. } public static boolean isVp8HwSupported() { - return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes) != null; + return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, supportedColorList) != null; + } + + public static boolean isVp9HwSupported() { + return findHwEncoder(VP9_MIME_TYPE, supportedVp9HwCodecPrefixes, supportedColorList) != null; } public static boolean isH264HwSupported() { - return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null; + return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes, supportedColorList) != null; + } + + public static boolean isVp8HwSupportedUsingTextures() { + return findHwEncoder( + VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, supportedSurfaceColorList) != null; + } + + public static boolean isVp9HwSupportedUsingTextures() { + return findHwEncoder( + VP9_MIME_TYPE, supportedVp9HwCodecPrefixes, supportedSurfaceColorList) != null; + } + + public static boolean isH264HwSupportedUsingTextures() { + return findHwEncoder( + H264_MIME_TYPE, supportedH264HwCodecPrefixes, supportedSurfaceColorList) != null; } private void checkOnMediaCodecThread() { @@ -223,32 +270,43 @@ } } - // Return the array of input buffers, or null on failure. - private ByteBuffer[] initEncode( - VideoCodecType type, int width, int height, int kbps, int fps) { + boolean initEncode(VideoCodecType type, int width, int height, int kbps, int fps, + EglBase14.Context sharedContext) { + final boolean useSurface = sharedContext != null; Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height + - ". @ " + kbps + " kbps. Fps: " + fps + - ". Color: 0x" + Integer.toHexString(colorFormat)); + ". @ " + kbps + " kbps. Fps: " + fps + ". Encode from texture : " + useSurface); + + this.width = width; + this.height = height; if (mediaCodecThread != null) { throw new RuntimeException("Forgot to release()?"); } - this.type = type; EncoderProperties properties = null; String mime = null; int keyFrameIntervalSec = 0; if (type == VideoCodecType.VIDEO_CODEC_VP8) { mime = VP8_MIME_TYPE; - properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes); + properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, + useSurface ? supportedSurfaceColorList : supportedColorList); + keyFrameIntervalSec = 100; + } else if (type == VideoCodecType.VIDEO_CODEC_VP9) { + mime = VP9_MIME_TYPE; + properties = findHwEncoder(VP9_MIME_TYPE, supportedH264HwCodecPrefixes, + useSurface ? supportedSurfaceColorList : supportedColorList); keyFrameIntervalSec = 100; } else if (type == VideoCodecType.VIDEO_CODEC_H264) { mime = H264_MIME_TYPE; - properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes); + properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes, + useSurface ? supportedSurfaceColorList : supportedColorList); keyFrameIntervalSec = 20; } if (properties == null) { throw new RuntimeException("Can not find HW encoder for " + type); } runningInstance = this; // Encoder is now running and can be queried for stack traces. + colorFormat = properties.colorFormat; + Logging.d(TAG, "Color format: " + colorFormat); + mediaCodecThread = Thread.currentThread(); try { MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); @@ -259,26 +317,39 @@ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); Logging.d(TAG, " Format: " + format); mediaCodec = createByCodecName(properties.codecName); + this.type = type; if (mediaCodec == null) { Logging.e(TAG, "Can not create media encoder"); - return null; + return false; } mediaCodec.configure( format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); + + if (useSurface) { + eglBase = new EglBase14(sharedContext, EglBase.CONFIG_RECORDABLE); + // Create an input surface and keep a reference since we must release the surface when done. + inputSurface = mediaCodec.createInputSurface(); + eglBase.createSurface(inputSurface); + drawer = new GlRectDrawer(); + } mediaCodec.start(); - colorFormat = properties.colorFormat; outputBuffers = mediaCodec.getOutputBuffers(); - ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); - Logging.d(TAG, "Input buffers: " + inputBuffers.length + - ". Output buffers: " + outputBuffers.length); - return inputBuffers; + Logging.d(TAG, "Output buffers: " + outputBuffers.length); + } catch (IllegalStateException e) { Logging.e(TAG, "initEncode failed", e); - return null; + return false; } + return true; } - private boolean encode( + ByteBuffer[] getInputBuffers() { + ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); + Logging.d(TAG, "Input buffers: " + inputBuffers.length); + return inputBuffers; + } + + boolean encodeBuffer( boolean isKeyframe, int inputBuffer, int size, long presentationTimestampUs) { checkOnMediaCodecThread(); @@ -298,22 +369,82 @@ return true; } catch (IllegalStateException e) { - Logging.e(TAG, "encode failed", e); + Logging.e(TAG, "encodeBuffer failed", e); return false; } } - private void release() { - Logging.d(TAG, "Java releaseEncoder"); + boolean encodeTexture(boolean isKeyframe, int oesTextureId, float[] transformationMatrix, + long presentationTimestampUs) { checkOnMediaCodecThread(); try { - mediaCodec.stop(); - mediaCodec.release(); - } catch (IllegalStateException e) { - Logging.e(TAG, "release failed", e); + if (isKeyframe) { + Logging.d(TAG, "Sync frame request"); + Bundle b = new Bundle(); + b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); + mediaCodec.setParameters(b); + } + eglBase.makeCurrent(); + // TODO(perkj): glClear() shouldn't be necessary since every pixel is covered anyway, + // but it's a workaround for bug webrtc:5147. + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + drawer.drawOes(oesTextureId, transformationMatrix, 0, 0, width, height); + eglBase.swapBuffers(TimeUnit.MICROSECONDS.toNanos(presentationTimestampUs)); + return true; } + catch (RuntimeException e) { + Logging.e(TAG, "encodeTexture failed", e); + return false; + } + } + + void release() { + Logging.d(TAG, "Java releaseEncoder"); + checkOnMediaCodecThread(); + + // Run Mediacodec stop() and release() on separate thread since sometime + // Mediacodec.stop() may hang. + final CountDownLatch releaseDone = new CountDownLatch(1); + + Runnable runMediaCodecRelease = new Runnable() { + @Override + public void run() { + try { + Logging.d(TAG, "Java releaseEncoder on release thread"); + mediaCodec.stop(); + mediaCodec.release(); + Logging.d(TAG, "Java releaseEncoder on release thread done"); + } catch (Exception e) { + Logging.e(TAG, "Media encoder release failed", e); + } + releaseDone.countDown(); + } + }; + new Thread(runMediaCodecRelease).start(); + + if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIMEOUT_MS)) { + Logging.e(TAG, "Media encoder release timeout"); + codecErrors++; + if (errorCallback != null) { + Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors); + errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors); + } + } + mediaCodec = null; mediaCodecThread = null; + if (drawer != null) { + drawer.release(); + drawer = null; + } + if (eglBase != null) { + eglBase.release(); + eglBase = null; + } + if (inputSurface != null) { + inputSurface.release(); + inputSurface = null; + } runningInstance = null; Logging.d(TAG, "Java releaseEncoder done"); } @@ -336,7 +467,7 @@ // Dequeue an input buffer and return its index, -1 if no input buffer is // available, or -2 if the codec is no longer operative. - private int dequeueInputBuffer() { + int dequeueInputBuffer() { checkOnMediaCodecThread(); try { return mediaCodec.dequeueInputBuffer(DEQUEUE_TIMEOUT); @@ -347,7 +478,7 @@ } // Helper struct for dequeueOutputBuffer() below. - private static class OutputBufferInfo { + static class OutputBufferInfo { public OutputBufferInfo( int index, ByteBuffer buffer, boolean isKeyFrame, long presentationTimestampUs) { @@ -357,15 +488,15 @@ this.presentationTimestampUs = presentationTimestampUs; } - private final int index; - private final ByteBuffer buffer; - private final boolean isKeyFrame; - private final long presentationTimestampUs; + public final int index; + public final ByteBuffer buffer; + public final boolean isKeyFrame; + public final long presentationTimestampUs; } // Dequeue and return an output buffer, or null if no output is ready. Return // a fake OutputBufferInfo with index -1 if the codec is no longer operable. - private OutputBufferInfo dequeueOutputBuffer() { + OutputBufferInfo dequeueOutputBuffer() { checkOnMediaCodecThread(); try { MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); @@ -434,7 +565,7 @@ // Release a dequeued output buffer back to the codec for re-use. Return // false if the codec is no longer operable. - private boolean releaseOutputBuffer(int index) { + boolean releaseOutputBuffer(int index) { checkOnMediaCodecThread(); try { mediaCodec.releaseOutputBuffer(index, false);
diff --git a/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java b/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java index 5002300..36cd075 100644 --- a/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java +++ b/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java
@@ -28,7 +28,6 @@ package org.webrtc; -import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -151,6 +150,7 @@ public int audioJitterBufferMaxPackets; public boolean audioJitterBufferFastAccelerate; public int iceConnectionReceivingTimeout; + public int iceBackupCandidatePairPingInterval; public KeyType keyType; public ContinualGatheringPolicy continualGatheringPolicy; @@ -163,6 +163,7 @@ audioJitterBufferMaxPackets = 50; audioJitterBufferFastAccelerate = false; iceConnectionReceivingTimeout = -1; + iceBackupCandidatePairPingInterval = -1; keyType = KeyType.ECDSA; continualGatheringPolicy = ContinualGatheringPolicy.GATHER_ONCE; } @@ -223,6 +224,14 @@ localStreams.remove(stream); } + public RtpSender createSender(String kind, String stream_id) { + RtpSender new_sender = nativeCreateSender(kind, stream_id); + if (new_sender != null) { + senders.add(new_sender); + } + return new_sender; + } + // Note that calling getSenders will dispose of the senders previously // returned (and same goes for getReceivers). public List<RtpSender> getSenders() { @@ -288,6 +297,8 @@ private native boolean nativeGetStats( StatsObserver observer, long nativeTrack); + private native RtpSender nativeCreateSender(String kind, String stream_id); + private native List<RtpSender> nativeGetSenders(); private native List<RtpReceiver> nativeGetReceivers();
diff --git a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java index 83999ec..d759c69 100644 --- a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java +++ b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
@@ -73,6 +73,15 @@ // Field trial initialization. Must be called before PeerConnectionFactory // is created. public static native void initializeFieldTrials(String fieldTrialsInitString); + // Internal tracing initialization. Must be called before PeerConnectionFactory is created to + // prevent racing with tracing code. + public static native void initializeInternalTracer(); + // Internal tracing shutdown, called to prevent resource leaks. Must be called after + // PeerConnectionFactory is gone to prevent races with code performing tracing. + public static native void shutdownInternalTracer(); + // Start/stop internal capturing of internal tracing. + public static native boolean startInternalTracingCapture(String tracing_filename); + public static native void stopInternalTracingCapture(); public PeerConnectionFactory() { nativeFactory = nativeCreatePeerConnectionFactory(); @@ -131,12 +140,52 @@ nativeFactory, id, source.nativeSource)); } + // Starts recording an AEC dump. Ownership of the file is transfered to the + // native code. If an AEC dump is already in progress, it will be stopped and + // a new one will start using the provided file. + public boolean startAecDump(int file_descriptor) { + return nativeStartAecDump(nativeFactory, file_descriptor); + } + + // Stops recording an AEC dump. If no AEC dump is currently being recorded, + // this call will have no effect. + public void stopAecDump() { + nativeStopAecDump(nativeFactory); + } + + // Starts recording an RTC event log. Ownership of the file is transfered to + // the native code. If an RTC event log is already being recorded, it will be + // stopped and a new one will start using the provided file. + public boolean startRtcEventLog(int file_descriptor) { + return nativeStartRtcEventLog(nativeFactory, file_descriptor); + } + + // Stops recording an RTC event log. If no RTC event log is currently being + // recorded, this call will have no effect. + public void StopRtcEventLog() { + nativeStopRtcEventLog(nativeFactory); + } + public void setOptions(Options options) { nativeSetOptions(nativeFactory, options); } + @Deprecated public void setVideoHwAccelerationOptions(Object renderEGLContext) { - nativeSetVideoHwAccelerationOptions(nativeFactory, renderEGLContext); + nativeSetVideoHwAccelerationOptions(nativeFactory, renderEGLContext, renderEGLContext); + } + + /** Set the EGL context used by HW Video encoding and decoding. + * + * + * @param localEGLContext An instance of javax.microedition.khronos.egl.EGLContext. + * Must be the same as used by VideoCapturerAndroid and any local + * video renderer. + * @param remoteEGLContext An instance of javax.microedition.khronos.egl.EGLContext. + * Must be the same as used by any remote video renderer. + */ + public void setVideoHwAccelerationOptions(Object localEGLContext, Object remoteEGLContext) { + nativeSetVideoHwAccelerationOptions(nativeFactory, localEGLContext, remoteEGLContext); } public void dispose() { @@ -201,10 +250,18 @@ private static native long nativeCreateAudioTrack( long nativeFactory, String id, long nativeSource); + private static native boolean nativeStartAecDump(long nativeFactory, int file_descriptor); + + private static native void nativeStopAecDump(long nativeFactory); + + private static native boolean nativeStartRtcEventLog(long nativeFactory, int file_descriptor); + + private static native void nativeStopRtcEventLog(long nativeFactory); + public native void nativeSetOptions(long nativeFactory, Options options); private static native void nativeSetVideoHwAccelerationOptions( - long nativeFactory, Object renderEGLContext); + long nativeFactory, Object localEGLContext, Object remoteEGLContext); private static native void nativeThreadsCallbacks(long nativeFactory);
diff --git a/talk/app/webrtc/java/src/org/webrtc/RtpSender.java b/talk/app/webrtc/java/src/org/webrtc/RtpSender.java index 37357c0..9ac2e70 100644 --- a/talk/app/webrtc/java/src/org/webrtc/RtpSender.java +++ b/talk/app/webrtc/java/src/org/webrtc/RtpSender.java
@@ -32,6 +32,7 @@ final long nativeRtpSender; private MediaStreamTrack cachedTrack; + private boolean ownsTrack = true; public RtpSender(long nativeRtpSender) { this.nativeRtpSender = nativeRtpSender; @@ -40,14 +41,22 @@ cachedTrack = (track == 0) ? null : new MediaStreamTrack(track); } - // NOTE: This should not be called with a track that's already used by - // another RtpSender, because then it would be double-disposed. - public void setTrack(MediaStreamTrack track) { - if (cachedTrack != null) { + // If |takeOwnership| is true, the RtpSender takes ownership of the track + // from the caller, and will auto-dispose of it when no longer needed. + // |takeOwnership| should only be used if the caller owns the track; it is + // not appropriate when the track is owned by, for example, another RtpSender + // or a MediaStream. + public boolean setTrack(MediaStreamTrack track, boolean takeOwnership) { + if (!nativeSetTrack(nativeRtpSender, + (track == null) ? 0 : track.nativeTrack)) { + return false; + } + if (cachedTrack != null && ownsTrack) { cachedTrack.dispose(); } cachedTrack = track; - nativeSetTrack(nativeRtpSender, (track == null) ? 0 : track.nativeTrack); + ownsTrack = takeOwnership; + return true; } public MediaStreamTrack track() { @@ -59,14 +68,14 @@ } public void dispose() { - if (cachedTrack != null) { + if (cachedTrack != null && ownsTrack) { cachedTrack.dispose(); } free(nativeRtpSender); } - private static native void nativeSetTrack(long nativeRtpSender, - long nativeTrack); + private static native boolean nativeSetTrack(long nativeRtpSender, + long nativeTrack); // This should increment the reference count of the track. // Will be released in dispose() or setTrack().
diff --git a/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java b/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java index 3c255dd..2e307fc 100644 --- a/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java +++ b/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java
@@ -46,7 +46,11 @@ public final int[] yuvStrides; public ByteBuffer[] yuvPlanes; public final boolean yuvFrame; - public Object textureObject; + // Matrix that transforms standard coordinates to their proper sampling locations in + // the texture. This transform compensates for any properties of the video source that + // cause it to appear different from a normalized texture. This matrix does not take + // |rotationDegree| into account. + public final float[] samplingMatrix; public int textureId; // Frame pointer in C++. private long nativeFramePointer; @@ -70,19 +74,27 @@ if (rotationDegree % 90 != 0) { throw new IllegalArgumentException("Rotation degree not multiple of 90: " + rotationDegree); } + // The convention in WebRTC is that the first element in a ByteBuffer corresponds to the + // top-left corner of the image, but in glTexImage2D() the first element corresponds to the + // bottom-left corner. This discrepancy is corrected by setting a vertical flip as sampling + // matrix. + samplingMatrix = new float[] { + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 1}; } /** * Construct a texture frame of the given dimensions with data in SurfaceTexture */ - I420Frame( - int width, int height, int rotationDegree, - Object textureObject, int textureId, long nativeFramePointer) { + I420Frame(int width, int height, int rotationDegree, int textureId, float[] samplingMatrix, + long nativeFramePointer) { this.width = width; this.height = height; this.yuvStrides = null; this.yuvPlanes = null; - this.textureObject = textureObject; + this.samplingMatrix = samplingMatrix; this.textureId = textureId; this.yuvFrame = false; this.rotationDegree = rotationDegree; @@ -125,7 +137,6 @@ */ public static void renderFrameDone(I420Frame frame) { frame.yuvPlanes = null; - frame.textureObject = null; frame.textureId = 0; if (frame.nativeFramePointer != 0) { releaseNativeFrame(frame.nativeFramePointer);
diff --git a/talk/app/webrtc/jsepsessiondescription.cc b/talk/app/webrtc/jsepsessiondescription.cc index 24bd9d4..226432d 100644 --- a/talk/app/webrtc/jsepsessiondescription.cc +++ b/talk/app/webrtc/jsepsessiondescription.cc
@@ -29,6 +29,7 @@ #include "talk/app/webrtc/webrtcsdp.h" #include "talk/session/media/mediasession.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/stringencode.h" using rtc::scoped_ptr; @@ -44,7 +45,7 @@ static bool IsTypeSupported(const std::string& type) { bool type_supported = false; - for (size_t i = 0; i < ARRAY_SIZE(kSupportedTypes); ++i) { + for (size_t i = 0; i < arraysize(kSupportedTypes); ++i) { if (kSupportedTypes[i] == type) { type_supported = true; break;
diff --git a/talk/app/webrtc/localaudiosource.cc b/talk/app/webrtc/localaudiosource.cc index 63c6f13..591877a 100644 --- a/talk/app/webrtc/localaudiosource.cc +++ b/talk/app/webrtc/localaudiosource.cc
@@ -49,7 +49,7 @@ // a different algorithm will be required. struct { const char* name; - cricket::Settable<bool>& value; + rtc::Optional<bool>& value; } key_to_value[] = { {MediaConstraintsInterface::kGoogEchoCancellation, options->echo_cancellation}, @@ -78,7 +78,7 @@ for (auto& entry : key_to_value) { if (constraint.key.compare(entry.name) == 0) - entry.value.Set(value); + entry.value = rtc::Optional<bool>(value); } } }
diff --git a/talk/app/webrtc/localaudiosource.h b/talk/app/webrtc/localaudiosource.h index 557745b..5158eb1 100644 --- a/talk/app/webrtc/localaudiosource.h +++ b/talk/app/webrtc/localaudiosource.h
@@ -48,16 +48,17 @@ const PeerConnectionFactoryInterface::Options& options, const MediaConstraintsInterface* constraints); - virtual SourceState state() const { return source_state_; } + SourceState state() const override { return source_state_; } + bool remote() const override { return false; } + virtual const cricket::AudioOptions& options() const { return options_; } - protected: - LocalAudioSource() - : source_state_(kInitializing) { - } + void AddSink(AudioTrackSinkInterface* sink) override {} + void RemoveSink(AudioTrackSinkInterface* sink) override {} - ~LocalAudioSource() { - } + protected: + LocalAudioSource() : source_state_(kInitializing) {} + ~LocalAudioSource() override {} private: void Initialize(const PeerConnectionFactoryInterface::Options& options,
diff --git a/talk/app/webrtc/localaudiosource_unittest.cc b/talk/app/webrtc/localaudiosource_unittest.cc index 8e05c18..75d0c35 100644 --- a/talk/app/webrtc/localaudiosource_unittest.cc +++ b/talk/app/webrtc/localaudiosource_unittest.cc
@@ -58,23 +58,14 @@ LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(), &constraints); - bool value; - EXPECT_TRUE(source->options().echo_cancellation.Get(&value)); - EXPECT_FALSE(value); - EXPECT_TRUE(source->options().extended_filter_aec.Get(&value)); - EXPECT_TRUE(value); - EXPECT_TRUE(source->options().delay_agnostic_aec.Get(&value)); - EXPECT_TRUE(value); - EXPECT_TRUE(source->options().auto_gain_control.Get(&value)); - EXPECT_TRUE(value); - EXPECT_TRUE(source->options().experimental_agc.Get(&value)); - EXPECT_TRUE(value); - EXPECT_TRUE(source->options().noise_suppression.Get(&value)); - EXPECT_FALSE(value); - EXPECT_TRUE(source->options().highpass_filter.Get(&value)); - EXPECT_TRUE(value); - EXPECT_TRUE(source->options().aec_dump.Get(&value)); - EXPECT_TRUE(value); + EXPECT_EQ(rtc::Optional<bool>(false), source->options().echo_cancellation); + EXPECT_EQ(rtc::Optional<bool>(true), source->options().extended_filter_aec); + EXPECT_EQ(rtc::Optional<bool>(true), source->options().delay_agnostic_aec); + EXPECT_EQ(rtc::Optional<bool>(true), source->options().auto_gain_control); + EXPECT_EQ(rtc::Optional<bool>(true), source->options().experimental_agc); + EXPECT_EQ(rtc::Optional<bool>(false), source->options().noise_suppression); + EXPECT_EQ(rtc::Optional<bool>(true), source->options().highpass_filter); + EXPECT_EQ(rtc::Optional<bool>(true), source->options().aec_dump); } TEST(LocalAudioSourceTest, OptionNotSet) { @@ -82,8 +73,7 @@ rtc::scoped_refptr<LocalAudioSource> source = LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(), &constraints); - bool value; - EXPECT_FALSE(source->options().highpass_filter.Get(&value)); + EXPECT_EQ(rtc::Optional<bool>(), source->options().highpass_filter); } TEST(LocalAudioSourceTest, MandatoryOverridesOptional) { @@ -97,9 +87,7 @@ LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(), &constraints); - bool value; - EXPECT_TRUE(source->options().echo_cancellation.Get(&value)); - EXPECT_FALSE(value); + EXPECT_EQ(rtc::Optional<bool>(false), source->options().echo_cancellation); } TEST(LocalAudioSourceTest, InvalidOptional) { @@ -112,9 +100,7 @@ &constraints); EXPECT_EQ(MediaSourceInterface::kLive, source->state()); - bool value; - EXPECT_TRUE(source->options().highpass_filter.Get(&value)); - EXPECT_FALSE(value); + EXPECT_EQ(rtc::Optional<bool>(false), source->options().highpass_filter); } TEST(LocalAudioSourceTest, InvalidMandatory) { @@ -127,7 +113,5 @@ &constraints); EXPECT_EQ(MediaSourceInterface::kLive, source->state()); - bool value; - EXPECT_TRUE(source->options().highpass_filter.Get(&value)); - EXPECT_FALSE(value); + EXPECT_EQ(rtc::Optional<bool>(false), source->options().highpass_filter); }
diff --git a/talk/app/webrtc/mediacontroller.cc b/talk/app/webrtc/mediacontroller.cc index f7d8511..24f5877 100644 --- a/talk/app/webrtc/mediacontroller.cc +++ b/talk/app/webrtc/mediacontroller.cc
@@ -47,11 +47,10 @@ RTC_DCHECK(nullptr != worker_thread); worker_thread_->Invoke<void>( rtc::Bind(&MediaController::Construct_w, this, - channel_manager_->media_engine()->GetVoE())); + channel_manager_->media_engine())); } ~MediaController() override { - worker_thread_->Invoke<void>( - rtc::Bind(&MediaController::Destruct_w, this)); + worker_thread_->Invoke<void>(rtc::Bind(&MediaController::Destruct_w, this)); } webrtc::Call* call_w() override { @@ -64,10 +63,11 @@ } private: - void Construct_w(webrtc::VoiceEngine* voice_engine) { + void Construct_w(cricket::MediaEngineInterface* media_engine) { RTC_DCHECK(worker_thread_->IsCurrent()); + RTC_DCHECK(media_engine); webrtc::Call::Config config; - config.voice_engine = voice_engine; + config.audio_state = media_engine->GetAudioState(); config.bitrate_config.min_bitrate_bps = kMinBandwidthBps; config.bitrate_config.start_bitrate_bps = kStartBandwidthBps; config.bitrate_config.max_bitrate_bps = kMaxBandwidthBps; @@ -84,7 +84,7 @@ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(MediaController); }; -} // namespace { +} // namespace { namespace webrtc { @@ -93,4 +93,4 @@ cricket::ChannelManager* channel_manager) { return new MediaController(worker_thread, channel_manager); } -} // namespace webrtc +} // namespace webrtc
diff --git a/talk/app/webrtc/mediastream_unittest.cc b/talk/app/webrtc/mediastream_unittest.cc index 2cf930c..f19b945 100644 --- a/talk/app/webrtc/mediastream_unittest.cc +++ b/talk/app/webrtc/mediastream_unittest.cc
@@ -48,9 +48,23 @@ // Helper class to test Observer. class MockObserver : public ObserverInterface { public: - MockObserver() {} + explicit MockObserver(NotifierInterface* notifier) : notifier_(notifier) { + notifier_->RegisterObserver(this); + } + + ~MockObserver() { Unregister(); } + + void Unregister() { + if (notifier_) { + notifier_->UnregisterObserver(this); + notifier_ = nullptr; + } + } MOCK_METHOD0(OnChanged, void()); + + private: + NotifierInterface* notifier_; }; class MediaStreamTest: public testing::Test { @@ -75,8 +89,7 @@ } void ChangeTrack(MediaStreamTrackInterface* track) { - MockObserver observer; - track->RegisterObserver(&observer); + MockObserver observer(track); EXPECT_CALL(observer, OnChanged()) .Times(Exactly(1)); @@ -127,8 +140,7 @@ } TEST_F(MediaStreamTest, RemoveTrack) { - MockObserver observer; - stream_->RegisterObserver(&observer); + MockObserver observer(stream_); EXPECT_CALL(observer, OnChanged()) .Times(Exactly(2));
diff --git a/talk/app/webrtc/mediastreaminterface.h b/talk/app/webrtc/mediastreaminterface.h index 5911e85..9b137d9 100644 --- a/talk/app/webrtc/mediastreaminterface.h +++ b/talk/app/webrtc/mediastreaminterface.h
@@ -71,8 +71,6 @@ // Base class for sources. A MediaStreamTrack have an underlying source that // provide media. A source can be shared with multiple tracks. -// TODO(perkj): Implement sources for local and remote audio tracks and -// remote video tracks. class MediaSourceInterface : public rtc::RefCountInterface, public NotifierInterface { public: @@ -85,6 +83,8 @@ virtual SourceState state() const = 0; + virtual bool remote() const = 0; + protected: virtual ~MediaSourceInterface() {} }; @@ -100,6 +100,9 @@ kFailed = 3, // Track negotiation failed. }; + static const char kAudioKind[]; + static const char kVideoKind[]; + virtual std::string kind() const = 0; virtual std::string id() const = 0; virtual bool enabled() const = 0; @@ -115,13 +118,6 @@ // Interface for rendering VideoFrames from a VideoTrack class VideoRendererInterface { public: - // TODO(guoweis): Remove this function. Obsolete. The implementation of - // VideoRendererInterface should be able to handle different frame size as - // well as pending rotation. If it can't apply the frame rotation by itself, - // it should call |frame|.GetCopyWithRotationApplied() to get a frame that has - // the rotation applied. - virtual void SetSize(int width, int height) {} - // |frame| may have pending rotation. For clients which can't apply rotation, // |frame|->GetCopyWithRotationApplied() will return a frame that has the // rotation applied. @@ -149,6 +145,19 @@ virtual ~VideoTrackInterface() {} }; +// Interface for receiving audio data from a AudioTrack. +class AudioTrackSinkInterface { + public: + virtual void OnData(const void* audio_data, + int bits_per_sample, + int sample_rate, + size_t number_of_channels, + size_t number_of_frames) = 0; + + protected: + virtual ~AudioTrackSinkInterface() {} +}; + // AudioSourceInterface is a reference counted source used for AudioTracks. // The same source can be used in multiple AudioTracks. class AudioSourceInterface : public MediaSourceInterface { @@ -164,23 +173,17 @@ // TODO(xians): Makes all the interface pure virtual after Chrome has their // implementations. // Sets the volume to the source. |volume| is in the range of [0, 10]. + // TODO(tommi): This method should be on the track and ideally volume should + // be applied in the track in a way that does not affect clones of the track. virtual void SetVolume(double volume) {} // Registers/unregisters observer to the audio source. virtual void RegisterAudioObserver(AudioObserver* observer) {} virtual void UnregisterAudioObserver(AudioObserver* observer) {} -}; -// Interface for receiving audio data from a AudioTrack. -class AudioTrackSinkInterface { - public: - virtual void OnData(const void* audio_data, - int bits_per_sample, - int sample_rate, - int number_of_channels, - size_t number_of_frames) = 0; - protected: - virtual ~AudioTrackSinkInterface() {} + // TODO(tommi): Make pure virtual. + virtual void AddSink(AudioTrackSinkInterface* sink) {} + virtual void RemoveSink(AudioTrackSinkInterface* sink) {} }; // Interface of the audio processor used by the audio track to collect
diff --git a/talk/app/webrtc/mediastreamobserver.cc b/talk/app/webrtc/mediastreamobserver.cc new file mode 100644 index 0000000..2650b9a --- /dev/null +++ b/talk/app/webrtc/mediastreamobserver.cc
@@ -0,0 +1,101 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/app/webrtc/mediastreamobserver.h" + +#include <algorithm> + +namespace webrtc { + +MediaStreamObserver::MediaStreamObserver(MediaStreamInterface* stream) + : stream_(stream), + cached_audio_tracks_(stream->GetAudioTracks()), + cached_video_tracks_(stream->GetVideoTracks()) { + stream_->RegisterObserver(this); +} + +MediaStreamObserver::~MediaStreamObserver() { + stream_->UnregisterObserver(this); +} + +void MediaStreamObserver::OnChanged() { + AudioTrackVector new_audio_tracks = stream_->GetAudioTracks(); + VideoTrackVector new_video_tracks = stream_->GetVideoTracks(); + + // Find removed audio tracks. + for (const auto& cached_track : cached_audio_tracks_) { + auto it = std::find_if( + new_audio_tracks.begin(), new_audio_tracks.end(), + [cached_track](const AudioTrackVector::value_type& new_track) { + return new_track->id().compare(cached_track->id()) == 0; + }); + if (it == new_audio_tracks.end()) { + SignalAudioTrackRemoved(cached_track.get(), stream_); + } + } + + // Find added audio tracks. + for (const auto& new_track : new_audio_tracks) { + auto it = std::find_if( + cached_audio_tracks_.begin(), cached_audio_tracks_.end(), + [new_track](const AudioTrackVector::value_type& cached_track) { + return new_track->id().compare(cached_track->id()) == 0; + }); + if (it == cached_audio_tracks_.end()) { + SignalAudioTrackAdded(new_track.get(), stream_); + } + } + + // Find removed video tracks. + for (const auto& cached_track : cached_video_tracks_) { + auto it = std::find_if( + new_video_tracks.begin(), new_video_tracks.end(), + [cached_track](const VideoTrackVector::value_type& new_track) { + return new_track->id().compare(cached_track->id()) == 0; + }); + if (it == new_video_tracks.end()) { + SignalVideoTrackRemoved(cached_track.get(), stream_); + } + } + + // Find added video tracks. + for (const auto& new_track : new_video_tracks) { + auto it = std::find_if( + cached_video_tracks_.begin(), cached_video_tracks_.end(), + [new_track](const VideoTrackVector::value_type& cached_track) { + return new_track->id().compare(cached_track->id()) == 0; + }); + if (it == cached_video_tracks_.end()) { + SignalVideoTrackAdded(new_track.get(), stream_); + } + } + + cached_audio_tracks_ = new_audio_tracks; + cached_video_tracks_ = new_video_tracks; +} + +} // namespace webrtc
diff --git a/talk/app/webrtc/mediastreamobserver.h b/talk/app/webrtc/mediastreamobserver.h new file mode 100644 index 0000000..1dd6c4c --- /dev/null +++ b/talk/app/webrtc/mediastreamobserver.h
@@ -0,0 +1,65 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TALK_APP_WEBRTC_MEDIASTREAMOBSERVER_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMOBSERVER_H_ + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/base/sigslot.h" + +namespace webrtc { + +// Helper class which will listen for changes to a stream and emit the +// corresponding signals. +class MediaStreamObserver : public ObserverInterface { + public: + explicit MediaStreamObserver(MediaStreamInterface* stream); + ~MediaStreamObserver(); + + const MediaStreamInterface* stream() const { return stream_; } + + void OnChanged() override; + + sigslot::signal2<AudioTrackInterface*, MediaStreamInterface*> + SignalAudioTrackAdded; + sigslot::signal2<AudioTrackInterface*, MediaStreamInterface*> + SignalAudioTrackRemoved; + sigslot::signal2<VideoTrackInterface*, MediaStreamInterface*> + SignalVideoTrackAdded; + sigslot::signal2<VideoTrackInterface*, MediaStreamInterface*> + SignalVideoTrackRemoved; + + private: + rtc::scoped_refptr<MediaStreamInterface> stream_; + AudioTrackVector cached_audio_tracks_; + VideoTrackVector cached_video_tracks_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMOBSERVER_H_
diff --git a/talk/app/webrtc/mediastreamprovider.h b/talk/app/webrtc/mediastreamprovider.h index 1c62daf..585d51b 100644 --- a/talk/app/webrtc/mediastreamprovider.h +++ b/talk/app/webrtc/mediastreamprovider.h
@@ -29,6 +29,7 @@ #define TALK_APP_WEBRTC_MEDIASTREAMPROVIDER_H_ #include "webrtc/base/basictypes.h" +#include "webrtc/base/scoped_ptr.h" namespace cricket { @@ -42,6 +43,8 @@ namespace webrtc { +class AudioSinkInterface; + // TODO(deadbeef): Change the key from an ssrc to a "sender_id" or // "receiver_id" string, which will be the MSID in the short term and MID in // the long term. @@ -50,8 +53,8 @@ // RtpSenders/Receivers to get to the BaseChannels. These interfaces should be // refactored away eventually, as the classes converge. -// This interface is called by AudioTrackHandler classes in mediastreamhandler.h -// to change the settings of an audio track connected to certain PeerConnection. +// This interface is called by AudioRtpSender/Receivers to change the settings +// of an audio track connected to certain PeerConnection. class AudioProviderInterface { public: // Enable/disable the audio playout of a remote audio track with |ssrc|. @@ -67,13 +70,19 @@ // |volume| is in the range of [0, 10]. virtual void SetAudioPlayoutVolume(uint32_t ssrc, double volume) = 0; + // Allows for setting a direct audio sink for an incoming audio source. + // Only one audio sink is supported per ssrc and ownership of the sink is + // passed to the provider. + virtual void SetRawAudioSink( + uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) = 0; + protected: virtual ~AudioProviderInterface() {} }; -// This interface is called by VideoTrackHandler classes in mediastreamhandler.h -// to change the settings of a video track connected to a certain -// PeerConnection. +// This interface is called by VideoRtpSender/Receivers to change the settings +// of a video track connected to a certain PeerConnection. class VideoProviderInterface { public: virtual bool SetCaptureDevice(uint32_t ssrc,
diff --git a/talk/app/webrtc/mediastreamsignaling.cc b/talk/app/webrtc/mediastreamsignaling.cc deleted file mode 100644 index b405273..0000000 --- a/talk/app/webrtc/mediastreamsignaling.cc +++ /dev/null
@@ -1,30 +0,0 @@ -/* - * libjingle - * Copyright 2012 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/app/webrtc/mediastreamsignaling.h" - -// TODO(deadbeef): Remove this file once Chrome build files don't reference it.
diff --git a/talk/app/webrtc/mediastreamsignaling.h b/talk/app/webrtc/mediastreamsignaling.h deleted file mode 100644 index e8c5c11..0000000 --- a/talk/app/webrtc/mediastreamsignaling.h +++ /dev/null
@@ -1,28 +0,0 @@ -/* - * libjingle - * Copyright 2012 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// TODO(deadbeef): Remove this file once Chrome build files don't reference it.
diff --git a/talk/app/webrtc/objc/README b/talk/app/webrtc/objc/README index 692fbbc..c323e73 100644 --- a/talk/app/webrtc/objc/README +++ b/talk/app/webrtc/objc/README
@@ -12,69 +12,59 @@ up for building for iOS-device, iOS-simulator, and Mac (resp) are: function wrbase() { cd /path/to/webrtc/trunk - export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0 libjingle_objc=1" + export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0" export GYP_GENERATORS="ninja" } function wrios() { wrbase - export GYP_DEFINES="$GYP_DEFINES OS=ios target_arch=armv7" + export GYP_DEFINES="$GYP_DEFINES OS=ios" export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_ios" export GYP_CROSSCOMPILE=1 } +function wrios32() { + wrios + export GYP_DEFINES="$GYP_DEFINES target_arch=arm" +} + +function wrios64() { + wrios + export GYP_DEFINES="$GYP_DEFINES target_arch=arm64" +} + function wrsim() { wrbase - export GYP_DEFINES="$GYP_DEFINES OS=ios target_arch=ia32" + export GYP_DEFINES="$GYP_DEFINES OS=ios target_subarch=arm32 target_arch=ia32" export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_sim" export GYP_CROSSCOMPILE=1 } function wrmac() { wrbase - export GYP_DEFINES="$GYP_DEFINES OS=mac target_arch=x64" + export GYP_DEFINES="$GYP_DEFINES OS=mac target_subarch=arm64 target_arch=x64" export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_mac" } -- Finally, run "gclient runhooks" to generate ninja files. +- Finally, run "webrtc/build/gyp_webrtc" to generate ninja files. Example of building & using the unittest & app: - To build & run the unittest (must target mac): - wrmac && gclient runhooks && \ + wrmac && ./webrtc/build/gyp_webrtc && \ ninja -C out_mac/Debug libjingle_peerconnection_objc_test && \ ./out_mac/Debug/libjingle_peerconnection_objc_test.app/Contents/MacOS/libjingle_peerconnection_objc_test - To build & launch the sample app on OSX: - wrmac && gclient runhooks && ninja -C out_mac/Debug AppRTCDemo && \ + wrmac && ./webrtc/build/gyp_webrtc && ninja -C out_mac/Debug AppRTCDemo && \ ./out_mac/Debug/AppRTCDemo.app/Contents/MacOS/AppRTCDemo - To build & launch the sample app on the iOS simulator: - wrsim && gclient runhooks && ninja -C out_sim/Debug iossim AppRTCDemo && \ + wrsim && ./webrtc/build/gyp_webrtc && ninja -C out_sim/Debug iossim AppRTCDemo && \ ./out_sim/Debug/iossim out_sim/Debug/AppRTCDemo.app -- To build & sign the sample app for an iOS device: - wrios && gclient runhooks && ninja -C out_ios/Debug-iphoneos AppRTCDemo +- To build & sign the sample app for an iOS device (32 bit): + wrios32 && ./webrtc/build/gyp_webrtc && ninja -C out_ios/Debug-iphoneos AppRTCDemo -- To install the sample app on an iOS device: - ideviceinstaller -i out_ios/Debug-iphoneos/AppRTCDemo.app - (if installing ideviceinstaller from brew, use --HEAD to get support - for .app directories) -- Alternatively, use iPhone Configuration Utility: - - Open "iPhone Configuration Utility" (http://support.apple.com/kb/DL1465) - - Click the "Add" icon (command-o) - - Open the app under out_ios/Debug-iphoneos/AppRTCDemo (should be added to the Applications tab) - - Click the device's name in the left-hand panel and select the Applications tab - - Click Install on the AppRTCDemo line. - (If you have any problems deploying for the first time, check - the Info.plist file to ensure that the Bundle Identifier matches - your phone provisioning profile, or use a development wildcard - provisioning profile.) -- Alternately, use ios-deploy: - ios-deploy -d -b out_ios/Debug-iphoneos/AppRTCDemo.app - -- Once installed: - - Tap AppRTCDemo on the iOS device's home screen (might have to scroll to find it). - - In desktop chrome, navigate to http://apprtc.appspot.com and note - the r=<NNN> room number in the resulting URL; enter that number - into the text field on the phone. +- To build & sign the sample app for an iOS device (64 bit): + wrios64 && ./webrtc/build/gyp_webrtc && ninja -C out_ios/Debug-iphoneos AppRTCDemo
diff --git a/talk/app/webrtc/objc/RTCFileLogger.mm b/talk/app/webrtc/objc/RTCFileLogger.mm index c4e4696..44ada3e 100644 --- a/talk/app/webrtc/objc/RTCFileLogger.mm +++ b/talk/app/webrtc/objc/RTCFileLogger.mm
@@ -35,15 +35,17 @@ NSString *const kDefaultLogDirName = @"webrtc_logs"; NSUInteger const kDefaultMaxFileSize = 10 * 1024 * 1024; // 10MB. +const char *kRTCFileLoggerRotatingLogPrefix = "rotating_log"; @implementation RTCFileLogger { BOOL _hasStarted; NSString *_dirPath; NSUInteger _maxFileSize; - rtc::scoped_ptr<rtc::CallSessionFileRotatingLogSink> _logSink; + rtc::scoped_ptr<rtc::FileRotatingLogSink> _logSink; } @synthesize severity = _severity; +@synthesize rotationType = _rotationType; - (instancetype)init { NSArray *paths = NSSearchPathForDirectoriesInDomains( @@ -57,6 +59,14 @@ - (instancetype)initWithDirPath:(NSString *)dirPath maxFileSize:(NSUInteger)maxFileSize { + return [self initWithDirPath:dirPath + maxFileSize:maxFileSize + rotationType:kRTCFileLoggerTypeCall]; +} + +- (instancetype)initWithDirPath:(NSString *)dirPath + maxFileSize:(NSUInteger)maxFileSize + rotationType:(RTCFileLoggerRotationType)rotationType { NSParameterAssert(dirPath.length); NSParameterAssert(maxFileSize); if (self = [super init]) { @@ -91,8 +101,20 @@ if (_hasStarted) { return; } - _logSink.reset(new rtc::CallSessionFileRotatingLogSink(_dirPath.UTF8String, - _maxFileSize)); + switch (_rotationType) { + case kRTCFileLoggerTypeApp: + _logSink.reset( + new rtc::FileRotatingLogSink(_dirPath.UTF8String, + kRTCFileLoggerRotatingLogPrefix, + _maxFileSize, + _maxFileSize / 10)); + break; + case kRTCFileLoggerTypeCall: + _logSink.reset( + new rtc::CallSessionFileRotatingLogSink(_dirPath.UTF8String, + _maxFileSize)); + break; + } if (!_logSink->Init()) { LOG(LS_ERROR) << "Failed to open log files at path: " << _dirPath.UTF8String; @@ -120,8 +142,17 @@ return nil; } NSMutableData* logData = [NSMutableData data]; - rtc::scoped_ptr<rtc::CallSessionFileRotatingStream> stream( - new rtc::CallSessionFileRotatingStream(_dirPath.UTF8String)); + rtc::scoped_ptr<rtc::FileRotatingStream> stream; + switch(_rotationType) { + case kRTCFileLoggerTypeApp: + stream.reset( + new rtc::FileRotatingStream(_dirPath.UTF8String, + kRTCFileLoggerRotatingLogPrefix)); + break; + case kRTCFileLoggerTypeCall: + stream.reset(new rtc::CallSessionFileRotatingStream(_dirPath.UTF8String)); + break; + } if (!stream->Open()) { return logData; }
diff --git a/talk/app/webrtc/objc/RTCPeerConnection.mm b/talk/app/webrtc/objc/RTCPeerConnection.mm index 44d39cb..f814f06 100644 --- a/talk/app/webrtc/objc/RTCPeerConnection.mm +++ b/talk/app/webrtc/objc/RTCPeerConnection.mm
@@ -271,11 +271,13 @@ - (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface*)factory iceServers:(const webrtc::PeerConnectionInterface::IceServers&)iceServers constraints:(const webrtc::MediaConstraintsInterface*)constraints { - NSParameterAssert(factory != NULL); + NSParameterAssert(factory != nullptr); if (self = [super init]) { + webrtc::PeerConnectionInterface::RTCConfiguration config; + config.servers = iceServers; _observer.reset(new webrtc::RTCPeerConnectionObserver(self)); _peerConnection = factory->CreatePeerConnection( - iceServers, constraints, NULL, NULL, _observer.get()); + config, constraints, nullptr, nullptr, _observer.get()); _localStreams = [[NSMutableArray alloc] init]; } return self;
diff --git a/talk/app/webrtc/objc/RTCPeerConnectionInterface.mm b/talk/app/webrtc/objc/RTCPeerConnectionInterface.mm index 58d12ac..ff45bd2 100644 --- a/talk/app/webrtc/objc/RTCPeerConnectionInterface.mm +++ b/talk/app/webrtc/objc/RTCPeerConnectionInterface.mm
@@ -39,6 +39,7 @@ @synthesize tcpCandidatePolicy = _tcpCandidatePolicy; @synthesize audioJitterBufferMaxPackets = _audioJitterBufferMaxPackets; @synthesize iceConnectionReceivingTimeout = _iceConnectionReceivingTimeout; +@synthesize iceBackupCandidatePairPingInterval = _iceBackupCandidatePairPingInterval; - (instancetype)init { if (self = [super init]) { @@ -51,6 +52,7 @@ [RTCEnumConverter tcpCandidatePolicyForNativeEnum:config.tcp_candidate_policy]; _audioJitterBufferMaxPackets = config.audio_jitter_buffer_max_packets; _iceConnectionReceivingTimeout = config.ice_connection_receiving_timeout; + _iceBackupCandidatePairPingInterval = config.ice_backup_candidate_pair_ping_interval; } return self; } @@ -60,7 +62,8 @@ rtcpMuxPolicy:(RTCRtcpMuxPolicy)rtcpMuxPolicy tcpCandidatePolicy:(RTCTcpCandidatePolicy)tcpCandidatePolicy audioJitterBufferMaxPackets:(int)audioJitterBufferMaxPackets - iceConnectionReceivingTimeout:(int)iceConnectionReceivingTimeout { + iceConnectionReceivingTimeout:(int)iceConnectionReceivingTimeout + iceBackupCandidatePairPingInterval:(int)iceBackupCandidatePairPingInterval { if (self = [super init]) { _iceTransportsType = iceTransportsType; _bundlePolicy = bundlePolicy; @@ -68,6 +71,7 @@ _tcpCandidatePolicy = tcpCandidatePolicy; _audioJitterBufferMaxPackets = audioJitterBufferMaxPackets; _iceConnectionReceivingTimeout = iceConnectionReceivingTimeout; + _iceBackupCandidatePairPingInterval = iceBackupCandidatePairPingInterval; } return self; } @@ -85,8 +89,8 @@ nativeConfig.tcp_candidate_policy = [RTCEnumConverter nativeEnumForTcpCandidatePolicy:_tcpCandidatePolicy]; nativeConfig.audio_jitter_buffer_max_packets = _audioJitterBufferMaxPackets; - nativeConfig.ice_connection_receiving_timeout = - _iceConnectionReceivingTimeout; + nativeConfig.ice_connection_receiving_timeout = _iceConnectionReceivingTimeout; + nativeConfig.ice_backup_candidate_pair_ping_interval = _iceBackupCandidatePairPingInterval; return nativeConfig; }
diff --git a/talk/app/webrtc/objc/avfoundationvideocapturer.h b/talk/app/webrtc/objc/avfoundationvideocapturer.h index ded80f6..32de09a 100644 --- a/talk/app/webrtc/objc/avfoundationvideocapturer.h +++ b/talk/app/webrtc/objc/avfoundationvideocapturer.h
@@ -71,7 +71,6 @@ RTCAVFoundationVideoCapturerInternal* _capturer; rtc::Thread* _startThread; // Set in Start(), unset in Stop(). - uint64_t _startTime; }; // AVFoundationVideoCapturer } // namespace webrtc
diff --git a/talk/app/webrtc/objc/avfoundationvideocapturer.mm b/talk/app/webrtc/objc/avfoundationvideocapturer.mm index e1b0f88..0f9dc68 100644 --- a/talk/app/webrtc/objc/avfoundationvideocapturer.mm +++ b/talk/app/webrtc/objc/avfoundationvideocapturer.mm
@@ -33,6 +33,8 @@ #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> +#import "webrtc/base/objc/RTCDispatcher.h" + // TODO(tkchin): support other formats. static NSString* const kDefaultPreset = AVCaptureSessionPreset640x480; static cricket::VideoFormat const kDefaultFormat = @@ -41,11 +43,6 @@ cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_NV12); -// This queue is used to start and stop the capturer without blocking the -// calling thread. -[AVCaptureSession startRunning] blocks until the camera is -// running. -static dispatch_queue_t kBackgroundQueue = nil; - // This class used to capture frames using AVFoundation APIs on iOS. It is meant // to be owned by an instance of AVFoundationVideoCapturer. The reason for this // because other webrtc objects own cricket::VideoCapturer, which is not @@ -80,15 +77,6 @@ @synthesize useBackCamera = _useBackCamera; @synthesize isRunning = _isRunning; -+ (void)initialize { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - kBackgroundQueue = dispatch_queue_create( - "com.google.webrtc.RTCAVFoundationCapturerBackground", - DISPATCH_QUEUE_SERIAL); - }); -} - - (instancetype)initWithCapturer:(webrtc::AVFoundationVideoCapturer*)capturer { NSParameterAssert(capturer); if (self = [super init]) { @@ -132,9 +120,10 @@ _orientationHasChanged = NO; [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; AVCaptureSession* session = _captureSession; - dispatch_async(kBackgroundQueue, ^{ + [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession + block:^{ [session startRunning]; - }); + }]; _isRunning = YES; } @@ -144,9 +133,10 @@ } [_videoOutput setSampleBufferDelegate:nil queue:nullptr]; AVCaptureSession* session = _captureSession; - dispatch_async(kBackgroundQueue, ^{ + [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession + block:^{ [session stopRunning]; - }); + }]; [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; _isRunning = NO; }
diff --git a/talk/app/webrtc/objc/public/RTCFileLogger.h b/talk/app/webrtc/objc/public/RTCFileLogger.h index 3900cb6..70b3825 100644 --- a/talk/app/webrtc/objc/public/RTCFileLogger.h +++ b/talk/app/webrtc/objc/public/RTCFileLogger.h
@@ -39,21 +39,38 @@ kRTCFileLoggerSeverityError }; +typedef NS_ENUM(NSUInteger, RTCFileLoggerRotationType) { + kRTCFileLoggerTypeCall, + kRTCFileLoggerTypeApp, +}; + // This class intercepts WebRTC logs and saves them to a file. The file size // will not exceed the given maximum bytesize. When the maximum bytesize is -// reached logs from the beginning and the end are preserved while the middle -// section is overwritten instead. +// reached, logs are rotated according to the rotationType specified. +// For kRTCFileLoggerTypeCall, logs from the beginning and the end +// are preserved while the middle section is overwritten instead. +// For kRTCFileLoggerTypeApp, the oldest log is overwritten. // This class is not threadsafe. @interface RTCFileLogger : NSObject // The severity level to capture. The default is kRTCFileLoggerSeverityInfo. @property(nonatomic, assign) RTCFileLoggerSeverity severity; -// Default constructor provides default settings for dir path and file size. +// The rotation type for this file logger. The default is +// kRTCFileLoggerTypeCall. +@property(nonatomic, readonly) RTCFileLoggerRotationType rotationType; + +// Default constructor provides default settings for dir path, file size and +// rotation type. - (instancetype)init; +// Create file logger with default rotation type. +- (instancetype)initWithDirPath:(NSString *)dirPath + maxFileSize:(NSUInteger)maxFileSize; + - (instancetype)initWithDirPath:(NSString *)dirPath maxFileSize:(NSUInteger)maxFileSize + rotationType:(RTCFileLoggerRotationType)rotationType NS_DESIGNATED_INITIALIZER; // Starts writing WebRTC logs to disk if not already started. Overwrites any
diff --git a/talk/app/webrtc/objc/public/RTCPeerConnectionInterface.h b/talk/app/webrtc/objc/public/RTCPeerConnectionInterface.h index b0cc72b..44b971c 100644 --- a/talk/app/webrtc/objc/public/RTCPeerConnectionInterface.h +++ b/talk/app/webrtc/objc/public/RTCPeerConnectionInterface.h
@@ -64,12 +64,14 @@ @property(nonatomic, assign) RTCTcpCandidatePolicy tcpCandidatePolicy; @property(nonatomic, assign) int audioJitterBufferMaxPackets; @property(nonatomic, assign) int iceConnectionReceivingTimeout; +@property(nonatomic, assign) int iceBackupCandidatePairPingInterval; - (instancetype)initWithIceTransportsType:(RTCIceTransportsType)iceTransportsType bundlePolicy:(RTCBundlePolicy)bundlePolicy rtcpMuxPolicy:(RTCRtcpMuxPolicy)rtcpMuxPolicy tcpCandidatePolicy:(RTCTcpCandidatePolicy)tcpCandidatePolicy audioJitterBufferMaxPackets:(int)audioJitterBufferMaxPackets - iceConnectionReceivingTimeout:(int)iceConnectionReceivingTimeout; + iceConnectionReceivingTimeout:(int)iceConnectionReceivingTimeout + iceBackupCandidatePairPingInterval:(int)iceBackupCandidatePairPingInterval; @end
diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc index 0d519b2..ccca18a 100644 --- a/talk/app/webrtc/peerconnection.cc +++ b/talk/app/webrtc/peerconnection.cc
@@ -27,8 +27,10 @@ #include "talk/app/webrtc/peerconnection.h" -#include <vector> +#include <algorithm> #include <cctype> // for isdigit +#include <utility> +#include <vector> #include "talk/app/webrtc/audiotrack.h" #include "talk/app/webrtc/dtmfsender.h" @@ -36,6 +38,7 @@ #include "talk/app/webrtc/jsepsessiondescription.h" #include "talk/app/webrtc/mediaconstraintsinterface.h" #include "talk/app/webrtc/mediastream.h" +#include "talk/app/webrtc/mediastreamobserver.h" #include "talk/app/webrtc/mediastreamproxy.h" #include "talk/app/webrtc/mediastreamtrackproxy.h" #include "talk/app/webrtc/remoteaudiosource.h" @@ -46,11 +49,13 @@ #include "talk/app/webrtc/videosource.h" #include "talk/app/webrtc/videotrack.h" #include "talk/media/sctp/sctpdataengine.h" -#include "webrtc/p2p/client/basicportallocator.h" #include "talk/session/media/channelmanager.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/logging.h" #include "webrtc/base/stringencode.h" #include "webrtc/base/stringutils.h" +#include "webrtc/base/trace_event.h" +#include "webrtc/p2p/client/basicportallocator.h" #include "webrtc/system_wrappers/include/field_trial.h" namespace { @@ -59,13 +64,8 @@ using webrtc::MediaConstraintsInterface; using webrtc::MediaStreamInterface; using webrtc::PeerConnectionInterface; +using webrtc::RtpSenderInterface; using webrtc::StreamCollection; -using webrtc::StunConfigurations; -using webrtc::TurnConfigurations; -typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration - StunConfiguration; -typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration - TurnConfiguration; static const char kDefaultStreamLabel[] = "default"; static const char kDefaultAudioTrackLabel[] = "defaulta0"; @@ -80,8 +80,6 @@ static const int kDefaultStunPort = 3478; static const int kDefaultStunTlsPort = 5349; static const char kTransport[] = "transport"; -static const char kUdpTransportType[] = "udp"; -static const char kTcpTransportType[] = "tcp"; // NOTE: Must be in the same order as the ServiceType enum. static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"}; @@ -95,7 +93,7 @@ TURNS, // Indicates a TURN server used with a TLS session. INVALID, // Unknown. }; -static_assert(INVALID == ARRAY_SIZE(kValidIceServiceTypes), +static_assert(INVALID == arraysize(kValidIceServiceTypes), "kValidIceServiceTypes must have as many strings as ServiceType " "has values."); @@ -104,6 +102,7 @@ MSG_SET_SESSIONDESCRIPTION_FAILED, MSG_CREATE_SESSIONDESCRIPTION_FAILED, MSG_GETSTATS, + MSG_FREE_DATACHANNELS, }; struct SetSessionDescriptionMsg : public rtc::MessageData { @@ -156,7 +155,7 @@ return false; } *service_type = INVALID; - for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) { + for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) { if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) { *service_type = static_cast<ServiceType>(i); break; @@ -216,12 +215,12 @@ return !host->empty(); } -// Adds a StunConfiguration or TurnConfiguration to the appropriate list, +// Adds a STUN or TURN server to the appropriate list, // by parsing |url| and using the username/password in |server|. bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server, const std::string& url, - StunConfigurations* stun_config, - TurnConfigurations* turn_config) { + cricket::ServerAddresses* stun_servers, + std::vector<cricket::RelayServerConfig>* turn_servers) { // draft-nandakumar-rtcweb-stun-uri-01 // stunURI = scheme ":" stun-host [ ":" stun-port ] // scheme = "stun" / "stuns" @@ -236,10 +235,10 @@ // transport-ext = 1*unreserved // turn-host = IP-literal / IPv4address / reg-name // turn-port = *DIGIT - RTC_DCHECK(stun_config != nullptr); - RTC_DCHECK(turn_config != nullptr); + RTC_DCHECK(stun_servers != nullptr); + RTC_DCHECK(turn_servers != nullptr); std::vector<std::string> tokens; - std::string turn_transport_type = kUdpTransportType; + cricket::ProtocolType turn_transport_type = cricket::PROTO_UDP; RTC_DCHECK(!url.empty()); rtc::tokenize(url, '?', &tokens); std::string uri_without_transport = tokens[0]; @@ -250,11 +249,12 @@ if (tokens[0] == kTransport) { // As per above grammar transport param will be consist of lower case // letters. - if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) { + if (!cricket::StringToProto(tokens[1].c_str(), &turn_transport_type) || + (turn_transport_type != cricket::PROTO_UDP && + turn_transport_type != cricket::PROTO_TCP)) { LOG(LS_WARNING) << "Transport param should always be udp or tcp."; return false; } - turn_transport_type = tokens[1]; } } @@ -293,7 +293,7 @@ int port = kDefaultStunPort; if (service_type == TURNS) { port = kDefaultStunTlsPort; - turn_transport_type = kTcpTransportType; + turn_transport_type = cricket::PROTO_TCP; } std::string address; @@ -310,16 +310,14 @@ switch (service_type) { case STUN: case STUNS: - stun_config->push_back(StunConfiguration(address, port)); + stun_servers->insert(rtc::SocketAddress(address, port)); break; case TURN: case TURNS: { bool secure = (service_type == TURNS); - turn_config->push_back(TurnConfiguration(address, port, - username, - server.password, - turn_transport_type, - secure)); + turn_servers->push_back( + cricket::RelayServerConfig(address, port, username, server.password, + turn_transport_type, secure)); break; } case INVALID: @@ -365,25 +363,15 @@ } // Add the stream and RTP data channel info to |session_options|. -void SetStreams(cricket::MediaSessionOptions* session_options, - rtc::scoped_refptr<StreamCollection> streams, - const std::map<std::string, rtc::scoped_refptr<DataChannel>>& - rtp_data_channels) { +void AddSendStreams( + cricket::MediaSessionOptions* session_options, + const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders, + const std::map<std::string, rtc::scoped_refptr<DataChannel>>& + rtp_data_channels) { session_options->streams.clear(); - if (streams != nullptr) { - for (size_t i = 0; i < streams->count(); ++i) { - MediaStreamInterface* stream = streams->at(i); - // For each audio track in the stream, add it to the MediaSessionOptions. - for (const auto& track : stream->GetAudioTracks()) { - session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, track->id(), - stream->label()); - } - // For each video track in the stream, add it to the MediaSessionOptions. - for (const auto& track : stream->GetVideoTracks()) { - session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, track->id(), - stream->label()); - } - } + for (const auto& sender : senders) { + session_options->AddSendStream(sender->media_type(), sender->id(), + sender->stream_id()); } // Check for data channels. @@ -421,10 +409,12 @@ MediaStream::Create(stream_label)); } - AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream, + AudioTrackInterface* AddAudioTrack(uint32_t ssrc, + AudioProviderInterface* provider, + webrtc::MediaStreamInterface* stream, const std::string& track_id) { return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>( - stream, track_id, RemoteAudioSource::Create().get()); + stream, track_id, RemoteAudioSource::Create(ssrc, provider)); } VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream, @@ -432,7 +422,7 @@ return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>( stream, track_id, VideoSource::Create(channel_manager_, new RemoteVideoCapturer(), - nullptr) + nullptr, true) .get()); } @@ -440,7 +430,7 @@ template <typename TI, typename T, typename TP, typename S> TI* AddTrack(MediaStreamInterface* stream, const std::string& track_id, - S* source) { + const S& source) { rtc::scoped_refptr<TI> track( TP::Create(signaling_thread_, T::Create(track_id, source))); track->set_state(webrtc::MediaStreamTrackInterface::kLive); @@ -471,7 +461,11 @@ } session_options->vad_enabled = rtc_options.voice_activity_detection; - session_options->transport_options.ice_restart = rtc_options.ice_restart; + session_options->audio_transport_options.ice_restart = + rtc_options.ice_restart; + session_options->video_transport_options.ice_restart = + rtc_options.ice_restart; + session_options->data_transport_options.ice_restart = rtc_options.ice_restart; session_options->bundle_enabled = rtc_options.use_rtp_mux; return true; @@ -517,10 +511,14 @@ if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart, &value, &mandatory_constraints_satisfied)) { - session_options->transport_options.ice_restart = value; + session_options->audio_transport_options.ice_restart = value; + session_options->video_transport_options.ice_restart = value; + session_options->data_transport_options.ice_restart = value; } else { // kIceRestart defaults to false according to spec. - session_options->transport_options.ice_restart = false; + session_options->audio_transport_options.ice_restart = false; + session_options->video_transport_options.ice_restart = false; + session_options->data_transport_options.ice_restart = false; } if (!constraints) { @@ -530,8 +528,8 @@ } bool ParseIceServers(const PeerConnectionInterface::IceServers& servers, - StunConfigurations* stun_config, - TurnConfigurations* turn_config) { + cricket::ServerAddresses* stun_servers, + std::vector<cricket::RelayServerConfig>* turn_servers) { for (const webrtc::PeerConnectionInterface::IceServer& server : servers) { if (!server.urls.empty()) { for (const std::string& url : server.urls) { @@ -539,13 +537,13 @@ LOG(LS_ERROR) << "Empty uri."; return false; } - if (!ParseIceServerUrl(server, url, stun_config, turn_config)) { + if (!ParseIceServerUrl(server, url, stun_servers, turn_servers)) { return false; } } } else if (!server.uri.empty()) { // Fallback to old .uri if new .urls isn't present. - if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) { + if (!ParseIceServerUrl(server, server.uri, stun_servers, turn_servers)) { return false; } } else { @@ -553,6 +551,13 @@ return false; } } + // Candidates must have unique priorities, so that connectivity checks + // are performed in a well-defined order. + int priority = static_cast<int>(turn_servers->size() - 1); + for (cricket::RelayServerConfig& turn_server : *turn_servers) { + // First in the list gets highest priority. + turn_server.priority = priority--; + } return true; } @@ -568,6 +573,7 @@ remote_streams_(StreamCollection::Create()) {} PeerConnection::~PeerConnection() { + TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection"); RTC_DCHECK(signaling_thread()->IsCurrent()); // Need to detach RTP senders/receivers from WebRtcSession, // since it's about to be destroyed. @@ -582,22 +588,24 @@ bool PeerConnection::Initialize( const PeerConnectionInterface::RTCConfiguration& configuration, const MediaConstraintsInterface* constraints, - PortAllocatorFactoryInterface* allocator_factory, + rtc::scoped_ptr<cricket::PortAllocator> allocator, rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, PeerConnectionObserver* observer) { + TRACE_EVENT0("webrtc", "PeerConnection::Initialize"); RTC_DCHECK(observer != nullptr); if (!observer) { return false; } observer_ = observer; - std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config; - std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config; - if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) { + port_allocator_ = std::move(allocator); + + cricket::ServerAddresses stun_servers; + std::vector<cricket::RelayServerConfig> turn_servers; + if (!ParseIceServers(configuration.servers, &stun_servers, &turn_servers)) { return false; } - port_allocator_.reset( - allocator_factory->CreatePortAllocator(stun_config, turn_config)); + port_allocator_->SetIceServers(stun_servers, turn_servers); // To handle both internal and externally created port allocator, we will // enable BUNDLE here. @@ -637,7 +645,7 @@ // Initialize the WebRtcSession. It creates transport channels etc. if (!session_->Initialize(factory_->options(), constraints, - dtls_identity_store.Pass(), configuration)) { + std::move(dtls_identity_store), configuration)) { return false; } @@ -668,9 +676,8 @@ return remote_streams_; } -// TODO(deadbeef): Create RtpSenders immediately here, even if local -// description hasn't yet been set. bool PeerConnection::AddStream(MediaStreamInterface* local_stream) { + TRACE_EVENT0("webrtc", "PeerConnection::AddStream"); if (IsClosed()) { return false; } @@ -679,25 +686,22 @@ } local_streams_->AddStream(local_stream); + MediaStreamObserver* observer = new MediaStreamObserver(local_stream); + observer->SignalAudioTrackAdded.connect(this, + &PeerConnection::OnAudioTrackAdded); + observer->SignalAudioTrackRemoved.connect( + this, &PeerConnection::OnAudioTrackRemoved); + observer->SignalVideoTrackAdded.connect(this, + &PeerConnection::OnVideoTrackAdded); + observer->SignalVideoTrackRemoved.connect( + this, &PeerConnection::OnVideoTrackRemoved); + stream_observers_.push_back(rtc::scoped_ptr<MediaStreamObserver>(observer)); - // Find tracks that have already been configured in SDP. This can occur if a - // local session description that contains the MSID of these tracks is set - // before AddLocalStream is called. It can also occur if the local session - // description is not changed and RemoveLocalStream is called and later - // AddLocalStream is called again with the same stream. for (const auto& track : local_stream->GetAudioTracks()) { - const TrackInfo* track_info = - FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id()); - if (track_info) { - CreateAudioSender(local_stream, track.get(), track_info->ssrc); - } + OnAudioTrackAdded(track.get(), local_stream); } for (const auto& track : local_stream->GetVideoTracks()) { - const TrackInfo* track_info = - FindTrackInfo(local_video_tracks_, local_stream->label(), track->id()); - if (track_info) { - CreateVideoSender(local_stream, track.get(), track_info->ssrc); - } + OnVideoTrackAdded(track.get(), local_stream); } stats_->AddStream(local_stream); @@ -705,25 +709,24 @@ return true; } -// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around -// indefinitely. void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) { + TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream"); for (const auto& track : local_stream->GetAudioTracks()) { - const TrackInfo* track_info = - FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id()); - if (track_info) { - DestroyAudioSender(local_stream, track.get(), track_info->ssrc); - } + OnAudioTrackRemoved(track.get(), local_stream); } for (const auto& track : local_stream->GetVideoTracks()) { - const TrackInfo* track_info = - FindTrackInfo(local_video_tracks_, local_stream->label(), track->id()); - if (track_info) { - DestroyVideoSender(local_stream, track.get()); - } + OnVideoTrackRemoved(track.get(), local_stream); } local_streams_->RemoveStream(local_stream); + stream_observers_.erase( + std::remove_if( + stream_observers_.begin(), stream_observers_.end(), + [local_stream](const rtc::scoped_ptr<MediaStreamObserver>& observer) { + return observer->stream()->label().compare(local_stream->label()) == + 0; + }), + stream_observers_.end()); if (IsClosed()) { return; @@ -733,6 +736,7 @@ rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender( AudioTrackInterface* track) { + TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender"); if (!track) { LOG(LS_ERROR) << "CreateDtmfSender - track is NULL."; return NULL; @@ -751,6 +755,26 @@ return DtmfSenderProxy::Create(signaling_thread(), sender.get()); } +rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender( + const std::string& kind, + const std::string& stream_id) { + TRACE_EVENT0("webrtc", "PeerConnection::CreateSender"); + RtpSenderInterface* new_sender; + if (kind == MediaStreamTrackInterface::kAudioKind) { + new_sender = new AudioRtpSender(session_.get(), stats_.get()); + } else if (kind == MediaStreamTrackInterface::kVideoKind) { + new_sender = new VideoRtpSender(session_.get()); + } else { + LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind; + return rtc::scoped_refptr<RtpSenderInterface>(); + } + if (!stream_id.empty()) { + new_sender->set_stream_id(stream_id); + } + senders_.push_back(new_sender); + return RtpSenderProxy::Create(signaling_thread(), new_sender); +} + std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders() const { std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders; @@ -773,6 +797,7 @@ bool PeerConnection::GetStats(StatsObserver* observer, MediaStreamTrackInterface* track, StatsOutputLevel level) { + TRACE_EVENT0("webrtc", "PeerConnection::GetStats"); RTC_DCHECK(signaling_thread()->IsCurrent()); if (!VERIFY(observer != NULL)) { LOG(LS_ERROR) << "GetStats - observer is NULL."; @@ -807,6 +832,7 @@ PeerConnection::CreateDataChannel( const std::string& label, const DataChannelInit* config) { + TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel"); bool first_datachannel = !HasDataChannels(); rtc::scoped_ptr<InternalDataChannelInit> internal_config; @@ -830,6 +856,7 @@ void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, const MediaConstraintsInterface* constraints) { + TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); if (!VERIFY(observer != nullptr)) { LOG(LS_ERROR) << "CreateOffer - observer is NULL."; return; @@ -881,6 +908,7 @@ void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, const RTCOfferAnswerOptions& options) { + TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); if (!VERIFY(observer != nullptr)) { LOG(LS_ERROR) << "CreateOffer - observer is NULL."; return; @@ -900,6 +928,7 @@ void PeerConnection::CreateAnswer( CreateSessionDescriptionObserver* observer, const MediaConstraintsInterface* constraints) { + TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); if (!VERIFY(observer != nullptr)) { LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; return; @@ -919,6 +948,7 @@ void PeerConnection::SetLocalDescription( SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc) { + TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription"); if (!VERIFY(observer != nullptr)) { LOG(LS_ERROR) << "SetLocalDescription - observer is NULL."; return; @@ -940,7 +970,7 @@ // SCTP sids. rtc::SSLRole role; if (session_->data_channel_type() == cricket::DCT_SCTP && - session_->GetSslRole(&role)) { + session_->GetSslRole(session_->data_channel(), &role)) { AllocateSctpSids(role); } @@ -949,19 +979,27 @@ const cricket::ContentInfo* audio_content = GetFirstAudioContent(desc->description()); if (audio_content) { - const cricket::AudioContentDescription* audio_desc = - static_cast<const cricket::AudioContentDescription*>( - audio_content->description); - UpdateLocalTracks(audio_desc->streams(), audio_desc->type()); + if (audio_content->rejected) { + RemoveTracks(cricket::MEDIA_TYPE_AUDIO); + } else { + const cricket::AudioContentDescription* audio_desc = + static_cast<const cricket::AudioContentDescription*>( + audio_content->description); + UpdateLocalTracks(audio_desc->streams(), audio_desc->type()); + } } const cricket::ContentInfo* video_content = GetFirstVideoContent(desc->description()); if (video_content) { - const cricket::VideoContentDescription* video_desc = - static_cast<const cricket::VideoContentDescription*>( - video_content->description); - UpdateLocalTracks(video_desc->streams(), video_desc->type()); + if (video_content->rejected) { + RemoveTracks(cricket::MEDIA_TYPE_VIDEO); + } else { + const cricket::VideoContentDescription* video_desc = + static_cast<const cricket::VideoContentDescription*>( + video_content->description); + UpdateLocalTracks(video_desc->streams(), video_desc->type()); + } } const cricket::ContentInfo* data_content = @@ -988,6 +1026,7 @@ void PeerConnection::SetRemoteDescription( SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc) { + TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription"); if (!VERIFY(observer != nullptr)) { LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL."; return; @@ -1009,11 +1048,27 @@ // SCTP sids. rtc::SSLRole role; if (session_->data_channel_type() == cricket::DCT_SCTP && - session_->GetSslRole(&role)) { + session_->GetSslRole(session_->data_channel(), &role)) { AllocateSctpSids(role); } const cricket::SessionDescription* remote_desc = desc->description(); + const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc); + const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc); + const cricket::AudioContentDescription* audio_desc = + GetFirstAudioContentDescription(remote_desc); + const cricket::VideoContentDescription* video_desc = + GetFirstVideoContentDescription(remote_desc); + const cricket::DataContentDescription* data_desc = + GetFirstDataContentDescription(remote_desc); + + // Check if the descriptions include streams, just in case the peer supports + // MSID, but doesn't indicate so with "a=msid-semantic". + if (remote_desc->msid_supported() || + (audio_desc && !audio_desc->streams().empty()) || + (video_desc && !video_desc->streams().empty())) { + remote_peer_supports_msid_ = true; + } // We wait to signal new streams until we finish processing the description, // since only at that point will new streams have all their tracks. @@ -1021,39 +1076,39 @@ // Find all audio rtp streams and create corresponding remote AudioTracks // and MediaStreams. - const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc); if (audio_content) { - const cricket::AudioContentDescription* desc = - static_cast<const cricket::AudioContentDescription*>( - audio_content->description); - UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(), new_streams); - remote_info_.default_audio_track_needed = - !remote_desc->msid_supported() && desc->streams().empty() && - MediaContentDirectionHasSend(desc->direction()); + if (audio_content->rejected) { + RemoveTracks(cricket::MEDIA_TYPE_AUDIO); + } else { + bool default_audio_track_needed = + !remote_peer_supports_msid_ && + MediaContentDirectionHasSend(audio_desc->direction()); + UpdateRemoteStreamsList(GetActiveStreams(audio_desc), + default_audio_track_needed, audio_desc->type(), + new_streams); + } } // Find all video rtp streams and create corresponding remote VideoTracks // and MediaStreams. - const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc); if (video_content) { - const cricket::VideoContentDescription* desc = - static_cast<const cricket::VideoContentDescription*>( - video_content->description); - UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(), new_streams); - remote_info_.default_video_track_needed = - !remote_desc->msid_supported() && desc->streams().empty() && - MediaContentDirectionHasSend(desc->direction()); + if (video_content->rejected) { + RemoveTracks(cricket::MEDIA_TYPE_VIDEO); + } else { + bool default_video_track_needed = + !remote_peer_supports_msid_ && + MediaContentDirectionHasSend(video_desc->direction()); + UpdateRemoteStreamsList(GetActiveStreams(video_desc), + default_video_track_needed, video_desc->type(), + new_streams); + } } // Update the DataChannels with the information from the remote peer. - const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc); - if (data_content) { - const cricket::DataContentDescription* desc = - static_cast<const cricket::DataContentDescription*>( - data_content->description); - if (rtc::starts_with(desc->protocol().data(), + if (data_desc) { + if (rtc::starts_with(data_desc->protocol().data(), cricket::kMediaProtocolRtpPrefix)) { - UpdateRemoteRtpDataChannels(GetActiveStreams(desc)); + UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc)); } } @@ -1064,58 +1119,21 @@ observer_->OnAddStream(new_stream); } - // Find removed MediaStreams. - if (remote_info_.IsDefaultMediaStreamNeeded() && - remote_streams_->find(kDefaultStreamLabel) != nullptr) { - // The default media stream already exists. No need to do anything. - } else { - UpdateEndedRemoteMediaStreams(); - remote_info_.msid_supported |= remote_streams_->count() > 0; - } - MaybeCreateDefaultStream(); + UpdateEndedRemoteMediaStreams(); SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer); signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg); } bool PeerConnection::SetConfiguration(const RTCConfiguration& config) { + TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration"); if (port_allocator_) { - std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns; - std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns; - if (!ParseIceServers(config.servers, &stuns, &turns)) { + cricket::ServerAddresses stun_servers; + std::vector<cricket::RelayServerConfig> turn_servers; + if (!ParseIceServers(config.servers, &stun_servers, &turn_servers)) { return false; } - - std::vector<rtc::SocketAddress> stun_hosts; - typedef std::vector<StunConfiguration>::const_iterator StunIt; - for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) { - stun_hosts.push_back(stun_it->server); - } - - rtc::SocketAddress stun_addr; - if (!stun_hosts.empty()) { - stun_addr = stun_hosts.front(); - LOG(LS_INFO) << "SetConfiguration: StunServer Address: " - << stun_addr.ToString(); - } - - for (size_t i = 0; i < turns.size(); ++i) { - cricket::RelayCredentials credentials(turns[i].username, - turns[i].password); - cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); - cricket::ProtocolType protocol; - if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) { - relay_server.ports.push_back(cricket::ProtocolAddress( - turns[i].server, protocol, turns[i].secure)); - relay_server.credentials = credentials; - LOG(LS_INFO) << "SetConfiguration: TurnServer Address: " - << turns[i].server.ToString(); - } else { - LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". " - << "Reason= Incorrect " << turns[i].transport_type - << " transport parameter."; - } - } + port_allocator_->SetIceServers(stun_servers, turn_servers); } session_->SetIceConfig(session_->ParseIceConfig(config)); return session_->SetIceTransports(config.type); @@ -1123,10 +1141,12 @@ bool PeerConnection::AddIceCandidate( const IceCandidateInterface* ice_candidate) { + TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate"); return session_->ProcessIceMessage(ice_candidate); } void PeerConnection::RegisterUMAObserver(UMAObserver* observer) { + TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver"); uma_observer_ = observer; if (session_) { @@ -1156,6 +1176,7 @@ } void PeerConnection::Close() { + TRACE_EVENT0("webrtc", "PeerConnection::Close"); // Update stats here so that we have the most recent stats for tracks and // streams before the channels are closed. stats_->UpdateStats(kStatsOutputLevelStandard); @@ -1223,6 +1244,10 @@ delete param; break; } + case MSG_FREE_DATACHANNELS: { + sctp_data_channels_to_free_.clear(); + break; + } default: RTC_DCHECK(false && "Not implemented"); break; @@ -1267,49 +1292,6 @@ } } -void PeerConnection::CreateAudioSender(MediaStreamInterface* stream, - AudioTrackInterface* audio_track, - uint32_t ssrc) { - senders_.push_back(new AudioRtpSender(audio_track, ssrc, session_.get())); - stats_->AddLocalAudioTrack(audio_track, ssrc); -} - -void PeerConnection::CreateVideoSender(MediaStreamInterface* stream, - VideoTrackInterface* video_track, - uint32_t ssrc) { - senders_.push_back(new VideoRtpSender(video_track, ssrc, session_.get())); -} - -// TODO(deadbeef): Keep RtpSenders around even if track goes away in local -// description. -void PeerConnection::DestroyAudioSender(MediaStreamInterface* stream, - AudioTrackInterface* audio_track, - uint32_t ssrc) { - auto it = FindSenderForTrack(audio_track); - if (it == senders_.end()) { - LOG(LS_WARNING) << "RtpSender for track with id " << audio_track->id() - << " doesn't exist."; - return; - } else { - (*it)->Stop(); - senders_.erase(it); - } - stats_->RemoveLocalAudioTrack(audio_track, ssrc); -} - -void PeerConnection::DestroyVideoSender(MediaStreamInterface* stream, - VideoTrackInterface* video_track) { - auto it = FindSenderForTrack(video_track); - if (it == senders_.end()) { - LOG(LS_WARNING) << "RtpSender for track with id " << video_track->id() - << " doesn't exist."; - return; - } else { - (*it)->Stop(); - senders_.erase(it); - } -} - void PeerConnection::OnIceConnectionChange( PeerConnectionInterface::IceConnectionState new_state) { RTC_DCHECK(signaling_thread()->IsCurrent()); @@ -1362,6 +1344,80 @@ observer_->OnStateChange(PeerConnectionObserver::kSignalingState); } +void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track, + MediaStreamInterface* stream) { + auto sender = FindSenderForTrack(track); + if (sender != senders_.end()) { + // We already have a sender for this track, so just change the stream_id + // so that it's correct in the next call to CreateOffer. + (*sender)->set_stream_id(stream->label()); + return; + } + + // Normal case; we've never seen this track before. + AudioRtpSender* new_sender = + new AudioRtpSender(track, stream->label(), session_.get(), stats_.get()); + senders_.push_back(new_sender); + // If the sender has already been configured in SDP, we call SetSsrc, + // which will connect the sender to the underlying transport. This can + // occur if a local session description that contains the ID of the sender + // is set before AddStream is called. It can also occur if the local + // session description is not changed and RemoveStream is called, and + // later AddStream is called again with the same stream. + const TrackInfo* track_info = + FindTrackInfo(local_audio_tracks_, stream->label(), track->id()); + if (track_info) { + new_sender->SetSsrc(track_info->ssrc); + } +} + +// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around +// indefinitely, when we have unified plan SDP. +void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track, + MediaStreamInterface* stream) { + auto sender = FindSenderForTrack(track); + if (sender == senders_.end()) { + LOG(LS_WARNING) << "RtpSender for track with id " << track->id() + << " doesn't exist."; + return; + } + (*sender)->Stop(); + senders_.erase(sender); +} + +void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track, + MediaStreamInterface* stream) { + auto sender = FindSenderForTrack(track); + if (sender != senders_.end()) { + // We already have a sender for this track, so just change the stream_id + // so that it's correct in the next call to CreateOffer. + (*sender)->set_stream_id(stream->label()); + return; + } + + // Normal case; we've never seen this track before. + VideoRtpSender* new_sender = + new VideoRtpSender(track, stream->label(), session_.get()); + senders_.push_back(new_sender); + const TrackInfo* track_info = + FindTrackInfo(local_video_tracks_, stream->label(), track->id()); + if (track_info) { + new_sender->SetSsrc(track_info->ssrc); + } +} + +void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track, + MediaStreamInterface* stream) { + auto sender = FindSenderForTrack(track); + if (sender == senders_.end()) { + LOG(LS_WARNING) << "RtpSender for track with id " << track->id() + << " doesn't exist."; + return; + } + (*sender)->Stop(); + senders_.erase(sender); +} + void PeerConnection::PostSetSessionDescriptionFailure( SetSessionDescriptionObserver* observer, const std::string& error) { @@ -1385,7 +1441,7 @@ return false; } - SetStreams(session_options, local_streams_, rtp_data_channels_); + AddSendStreams(session_options, senders_, rtp_data_channels_); // Offer to receive audio/video if the constraint is not set and there are // send streams, or we're currently receiving. if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) { @@ -1418,7 +1474,7 @@ return false; } - SetStreams(session_options, local_streams_, rtp_data_channels_); + AddSendStreams(session_options, senders_, rtp_data_channels_); session_options->bundle_enabled = session_options->bundle_enabled && (session_options->has_audio() || session_options->has_video() || @@ -1433,25 +1489,34 @@ return true; } +void PeerConnection::RemoveTracks(cricket::MediaType media_type) { + UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type); + UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false, + media_type, nullptr); +} + void PeerConnection::UpdateRemoteStreamsList( const cricket::StreamParamsVec& streams, + bool default_track_needed, cricket::MediaType media_type, StreamCollection* new_streams) { TrackInfos* current_tracks = GetRemoteTracks(media_type); // Find removed tracks. I.e., tracks where the track id or ssrc don't match - // the - // new StreamParam. + // the new StreamParam. auto track_it = current_tracks->begin(); while (track_it != current_tracks->end()) { const TrackInfo& info = *track_it; const cricket::StreamParams* params = cricket::GetStreamBySsrc(streams, info.ssrc); - if (!params || params->id != info.track_id) { + bool track_exists = params && params->id == info.track_id; + // If this is a default track, and we still need it, don't remove it. + if ((info.stream_label == kDefaultStreamLabel && default_track_needed) || + track_exists) { + ++track_it; + } else { OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type); track_it = current_tracks->erase(track_it); - } else { - ++track_it; } } @@ -1479,6 +1544,29 @@ OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type); } } + + // Add default track if necessary. + if (default_track_needed) { + rtc::scoped_refptr<MediaStreamInterface> default_stream = + remote_streams_->find(kDefaultStreamLabel); + if (!default_stream) { + // Create the new default MediaStream. + default_stream = + remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel); + remote_streams_->AddStream(default_stream); + new_streams->AddStream(default_stream); + } + std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO) + ? kDefaultAudioTrackLabel + : kDefaultVideoTrackLabel; + const TrackInfo* default_track_info = + FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id); + if (!default_track_info) { + current_tracks->push_back( + TrackInfo(kDefaultStreamLabel, default_track_id, 0)); + OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type); + } + } } void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label, @@ -1488,8 +1576,8 @@ MediaStreamInterface* stream = remote_streams_->find(stream_label); if (media_type == cricket::MEDIA_TYPE_AUDIO) { - AudioTrackInterface* audio_track = - remote_stream_factory_->AddAudioTrack(stream, track_id); + AudioTrackInterface* audio_track = remote_stream_factory_->AddAudioTrack( + ssrc, session_.get(), stream, track_id); CreateAudioReceiver(stream, audio_track, ssrc); } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { VideoTrackInterface* video_track = @@ -1541,41 +1629,6 @@ } } -void PeerConnection::MaybeCreateDefaultStream() { - if (!remote_info_.IsDefaultMediaStreamNeeded()) { - return; - } - - bool default_created = false; - - rtc::scoped_refptr<MediaStreamInterface> default_remote_stream = - remote_streams_->find(kDefaultStreamLabel); - if (default_remote_stream == nullptr) { - default_created = true; - default_remote_stream = - remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel); - remote_streams_->AddStream(default_remote_stream); - } - if (remote_info_.default_audio_track_needed && - default_remote_stream->GetAudioTracks().size() == 0) { - remote_audio_tracks_.push_back( - TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0)); - OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0, - cricket::MEDIA_TYPE_AUDIO); - } - if (remote_info_.default_video_track_needed && - default_remote_stream->GetVideoTracks().size() == 0) { - remote_video_tracks_.push_back( - TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0)); - OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0, - cricket::MEDIA_TYPE_VIDEO); - } - if (default_created) { - stats_->AddStream(default_remote_stream); - observer_->OnAddStream(default_remote_stream); - } -} - void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) { TrackInfos* current_tracks = GetRemoteTracks(media_type); for (TrackInfos::iterator track_it = current_tracks->begin(); @@ -1643,62 +1696,44 @@ const std::string& track_id, uint32_t ssrc, cricket::MediaType media_type) { - MediaStreamInterface* stream = local_streams_->find(stream_label); - if (!stream) { - LOG(LS_WARNING) << "An unknown local MediaStream with label " - << stream_label << " has been configured."; + RtpSenderInterface* sender = FindSenderById(track_id); + if (!sender) { + LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id + << " has been configured in the local description."; return; } - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id); - if (!audio_track) { - LOG(LS_WARNING) << "An unknown local AudioTrack with id , " << track_id - << " has been configured."; - return; - } - CreateAudioSender(stream, audio_track, ssrc); - } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { - VideoTrackInterface* video_track = stream->FindVideoTrack(track_id); - if (!video_track) { - LOG(LS_WARNING) << "An unknown local VideoTrack with id , " << track_id - << " has been configured."; - return; - } - CreateVideoSender(stream, video_track, ssrc); - } else { - RTC_DCHECK(false && "Invalid media type"); + if (sender->media_type() != media_type) { + LOG(LS_WARNING) << "An RtpSender has been configured in the local" + << " description with an unexpected media type."; + return; } + + sender->set_stream_id(stream_label); + sender->SetSsrc(ssrc); } void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label, const std::string& track_id, uint32_t ssrc, cricket::MediaType media_type) { - MediaStreamInterface* stream = local_streams_->find(stream_label); - if (!stream) { - // This is the normal case. I.e., RemoveLocalStream has been called and the + RtpSenderInterface* sender = FindSenderById(track_id); + if (!sender) { + // This is the normal case. I.e., RemoveStream has been called and the // SessionDescriptions has been renegotiated. return; } - // A track has been removed from the SessionDescription but the MediaStream - // is still associated with PeerConnection. This only occurs if the SDP - // doesn't match with the calls to AddLocalStream and RemoveLocalStream. - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id); - if (!audio_track) { - return; - } - DestroyAudioSender(stream, audio_track, ssrc); - } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { - VideoTrackInterface* video_track = stream->FindVideoTrack(track_id); - if (!video_track) { - return; - } - DestroyVideoSender(stream, video_track); - } else { - RTC_DCHECK(false && "Invalid media type."); + + // A sender has been removed from the SessionDescription but it's still + // associated with the PeerConnection. This only occurs if the SDP doesn't + // match with the calls to CreateSender, AddStream and RemoveStream. + if (sender->media_type() != media_type) { + LOG(LS_WARNING) << "An RtpSender has been configured in the local" + << " description with an unexpected media type."; + return; } + + sender->SetSsrc(0); } void PeerConnection::UpdateLocalRtpDataChannels( @@ -1806,7 +1841,7 @@ if (session_->data_channel_type() == cricket::DCT_SCTP) { if (new_config.id < 0) { rtc::SSLRole role; - if (session_->GetSslRole(&role) && + if ((session_->GetSslRole(session_->data_channel(), &role)) && !sid_allocator_.AllocateSid(role, &new_config.id)) { LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel."; return nullptr; @@ -1860,13 +1895,18 @@ } void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) { + RTC_DCHECK(signaling_thread()->IsCurrent()); for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end(); ++it) { if (it->get() == channel) { if (channel->id() >= 0) { sid_allocator_.ReleaseSid(channel->id()); } + // Since this method is triggered by a signal from the DataChannel, + // we can't free it directly here; we need to free it asynchronously. + sctp_data_channels_to_free_.push_back(*it); sctp_data_channels_.erase(it); + signaling_thread()->Post(this, MSG_FREE_DATACHANNELS, nullptr); return; } } @@ -1916,6 +1956,15 @@ DataChannelProxy::Create(signaling_thread(), channel)); } +RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) { + auto it = + std::find_if(senders_.begin(), senders_.end(), + [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) { + return sender->id() == id; + }); + return it != senders_.end() ? it->get() : nullptr; +} + std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) { return std::find_if(
diff --git a/talk/app/webrtc/peerconnection.h b/talk/app/webrtc/peerconnection.h index 2d388ae..6e2b967 100644 --- a/talk/app/webrtc/peerconnection.h +++ b/talk/app/webrtc/peerconnection.h
@@ -42,13 +42,9 @@ namespace webrtc { +class MediaStreamObserver; class RemoteMediaStreamFactory; -typedef std::vector<PortAllocatorFactoryInterface::StunConfiguration> - StunConfigurations; -typedef std::vector<PortAllocatorFactoryInterface::TurnConfiguration> - TurnConfigurations; - // Populates |session_options| from |rtc_options|, and returns true if options // are valid. bool ConvertRtcOptionsForOffer( @@ -60,11 +56,11 @@ bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints, cricket::MediaSessionOptions* session_options); -// Parses the URLs for each server in |servers| to build |stun_config| and -// |turn_config|. +// Parses the URLs for each server in |servers| to build |stun_servers| and +// |turn_servers|. bool ParseIceServers(const PeerConnectionInterface::IceServers& servers, - StunConfigurations* stun_config, - TurnConfigurations* turn_config); + cricket::ServerAddresses* stun_servers, + std::vector<cricket::RelayServerConfig>* turn_servers); // PeerConnection implements the PeerConnectionInterface interface. // It uses WebRtcSession to implement the PeerConnection functionality. @@ -78,9 +74,10 @@ bool Initialize( const PeerConnectionInterface::RTCConfiguration& configuration, const MediaConstraintsInterface* constraints, - PortAllocatorFactoryInterface* allocator_factory, + rtc::scoped_ptr<cricket::PortAllocator> allocator, rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, PeerConnectionObserver* observer); + rtc::scoped_refptr<StreamCollectionInterface> local_streams() override; rtc::scoped_refptr<StreamCollectionInterface> remote_streams() override; bool AddStream(MediaStreamInterface* local_stream) override; @@ -91,6 +88,10 @@ rtc::scoped_refptr<DtmfSenderInterface> CreateDtmfSender( AudioTrackInterface* track) override; + rtc::scoped_refptr<RtpSenderInterface> CreateSender( + const std::string& kind, + const std::string& stream_id) override; + std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders() const override; std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers() @@ -148,32 +149,16 @@ const std::string track_id, uint32_t ssrc) : stream_label(stream_label), track_id(track_id), ssrc(ssrc) {} + bool operator==(const TrackInfo& other) { + return this->stream_label == other.stream_label && + this->track_id == other.track_id && this->ssrc == other.ssrc; + } std::string stream_label; std::string track_id; uint32_t ssrc; }; typedef std::vector<TrackInfo> TrackInfos; - struct RemotePeerInfo { - RemotePeerInfo() - : msid_supported(false), - default_audio_track_needed(false), - default_video_track_needed(false) {} - // True if it has been discovered that the remote peer support MSID. - bool msid_supported; - // The remote peer indicates in the session description that audio will be - // sent but no MSID is given. - bool default_audio_track_needed; - // The remote peer indicates in the session description that video will be - // sent but no MSID is given. - bool default_video_track_needed; - - bool IsDefaultMediaStreamNeeded() { - return !msid_supported && - (default_audio_track_needed || default_video_track_needed); - } - }; - // Implements MessageHandler. void OnMessage(rtc::Message* msg) override; @@ -187,12 +172,6 @@ AudioTrackInterface* audio_track); void DestroyVideoReceiver(MediaStreamInterface* stream, VideoTrackInterface* video_track); - void CreateAudioSender(MediaStreamInterface* stream, - AudioTrackInterface* audio_track, - uint32_t ssrc); - void CreateVideoSender(MediaStreamInterface* stream, - VideoTrackInterface* video_track, - uint32_t ssrc); void DestroyAudioSender(MediaStreamInterface* stream, AudioTrackInterface* audio_track, uint32_t ssrc); @@ -210,6 +189,16 @@ void OnSessionStateChange(WebRtcSession* session, WebRtcSession::State state); void ChangeSignalingState(SignalingState signaling_state); + // Signals from MediaStreamObserver. + void OnAudioTrackAdded(AudioTrackInterface* track, + MediaStreamInterface* stream); + void OnAudioTrackRemoved(AudioTrackInterface* track, + MediaStreamInterface* stream); + void OnVideoTrackAdded(VideoTrackInterface* track, + MediaStreamInterface* stream); + void OnVideoTrackRemoved(VideoTrackInterface* track, + MediaStreamInterface* stream); + rtc::Thread* signaling_thread() const { return factory_->signaling_thread(); } @@ -236,12 +225,19 @@ const MediaConstraintsInterface* constraints, cricket::MediaSessionOptions* session_options); - // Makes sure a MediaStream Track is created for each StreamParam in - // |streams|. |media_type| is the type of the |streams| and can be either - // audio or video. + // Remove all local and remote tracks of type |media_type|. + // Called when a media type is rejected (m-line set to port 0). + void RemoveTracks(cricket::MediaType media_type); + + // Makes sure a MediaStreamTrack is created for each StreamParam in |streams|, + // and existing MediaStreamTracks are removed if there is no corresponding + // StreamParam. If |default_track_needed| is true, a default MediaStreamTrack + // is created if it doesn't exist; if false, it's removed if it exists. + // |media_type| is the type of the |streams| and can be either audio or video. // If a new MediaStream is created it is added to |new_streams|. void UpdateRemoteStreamsList( const std::vector<cricket::StreamParams>& streams, + bool default_track_needed, cricket::MediaType media_type, StreamCollection* new_streams); @@ -265,8 +261,6 @@ // exist. void UpdateEndedRemoteMediaStreams(); - void MaybeCreateDefaultStream(); - // Set the MediaStreamTrackInterface::TrackState to |kEnded| on all remote // tracks of type |media_type|. void EndRemoteTracks(cricket::MediaType media_type); @@ -328,6 +322,8 @@ void OnDataChannelOpenMessage(const std::string& label, const InternalDataChannelInit& config); + RtpSenderInterface* FindSenderById(const std::string& id); + std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator FindSenderForTrack(MediaStreamTrackInterface* track); std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator @@ -366,6 +362,8 @@ // Streams created as a result of SetRemoteDescription. rtc::scoped_refptr<StreamCollection> remote_streams_; + std::vector<rtc::scoped_ptr<MediaStreamObserver>> stream_observers_; + // These lists store track info seen in local/remote descriptions. TrackInfos remote_audio_tracks_; TrackInfos remote_video_tracks_; @@ -376,8 +374,9 @@ // label -> DataChannel std::map<std::string, rtc::scoped_refptr<DataChannel>> rtp_data_channels_; std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_; + std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_to_free_; - RemotePeerInfo remote_info_; + bool remote_peer_supports_msid_ = false; rtc::scoped_ptr<RemoteMediaStreamFactory> remote_stream_factory_; std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders_;
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc index 3cf66d6..8d0793e 100644 --- a/talk/app/webrtc/peerconnection_unittest.cc +++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -30,11 +30,11 @@ #include <algorithm> #include <list> #include <map> +#include <utility> #include <vector> #include "talk/app/webrtc/dtmfsender.h" #include "talk/app/webrtc/fakemetricsobserver.h" -#include "talk/app/webrtc/fakeportallocatorfactory.h" #include "talk/app/webrtc/localaudiosource.h" #include "talk/app/webrtc/mediastreaminterface.h" #include "talk/app/webrtc/peerconnection.h" @@ -58,6 +58,7 @@ #include "webrtc/base/virtualsocketserver.h" #include "webrtc/p2p/base/constants.h" #include "webrtc/p2p/base/sessiondescription.h" +#include "webrtc/p2p/client/fakeportallocator.h" #define MAYBE_SKIP_TEST(feature) \ if (!(feature())) { \ @@ -78,11 +79,13 @@ using webrtc::DtmfSenderObserverInterface; using webrtc::FakeConstraints; using webrtc::MediaConstraintsInterface; +using webrtc::MediaStreamInterface; using webrtc::MediaStreamTrackInterface; using webrtc::MockCreateSessionDescriptionObserver; using webrtc::MockDataChannelObserver; using webrtc::MockSetSessionDescriptionObserver; using webrtc::MockStatsObserver; +using webrtc::ObserverInterface; using webrtc::PeerConnectionInterface; using webrtc::PeerConnectionFactory; using webrtc::SessionDescriptionInterface; @@ -96,6 +99,7 @@ #if !defined(THREAD_SANITIZER) static const int kMaxWaitForStatsMs = 3000; #endif +static const int kMaxWaitForActivationMs = 5000; static const int kMaxWaitForFramesMs = 10000; static const int kEndAudioFrameCount = 3; static const int kEndVideoFrameCount = 3; @@ -111,7 +115,7 @@ #if !defined(THREAD_SANITIZER) // SRTP cipher name negotiated by the tests. This must be updated if the // default changes. -static const char kDefaultSrtpCipher[] = "AES_CM_128_HMAC_SHA1_32"; +static const int kDefaultSrtpCryptoSuite = rtc::SRTP_AES128_CM_SHA1_32; #endif static void RemoveLinesFromSdp(const std::string& line_start, @@ -139,26 +143,35 @@ }; class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, - public SignalingMessageReceiver { + public SignalingMessageReceiver, + public ObserverInterface { public: - static PeerConnectionTestClient* CreateClient( + static PeerConnectionTestClient* CreateClientWithDtlsIdentityStore( const std::string& id, const MediaConstraintsInterface* constraints, - const PeerConnectionFactory::Options* options) { + const PeerConnectionFactory::Options* options, + rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store) { PeerConnectionTestClient* client(new PeerConnectionTestClient(id)); - if (!client->Init(constraints, options)) { + if (!client->Init(constraints, options, std::move(dtls_identity_store))) { delete client; return nullptr; } return client; } + static PeerConnectionTestClient* CreateClient( + const std::string& id, + const MediaConstraintsInterface* constraints, + const PeerConnectionFactory::Options* options) { + rtc::scoped_ptr<FakeDtlsIdentityStore> dtls_identity_store( + rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeDtlsIdentityStore() + : nullptr); + + return CreateClientWithDtlsIdentityStore(id, constraints, options, + std::move(dtls_identity_store)); + } + ~PeerConnectionTestClient() { - while (!fake_video_renderers_.empty()) { - RenderMap::iterator it = fake_video_renderers_.begin(); - delete it->second; - fake_video_renderers_.erase(it); - } } void Negotiate() { Negotiate(true, true); } @@ -206,16 +219,17 @@ webrtc::PeerConnectionInterface::SignalingState new_state) override { EXPECT_EQ(pc()->signaling_state(), new_state); } - void OnAddStream(webrtc::MediaStreamInterface* media_stream) override { + void OnAddStream(MediaStreamInterface* media_stream) override { + media_stream->RegisterObserver(this); for (size_t i = 0; i < media_stream->GetVideoTracks().size(); ++i) { const std::string id = media_stream->GetVideoTracks()[i]->id(); ASSERT_TRUE(fake_video_renderers_.find(id) == fake_video_renderers_.end()); - fake_video_renderers_[id] = - new webrtc::FakeVideoTrackRenderer(media_stream->GetVideoTracks()[i]); + fake_video_renderers_[id].reset(new webrtc::FakeVideoTrackRenderer( + media_stream->GetVideoTracks()[i])); } } - void OnRemoveStream(webrtc::MediaStreamInterface* media_stream) override {} + void OnRemoveStream(MediaStreamInterface* media_stream) override {} void OnRenegotiationNeeded() override {} void OnIceConnectionChange( webrtc::PeerConnectionInterface::IceConnectionState new_state) override { @@ -238,6 +252,40 @@ candidate->sdp_mid(), candidate->sdp_mline_index(), ice_sdp); } + // MediaStreamInterface callback + void OnChanged() override { + // Track added or removed from MediaStream, so update our renderers. + rtc::scoped_refptr<StreamCollectionInterface> remote_streams = + pc()->remote_streams(); + // Remove renderers for tracks that were removed. + for (auto it = fake_video_renderers_.begin(); + it != fake_video_renderers_.end();) { + if (remote_streams->FindVideoTrack(it->first) == nullptr) { + auto to_remove = it++; + removed_fake_video_renderers_.push_back(std::move(to_remove->second)); + fake_video_renderers_.erase(to_remove); + } else { + ++it; + } + } + // Create renderers for new video tracks. + for (size_t stream_index = 0; stream_index < remote_streams->count(); + ++stream_index) { + MediaStreamInterface* remote_stream = remote_streams->at(stream_index); + for (size_t track_index = 0; + track_index < remote_stream->GetVideoTracks().size(); + ++track_index) { + const std::string id = + remote_stream->GetVideoTracks()[track_index]->id(); + if (fake_video_renderers_.find(id) != fake_video_renderers_.end()) { + continue; + } + fake_video_renderers_[id].reset(new webrtc::FakeVideoTrackRenderer( + remote_stream->GetVideoTracks()[track_index])); + } + } + } + void SetVideoConstraints(const webrtc::FakeConstraints& video_constraint) { video_constraints_ = video_constraint; } @@ -246,22 +294,11 @@ std::string stream_label = kStreamLabelBase + rtc::ToString<int>(static_cast<int>(pc()->local_streams()->count())); - rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = + rtc::scoped_refptr<MediaStreamInterface> stream = peer_connection_factory_->CreateLocalMediaStream(stream_label); if (audio && can_receive_audio()) { - FakeConstraints constraints; - // Disable highpass filter so that we can get all the test audio frames. - constraints.AddMandatory( - MediaConstraintsInterface::kHighpassFilter, false); - rtc::scoped_refptr<webrtc::AudioSourceInterface> source = - peer_connection_factory_->CreateAudioSource(&constraints); - // TODO(perkj): Test audio source when it is implemented. Currently audio - // always use the default input. - std::string label = stream_label + kAudioTrackLabelBase; - rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( - peer_connection_factory_->CreateAudioTrack(label, source)); - stream->AddTrack(audio_track); + stream->AddTrack(CreateLocalAudioTrack(stream_label)); } if (video && can_receive_video()) { stream->AddTrack(CreateLocalVideoTrack(stream_label)); @@ -276,6 +313,12 @@ return pc()->signaling_state() == webrtc::PeerConnectionInterface::kStable; } + // Automatically add a stream when receiving an offer, if we don't have one. + // Defaults to true. + void set_auto_add_stream(bool auto_add_stream) { + auto_add_stream_ = auto_add_stream; + } + void set_signaling_message_receiver( SignalingMessageReceiver* signaling_message_receiver) { signaling_message_receiver_ = signaling_message_receiver; @@ -357,6 +400,35 @@ data_observer_.reset(new MockDataChannelObserver(data_channel_)); } + rtc::scoped_refptr<webrtc::AudioTrackInterface> CreateLocalAudioTrack( + const std::string& stream_label) { + FakeConstraints constraints; + // Disable highpass filter so that we can get all the test audio frames. + constraints.AddMandatory(MediaConstraintsInterface::kHighpassFilter, false); + rtc::scoped_refptr<webrtc::AudioSourceInterface> source = + peer_connection_factory_->CreateAudioSource(&constraints); + // TODO(perkj): Test audio source when it is implemented. Currently audio + // always use the default input. + std::string label = stream_label + kAudioTrackLabelBase; + return peer_connection_factory_->CreateAudioTrack(label, source); + } + + rtc::scoped_refptr<webrtc::VideoTrackInterface> CreateLocalVideoTrack( + const std::string& stream_label) { + // Set max frame rate to 10fps to reduce the risk of the tests to be flaky. + FakeConstraints source_constraints = video_constraints_; + source_constraints.SetMandatoryMaxFrameRate(10); + + cricket::FakeVideoCapturer* fake_capturer = + new webrtc::FakePeriodicVideoCapturer(); + video_capturers_.push_back(fake_capturer); + rtc::scoped_refptr<webrtc::VideoSourceInterface> source = + peer_connection_factory_->CreateVideoSource(fake_capturer, + &source_constraints); + std::string label = stream_label + kVideoTrackLabelBase; + return peer_connection_factory_->CreateVideoTrack(label, source); + } + DataChannelInterface* data_channel() { return data_channel_; } const MockDataChannelObserver* data_observer() const { return data_observer_.get(); @@ -376,6 +448,10 @@ return number_of_frames <= fake_audio_capture_module_->frames_received(); } + int audio_frames_received() const { + return fake_audio_capture_module_->frames_received(); + } + bool VideoFramesReceivedCheck(int number_of_frames) { if (video_decoder_factory_enabled_) { const std::vector<FakeWebRtcVideoDecoder*>& decoders @@ -384,9 +460,8 @@ return number_of_frames <= 0; } - for (std::vector<FakeWebRtcVideoDecoder*>::const_iterator - it = decoders.begin(); it != decoders.end(); ++it) { - if (number_of_frames > (*it)->GetNumFramesReceived()) { + for (FakeWebRtcVideoDecoder* decoder : decoders) { + if (number_of_frames > decoder->GetNumFramesReceived()) { return false; } } @@ -396,9 +471,8 @@ return number_of_frames <= 0; } - for (RenderMap::const_iterator it = fake_video_renderers_.begin(); - it != fake_video_renderers_.end(); ++it) { - if (number_of_frames > it->second->num_rendered_frames()) { + for (const auto& pair : fake_video_renderers_) { + if (number_of_frames > pair.second->num_rendered_frames()) { return false; } } @@ -406,6 +480,25 @@ } } + int video_frames_received() const { + int total = 0; + if (video_decoder_factory_enabled_) { + const std::vector<FakeWebRtcVideoDecoder*>& decoders = + fake_video_decoder_factory_->decoders(); + for (const FakeWebRtcVideoDecoder* decoder : decoders) { + total += decoder->GetNumFramesReceived(); + } + } else { + for (const auto& pair : fake_video_renderers_) { + total += pair.second->num_rendered_frames(); + } + for (const auto& renderer : removed_fake_video_renderers_) { + total += renderer->num_rendered_frames(); + } + } + return total; + } + // Verify the CreateDtmfSender interface void VerifyDtmf() { rtc::scoped_ptr<DummyDtmfObserver> observer(new DummyDtmfObserver()); @@ -641,14 +734,14 @@ explicit PeerConnectionTestClient(const std::string& id) : id_(id) {} - bool Init(const MediaConstraintsInterface* constraints, - const PeerConnectionFactory::Options* options) { + bool Init( + const MediaConstraintsInterface* constraints, + const PeerConnectionFactory::Options* options, + rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store) { EXPECT_TRUE(!peer_connection_); EXPECT_TRUE(!peer_connection_factory_); - allocator_factory_ = webrtc::FakePortAllocatorFactory::Create(); - if (!allocator_factory_) { - return false; - } + rtc::scoped_ptr<cricket::PortAllocator> port_allocator( + new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr)); fake_audio_capture_module_ = FakeAudioCaptureModule::Create(); if (fake_audio_capture_module_ == nullptr) { @@ -666,46 +759,29 @@ if (options) { peer_connection_factory_->SetOptions(*options); } - peer_connection_ = CreatePeerConnection(allocator_factory_.get(), - constraints); + peer_connection_ = CreatePeerConnection( + std::move(port_allocator), constraints, std::move(dtls_identity_store)); return peer_connection_.get() != nullptr; } - rtc::scoped_refptr<webrtc::VideoTrackInterface> - CreateLocalVideoTrack(const std::string stream_label) { - // Set max frame rate to 10fps to reduce the risk of the tests to be flaky. - FakeConstraints source_constraints = video_constraints_; - source_constraints.SetMandatoryMaxFrameRate(10); - - cricket::FakeVideoCapturer* fake_capturer = - new webrtc::FakePeriodicVideoCapturer(); - video_capturers_.push_back(fake_capturer); - rtc::scoped_refptr<webrtc::VideoSourceInterface> source = - peer_connection_factory_->CreateVideoSource( - fake_capturer, &source_constraints); - std::string label = stream_label + kVideoTrackLabelBase; - return peer_connection_factory_->CreateVideoTrack(label, source); - } - rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection( - webrtc::PortAllocatorFactoryInterface* factory, - const MediaConstraintsInterface* constraints) { - // CreatePeerConnection with IceServers. - webrtc::PeerConnectionInterface::IceServers ice_servers; + rtc::scoped_ptr<cricket::PortAllocator> port_allocator, + const MediaConstraintsInterface* constraints, + rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store) { + // CreatePeerConnection with RTCConfiguration. + webrtc::PeerConnectionInterface::RTCConfiguration config; webrtc::PeerConnectionInterface::IceServer ice_server; ice_server.uri = "stun:stun.l.google.com:19302"; - ice_servers.push_back(ice_server); + config.servers.push_back(ice_server); - rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store( - rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeDtlsIdentityStore() - : nullptr); return peer_connection_factory_->CreatePeerConnection( - ice_servers, constraints, factory, dtls_identity_store.Pass(), this); + config, constraints, std::move(port_allocator), + std::move(dtls_identity_store), this); } void HandleIncomingOffer(const std::string& msg) { LOG(INFO) << id_ << "HandleIncomingOffer "; - if (NumberOfLocalMediaStreams() == 0) { + if (NumberOfLocalMediaStreams() == 0 && auto_add_stream_) { // If we are not sending any streams ourselves it is time to add some. AddMediaStream(true, true); } @@ -807,20 +883,24 @@ std::string id_; - rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface> allocator_factory_; rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_; rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory_; + bool auto_add_stream_ = true; + typedef std::pair<std::string, std::string> IceUfragPwdPair; std::map<int, IceUfragPwdPair> ice_ufrag_pwd_; bool expect_ice_restart_ = false; - // Needed to keep track of number of frames send. + // Needed to keep track of number of frames sent. rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_; // Needed to keep track of number of frames received. - typedef std::map<std::string, webrtc::FakeVideoTrackRenderer*> RenderMap; - RenderMap fake_video_renderers_; + std::map<std::string, rtc::scoped_ptr<webrtc::FakeVideoTrackRenderer>> + fake_video_renderers_; + // Needed to ensure frames aren't received for removed tracks. + std::vector<rtc::scoped_ptr<webrtc::FakeVideoTrackRenderer>> + removed_fake_video_renderers_; // Needed to keep track of number of frames received when external decoder // used. FakeWebRtcVideoDecoderFactory* fake_video_decoder_factory_ = nullptr; @@ -846,11 +926,9 @@ rtc::scoped_ptr<MockDataChannelObserver> data_observer_; }; -// TODO(deadbeef): Rename this to P2PTestConductor once the Linux memcheck and -// Windows DrMemory Full bots' blacklists are updated. -class JsepPeerConnectionP2PTestClient : public testing::Test { +class P2PTestConductor : public testing::Test { public: - JsepPeerConnectionP2PTestClient() + P2PTestConductor() : pss_(new rtc::PhysicalSocketServer), ss_(new rtc::VirtualSocketServer(pss_.get())), ss_scope_(ss_.get()) {} @@ -882,13 +960,26 @@ } void TestUpdateOfferWithRejectedContent() { + // Renegotiate, rejecting the video m-line. initiating_client_->Negotiate(true, false); - EXPECT_TRUE_WAIT( - FramesNotPending(kEndAudioFrameCount * 2, kEndVideoFrameCount), - kMaxWaitForFramesMs); - // There shouldn't be any more video frame after the new offer is - // negotiated. - EXPECT_FALSE(VideoFramesReceivedCheck(kEndVideoFrameCount + 1)); + ASSERT_TRUE_WAIT(SessionActive(), kMaxWaitForActivationMs); + + int pc1_audio_received = initiating_client_->audio_frames_received(); + int pc1_video_received = initiating_client_->video_frames_received(); + int pc2_audio_received = receiving_client_->audio_frames_received(); + int pc2_video_received = receiving_client_->video_frames_received(); + + // Wait for some additional audio frames to be received. + EXPECT_TRUE_WAIT(initiating_client_->AudioFramesReceivedCheck( + pc1_audio_received + kEndAudioFrameCount) && + receiving_client_->AudioFramesReceivedCheck( + pc2_audio_received + kEndAudioFrameCount), + kMaxWaitForFramesMs); + + // During this time, we shouldn't have received any additional video frames + // for the rejected video tracks. + EXPECT_EQ(pc1_video_received, initiating_client_->video_frames_received()); + EXPECT_EQ(pc2_video_received, receiving_client_->video_frames_received()); } void VerifyRenderedSize(int width, int height) { @@ -905,7 +996,7 @@ receiving_client_->VerifyLocalIceUfragAndPassword(); } - ~JsepPeerConnectionP2PTestClient() { + ~P2PTestConductor() { if (initiating_client_) { initiating_client_->set_signaling_message_receiver(nullptr); } @@ -922,6 +1013,11 @@ nullptr); } + void SetSignalingReceivers() { + initiating_client_->set_signaling_message_receiver(receiving_client_.get()); + receiving_client_->set_signaling_message_receiver(initiating_client_.get()); + } + bool CreateTestClients(MediaConstraintsInterface* init_constraints, PeerConnectionFactory::Options* init_options, MediaConstraintsInterface* recv_constraints, @@ -933,8 +1029,7 @@ if (!initiating_client_ || !receiving_client_) { return false; } - initiating_client_->set_signaling_message_receiver(receiving_client_.get()); - receiving_client_->set_signaling_message_receiver(initiating_client_.get()); + SetSignalingReceivers(); return true; } @@ -957,13 +1052,11 @@ initiating_client_->AddMediaStream(true, true); } initiating_client_->Negotiate(); - const int kMaxWaitForActivationMs = 5000; // Assert true is used here since next tests are guaranteed to fail and // would eat up 5 seconds. ASSERT_TRUE_WAIT(SessionActive(), kMaxWaitForActivationMs); VerifySessionDescriptions(); - int audio_frame_count = kEndAudioFrameCount; // TODO(ronghuawu): Add test to cover the case of sendonly and recvonly. if (!initiating_client_->can_receive_audio() || @@ -1013,6 +1106,32 @@ kMaxWaitForFramesMs); } + void SetupAndVerifyDtlsCall() { + MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); + FakeConstraints setup_constraints; + setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, + true); + ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints)); + LocalP2PTest(); + VerifyRenderedSize(640, 480); + } + + PeerConnectionTestClient* CreateDtlsClientWithAlternateKey() { + FakeConstraints setup_constraints; + setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, + true); + + rtc::scoped_ptr<FakeDtlsIdentityStore> dtls_identity_store( + rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeDtlsIdentityStore() + : nullptr); + dtls_identity_store->use_alternate_key(); + + // Make sure the new client is using a different certificate. + return PeerConnectionTestClient::CreateClientWithDtlsIdentityStore( + "New Peer: ", &setup_constraints, nullptr, + std::move(dtls_identity_store)); + } + void SendRtpData(webrtc::DataChannelInterface* dc, const std::string& data) { // Messages may get lost on the unreliable DataChannel, so we send multiple // times to avoid test flakiness. @@ -1026,10 +1145,29 @@ PeerConnectionTestClient* initializing_client() { return initiating_client_.get(); } + + // Set the |initiating_client_| to the |client| passed in and return the + // original |initiating_client_|. + PeerConnectionTestClient* set_initializing_client( + PeerConnectionTestClient* client) { + PeerConnectionTestClient* old = initiating_client_.release(); + initiating_client_.reset(client); + return old; + } + PeerConnectionTestClient* receiving_client() { return receiving_client_.get(); } + // Set the |receiving_client_| to the |client| passed in and return the + // original |receiving_client_|. + PeerConnectionTestClient* set_receiving_client( + PeerConnectionTestClient* client) { + PeerConnectionTestClient* old = receiving_client_.release(); + receiving_client_.reset(client); + return old; + } + private: rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; rtc::scoped_ptr<rtc::VirtualSocketServer> ss_; @@ -1045,7 +1183,7 @@ // This test sets up a Jsep call between two parties and test Dtmf. // TODO(holmer): Disabled due to sometimes crashing on buildbots. // See issue webrtc/2378. -TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTestDtmf) { +TEST_F(P2PTestConductor, DISABLED_LocalP2PTestDtmf) { ASSERT_TRUE(CreateTestClients()); LocalP2PTest(); VerifyDtmf(); @@ -1053,7 +1191,7 @@ // This test sets up a Jsep call between two parties and test that we can get a // video aspect ratio of 16:9. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTest16To9) { +TEST_F(P2PTestConductor, LocalP2PTest16To9) { ASSERT_TRUE(CreateTestClients()); FakeConstraints constraint; double requested_ratio = 640.0/360; @@ -1078,7 +1216,7 @@ // received video has a resolution of 1280*720. // TODO(mallinath): Enable when // http://code.google.com/p/webrtc/issues/detail?id=981 is fixed. -TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTest1280By720) { +TEST_F(P2PTestConductor, DISABLED_LocalP2PTest1280By720) { ASSERT_TRUE(CreateTestClients()); FakeConstraints constraint; constraint.SetMandatoryMinWidth(1280); @@ -1090,19 +1228,13 @@ // This test sets up a call between two endpoints that are configured to use // DTLS key agreement. As a result, DTLS is negotiated and used for transport. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDtls) { - MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); - FakeConstraints setup_constraints; - setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, - true); - ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints)); - LocalP2PTest(); - VerifyRenderedSize(640, 480); +TEST_F(P2PTestConductor, LocalP2PTestDtls) { + SetupAndVerifyDtlsCall(); } // This test sets up a audio call initially and then upgrades to audio/video, // using DTLS. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDtlsRenegotiate) { +TEST_F(P2PTestConductor, LocalP2PTestDtlsRenegotiate) { MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); FakeConstraints setup_constraints; setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, @@ -1114,10 +1246,66 @@ receiving_client()->Negotiate(); } +// This test sets up a call transfer to a new caller with a different DTLS +// fingerprint. +TEST_F(P2PTestConductor, LocalP2PTestDtlsTransferCallee) { + MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); + SetupAndVerifyDtlsCall(); + + // Keeping the original peer around which will still send packets to the + // receiving client. These SRTP packets will be dropped. + rtc::scoped_ptr<PeerConnectionTestClient> original_peer( + set_initializing_client(CreateDtlsClientWithAlternateKey())); + original_peer->pc()->Close(); + + SetSignalingReceivers(); + receiving_client()->SetExpectIceRestart(true); + LocalP2PTest(); + VerifyRenderedSize(640, 480); +} + +// This test sets up a non-bundle call and apply bundle during ICE restart. When +// bundle is in effect in the restart, the channel can successfully reset its +// DTLS-SRTP context. +TEST_F(P2PTestConductor, LocalP2PTestDtlsBundleInIceRestart) { + MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); + FakeConstraints setup_constraints; + setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, + true); + ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints)); + receiving_client()->RemoveBundleFromReceivedSdp(true); + LocalP2PTest(); + VerifyRenderedSize(640, 480); + + initializing_client()->IceRestart(); + receiving_client()->SetExpectIceRestart(true); + receiving_client()->RemoveBundleFromReceivedSdp(false); + LocalP2PTest(); + VerifyRenderedSize(640, 480); +} + +// This test sets up a call transfer to a new callee with a different DTLS +// fingerprint. +TEST_F(P2PTestConductor, LocalP2PTestDtlsTransferCaller) { + MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); + SetupAndVerifyDtlsCall(); + + // Keeping the original peer around which will still send packets to the + // receiving client. These SRTP packets will be dropped. + rtc::scoped_ptr<PeerConnectionTestClient> original_peer( + set_receiving_client(CreateDtlsClientWithAlternateKey())); + original_peer->pc()->Close(); + + SetSignalingReceivers(); + initializing_client()->IceRestart(); + LocalP2PTest(); + VerifyRenderedSize(640, 480); +} + // This test sets up a call between two endpoints that are configured to use // DTLS key agreement. The offerer don't support SDES. As a result, DTLS is // negotiated and used for transport. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestOfferDtlsButNotSdes) { +TEST_F(P2PTestConductor, LocalP2PTestOfferDtlsButNotSdes) { MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); FakeConstraints setup_constraints; setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, @@ -1130,7 +1318,7 @@ // This test sets up a Jsep call between two parties, and the callee only // accept to receive video. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestAnswerVideo) { +TEST_F(P2PTestConductor, LocalP2PTestAnswerVideo) { ASSERT_TRUE(CreateTestClients()); receiving_client()->SetReceiveAudioVideo(false, true); LocalP2PTest(); @@ -1138,7 +1326,7 @@ // This test sets up a Jsep call between two parties, and the callee only // accept to receive audio. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestAnswerAudio) { +TEST_F(P2PTestConductor, LocalP2PTestAnswerAudio) { ASSERT_TRUE(CreateTestClients()); receiving_client()->SetReceiveAudioVideo(true, false); LocalP2PTest(); @@ -1146,7 +1334,7 @@ // This test sets up a Jsep call between two parties, and the callee reject both // audio and video. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestAnswerNone) { +TEST_F(P2PTestConductor, LocalP2PTestAnswerNone) { ASSERT_TRUE(CreateTestClients()); receiving_client()->SetReceiveAudioVideo(false, false); LocalP2PTest(); @@ -1156,9 +1344,7 @@ // runs for a while (10 frames), the caller sends an update offer with video // being rejected. Once the re-negotiation is done, the video flow should stop // and the audio flow should continue. -// Disabled due to b/14955157. -TEST_F(JsepPeerConnectionP2PTestClient, - DISABLED_UpdateOfferWithRejectedContent) { +TEST_F(P2PTestConductor, UpdateOfferWithRejectedContent) { ASSERT_TRUE(CreateTestClients()); LocalP2PTest(); TestUpdateOfferWithRejectedContent(); @@ -1166,8 +1352,7 @@ // This test sets up a Jsep call between two parties. The MSID is removed from // the SDP strings from the caller. -// Disabled due to b/14955157. -TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTestWithoutMsid) { +TEST_F(P2PTestConductor, LocalP2PTestWithoutMsid) { ASSERT_TRUE(CreateTestClients()); receiving_client()->RemoveMsidFromReceivedSdp(true); // TODO(perkj): Currently there is a bug that cause audio to stop playing if @@ -1182,7 +1367,7 @@ // sends two steams. // TODO(perkj): Disabled due to // https://code.google.com/p/webrtc/issues/detail?id=1454 -TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTestTwoStreams) { +TEST_F(P2PTestConductor, DISABLED_LocalP2PTestTwoStreams) { ASSERT_TRUE(CreateTestClients()); // Set optional video constraint to max 320pixels to decrease CPU usage. FakeConstraints constraint; @@ -1196,7 +1381,7 @@ } // Test that we can receive the audio output level from a remote audio track. -TEST_F(JsepPeerConnectionP2PTestClient, GetAudioOutputLevelStats) { +TEST_F(P2PTestConductor, GetAudioOutputLevelStats) { ASSERT_TRUE(CreateTestClients()); LocalP2PTest(); @@ -1215,7 +1400,7 @@ } // Test that an audio input level is reported. -TEST_F(JsepPeerConnectionP2PTestClient, GetAudioInputLevelStats) { +TEST_F(P2PTestConductor, GetAudioInputLevelStats) { ASSERT_TRUE(CreateTestClients()); LocalP2PTest(); @@ -1226,7 +1411,7 @@ } // Test that we can get incoming byte counts from both audio and video tracks. -TEST_F(JsepPeerConnectionP2PTestClient, GetBytesReceivedStats) { +TEST_F(P2PTestConductor, GetBytesReceivedStats) { ASSERT_TRUE(CreateTestClients()); LocalP2PTest(); @@ -1248,7 +1433,7 @@ } // Test that we can get outgoing byte counts from both audio and video tracks. -TEST_F(JsepPeerConnectionP2PTestClient, GetBytesSentStats) { +TEST_F(P2PTestConductor, GetBytesSentStats) { ASSERT_TRUE(CreateTestClients()); LocalP2PTest(); @@ -1270,7 +1455,7 @@ } // Test that DTLS 1.0 is used if both sides only support DTLS 1.0. -TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12None) { +TEST_F(P2PTestConductor, GetDtls12None) { PeerConnectionFactory::Options init_options; init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10; PeerConnectionFactory::Options recv_options; @@ -1282,7 +1467,7 @@ initializing_client()->pc()->RegisterUMAObserver(init_observer); LocalP2PTest(); - EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::GetSslCipherSuiteName( + EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::SslCipherSuiteToName( rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_10, rtc::KT_DEFAULT)), initializing_client()->GetDtlsCipherStats(), @@ -1292,16 +1477,23 @@ rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_10, rtc::KT_DEFAULT))); - EXPECT_EQ_WAIT(kDefaultSrtpCipher, + EXPECT_EQ_WAIT(rtc::SrtpCryptoSuiteToName(kDefaultSrtpCryptoSuite), initializing_client()->GetSrtpCipherStats(), kMaxWaitForStatsMs); - EXPECT_EQ(1, init_observer->GetEnumCounter( - webrtc::kEnumCounterAudioSrtpCipher, - rtc::GetSrtpCryptoSuiteFromName(kDefaultSrtpCipher))); + EXPECT_EQ(1, + init_observer->GetEnumCounter(webrtc::kEnumCounterAudioSrtpCipher, + kDefaultSrtpCryptoSuite)); } +#if defined(MEMORY_SANITIZER) +// Fails under MemorySanitizer: +// See https://code.google.com/p/webrtc/issues/detail?id=5381. +#define MAYBE_GetDtls12Both DISABLED_GetDtls12Both +#else +#define MAYBE_GetDtls12Both GetDtls12Both +#endif // Test that DTLS 1.2 is used if both ends support it. -TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12Both) { +TEST_F(P2PTestConductor, MAYBE_GetDtls12Both) { PeerConnectionFactory::Options init_options; init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12; PeerConnectionFactory::Options recv_options; @@ -1313,7 +1505,7 @@ initializing_client()->pc()->RegisterUMAObserver(init_observer); LocalP2PTest(); - EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::GetSslCipherSuiteName( + EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::SslCipherSuiteToName( rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_12, rtc::KT_DEFAULT)), initializing_client()->GetDtlsCipherStats(), @@ -1323,17 +1515,17 @@ rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_12, rtc::KT_DEFAULT))); - EXPECT_EQ_WAIT(kDefaultSrtpCipher, + EXPECT_EQ_WAIT(rtc::SrtpCryptoSuiteToName(kDefaultSrtpCryptoSuite), initializing_client()->GetSrtpCipherStats(), kMaxWaitForStatsMs); - EXPECT_EQ(1, init_observer->GetEnumCounter( - webrtc::kEnumCounterAudioSrtpCipher, - rtc::GetSrtpCryptoSuiteFromName(kDefaultSrtpCipher))); + EXPECT_EQ(1, + init_observer->GetEnumCounter(webrtc::kEnumCounterAudioSrtpCipher, + kDefaultSrtpCryptoSuite)); } // Test that DTLS 1.0 is used if the initator supports DTLS 1.2 and the // received supports 1.0. -TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12Init) { +TEST_F(P2PTestConductor, GetDtls12Init) { PeerConnectionFactory::Options init_options; init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12; PeerConnectionFactory::Options recv_options; @@ -1345,7 +1537,7 @@ initializing_client()->pc()->RegisterUMAObserver(init_observer); LocalP2PTest(); - EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::GetSslCipherSuiteName( + EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::SslCipherSuiteToName( rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_10, rtc::KT_DEFAULT)), initializing_client()->GetDtlsCipherStats(), @@ -1355,17 +1547,17 @@ rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_10, rtc::KT_DEFAULT))); - EXPECT_EQ_WAIT(kDefaultSrtpCipher, + EXPECT_EQ_WAIT(rtc::SrtpCryptoSuiteToName(kDefaultSrtpCryptoSuite), initializing_client()->GetSrtpCipherStats(), kMaxWaitForStatsMs); - EXPECT_EQ(1, init_observer->GetEnumCounter( - webrtc::kEnumCounterAudioSrtpCipher, - rtc::GetSrtpCryptoSuiteFromName(kDefaultSrtpCipher))); + EXPECT_EQ(1, + init_observer->GetEnumCounter(webrtc::kEnumCounterAudioSrtpCipher, + kDefaultSrtpCryptoSuite)); } // Test that DTLS 1.0 is used if the initator supports DTLS 1.0 and the // received supports 1.2. -TEST_F(JsepPeerConnectionP2PTestClient, GetDtls12Recv) { +TEST_F(P2PTestConductor, GetDtls12Recv) { PeerConnectionFactory::Options init_options; init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10; PeerConnectionFactory::Options recv_options; @@ -1377,7 +1569,7 @@ initializing_client()->pc()->RegisterUMAObserver(init_observer); LocalP2PTest(); - EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::GetSslCipherSuiteName( + EXPECT_EQ_WAIT(rtc::SSLStreamAdapter::SslCipherSuiteToName( rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_10, rtc::KT_DEFAULT)), initializing_client()->GetDtlsCipherStats(), @@ -1387,16 +1579,17 @@ rtc::SSLStreamAdapter::GetDefaultSslCipherForTest( rtc::SSL_PROTOCOL_DTLS_10, rtc::KT_DEFAULT))); - EXPECT_EQ_WAIT(kDefaultSrtpCipher, + EXPECT_EQ_WAIT(rtc::SrtpCryptoSuiteToName(kDefaultSrtpCryptoSuite), initializing_client()->GetSrtpCipherStats(), kMaxWaitForStatsMs); - EXPECT_EQ(1, init_observer->GetEnumCounter( - webrtc::kEnumCounterAudioSrtpCipher, - rtc::GetSrtpCryptoSuiteFromName(kDefaultSrtpCipher))); + EXPECT_EQ(1, + init_observer->GetEnumCounter(webrtc::kEnumCounterAudioSrtpCipher, + kDefaultSrtpCryptoSuite)); } -// This test sets up a call between two parties with audio, video and data. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) { +// This test sets up a call between two parties with audio, video and an RTP +// data channel. +TEST_F(P2PTestConductor, LocalP2PTestRtpDataChannel) { FakeConstraints setup_constraints; setup_constraints.SetAllowRtpDataChannels(); ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints)); @@ -1426,6 +1619,34 @@ EXPECT_FALSE(receiving_client()->data_observer()->IsOpen()); } +// This test sets up a call between two parties with audio, video and an SCTP +// data channel. +TEST_F(P2PTestConductor, LocalP2PTestSctpDataChannel) { + ASSERT_TRUE(CreateTestClients()); + initializing_client()->CreateDataChannel(); + LocalP2PTest(); + ASSERT_TRUE(initializing_client()->data_channel() != nullptr); + EXPECT_TRUE_WAIT(receiving_client()->data_channel() != nullptr, kMaxWaitMs); + EXPECT_TRUE_WAIT(initializing_client()->data_observer()->IsOpen(), + kMaxWaitMs); + EXPECT_TRUE_WAIT(receiving_client()->data_observer()->IsOpen(), kMaxWaitMs); + + std::string data = "hello world"; + + initializing_client()->data_channel()->Send(DataBuffer(data)); + EXPECT_EQ_WAIT(data, receiving_client()->data_observer()->last_message(), + kMaxWaitMs); + + receiving_client()->data_channel()->Send(DataBuffer(data)); + EXPECT_EQ_WAIT(data, initializing_client()->data_observer()->last_message(), + kMaxWaitMs); + + receiving_client()->data_channel()->Close(); + EXPECT_TRUE_WAIT(!initializing_client()->data_observer()->IsOpen(), + kMaxWaitMs); + EXPECT_TRUE_WAIT(!receiving_client()->data_observer()->IsOpen(), kMaxWaitMs); +} + // This test sets up a call between two parties and creates a data channel. // The test tests that received data is buffered unless an observer has been // registered. @@ -1433,7 +1654,7 @@ // transport has detected that a channel is writable and thus data can be // received before the data channel state changes to open. That is hard to test // but the same buffering is used in that case. -TEST_F(JsepPeerConnectionP2PTestClient, RegisterDataChannelObserver) { +TEST_F(P2PTestConductor, RegisterDataChannelObserver) { FakeConstraints setup_constraints; setup_constraints.SetAllowRtpDataChannels(); ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints)); @@ -1463,7 +1684,7 @@ // This test sets up a call between two parties with audio, video and but only // the initiating client support data. -TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestReceiverDoesntSupportData) { +TEST_F(P2PTestConductor, LocalP2PTestReceiverDoesntSupportData) { FakeConstraints setup_constraints_1; setup_constraints_1.SetAllowRtpDataChannels(); // Must disable DTLS to make negotiation succeed. @@ -1482,7 +1703,7 @@ // This test sets up a call between two parties with audio, video. When audio // and video is setup and flowing and data channel is negotiated. -TEST_F(JsepPeerConnectionP2PTestClient, AddDataChannelAfterRenegotiation) { +TEST_F(P2PTestConductor, AddDataChannelAfterRenegotiation) { FakeConstraints setup_constraints; setup_constraints.SetAllowRtpDataChannels(); ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints)); @@ -1501,7 +1722,7 @@ // This test sets up a Jsep call with SCTP DataChannel and verifies the // negotiation is completed without error. #ifdef HAVE_SCTP -TEST_F(JsepPeerConnectionP2PTestClient, CreateOfferWithSctpDataChannel) { +TEST_F(P2PTestConductor, CreateOfferWithSctpDataChannel) { MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); FakeConstraints constraints; constraints.SetMandatory( @@ -1515,7 +1736,7 @@ // This test sets up a call between two parties with audio, and video. // During the call, the initializing side restart ice and the test verifies that // new ice candidates are generated and audio and video still can flow. -TEST_F(JsepPeerConnectionP2PTestClient, IceRestart) { +TEST_F(P2PTestConductor, IceRestart) { ASSERT_TRUE(CreateTestClients()); // Negotiate and wait for ice completion and make sure audio and video plays. @@ -1562,17 +1783,69 @@ EXPECT_NE(receiver_candidate, receiver_candidate_restart); } +// This test sets up a call between two parties with audio, and video. +// It then renegotiates setting the video m-line to "port 0", then later +// renegotiates again, enabling video. +TEST_F(P2PTestConductor, LocalP2PTestVideoDisableEnable) { + ASSERT_TRUE(CreateTestClients()); + + // Do initial negotiation. Will result in video and audio sendonly m-lines. + receiving_client()->set_auto_add_stream(false); + initializing_client()->AddMediaStream(true, true); + initializing_client()->Negotiate(); + + // Negotiate again, disabling the video m-line (receiving client will + // set port to 0 due to mandatory "OfferToReceiveVideo: false" constraint). + receiving_client()->SetReceiveVideo(false); + initializing_client()->Negotiate(); + + // Enable video and do negotiation again, making sure video is received + // end-to-end. + receiving_client()->SetReceiveVideo(true); + receiving_client()->AddMediaStream(true, true); + LocalP2PTest(); +} + // This test sets up a Jsep call between two parties with external // VideoDecoderFactory. // TODO(holmer): Disabled due to sometimes crashing on buildbots. // See issue webrtc/2378. -TEST_F(JsepPeerConnectionP2PTestClient, - DISABLED_LocalP2PTestWithVideoDecoderFactory) { +TEST_F(P2PTestConductor, DISABLED_LocalP2PTestWithVideoDecoderFactory) { ASSERT_TRUE(CreateTestClients()); EnableVideoDecoderFactory(); LocalP2PTest(); } +// This tests that if we negotiate after calling CreateSender but before we +// have a track, then set a track later, frames from the newly-set track are +// received end-to-end. +TEST_F(P2PTestConductor, EarlyWarmupTest) { + ASSERT_TRUE(CreateTestClients()); + auto audio_sender = + initializing_client()->pc()->CreateSender("audio", "stream_id"); + auto video_sender = + initializing_client()->pc()->CreateSender("video", "stream_id"); + initializing_client()->Negotiate(); + // Wait for ICE connection to complete, without any tracks. + // Note that the receiving client WILL (in HandleIncomingOffer) create + // tracks, so it's only the initiator here that's doing early warmup. + ASSERT_TRUE_WAIT(SessionActive(), kMaxWaitForActivationMs); + VerifySessionDescriptions(); + EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionCompleted, + initializing_client()->ice_connection_state(), + kMaxWaitForFramesMs); + EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionConnected, + receiving_client()->ice_connection_state(), + kMaxWaitForFramesMs); + // Now set the tracks, and expect frames to immediately start flowing. + EXPECT_TRUE( + audio_sender->SetTrack(initializing_client()->CreateLocalAudioTrack(""))); + EXPECT_TRUE( + video_sender->SetTrack(initializing_client()->CreateLocalVideoTrack(""))); + EXPECT_TRUE_WAIT(FramesNotPending(kEndAudioFrameCount, kEndVideoFrameCount), + kMaxWaitForFramesMs); +} + class IceServerParsingTest : public testing::Test { public: // Convenience for parsing a single URL. @@ -1589,38 +1862,37 @@ server.username = username; server.password = password; servers.push_back(server); - return webrtc::ParseIceServers(servers, &stun_configurations_, - &turn_configurations_); + return webrtc::ParseIceServers(servers, &stun_servers_, &turn_servers_); } protected: - webrtc::StunConfigurations stun_configurations_; - webrtc::TurnConfigurations turn_configurations_; + cricket::ServerAddresses stun_servers_; + std::vector<cricket::RelayServerConfig> turn_servers_; }; // Make sure all STUN/TURN prefixes are parsed correctly. TEST_F(IceServerParsingTest, ParseStunPrefixes) { EXPECT_TRUE(ParseUrl("stun:hostname")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ(0U, turn_configurations_.size()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ(0U, turn_servers_.size()); + stun_servers_.clear(); EXPECT_TRUE(ParseUrl("stuns:hostname")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ(0U, turn_configurations_.size()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ(0U, turn_servers_.size()); + stun_servers_.clear(); EXPECT_TRUE(ParseUrl("turn:hostname")); - EXPECT_EQ(0U, stun_configurations_.size()); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_FALSE(turn_configurations_[0].secure); - turn_configurations_.clear(); + EXPECT_EQ(0U, stun_servers_.size()); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_FALSE(turn_servers_[0].ports[0].secure); + turn_servers_.clear(); EXPECT_TRUE(ParseUrl("turns:hostname")); - EXPECT_EQ(0U, stun_configurations_.size()); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_TRUE(turn_configurations_[0].secure); - turn_configurations_.clear(); + EXPECT_EQ(0U, stun_servers_.size()); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_TRUE(turn_servers_[0].ports[0].secure); + turn_servers_.clear(); // invalid prefixes EXPECT_FALSE(ParseUrl("stunn:hostname")); @@ -1632,67 +1904,69 @@ TEST_F(IceServerParsingTest, VerifyDefaults) { // TURNS defaults EXPECT_TRUE(ParseUrl("turns:hostname")); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_EQ(5349, turn_configurations_[0].server.port()); - EXPECT_EQ("tcp", turn_configurations_[0].transport_type); - turn_configurations_.clear(); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_EQ(5349, turn_servers_[0].ports[0].address.port()); + EXPECT_EQ(cricket::PROTO_TCP, turn_servers_[0].ports[0].proto); + turn_servers_.clear(); // TURN defaults EXPECT_TRUE(ParseUrl("turn:hostname")); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_EQ(3478, turn_configurations_[0].server.port()); - EXPECT_EQ("udp", turn_configurations_[0].transport_type); - turn_configurations_.clear(); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_EQ(3478, turn_servers_[0].ports[0].address.port()); + EXPECT_EQ(cricket::PROTO_UDP, turn_servers_[0].ports[0].proto); + turn_servers_.clear(); // STUN defaults EXPECT_TRUE(ParseUrl("stun:hostname")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ(3478, stun_configurations_[0].server.port()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ(3478, stun_servers_.begin()->port()); + stun_servers_.clear(); } // Check that the 6 combinations of IPv4/IPv6/hostname and with/without port // can be parsed correctly. TEST_F(IceServerParsingTest, ParseHostnameAndPort) { EXPECT_TRUE(ParseUrl("stun:1.2.3.4:1234")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ("1.2.3.4", stun_configurations_[0].server.hostname()); - EXPECT_EQ(1234, stun_configurations_[0].server.port()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ("1.2.3.4", stun_servers_.begin()->hostname()); + EXPECT_EQ(1234, stun_servers_.begin()->port()); + stun_servers_.clear(); EXPECT_TRUE(ParseUrl("stun:[1:2:3:4:5:6:7:8]:4321")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ("1:2:3:4:5:6:7:8", stun_configurations_[0].server.hostname()); - EXPECT_EQ(4321, stun_configurations_[0].server.port()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ("1:2:3:4:5:6:7:8", stun_servers_.begin()->hostname()); + EXPECT_EQ(4321, stun_servers_.begin()->port()); + stun_servers_.clear(); EXPECT_TRUE(ParseUrl("stun:hostname:9999")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ("hostname", stun_configurations_[0].server.hostname()); - EXPECT_EQ(9999, stun_configurations_[0].server.port()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ("hostname", stun_servers_.begin()->hostname()); + EXPECT_EQ(9999, stun_servers_.begin()->port()); + stun_servers_.clear(); EXPECT_TRUE(ParseUrl("stun:1.2.3.4")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ("1.2.3.4", stun_configurations_[0].server.hostname()); - EXPECT_EQ(3478, stun_configurations_[0].server.port()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ("1.2.3.4", stun_servers_.begin()->hostname()); + EXPECT_EQ(3478, stun_servers_.begin()->port()); + stun_servers_.clear(); EXPECT_TRUE(ParseUrl("stun:[1:2:3:4:5:6:7:8]")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ("1:2:3:4:5:6:7:8", stun_configurations_[0].server.hostname()); - EXPECT_EQ(3478, stun_configurations_[0].server.port()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ("1:2:3:4:5:6:7:8", stun_servers_.begin()->hostname()); + EXPECT_EQ(3478, stun_servers_.begin()->port()); + stun_servers_.clear(); EXPECT_TRUE(ParseUrl("stun:hostname")); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ("hostname", stun_configurations_[0].server.hostname()); - EXPECT_EQ(3478, stun_configurations_[0].server.port()); - stun_configurations_.clear(); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ("hostname", stun_servers_.begin()->hostname()); + EXPECT_EQ(3478, stun_servers_.begin()->port()); + stun_servers_.clear(); // Try some invalid hostname:port strings. EXPECT_FALSE(ParseUrl("stun:hostname:99a99")); EXPECT_FALSE(ParseUrl("stun:hostname:-1")); + EXPECT_FALSE(ParseUrl("stun:hostname:port:more")); + EXPECT_FALSE(ParseUrl("stun:hostname:port more")); EXPECT_FALSE(ParseUrl("stun:hostname:")); EXPECT_FALSE(ParseUrl("stun:[1:2:3:4:5:6:7:8]junk:1000")); EXPECT_FALSE(ParseUrl("stun::5555")); @@ -1702,14 +1976,14 @@ // Test parsing the "?transport=xxx" part of the URL. TEST_F(IceServerParsingTest, ParseTransport) { EXPECT_TRUE(ParseUrl("turn:hostname:1234?transport=tcp")); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_EQ("tcp", turn_configurations_[0].transport_type); - turn_configurations_.clear(); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_EQ(cricket::PROTO_TCP, turn_servers_[0].ports[0].proto); + turn_servers_.clear(); EXPECT_TRUE(ParseUrl("turn:hostname?transport=udp")); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_EQ("udp", turn_configurations_[0].transport_type); - turn_configurations_.clear(); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_EQ(cricket::PROTO_UDP, turn_servers_[0].ports[0].proto); + turn_servers_.clear(); EXPECT_FALSE(ParseUrl("turn:hostname?transport=invalid")); } @@ -1717,9 +1991,9 @@ // Test parsing ICE username contained in URL. TEST_F(IceServerParsingTest, ParseUsername) { EXPECT_TRUE(ParseUrl("turn:user@hostname")); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_EQ("user", turn_configurations_[0].username); - turn_configurations_.clear(); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_EQ("user", turn_servers_[0].credentials.username); + turn_servers_.clear(); EXPECT_FALSE(ParseUrl("turn:@hostname")); EXPECT_FALSE(ParseUrl("turn:username@")); @@ -1728,12 +2002,12 @@ } // Test that username and password from IceServer is copied into the resulting -// TurnConfiguration. +// RelayServerConfig. TEST_F(IceServerParsingTest, CopyUsernameAndPasswordFromIceServer) { EXPECT_TRUE(ParseUrl("turn:hostname", "username", "password")); - EXPECT_EQ(1U, turn_configurations_.size()); - EXPECT_EQ("username", turn_configurations_[0].username); - EXPECT_EQ("password", turn_configurations_[0].password); + EXPECT_EQ(1U, turn_servers_.size()); + EXPECT_EQ("username", turn_servers_[0].credentials.username); + EXPECT_EQ("password", turn_servers_[0].credentials.password); } // Ensure that if a server has multiple URLs, each one is parsed. @@ -1743,10 +2017,22 @@ server.urls.push_back("stun:hostname"); server.urls.push_back("turn:hostname"); servers.push_back(server); - EXPECT_TRUE(webrtc::ParseIceServers(servers, &stun_configurations_, - &turn_configurations_)); - EXPECT_EQ(1U, stun_configurations_.size()); - EXPECT_EQ(1U, turn_configurations_.size()); + EXPECT_TRUE(webrtc::ParseIceServers(servers, &stun_servers_, &turn_servers_)); + EXPECT_EQ(1U, stun_servers_.size()); + EXPECT_EQ(1U, turn_servers_.size()); +} + +// Ensure that TURN servers are given unique priorities, +// so that their resulting candidates have unique priorities. +TEST_F(IceServerParsingTest, TurnServerPrioritiesUnique) { + PeerConnectionInterface::IceServers servers; + PeerConnectionInterface::IceServer server; + server.urls.push_back("turn:hostname"); + server.urls.push_back("turn:hostname2"); + servers.push_back(server); + EXPECT_TRUE(webrtc::ParseIceServers(servers, &stun_servers_, &turn_servers_)); + EXPECT_EQ(2U, turn_servers_.size()); + EXPECT_NE(turn_servers_[0].priority, turn_servers_[1].priority); } #endif // if !defined(THREAD_SANITIZER)
diff --git a/talk/app/webrtc/peerconnectionendtoend_unittest.cc b/talk/app/webrtc/peerconnectionendtoend_unittest.cc index eacedd4..1a18031 100644 --- a/talk/app/webrtc/peerconnectionendtoend_unittest.cc +++ b/talk/app/webrtc/peerconnectionendtoend_unittest.cc
@@ -27,6 +27,9 @@ #include "talk/app/webrtc/test/peerconnectiontestwrapper.h" #include "talk/app/webrtc/test/mockpeerconnectionobservers.h" +#ifdef WEBRTC_ANDROID +#include "talk/app/webrtc/test/androidtestinitializer.h" +#endif #include "webrtc/base/gunit.h" #include "webrtc/base/logging.h" #include "webrtc/base/ssladapter.h" @@ -50,56 +53,6 @@ const size_t kMaxWait = 10000; -void RemoveLinesFromSdp(const std::string& line_start, - std::string* sdp) { - const char kSdpLineEnd[] = "\r\n"; - size_t ssrc_pos = 0; - while ((ssrc_pos = sdp->find(line_start, ssrc_pos)) != - std::string::npos) { - size_t end_ssrc = sdp->find(kSdpLineEnd, ssrc_pos); - sdp->erase(ssrc_pos, end_ssrc - ssrc_pos + strlen(kSdpLineEnd)); - } -} - -// Add |newlines| to the |message| after |line|. -void InjectAfter(const std::string& line, - const std::string& newlines, - std::string* message) { - const std::string tmp = line + newlines; - rtc::replace_substrs(line.c_str(), line.length(), - tmp.c_str(), tmp.length(), message); -} - -void Replace(const std::string& line, - const std::string& newlines, - std::string* message) { - rtc::replace_substrs(line.c_str(), line.length(), - newlines.c_str(), newlines.length(), message); -} - -void UseExternalSdes(std::string* sdp) { - // Remove current crypto specification. - RemoveLinesFromSdp("a=crypto", sdp); - RemoveLinesFromSdp("a=fingerprint", sdp); - // Add external crypto. - const char kAudioSdes[] = - "a=crypto:1 AES_CM_128_HMAC_SHA1_80 " - "inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR\r\n"; - const char kVideoSdes[] = - "a=crypto:1 AES_CM_128_HMAC_SHA1_80 " - "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj\r\n"; - const char kDataSdes[] = - "a=crypto:1 AES_CM_128_HMAC_SHA1_80 " - "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj\r\n"; - InjectAfter("a=mid:audio\r\n", kAudioSdes, sdp); - InjectAfter("a=mid:video\r\n", kVideoSdes, sdp); - InjectAfter("a=mid:data\r\n", kDataSdes, sdp); -} - -void RemoveBundle(std::string* sdp) { - RemoveLinesFromSdp("a=group:BUNDLE", sdp); -} - } // namespace class PeerConnectionEndToEndTest @@ -114,6 +67,9 @@ "caller")), callee_(new rtc::RefCountedObject<PeerConnectionTestWrapper>( "callee")) { +#ifdef WEBRTC_ANDROID + webrtc::InitializeAndroidObjects(); +#endif } void CreatePcs() { @@ -217,15 +173,20 @@ DataChannelList callee_signaled_data_channels_; }; +// Disabled for TSan v2, see +// https://bugs.chromium.org/p/webrtc/issues/detail?id=4719 for details. +// Disabled for Mac, see +// https://bugs.chromium.org/p/webrtc/issues/detail?id=5231 for details. +#if !defined(THREAD_SANITIZER) && !defined(WEBRTC_MAC) TEST_F(PeerConnectionEndToEndTest, Call) { CreatePcs(); GetAndAddUserMedia(); Negotiate(); WaitForCallEstablished(); } +#endif // if !defined(THREAD_SANITIZER) && !defined(WEBRTC_MAC) -// Disabled per b/14899892 -TEST_F(PeerConnectionEndToEndTest, DISABLED_CallWithLegacySdp) { +TEST_F(PeerConnectionEndToEndTest, CallWithLegacySdp) { FakeConstraints pc_constraints; pc_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, false); @@ -396,3 +357,30 @@ CloseDataChannels(caller_dc, callee_signaled_data_channels_, 1); } + +// This tests that if a data channel is closed remotely while not referenced +// by the application (meaning only the PeerConnection contributes to its +// reference count), no memory access violation will occur. +// See: https://code.google.com/p/chromium/issues/detail?id=565048 +TEST_F(PeerConnectionEndToEndTest, CloseDataChannelRemotelyWhileNotReferenced) { + MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); + + CreatePcs(); + + webrtc::DataChannelInit init; + rtc::scoped_refptr<DataChannelInterface> caller_dc( + caller_->CreateDataChannel("data", init)); + + Negotiate(); + WaitForConnection(); + + WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 0); + // This removes the reference to the remote data channel that we hold. + callee_signaled_data_channels_.clear(); + caller_dc->Close(); + EXPECT_EQ_WAIT(DataChannelInterface::kClosed, caller_dc->state(), kMaxWait); + + // Wait for a bit longer so the remote data channel will receive the + // close message and be destroyed. + rtc::Thread::Current()->ProcessMessages(100); +}
diff --git a/talk/app/webrtc/peerconnectionfactory.cc b/talk/app/webrtc/peerconnectionfactory.cc index b46b4b6..c58f88c 100644 --- a/talk/app/webrtc/peerconnectionfactory.cc +++ b/talk/app/webrtc/peerconnectionfactory.cc
@@ -27,6 +27,8 @@ #include "talk/app/webrtc/peerconnectionfactory.h" +#include <utility> + #include "talk/app/webrtc/audiotrack.h" #include "talk/app/webrtc/localaudiosource.h" #include "talk/app/webrtc/mediastream.h" @@ -35,7 +37,6 @@ #include "talk/app/webrtc/peerconnection.h" #include "talk/app/webrtc/peerconnectionfactoryproxy.h" #include "talk/app/webrtc/peerconnectionproxy.h" -#include "talk/app/webrtc/portallocatorfactory.h" #include "talk/app/webrtc/videosource.h" #include "talk/app/webrtc/videosourceproxy.h" #include "talk/app/webrtc/videotrack.h" @@ -44,6 +45,8 @@ #include "talk/media/webrtc/webrtcvideoencoderfactory.h" #include "webrtc/base/bind.h" #include "webrtc/modules/audio_device/include/audio_device.h" +#include "webrtc/p2p/base/basicpacketsocketfactory.h" +#include "webrtc/p2p/client/basicportallocator.h" namespace webrtc { @@ -153,11 +156,13 @@ PeerConnectionFactory::~PeerConnectionFactory() { RTC_DCHECK(signaling_thread_->IsCurrent()); channel_manager_.reset(nullptr); - default_allocator_factory_ = nullptr; // Make sure |worker_thread_| and |signaling_thread_| outlive - // |dtls_identity_store_|. + // |dtls_identity_store_|, |default_socket_factory_| and + // |default_network_manager_|. dtls_identity_store_ = nullptr; + default_socket_factory_ = nullptr; + default_network_manager_ = nullptr; if (owns_ptrs_) { if (wraps_current_thread_) @@ -170,9 +175,16 @@ RTC_DCHECK(signaling_thread_->IsCurrent()); rtc::InitRandom(rtc::Time()); - default_allocator_factory_ = PortAllocatorFactory::Create(worker_thread_); - if (!default_allocator_factory_) + default_network_manager_.reset(new rtc::BasicNetworkManager()); + if (!default_network_manager_) { return false; + } + + default_socket_factory_.reset( + new rtc::BasicPacketSocketFactory(worker_thread_)); + if (!default_socket_factory_) { + return false; + } // TODO: Need to make sure only one VoE is created inside // WebRtcMediaEngine. @@ -208,8 +220,8 @@ cricket::VideoCapturer* capturer, const MediaConstraintsInterface* constraints) { RTC_DCHECK(signaling_thread_->IsCurrent()); - rtc::scoped_refptr<VideoSource> source( - VideoSource::Create(channel_manager_.get(), capturer, constraints)); + rtc::scoped_refptr<VideoSource> source(VideoSource::Create( + channel_manager_.get(), capturer, constraints, false)); return VideoSourceProxy::Create(signaling_thread_, source); } @@ -237,11 +249,10 @@ PeerConnectionFactory::CreatePeerConnection( const PeerConnectionInterface::RTCConfiguration& configuration, const MediaConstraintsInterface* constraints, - PortAllocatorFactoryInterface* allocator_factory, + rtc::scoped_ptr<cricket::PortAllocator> allocator, rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, PeerConnectionObserver* observer) { RTC_DCHECK(signaling_thread_->IsCurrent()); - RTC_DCHECK(allocator_factory || default_allocator_factory_); if (!dtls_identity_store.get()) { // Because |pc|->Initialize takes ownership of the store we need a new @@ -251,19 +262,17 @@ new DtlsIdentityStoreWrapper(dtls_identity_store_)); } - PortAllocatorFactoryInterface* chosen_allocator_factory = - allocator_factory ? allocator_factory : default_allocator_factory_.get(); - chosen_allocator_factory->SetNetworkIgnoreMask(options_.network_ignore_mask); + if (!allocator) { + allocator.reset(new cricket::BasicPortAllocator( + default_network_manager_.get(), default_socket_factory_.get())); + } + allocator->SetNetworkIgnoreMask(options_.network_ignore_mask); rtc::scoped_refptr<PeerConnection> pc( new rtc::RefCountedObject<PeerConnection>(this)); - if (!pc->Initialize( - configuration, - constraints, - chosen_allocator_factory, - dtls_identity_store.Pass(), - observer)) { - return NULL; + if (!pc->Initialize(configuration, constraints, std::move(allocator), + std::move(dtls_identity_store), observer)) { + return nullptr; } return PeerConnectionProxy::Create(signaling_thread(), pc); } @@ -289,8 +298,7 @@ PeerConnectionFactory::CreateAudioTrack(const std::string& id, AudioSourceInterface* source) { RTC_DCHECK(signaling_thread_->IsCurrent()); - rtc::scoped_refptr<AudioTrackInterface> track( - AudioTrack::Create(id, source)); + rtc::scoped_refptr<AudioTrackInterface> track(AudioTrack::Create(id, source)); return AudioTrackProxy::Create(signaling_thread_, track); }
diff --git a/talk/app/webrtc/peerconnectionfactory.h b/talk/app/webrtc/peerconnectionfactory.h index af4117a..8b274e1 100644 --- a/talk/app/webrtc/peerconnectionfactory.h +++ b/talk/app/webrtc/peerconnectionfactory.h
@@ -39,6 +39,11 @@ #include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/base/thread.h" +namespace rtc { +class BasicNetworkManager; +class BasicPacketSocketFactory; +} + namespace webrtc { typedef rtc::RefCountedObject<DtlsIdentityStoreImpl> @@ -50,14 +55,12 @@ options_ = options; } - // webrtc::PeerConnectionFactoryInterface override; - rtc::scoped_refptr<PeerConnectionInterface> - CreatePeerConnection( - const PeerConnectionInterface::RTCConfiguration& configuration, - const MediaConstraintsInterface* constraints, - PortAllocatorFactoryInterface* allocator_factory, - rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, - PeerConnectionObserver* observer) override; + rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration& configuration, + const MediaConstraintsInterface* constraints, + rtc::scoped_ptr<cricket::PortAllocator> allocator, + rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, + PeerConnectionObserver* observer) override; bool Initialize(); @@ -107,7 +110,6 @@ rtc::Thread* signaling_thread_; rtc::Thread* worker_thread_; Options options_; - rtc::scoped_refptr<PortAllocatorFactoryInterface> default_allocator_factory_; // External Audio device used for audio playback. rtc::scoped_refptr<AudioDeviceModule> default_adm_; rtc::scoped_ptr<cricket::ChannelManager> channel_manager_; @@ -119,6 +121,8 @@ // injected any. In that case, video engine will use the internal SW decoder. rtc::scoped_ptr<cricket::WebRtcVideoDecoderFactory> video_decoder_factory_; + rtc::scoped_ptr<rtc::BasicNetworkManager> default_network_manager_; + rtc::scoped_ptr<rtc::BasicPacketSocketFactory> default_socket_factory_; rtc::scoped_refptr<RefCountedDtlsIdentityStore> dtls_identity_store_; };
diff --git a/talk/app/webrtc/peerconnectionfactory_unittest.cc b/talk/app/webrtc/peerconnectionfactory_unittest.cc index f1d5353..9fb013b 100644 --- a/talk/app/webrtc/peerconnectionfactory_unittest.cc +++ b/talk/app/webrtc/peerconnectionfactory_unittest.cc
@@ -26,10 +26,13 @@ */ #include <string> +#include <utility> -#include "talk/app/webrtc/fakeportallocatorfactory.h" #include "talk/app/webrtc/mediastreaminterface.h" #include "talk/app/webrtc/peerconnectionfactory.h" +#ifdef WEBRTC_ANDROID +#include "talk/app/webrtc/test/androidtestinitializer.h" +#endif #include "talk/app/webrtc/test/fakedtlsidentitystore.h" #include "talk/app/webrtc/test/fakevideotrackrenderer.h" #include "talk/app/webrtc/videosourceinterface.h" @@ -39,6 +42,7 @@ #include "webrtc/base/gunit.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/thread.h" +#include "webrtc/p2p/client/fakeportallocator.h" using webrtc::DataChannelInterface; using webrtc::DtlsIdentityStoreInterface; @@ -47,17 +51,11 @@ using webrtc::PeerConnectionFactoryInterface; using webrtc::PeerConnectionInterface; using webrtc::PeerConnectionObserver; -using webrtc::PortAllocatorFactoryInterface; using webrtc::VideoSourceInterface; using webrtc::VideoTrackInterface; namespace { -typedef std::vector<PortAllocatorFactoryInterface::StunConfiguration> - StunConfigurations; -typedef std::vector<PortAllocatorFactoryInterface::TurnConfiguration> - TurnConfigurations; - static const char kStunIceServer[] = "stun:stun.l.google.com:19302"; static const char kTurnIceServer[] = "turn:test%40hello.com@test.com:1234"; static const char kTurnIceServerWithTransport[] = @@ -103,6 +101,9 @@ class PeerConnectionFactoryTest : public testing::Test { void SetUp() { +#ifdef WEBRTC_ANDROID + webrtc::InitializeAndroidObjects(); +#endif factory_ = webrtc::CreatePeerConnectionFactory(rtc::Thread::Current(), rtc::Thread::Current(), NULL, @@ -110,57 +111,58 @@ NULL); ASSERT_TRUE(factory_.get() != NULL); - allocator_factory_ = webrtc::FakePortAllocatorFactory::Create(); + port_allocator_.reset( + new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr)); + raw_port_allocator_ = port_allocator_.get(); } protected: - void VerifyStunConfigurations(StunConfigurations stun_config) { - webrtc::FakePortAllocatorFactory* allocator = - static_cast<webrtc::FakePortAllocatorFactory*>( - allocator_factory_.get()); - ASSERT_TRUE(allocator != NULL); - EXPECT_EQ(stun_config.size(), allocator->stun_configs().size()); - for (size_t i = 0; i < stun_config.size(); ++i) { - EXPECT_EQ(stun_config[i].server.ToString(), - allocator->stun_configs()[i].server.ToString()); - } + void VerifyStunServers(cricket::ServerAddresses stun_servers) { + EXPECT_EQ(stun_servers, raw_port_allocator_->stun_servers()); } - void VerifyTurnConfigurations(TurnConfigurations turn_config) { - webrtc::FakePortAllocatorFactory* allocator = - static_cast<webrtc::FakePortAllocatorFactory*>( - allocator_factory_.get()); - ASSERT_TRUE(allocator != NULL); - EXPECT_EQ(turn_config.size(), allocator->turn_configs().size()); - for (size_t i = 0; i < turn_config.size(); ++i) { - EXPECT_EQ(turn_config[i].server.ToString(), - allocator->turn_configs()[i].server.ToString()); - EXPECT_EQ(turn_config[i].username, allocator->turn_configs()[i].username); - EXPECT_EQ(turn_config[i].password, allocator->turn_configs()[i].password); - EXPECT_EQ(turn_config[i].transport_type, - allocator->turn_configs()[i].transport_type); + void VerifyTurnServers(std::vector<cricket::RelayServerConfig> turn_servers) { + EXPECT_EQ(turn_servers.size(), raw_port_allocator_->turn_servers().size()); + for (size_t i = 0; i < turn_servers.size(); ++i) { + ASSERT_EQ(1u, turn_servers[i].ports.size()); + EXPECT_EQ(1u, raw_port_allocator_->turn_servers()[i].ports.size()); + EXPECT_EQ( + turn_servers[i].ports[0].address.ToString(), + raw_port_allocator_->turn_servers()[i].ports[0].address.ToString()); + EXPECT_EQ(turn_servers[i].ports[0].proto, + raw_port_allocator_->turn_servers()[i].ports[0].proto); + EXPECT_EQ(turn_servers[i].credentials.username, + raw_port_allocator_->turn_servers()[i].credentials.username); + EXPECT_EQ(turn_servers[i].credentials.password, + raw_port_allocator_->turn_servers()[i].credentials.password); } } rtc::scoped_refptr<PeerConnectionFactoryInterface> factory_; NullPeerConnectionObserver observer_; - rtc::scoped_refptr<PortAllocatorFactoryInterface> allocator_factory_; + rtc::scoped_ptr<cricket::FakePortAllocator> port_allocator_; + // Since the PC owns the port allocator after it's been initialized, + // this should only be used when known to be safe. + cricket::FakePortAllocator* raw_port_allocator_; }; // Verify creation of PeerConnection using internal ADM, video factory and // internal libjingle threads. TEST(PeerConnectionFactoryTestInternal, CreatePCUsingInternalModules) { +#ifdef WEBRTC_ANDROID + webrtc::InitializeAndroidObjects(); +#endif + rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( webrtc::CreatePeerConnectionFactory()); NullPeerConnectionObserver observer; - webrtc::PeerConnectionInterface::IceServers servers; + webrtc::PeerConnectionInterface::RTCConfiguration config; rtc::scoped_ptr<FakeDtlsIdentityStore> dtls_identity_store( new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory->CreatePeerConnection( - servers, nullptr, nullptr, dtls_identity_store.Pass(), &observer)); + rtc::scoped_refptr<PeerConnectionInterface> pc(factory->CreatePeerConnection( + config, nullptr, nullptr, std::move(dtls_identity_store), &observer)); EXPECT_TRUE(pc.get() != nullptr); } @@ -180,25 +182,22 @@ config.servers.push_back(ice_server); rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store( new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory_->CreatePeerConnection(config, nullptr, - allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_)); - EXPECT_TRUE(pc.get() != NULL); - StunConfigurations stun_configs; - webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( - "stun.l.google.com", 19302); - stun_configs.push_back(stun1); - VerifyStunConfigurations(stun_configs); - TurnConfigurations turn_configs; - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( - "test.com", 1234, "test@hello.com", kTurnPassword, "udp", false); - turn_configs.push_back(turn1); - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( - "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); - turn_configs.push_back(turn2); - VerifyTurnConfigurations(turn_configs); + rtc::scoped_refptr<PeerConnectionInterface> pc(factory_->CreatePeerConnection( + config, nullptr, std::move(port_allocator_), + std::move(dtls_identity_store), &observer_)); + ASSERT_TRUE(pc.get() != NULL); + cricket::ServerAddresses stun_servers; + rtc::SocketAddress stun1("stun.l.google.com", 19302); + stun_servers.insert(stun1); + VerifyStunServers(stun_servers); + std::vector<cricket::RelayServerConfig> turn_servers; + cricket::RelayServerConfig turn1("test.com", 1234, "test@hello.com", + kTurnPassword, cricket::PROTO_UDP, false); + turn_servers.push_back(turn1); + cricket::RelayServerConfig turn2("hello.com", kDefaultStunPort, "test", + kTurnPassword, cricket::PROTO_TCP, false); + turn_servers.push_back(turn2); + VerifyTurnServers(turn_servers); } // This test verifies creation of PeerConnection with valid STUN and TURN @@ -213,63 +212,22 @@ config.servers.push_back(ice_server); rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store( new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory_->CreatePeerConnection(config, nullptr, - allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_)); - EXPECT_TRUE(pc.get() != NULL); - StunConfigurations stun_configs; - webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( - "stun.l.google.com", 19302); - stun_configs.push_back(stun1); - VerifyStunConfigurations(stun_configs); - TurnConfigurations turn_configs; - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( - "test.com", 1234, "test@hello.com", kTurnPassword, "udp", false); - turn_configs.push_back(turn1); - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( - "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); - turn_configs.push_back(turn2); - VerifyTurnConfigurations(turn_configs); -} - -// This test verifies creation of PeerConnection with valid STUN and TURN -// configuration. Also verifies the URL's parsed correctly as expected. -// This version doesn't use RTCConfiguration. -// TODO(mallinath) - Remove this method after clients start using RTCConfig. -TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServersOldSignature) { - webrtc::PeerConnectionInterface::IceServers ice_servers; - webrtc::PeerConnectionInterface::IceServer ice_server; - ice_server.uri = kStunIceServer; - ice_servers.push_back(ice_server); - ice_server.uri = kTurnIceServer; - ice_server.password = kTurnPassword; - ice_servers.push_back(ice_server); - ice_server.uri = kTurnIceServerWithTransport; - ice_server.password = kTurnPassword; - ice_servers.push_back(ice_server); - rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store( - new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory_->CreatePeerConnection(ice_servers, nullptr, - allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_)); - EXPECT_TRUE(pc.get() != NULL); - StunConfigurations stun_configs; - webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( - "stun.l.google.com", 19302); - stun_configs.push_back(stun1); - VerifyStunConfigurations(stun_configs); - TurnConfigurations turn_configs; - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( - "test.com", 1234, "test@hello.com", kTurnPassword, "udp", false); - turn_configs.push_back(turn1); - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( - "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); - turn_configs.push_back(turn2); - VerifyTurnConfigurations(turn_configs); + rtc::scoped_refptr<PeerConnectionInterface> pc(factory_->CreatePeerConnection( + config, nullptr, std::move(port_allocator_), + std::move(dtls_identity_store), &observer_)); + ASSERT_TRUE(pc.get() != NULL); + cricket::ServerAddresses stun_servers; + rtc::SocketAddress stun1("stun.l.google.com", 19302); + stun_servers.insert(stun1); + VerifyStunServers(stun_servers); + std::vector<cricket::RelayServerConfig> turn_servers; + cricket::RelayServerConfig turn1("test.com", 1234, "test@hello.com", + kTurnPassword, cricket::PROTO_UDP, false); + turn_servers.push_back(turn1); + cricket::RelayServerConfig turn2("hello.com", kDefaultStunPort, "test", + kTurnPassword, cricket::PROTO_TCP, false); + turn_servers.push_back(turn2); + VerifyTurnServers(turn_servers); } TEST_F(PeerConnectionFactoryTest, CreatePCUsingNoUsernameInUri) { @@ -283,17 +241,15 @@ config.servers.push_back(ice_server); rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store( new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory_->CreatePeerConnection(config, nullptr, - allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_)); - EXPECT_TRUE(pc.get() != NULL); - TurnConfigurations turn_configs; - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn( - "test.com", 1234, kTurnUsername, kTurnPassword, "udp", false); - turn_configs.push_back(turn); - VerifyTurnConfigurations(turn_configs); + rtc::scoped_refptr<PeerConnectionInterface> pc(factory_->CreatePeerConnection( + config, nullptr, std::move(port_allocator_), + std::move(dtls_identity_store), &observer_)); + ASSERT_TRUE(pc.get() != NULL); + std::vector<cricket::RelayServerConfig> turn_servers; + cricket::RelayServerConfig turn("test.com", 1234, kTurnUsername, + kTurnPassword, cricket::PROTO_UDP, false); + turn_servers.push_back(turn); + VerifyTurnServers(turn_servers); } // This test verifies the PeerConnection created properly with TURN url which @@ -306,17 +262,15 @@ config.servers.push_back(ice_server); rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store( new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory_->CreatePeerConnection(config, nullptr, - allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_)); - EXPECT_TRUE(pc.get() != NULL); - TurnConfigurations turn_configs; - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn( - "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false); - turn_configs.push_back(turn); - VerifyTurnConfigurations(turn_configs); + rtc::scoped_refptr<PeerConnectionInterface> pc(factory_->CreatePeerConnection( + config, nullptr, std::move(port_allocator_), + std::move(dtls_identity_store), &observer_)); + ASSERT_TRUE(pc.get() != NULL); + std::vector<cricket::RelayServerConfig> turn_servers; + cricket::RelayServerConfig turn("hello.com", kDefaultStunPort, "test", + kTurnPassword, cricket::PROTO_TCP, false); + turn_servers.push_back(turn); + VerifyTurnServers(turn_servers); } TEST_F(PeerConnectionFactoryTest, CreatePCUsingSecureTurnUrl) { @@ -333,25 +287,23 @@ config.servers.push_back(ice_server); rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store( new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory_->CreatePeerConnection(config, nullptr, - allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_)); - EXPECT_TRUE(pc.get() != NULL); - TurnConfigurations turn_configs; - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( - "hello.com", kDefaultStunTlsPort, "test", kTurnPassword, "tcp", true); - turn_configs.push_back(turn1); + rtc::scoped_refptr<PeerConnectionInterface> pc(factory_->CreatePeerConnection( + config, nullptr, std::move(port_allocator_), + std::move(dtls_identity_store), &observer_)); + ASSERT_TRUE(pc.get() != NULL); + std::vector<cricket::RelayServerConfig> turn_servers; + cricket::RelayServerConfig turn1("hello.com", kDefaultStunTlsPort, "test", + kTurnPassword, cricket::PROTO_TCP, true); + turn_servers.push_back(turn1); // TURNS with transport param should be default to tcp. - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2( - "hello.com", 443, "test_no_transport", kTurnPassword, "tcp", true); - turn_configs.push_back(turn2); - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn3( - "hello.com", kDefaultStunTlsPort, "test_no_transport", - kTurnPassword, "tcp", true); - turn_configs.push_back(turn3); - VerifyTurnConfigurations(turn_configs); + cricket::RelayServerConfig turn2("hello.com", 443, "test_no_transport", + kTurnPassword, cricket::PROTO_TCP, true); + turn_servers.push_back(turn2); + cricket::RelayServerConfig turn3("hello.com", kDefaultStunTlsPort, + "test_no_transport", kTurnPassword, + cricket::PROTO_TCP, true); + turn_servers.push_back(turn3); + VerifyTurnServers(turn_servers); } TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) { @@ -370,32 +322,26 @@ config.servers.push_back(ice_server); rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store( new FakeDtlsIdentityStore()); - rtc::scoped_refptr<PeerConnectionInterface> pc( - factory_->CreatePeerConnection(config, nullptr, - allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_)); - EXPECT_TRUE(pc.get() != NULL); - StunConfigurations stun_configs; - webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1( - "1.2.3.4", 1234); - stun_configs.push_back(stun1); - webrtc::PortAllocatorFactoryInterface::StunConfiguration stun2( - "1.2.3.4", 3478); - stun_configs.push_back(stun2); // Default port - webrtc::PortAllocatorFactoryInterface::StunConfiguration stun3( - "2401:fa00:4::", 1234); - stun_configs.push_back(stun3); - webrtc::PortAllocatorFactoryInterface::StunConfiguration stun4( - "2401:fa00:4::", 3478); - stun_configs.push_back(stun4); // Default port - VerifyStunConfigurations(stun_configs); + rtc::scoped_refptr<PeerConnectionInterface> pc(factory_->CreatePeerConnection( + config, nullptr, std::move(port_allocator_), + std::move(dtls_identity_store), &observer_)); + ASSERT_TRUE(pc.get() != NULL); + cricket::ServerAddresses stun_servers; + rtc::SocketAddress stun1("1.2.3.4", 1234); + stun_servers.insert(stun1); + rtc::SocketAddress stun2("1.2.3.4", 3478); + stun_servers.insert(stun2); // Default port + rtc::SocketAddress stun3("2401:fa00:4::", 1234); + stun_servers.insert(stun3); + rtc::SocketAddress stun4("2401:fa00:4::", 3478); + stun_servers.insert(stun4); // Default port + VerifyStunServers(stun_servers); - TurnConfigurations turn_configs; - webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1( - "2401:fa00:4::", 1234, "test", kTurnPassword, "udp", false); - turn_configs.push_back(turn1); - VerifyTurnConfigurations(turn_configs); + std::vector<cricket::RelayServerConfig> turn_servers; + cricket::RelayServerConfig turn1("2401:fa00:4::", 1234, "test", kTurnPassword, + cricket::PROTO_UDP, false); + turn_servers.push_back(turn1); + VerifyTurnServers(turn_servers); } // This test verifies the captured stream is rendered locally using a
diff --git a/talk/app/webrtc/peerconnectionfactoryproxy.h b/talk/app/webrtc/peerconnectionfactoryproxy.h index 5e924df..714ce6b 100644 --- a/talk/app/webrtc/peerconnectionfactoryproxy.h +++ b/talk/app/webrtc/peerconnectionfactoryproxy.h
@@ -29,6 +29,7 @@ #define TALK_APP_WEBRTC_PEERCONNECTIONFACTORYPROXY_H_ #include <string> +#include <utility> #include "talk/app/webrtc/peerconnectioninterface.h" #include "talk/app/webrtc/proxy.h" @@ -38,17 +39,17 @@ BEGIN_PROXY_MAP(PeerConnectionFactory) PROXY_METHOD1(void, SetOptions, const Options&) - // Can't use PROXY_METHOD5 because scoped_ptr must be Pass()ed. + // Can't use PROXY_METHOD5 because scoped_ptr must be moved. // TODO(tommi,hbos): Use of templates to support scoped_ptr? rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection( const PeerConnectionInterface::RTCConfiguration& a1, const MediaConstraintsInterface* a2, - PortAllocatorFactoryInterface* a3, + rtc::scoped_ptr<cricket::PortAllocator> a3, rtc::scoped_ptr<DtlsIdentityStoreInterface> a4, PeerConnectionObserver* a5) override { return owner_thread_->Invoke<rtc::scoped_refptr<PeerConnectionInterface>>( rtc::Bind(&PeerConnectionFactoryProxy::CreatePeerConnection_ot, this, - a1, a2, a3, a4.release(), a5)); + a1, a2, a3.release(), a4.release(), a5)); } PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>, CreateLocalMediaStream, const std::string&) @@ -70,11 +71,13 @@ rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection_ot( const PeerConnectionInterface::RTCConfiguration& a1, const MediaConstraintsInterface* a2, - PortAllocatorFactoryInterface* a3, + cricket::PortAllocator* a3, DtlsIdentityStoreInterface* a4, PeerConnectionObserver* a5) { + rtc::scoped_ptr<cricket::PortAllocator> ptr_a3(a3); rtc::scoped_ptr<DtlsIdentityStoreInterface> ptr_a4(a4); - return c_->CreatePeerConnection(a1, a2, a3, ptr_a4.Pass(), a5); + return c_->CreatePeerConnection(a1, a2, std::move(ptr_a3), + std::move(ptr_a4), a5); } END_PROXY()
diff --git a/talk/app/webrtc/peerconnectioninterface.h b/talk/app/webrtc/peerconnectioninterface.h index 77caa9d..b9afbad 100644 --- a/talk/app/webrtc/peerconnectioninterface.h +++ b/talk/app/webrtc/peerconnectioninterface.h
@@ -69,6 +69,7 @@ #define TALK_APP_WEBRTC_PEERCONNECTIONINTERFACE_H_ #include <string> +#include <utility> #include <vector> #include "talk/app/webrtc/datachannelinterface.h" @@ -86,6 +87,7 @@ #include "webrtc/base/rtccertificate.h" #include "webrtc/base/sslstreamadapter.h" #include "webrtc/base/socketaddress.h" +#include "webrtc/p2p/base/portallocator.h" namespace rtc { class SSLIdentity; @@ -93,7 +95,6 @@ } namespace cricket { -class PortAllocator; class WebRtcVideoDecoderFactory; class WebRtcVideoEncoderFactory; } @@ -248,28 +249,27 @@ // TODO(pthatcher): Rename this ice_servers, but update Chromium // at the same time. IceServers servers; - // A localhost candidate is signaled whenever a candidate with the any - // address is allocated. - bool enable_localhost_ice_candidate; BundlePolicy bundle_policy; RtcpMuxPolicy rtcp_mux_policy; TcpCandidatePolicy tcp_candidate_policy; int audio_jitter_buffer_max_packets; bool audio_jitter_buffer_fast_accelerate; - int ice_connection_receiving_timeout; + int ice_connection_receiving_timeout; // ms + int ice_backup_candidate_pair_ping_interval; // ms ContinualGatheringPolicy continual_gathering_policy; std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates; - + bool disable_prerenderer_smoothing; RTCConfiguration() : type(kAll), - enable_localhost_ice_candidate(false), bundle_policy(kBundlePolicyBalanced), rtcp_mux_policy(kRtcpMuxPolicyNegotiate), tcp_candidate_policy(kTcpCandidatePolicyEnabled), audio_jitter_buffer_max_packets(kAudioJitterBufferMaxPackets), audio_jitter_buffer_fast_accelerate(false), ice_connection_receiving_timeout(kUndefined), - continual_gathering_policy(GATHER_ONCE) {} + ice_backup_candidate_pair_ping_interval(kUndefined), + continual_gathering_policy(GATHER_ONCE), + disable_prerenderer_smoothing(false) {} }; struct RTCOfferAnswerOptions { @@ -337,6 +337,15 @@ AudioTrackInterface* track) = 0; // TODO(deadbeef): Make these pure virtual once all subclasses implement them. + // |kind| must be "audio" or "video". + // |stream_id| is used to populate the msid attribute; if empty, one will + // be generated automatically. + virtual rtc::scoped_refptr<RtpSenderInterface> CreateSender( + const std::string& kind, + const std::string& stream_id) { + return rtc::scoped_refptr<RtpSenderInterface>(); + } + virtual std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders() const { return std::vector<rtc::scoped_refptr<RtpSenderInterface>>(); @@ -480,51 +489,6 @@ ~PeerConnectionObserver() {} }; -// Factory class used for creating cricket::PortAllocator that is used -// for ICE negotiation. -class PortAllocatorFactoryInterface : public rtc::RefCountInterface { - public: - struct StunConfiguration { - StunConfiguration(const std::string& address, int port) - : server(address, port) {} - // STUN server address and port. - rtc::SocketAddress server; - }; - - struct TurnConfiguration { - TurnConfiguration(const std::string& address, - int port, - const std::string& username, - const std::string& password, - const std::string& transport_type, - bool secure) - : server(address, port), - username(username), - password(password), - transport_type(transport_type), - secure(secure) {} - rtc::SocketAddress server; - std::string username; - std::string password; - std::string transport_type; - bool secure; - }; - - virtual cricket::PortAllocator* CreatePortAllocator( - const std::vector<StunConfiguration>& stun_servers, - const std::vector<TurnConfiguration>& turn_configurations) = 0; - - // TODO(phoglund): Make pure virtual when Chrome's factory implements this. - // After this method is called, the port allocator should consider loopback - // network interfaces as well. - virtual void SetNetworkIgnoreMask(int network_ignore_mask) { - } - - protected: - PortAllocatorFactoryInterface() {} - ~PortAllocatorFactoryInterface() {} -}; - // PeerConnectionFactoryInterface is the factory interface use for creating // PeerConnection, MediaStream and media tracks. // PeerConnectionFactoryInterface will create required libjingle threads, @@ -532,19 +496,18 @@ // If an application decides to provide its own threads and network // implementation of these classes it should use the alternate // CreatePeerConnectionFactory method which accepts threads as input and use the -// CreatePeerConnection version that takes a PortAllocatorFactoryInterface as +// CreatePeerConnection version that takes a PortAllocator as an // argument. class PeerConnectionFactoryInterface : public rtc::RefCountInterface { public: class Options { public: - Options() : - disable_encryption(false), - disable_sctp_data_channels(false), - disable_network_monitor(false), - network_ignore_mask(rtc::kDefaultNetworkIgnoreMask), - ssl_max_version(rtc::SSL_PROTOCOL_DTLS_10) { - } + Options() + : disable_encryption(false), + disable_sctp_data_channels(false), + disable_network_monitor(false), + network_ignore_mask(rtc::kDefaultNetworkIgnoreMask), + ssl_max_version(rtc::SSL_PROTOCOL_DTLS_12) {} bool disable_encryption; bool disable_sctp_data_channels; bool disable_network_monitor; @@ -562,31 +525,12 @@ virtual void SetOptions(const Options& options) = 0; - virtual rtc::scoped_refptr<PeerConnectionInterface> - CreatePeerConnection( - const PeerConnectionInterface::RTCConfiguration& configuration, - const MediaConstraintsInterface* constraints, - PortAllocatorFactoryInterface* allocator_factory, - rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, - PeerConnectionObserver* observer) = 0; - - // TODO(hbos): Remove below version after clients are updated to above method. - // In latest W3C WebRTC draft, PC constructor will take RTCConfiguration, - // and not IceServers. RTCConfiguration is made up of ice servers and - // ice transport type. - // http://dev.w3.org/2011/webrtc/editor/webrtc.html - inline rtc::scoped_refptr<PeerConnectionInterface> - CreatePeerConnection( - const PeerConnectionInterface::IceServers& servers, - const MediaConstraintsInterface* constraints, - PortAllocatorFactoryInterface* allocator_factory, - rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, - PeerConnectionObserver* observer) { - PeerConnectionInterface::RTCConfiguration rtc_config; - rtc_config.servers = servers; - return CreatePeerConnection(rtc_config, constraints, allocator_factory, - dtls_identity_store.Pass(), observer); - } + virtual rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration& configuration, + const MediaConstraintsInterface* constraints, + rtc::scoped_ptr<cricket::PortAllocator> allocator, + rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, + PeerConnectionObserver* observer) = 0; virtual rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream(const std::string& label) = 0;
diff --git a/talk/app/webrtc/peerconnectioninterface_unittest.cc b/talk/app/webrtc/peerconnectioninterface_unittest.cc index 63163fd..c3789b7 100644 --- a/talk/app/webrtc/peerconnectioninterface_unittest.cc +++ b/talk/app/webrtc/peerconnectioninterface_unittest.cc
@@ -26,9 +26,9 @@ */ #include <string> +#include <utility> #include "talk/app/webrtc/audiotrack.h" -#include "talk/app/webrtc/fakeportallocatorfactory.h" #include "talk/app/webrtc/jsepsessiondescription.h" #include "talk/app/webrtc/mediastream.h" #include "talk/app/webrtc/mediastreaminterface.h" @@ -37,6 +37,9 @@ #include "talk/app/webrtc/rtpreceiverinterface.h" #include "talk/app/webrtc/rtpsenderinterface.h" #include "talk/app/webrtc/streamcollection.h" +#ifdef WEBRTC_ANDROID +#include "talk/app/webrtc/test/androidtestinitializer.h" +#endif #include "talk/app/webrtc/test/fakeconstraints.h" #include "talk/app/webrtc/test/fakedtlsidentitystore.h" #include "talk/app/webrtc/test/mockpeerconnectionobservers.h" @@ -52,6 +55,7 @@ #include "webrtc/base/sslstreamadapter.h" #include "webrtc/base/stringutils.h" #include "webrtc/base/thread.h" +#include "webrtc/p2p/client/fakeportallocator.h" static const char kStreamLabel1[] = "local_stream_1"; static const char kStreamLabel2[] = "local_stream_2"; @@ -258,7 +262,6 @@ using webrtc::DataBuffer; using webrtc::DataChannelInterface; using webrtc::FakeConstraints; -using webrtc::FakePortAllocatorFactory; using webrtc::IceCandidateInterface; using webrtc::MediaConstraintsInterface; using webrtc::MediaStream; @@ -270,7 +273,6 @@ using webrtc::MockStatsObserver; using webrtc::PeerConnectionInterface; using webrtc::PeerConnectionObserver; -using webrtc::PortAllocatorFactoryInterface; using webrtc::RtpReceiverInterface; using webrtc::RtpSenderInterface; using webrtc::SdpParseError; @@ -515,6 +517,12 @@ class PeerConnectionInterfaceTest : public testing::Test { protected: + PeerConnectionInterfaceTest() { +#ifdef WEBRTC_ANDROID + webrtc::InitializeAndroidObjects(); +#endif + } + virtual void SetUp() { pc_factory_ = webrtc::CreatePeerConnectionFactory( rtc::Thread::Current(), rtc::Thread::Current(), NULL, NULL, @@ -533,15 +541,17 @@ void CreatePeerConnection(const std::string& uri, const std::string& password, webrtc::MediaConstraintsInterface* constraints) { + PeerConnectionInterface::RTCConfiguration config; PeerConnectionInterface::IceServer server; - PeerConnectionInterface::IceServers servers; if (!uri.empty()) { server.uri = uri; server.password = password; - servers.push_back(server); + config.servers.push_back(server); } - port_allocator_factory_ = FakePortAllocatorFactory::Create(); + rtc::scoped_ptr<cricket::FakePortAllocator> port_allocator( + new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr)); + port_allocator_ = port_allocator.get(); // DTLS does not work in a loopback call, so is disabled for most of the // tests in this file. We only create a FakeIdentityService if the test @@ -562,52 +572,47 @@ nullptr) && dtls) { dtls_identity_store.reset(new FakeDtlsIdentityStore()); } - pc_ = pc_factory_->CreatePeerConnection(servers, constraints, - port_allocator_factory_.get(), - dtls_identity_store.Pass(), - &observer_); + pc_ = pc_factory_->CreatePeerConnection( + config, constraints, std::move(port_allocator), + std::move(dtls_identity_store), &observer_); ASSERT_TRUE(pc_.get() != NULL); observer_.SetPeerConnectionInterface(pc_.get()); EXPECT_EQ(PeerConnectionInterface::kStable, observer_.state_); } void CreatePeerConnectionExpectFail(const std::string& uri) { + PeerConnectionInterface::RTCConfiguration config; PeerConnectionInterface::IceServer server; - PeerConnectionInterface::IceServers servers; server.uri = uri; - servers.push_back(server); + config.servers.push_back(server); - scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store; - port_allocator_factory_ = FakePortAllocatorFactory::Create(); scoped_refptr<PeerConnectionInterface> pc; - pc = pc_factory_->CreatePeerConnection( - servers, nullptr, port_allocator_factory_.get(), - dtls_identity_store.Pass(), &observer_); - ASSERT_EQ(nullptr, pc); + pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr, nullptr, + &observer_); + EXPECT_EQ(nullptr, pc); } void CreatePeerConnectionWithDifferentConfigurations() { CreatePeerConnection(kStunAddressOnly, "", NULL); - EXPECT_EQ(1u, port_allocator_factory_->stun_configs().size()); - EXPECT_EQ(0u, port_allocator_factory_->turn_configs().size()); - EXPECT_EQ("address", - port_allocator_factory_->stun_configs()[0].server.hostname()); + EXPECT_EQ(1u, port_allocator_->stun_servers().size()); + EXPECT_EQ(0u, port_allocator_->turn_servers().size()); + EXPECT_EQ("address", port_allocator_->stun_servers().begin()->hostname()); EXPECT_EQ(kDefaultStunPort, - port_allocator_factory_->stun_configs()[0].server.port()); + port_allocator_->stun_servers().begin()->port()); CreatePeerConnectionExpectFail(kStunInvalidPort); CreatePeerConnectionExpectFail(kStunAddressPortAndMore1); CreatePeerConnectionExpectFail(kStunAddressPortAndMore2); CreatePeerConnection(kTurnIceServerUri, kTurnPassword, NULL); - EXPECT_EQ(0u, port_allocator_factory_->stun_configs().size()); - EXPECT_EQ(1u, port_allocator_factory_->turn_configs().size()); + EXPECT_EQ(0u, port_allocator_->stun_servers().size()); + EXPECT_EQ(1u, port_allocator_->turn_servers().size()); EXPECT_EQ(kTurnUsername, - port_allocator_factory_->turn_configs()[0].username); + port_allocator_->turn_servers()[0].credentials.username); EXPECT_EQ(kTurnPassword, - port_allocator_factory_->turn_configs()[0].password); + port_allocator_->turn_servers()[0].credentials.password); EXPECT_EQ(kTurnHostname, - port_allocator_factory_->turn_configs()[0].server.hostname()); + port_allocator_->turn_servers()[0].ports[0].address.hostname()); } void ReleasePeerConnection() { @@ -926,7 +931,7 @@ ASSERT_TRUE(stream->AddTrack(video_track)); } - scoped_refptr<FakePortAllocatorFactory> port_allocator_factory_; + cricket::FakePortAllocator* port_allocator_ = nullptr; scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_; scoped_refptr<PeerConnectionInterface> pc_; MockPeerConnectionObserver observer_; @@ -1156,6 +1161,64 @@ EXPECT_NE(audio_ssrc, video_ssrc); } +// Test that it's possible to call AddTrack on a MediaStream after adding +// the stream to a PeerConnection. +// TODO(deadbeef): Remove this test once this behavior is no longer supported. +TEST_F(PeerConnectionInterfaceTest, AddTrackAfterAddStream) { + CreatePeerConnection(); + // Create audio stream and add to PeerConnection. + AddVoiceStream(kStreamLabel1); + MediaStreamInterface* stream = pc_->local_streams()->at(0); + + // Add video track to the audio-only stream. + scoped_refptr<VideoTrackInterface> video_track( + pc_factory_->CreateVideoTrack("video_label", nullptr)); + stream->AddTrack(video_track.get()); + + scoped_ptr<SessionDescriptionInterface> offer; + ASSERT_TRUE(DoCreateOffer(offer.use(), nullptr)); + + const cricket::MediaContentDescription* video_desc = + cricket::GetFirstVideoContentDescription(offer->description()); + EXPECT_TRUE(video_desc != nullptr); +} + +// Test that it's possible to call RemoveTrack on a MediaStream after adding +// the stream to a PeerConnection. +// TODO(deadbeef): Remove this test once this behavior is no longer supported. +TEST_F(PeerConnectionInterfaceTest, RemoveTrackAfterAddStream) { + CreatePeerConnection(); + // Create audio/video stream and add to PeerConnection. + AddAudioVideoStream(kStreamLabel1, "audio_label", "video_label"); + MediaStreamInterface* stream = pc_->local_streams()->at(0); + + // Remove the video track. + stream->RemoveTrack(stream->GetVideoTracks()[0]); + + scoped_ptr<SessionDescriptionInterface> offer; + ASSERT_TRUE(DoCreateOffer(offer.use(), nullptr)); + + const cricket::MediaContentDescription* video_desc = + cricket::GetFirstVideoContentDescription(offer->description()); + EXPECT_TRUE(video_desc == nullptr); +} + +// Test creating a sender with a stream ID, and ensure the ID is populated +// in the offer. +TEST_F(PeerConnectionInterfaceTest, CreateSenderWithStream) { + CreatePeerConnection(); + pc_->CreateSender("video", kStreamLabel1); + + scoped_ptr<SessionDescriptionInterface> offer; + ASSERT_TRUE(DoCreateOffer(offer.use(), nullptr)); + + const cricket::MediaContentDescription* video_desc = + cricket::GetFirstVideoContentDescription(offer->description()); + ASSERT_TRUE(video_desc != nullptr); + ASSERT_EQ(1u, video_desc->streams().size()); + EXPECT_EQ(kStreamLabel1, video_desc->streams()[0].sync_label); +} + // Test that we can specify a certain track that we want statistics about. TEST_F(PeerConnectionInterfaceTest, GetStatsForSpecificTrack) { InitiateCall(); @@ -1660,6 +1723,22 @@ ASSERT_EQ(cricket::MD_INACTIVE, audio_desc->direction()); } +// Test that we can use SetConfiguration to change the ICE servers of the +// PortAllocator. +TEST_F(PeerConnectionInterfaceTest, SetConfigurationChangesIceServers) { + CreatePeerConnection(); + + PeerConnectionInterface::RTCConfiguration config; + PeerConnectionInterface::IceServer server; + server.uri = "stun:test_hostname"; + config.servers.push_back(server); + EXPECT_TRUE(pc_->SetConfiguration(config)); + + EXPECT_EQ(1u, port_allocator_->stun_servers().size()); + EXPECT_EQ("test_hostname", + port_allocator_->stun_servers().begin()->hostname()); +} + // Test that PeerConnection::Close changes the states to closed and all remote // tracks change state to ended. TEST_F(PeerConnectionInterfaceTest, CloseAndTestStreamsAndStates) { @@ -1977,6 +2056,28 @@ EXPECT_EQ(0u, observer_.remote_streams()->count()); } +// This tests that when setting a new description, the old default tracks are +// not destroyed and recreated. +// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=5250 +TEST_F(PeerConnectionInterfaceTest, DefaultTracksNotDestroyedAndRecreated) { + FakeConstraints constraints; + constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, + true); + CreatePeerConnection(&constraints); + CreateAndSetRemoteOffer(kSdpStringWithoutStreamsAudioOnly); + + ASSERT_EQ(1u, observer_.remote_streams()->count()); + MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0); + ASSERT_EQ(1u, remote_stream->GetAudioTracks().size()); + + // Set the track to "disabled", then set a new description and ensure the + // track is still disabled, which ensures it hasn't been recreated. + remote_stream->GetAudioTracks()[0]->set_enabled(false); + CreateAndSetRemoteOffer(kSdpStringWithoutStreamsAudioOnly); + ASSERT_EQ(1u, remote_stream->GetAudioTracks().size()); + EXPECT_FALSE(remote_stream->GetAudioTracks()[0]->enabled()); +} + // This tests that a default MediaStream is not created if a remote session // description is updated to not have any MediaStreams. TEST_F(PeerConnectionInterfaceTest, VerifyDefaultStreamIsNotCreated) { @@ -2020,8 +2121,10 @@ EXPECT_TRUE(ContainsSender(senders, kVideoTracks[1])); // Remove an audio and video track. + pc_->RemoveStream(reference_collection_->at(0)); rtc::scoped_ptr<SessionDescriptionInterface> desc_2; CreateSessionDescriptionAndReference(1, 1, desc_2.accept()); + pc_->AddStream(reference_collection_->at(0)); EXPECT_TRUE(DoSetLocalDescription(desc_2.release())); senders = pc_->GetSenders(); EXPECT_EQ(2u, senders.size()); @@ -2220,7 +2323,9 @@ EXPECT_FALSE(options.has_video()); EXPECT_TRUE(options.bundle_enabled); EXPECT_TRUE(options.vad_enabled); - EXPECT_FALSE(options.transport_options.ice_restart); + EXPECT_FALSE(options.audio_transport_options.ice_restart); + EXPECT_FALSE(options.video_transport_options.ice_restart); + EXPECT_FALSE(options.data_transport_options.ice_restart); } // Test that a correct MediaSessionOptions is created for an offer if @@ -2255,18 +2360,22 @@ // Test that a correct MediaSessionOptions is created to restart ice if // IceRestart is set. It also tests that subsequent MediaSessionOptions don't -// have |transport_options.ice_restart| set. +// have |audio_transport_options.ice_restart| etc. set. TEST(CreateSessionOptionsTest, GetMediaSessionOptionsForOfferWithIceRestart) { RTCOfferAnswerOptions rtc_options; rtc_options.ice_restart = true; cricket::MediaSessionOptions options; EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options)); - EXPECT_TRUE(options.transport_options.ice_restart); + EXPECT_TRUE(options.audio_transport_options.ice_restart); + EXPECT_TRUE(options.video_transport_options.ice_restart); + EXPECT_TRUE(options.data_transport_options.ice_restart); rtc_options = RTCOfferAnswerOptions(); EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options)); - EXPECT_FALSE(options.transport_options.ice_restart); + EXPECT_FALSE(options.audio_transport_options.ice_restart); + EXPECT_FALSE(options.video_transport_options.ice_restart); + EXPECT_FALSE(options.data_transport_options.ice_restart); } // Test that the MediaConstraints in an answer don't affect if audio and video
diff --git a/talk/app/webrtc/peerconnectionproxy.h b/talk/app/webrtc/peerconnectionproxy.h index d207fbb..3c983d7 100644 --- a/talk/app/webrtc/peerconnectionproxy.h +++ b/talk/app/webrtc/peerconnectionproxy.h
@@ -43,6 +43,10 @@ PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*) PROXY_METHOD1(rtc::scoped_refptr<DtmfSenderInterface>, CreateDtmfSender, AudioTrackInterface*) + PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>, + CreateSender, + const std::string&, + const std::string&) PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>, GetSenders) PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
diff --git a/talk/app/webrtc/portallocatorfactory.cc b/talk/app/webrtc/portallocatorfactory.cc index bd6cacc..64d714c 100644 --- a/talk/app/webrtc/portallocatorfactory.cc +++ b/talk/app/webrtc/portallocatorfactory.cc
@@ -1,6 +1,6 @@ /* * libjingle - * Copyright 2004--2011 Google Inc. + * Copyright 2011 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -24,69 +24,7 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// TODO(deadbeef): Remove this file once chromium build files no longer +// reference it. #include "talk/app/webrtc/portallocatorfactory.h" - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/network.h" -#include "webrtc/base/thread.h" - -namespace webrtc { - -using rtc::scoped_ptr; - -rtc::scoped_refptr<PortAllocatorFactoryInterface> -PortAllocatorFactory::Create( - rtc::Thread* worker_thread) { - rtc::RefCountedObject<PortAllocatorFactory>* allocator = - new rtc::RefCountedObject<PortAllocatorFactory>(worker_thread); - return allocator; -} - -PortAllocatorFactory::PortAllocatorFactory(rtc::Thread* worker_thread) - : network_manager_(new rtc::BasicNetworkManager()), - socket_factory_(new rtc::BasicPacketSocketFactory(worker_thread)) { -} - -PortAllocatorFactory::~PortAllocatorFactory() {} - -void PortAllocatorFactory::SetNetworkIgnoreMask(int network_ignore_mask) { - network_manager_->set_network_ignore_mask(network_ignore_mask); -} - -cricket::PortAllocator* PortAllocatorFactory::CreatePortAllocator( - const std::vector<StunConfiguration>& stun, - const std::vector<TurnConfiguration>& turn) { - cricket::ServerAddresses stun_hosts; - typedef std::vector<StunConfiguration>::const_iterator StunIt; - for (StunIt stun_it = stun.begin(); stun_it != stun.end(); ++stun_it) { - stun_hosts.insert(stun_it->server); - } - - scoped_ptr<cricket::BasicPortAllocator> allocator( - new cricket::BasicPortAllocator( - network_manager_.get(), socket_factory_.get(), stun_hosts)); - - for (size_t i = 0; i < turn.size(); ++i) { - cricket::RelayCredentials credentials(turn[i].username, turn[i].password); - cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); - cricket::ProtocolType protocol; - if (cricket::StringToProto(turn[i].transport_type.c_str(), &protocol)) { - relay_server.ports.push_back(cricket::ProtocolAddress( - turn[i].server, protocol, turn[i].secure)); - relay_server.credentials = credentials; - // First in the list gets highest priority. - relay_server.priority = static_cast<int>(turn.size() - i - 1); - allocator->AddRelay(relay_server); - } else { - LOG(LS_WARNING) << "Ignoring TURN server " << turn[i].server << ". " - << "Reason= Incorrect " << turn[i].transport_type - << " transport parameter."; - } - } - return allocator.release(); -} - -} // namespace webrtc
diff --git a/talk/app/webrtc/portallocatorfactory.h b/talk/app/webrtc/portallocatorfactory.h index 83376d0..bb6cf47 100644 --- a/talk/app/webrtc/portallocatorfactory.h +++ b/talk/app/webrtc/portallocatorfactory.h
@@ -24,49 +24,10 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -// This file defines the default implementation of -// PortAllocatorFactoryInterface. -// This implementation creates instances of cricket::HTTPPortAllocator and uses -// the BasicNetworkManager and BasicPacketSocketFactory. +// TODO(deadbeef): Remove this file once chromium build files no longer +// reference it. #ifndef TALK_APP_WEBRTC_PORTALLOCATORFACTORY_H_ #define TALK_APP_WEBRTC_PORTALLOCATORFACTORY_H_ -#include "talk/app/webrtc/peerconnectioninterface.h" -#include "webrtc/base/scoped_ptr.h" - -namespace cricket { -class PortAllocator; -} - -namespace rtc { -class BasicNetworkManager; -class BasicPacketSocketFactory; -} - -namespace webrtc { - -class PortAllocatorFactory : public PortAllocatorFactoryInterface { - public: - static rtc::scoped_refptr<PortAllocatorFactoryInterface> Create( - rtc::Thread* worker_thread); - - virtual cricket::PortAllocator* CreatePortAllocator( - const std::vector<StunConfiguration>& stun, - const std::vector<TurnConfiguration>& turn); - - virtual void SetNetworkIgnoreMask(int network_ignore_mask); - - protected: - explicit PortAllocatorFactory(rtc::Thread* worker_thread); - ~PortAllocatorFactory(); - - private: - rtc::scoped_ptr<rtc::BasicNetworkManager> network_manager_; - rtc::scoped_ptr<rtc::BasicPacketSocketFactory> socket_factory_; -}; - -} // namespace webrtc - #endif // TALK_APP_WEBRTC_PORTALLOCATORFACTORY_H_
diff --git a/talk/app/webrtc/remoteaudiosource.cc b/talk/app/webrtc/remoteaudiosource.cc index 41f3d87..e904dd9 100644 --- a/talk/app/webrtc/remoteaudiosource.cc +++ b/talk/app/webrtc/remoteaudiosource.cc
@@ -29,44 +29,148 @@ #include <algorithm> #include <functional> +#include <utility> +#include "talk/app/webrtc/mediastreamprovider.h" +#include "webrtc/base/checks.h" #include "webrtc/base/logging.h" +#include "webrtc/base/thread.h" namespace webrtc { -rtc::scoped_refptr<RemoteAudioSource> RemoteAudioSource::Create() { - return new rtc::RefCountedObject<RemoteAudioSource>(); +class RemoteAudioSource::MessageHandler : public rtc::MessageHandler { + public: + explicit MessageHandler(RemoteAudioSource* source) : source_(source) {} + + private: + ~MessageHandler() override {} + + void OnMessage(rtc::Message* msg) override { + source_->OnMessage(msg); + delete this; + } + + const rtc::scoped_refptr<RemoteAudioSource> source_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(MessageHandler); +}; + +class RemoteAudioSource::Sink : public AudioSinkInterface { + public: + explicit Sink(RemoteAudioSource* source) : source_(source) {} + ~Sink() override { source_->OnAudioProviderGone(); } + + private: + void OnData(const AudioSinkInterface::Data& audio) override { + if (source_) + source_->OnData(audio); + } + + const rtc::scoped_refptr<RemoteAudioSource> source_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Sink); +}; + +rtc::scoped_refptr<RemoteAudioSource> RemoteAudioSource::Create( + uint32_t ssrc, + AudioProviderInterface* provider) { + rtc::scoped_refptr<RemoteAudioSource> ret( + new rtc::RefCountedObject<RemoteAudioSource>()); + ret->Initialize(ssrc, provider); + return ret; } -RemoteAudioSource::RemoteAudioSource() { +RemoteAudioSource::RemoteAudioSource() + : main_thread_(rtc::Thread::Current()), + state_(MediaSourceInterface::kLive) { + RTC_DCHECK(main_thread_); } RemoteAudioSource::~RemoteAudioSource() { - ASSERT(audio_observers_.empty()); + RTC_DCHECK(main_thread_->IsCurrent()); + RTC_DCHECK(audio_observers_.empty()); + RTC_DCHECK(sinks_.empty()); } -MediaSourceInterface::SourceState RemoteAudioSource::state() const { - return MediaSourceInterface::kLive; -} - -void RemoteAudioSource::SetVolume(double volume) { - ASSERT(volume >= 0 && volume <= 10); - for (AudioObserverList::iterator it = audio_observers_.begin(); - it != audio_observers_.end(); ++it) { - (*it)->OnSetVolume(volume); +void RemoteAudioSource::Initialize(uint32_t ssrc, + AudioProviderInterface* provider) { + RTC_DCHECK(main_thread_->IsCurrent()); + // To make sure we always get notified when the provider goes out of scope, + // we register for callbacks here and not on demand in AddSink. + if (provider) { // May be null in tests. + provider->SetRawAudioSink( + ssrc, rtc::scoped_ptr<AudioSinkInterface>(new Sink(this))); } } +MediaSourceInterface::SourceState RemoteAudioSource::state() const { + RTC_DCHECK(main_thread_->IsCurrent()); + return state_; +} + +bool RemoteAudioSource::remote() const { + RTC_DCHECK(main_thread_->IsCurrent()); + return true; +} + +void RemoteAudioSource::SetVolume(double volume) { + RTC_DCHECK(volume >= 0 && volume <= 10); + for (auto* observer : audio_observers_) + observer->OnSetVolume(volume); +} + void RemoteAudioSource::RegisterAudioObserver(AudioObserver* observer) { - ASSERT(observer != NULL); - ASSERT(std::find(audio_observers_.begin(), audio_observers_.end(), - observer) == audio_observers_.end()); + RTC_DCHECK(observer != NULL); + RTC_DCHECK(std::find(audio_observers_.begin(), audio_observers_.end(), + observer) == audio_observers_.end()); audio_observers_.push_back(observer); } void RemoteAudioSource::UnregisterAudioObserver(AudioObserver* observer) { - ASSERT(observer != NULL); + RTC_DCHECK(observer != NULL); audio_observers_.remove(observer); } +void RemoteAudioSource::AddSink(AudioTrackSinkInterface* sink) { + RTC_DCHECK(main_thread_->IsCurrent()); + RTC_DCHECK(sink); + + if (state_ != MediaSourceInterface::kLive) { + LOG(LS_ERROR) << "Can't register sink as the source isn't live."; + return; + } + + rtc::CritScope lock(&sink_lock_); + RTC_DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end()); + sinks_.push_back(sink); +} + +void RemoteAudioSource::RemoveSink(AudioTrackSinkInterface* sink) { + RTC_DCHECK(main_thread_->IsCurrent()); + RTC_DCHECK(sink); + + rtc::CritScope lock(&sink_lock_); + sinks_.remove(sink); +} + +void RemoteAudioSource::OnData(const AudioSinkInterface::Data& audio) { + // Called on the externally-owned audio callback thread, via/from webrtc. + rtc::CritScope lock(&sink_lock_); + for (auto* sink : sinks_) { + sink->OnData(audio.data, 16, audio.sample_rate, audio.channels, + audio.samples_per_channel); + } +} + +void RemoteAudioSource::OnAudioProviderGone() { + // Called when the data provider is deleted. It may be the worker thread + // in libjingle or may be a different worker thread. + main_thread_->Post(new MessageHandler(this)); +} + +void RemoteAudioSource::OnMessage(rtc::Message* msg) { + RTC_DCHECK(main_thread_->IsCurrent()); + sinks_.clear(); + state_ = MediaSourceInterface::kEnded; + FireOnChanged(); +} + } // namespace webrtc
diff --git a/talk/app/webrtc/remoteaudiosource.h b/talk/app/webrtc/remoteaudiosource.h index e49aca5..d648ba4 100644 --- a/talk/app/webrtc/remoteaudiosource.h +++ b/talk/app/webrtc/remoteaudiosource.h
@@ -29,36 +29,66 @@ #define TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_ #include <list> +#include <string> #include "talk/app/webrtc/mediastreaminterface.h" #include "talk/app/webrtc/notifier.h" +#include "talk/media/base/audiorenderer.h" +#include "webrtc/audio/audio_sink.h" +#include "webrtc/base/criticalsection.h" + +namespace rtc { +struct Message; +class Thread; +} // namespace rtc namespace webrtc { -using webrtc::AudioSourceInterface; +class AudioProviderInterface; // This class implements the audio source used by the remote audio track. class RemoteAudioSource : public Notifier<AudioSourceInterface> { public: // Creates an instance of RemoteAudioSource. - static rtc::scoped_refptr<RemoteAudioSource> Create(); - - protected: - RemoteAudioSource(); - virtual ~RemoteAudioSource(); - - private: - typedef std::list<AudioObserver*> AudioObserverList; + static rtc::scoped_refptr<RemoteAudioSource> Create( + uint32_t ssrc, + AudioProviderInterface* provider); // MediaSourceInterface implementation. MediaSourceInterface::SourceState state() const override; + bool remote() const override; + + void AddSink(AudioTrackSinkInterface* sink) override; + void RemoveSink(AudioTrackSinkInterface* sink) override; + + protected: + RemoteAudioSource(); + ~RemoteAudioSource() override; + + // Post construction initialize where we can do things like save a reference + // to ourselves (need to be fully constructed). + void Initialize(uint32_t ssrc, AudioProviderInterface* provider); + + private: + typedef std::list<AudioObserver*> AudioObserverList; // AudioSourceInterface implementation. void SetVolume(double volume) override; void RegisterAudioObserver(AudioObserver* observer) override; void UnregisterAudioObserver(AudioObserver* observer) override; + class Sink; + void OnData(const AudioSinkInterface::Data& audio); + void OnAudioProviderGone(); + + class MessageHandler; + void OnMessage(rtc::Message* msg); + AudioObserverList audio_observers_; + rtc::CriticalSection sink_lock_; + std::list<AudioTrackSinkInterface*> sinks_; + rtc::Thread* const main_thread_; + SourceState state_; }; } // namespace webrtc
diff --git a/talk/app/webrtc/remoteaudiotrack.cc b/talk/app/webrtc/remoteaudiotrack.cc new file mode 100644 index 0000000..5f0b23e --- /dev/null +++ b/talk/app/webrtc/remoteaudiotrack.cc
@@ -0,0 +1,28 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// TODO(tommi): Delete this file when removed from build files in Chromium.
diff --git a/talk/app/webrtc/remoteaudiotrack.h b/talk/app/webrtc/remoteaudiotrack.h new file mode 100644 index 0000000..5f0b23e --- /dev/null +++ b/talk/app/webrtc/remoteaudiotrack.h
@@ -0,0 +1,28 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// TODO(tommi): Delete this file when removed from build files in Chromium.
diff --git a/talk/app/webrtc/rtpreceiver.cc b/talk/app/webrtc/rtpreceiver.cc index b88554f..9540f36 100644 --- a/talk/app/webrtc/rtpreceiver.cc +++ b/talk/app/webrtc/rtpreceiver.cc
@@ -39,6 +39,7 @@ ssrc_(ssrc), provider_(provider), cached_track_enabled_(track->enabled()) { + RTC_DCHECK(track_->GetSource()->remote()); track_->RegisterObserver(this); track_->GetSource()->RegisterAudioObserver(this); Reconfigure(); @@ -85,6 +86,7 @@ uint32_t ssrc, VideoProviderInterface* provider) : id_(track->id()), track_(track), ssrc_(ssrc), provider_(provider) { + RTC_DCHECK(track_->GetSource()->remote()); provider_->SetVideoPlayout(ssrc_, true, track_->GetSource()->FrameInput()); }
diff --git a/talk/app/webrtc/rtpreceiver.h b/talk/app/webrtc/rtpreceiver.h index a93ccbc..db021ba 100644 --- a/talk/app/webrtc/rtpreceiver.h +++ b/talk/app/webrtc/rtpreceiver.h
@@ -68,10 +68,10 @@ private: void Reconfigure(); - std::string id_; - rtc::scoped_refptr<AudioTrackInterface> track_; - uint32_t ssrc_; - AudioProviderInterface* provider_; + const std::string id_; + const rtc::scoped_refptr<AudioTrackInterface> track_; + const uint32_t ssrc_; + AudioProviderInterface* provider_; // Set to null in Stop(). bool cached_track_enabled_; };
diff --git a/talk/app/webrtc/rtpsender.cc b/talk/app/webrtc/rtpsender.cc index 3a78f45..91e484b 100644 --- a/talk/app/webrtc/rtpsender.cc +++ b/talk/app/webrtc/rtpsender.cc
@@ -29,6 +29,7 @@ #include "talk/app/webrtc/localaudiosource.h" #include "talk/app/webrtc/videosourceinterface.h" +#include "webrtc/base/helpers.h" namespace webrtc { @@ -43,7 +44,7 @@ void LocalAudioSinkAdapter::OnData(const void* audio_data, int bits_per_sample, int sample_rate, - int number_of_channels, + size_t number_of_channels, size_t number_of_frames) { rtc::CritScope lock(&lock_); if (sink_) { @@ -59,34 +60,49 @@ } AudioRtpSender::AudioRtpSender(AudioTrackInterface* track, - uint32_t ssrc, - AudioProviderInterface* provider) + const std::string& stream_id, + AudioProviderInterface* provider, + StatsCollector* stats) : id_(track->id()), - track_(track), - ssrc_(ssrc), + stream_id_(stream_id), provider_(provider), + stats_(stats), + track_(track), cached_track_enabled_(track->enabled()), sink_adapter_(new LocalAudioSinkAdapter()) { + RTC_DCHECK(provider != nullptr); track_->RegisterObserver(this); track_->AddSink(sink_adapter_.get()); - Reconfigure(); } +AudioRtpSender::AudioRtpSender(AudioProviderInterface* provider, + StatsCollector* stats) + : id_(rtc::CreateRandomUuid()), + stream_id_(rtc::CreateRandomUuid()), + provider_(provider), + stats_(stats), + sink_adapter_(new LocalAudioSinkAdapter()) {} + AudioRtpSender::~AudioRtpSender() { - track_->RemoveSink(sink_adapter_.get()); - track_->UnregisterObserver(this); Stop(); } void AudioRtpSender::OnChanged() { + RTC_DCHECK(!stopped_); if (cached_track_enabled_ != track_->enabled()) { cached_track_enabled_ = track_->enabled(); - Reconfigure(); + if (can_send_track()) { + SetAudioSend(); + } } } bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) { - if (track->kind() != "audio") { + if (stopped_) { + LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender."; + return false; + } + if (track && track->kind() != MediaStreamTrackInterface::kAudioKind) { LOG(LS_ERROR) << "SetTrack called on audio RtpSender with " << track->kind() << " track."; return false; @@ -94,36 +110,84 @@ AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track); // Detach from old track. - track_->RemoveSink(sink_adapter_.get()); - track_->UnregisterObserver(this); + if (track_) { + track_->RemoveSink(sink_adapter_.get()); + track_->UnregisterObserver(this); + } + + if (can_send_track() && stats_) { + stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); + } // Attach to new track. + bool prev_can_send_track = can_send_track(); track_ = audio_track; - cached_track_enabled_ = track_->enabled(); - track_->RegisterObserver(this); - track_->AddSink(sink_adapter_.get()); - Reconfigure(); + if (track_) { + cached_track_enabled_ = track_->enabled(); + track_->RegisterObserver(this); + track_->AddSink(sink_adapter_.get()); + } + + // Update audio provider. + if (can_send_track()) { + SetAudioSend(); + if (stats_) { + stats_->AddLocalAudioTrack(track_.get(), ssrc_); + } + } else if (prev_can_send_track) { + cricket::AudioOptions options; + provider_->SetAudioSend(ssrc_, false, options, nullptr); + } return true; } +void AudioRtpSender::SetSsrc(uint32_t ssrc) { + if (stopped_ || ssrc == ssrc_) { + return; + } + // If we are already sending with a particular SSRC, stop sending. + if (can_send_track()) { + cricket::AudioOptions options; + provider_->SetAudioSend(ssrc_, false, options, nullptr); + if (stats_) { + stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); + } + } + ssrc_ = ssrc; + if (can_send_track()) { + SetAudioSend(); + if (stats_) { + stats_->AddLocalAudioTrack(track_.get(), ssrc_); + } + } +} + void AudioRtpSender::Stop() { // TODO(deadbeef): Need to do more here to fully stop sending packets. - if (!provider_) { + if (stopped_) { return; } - cricket::AudioOptions options; - provider_->SetAudioSend(ssrc_, false, options, nullptr); - provider_ = nullptr; + if (track_) { + track_->RemoveSink(sink_adapter_.get()); + track_->UnregisterObserver(this); + } + if (can_send_track()) { + cricket::AudioOptions options; + provider_->SetAudioSend(ssrc_, false, options, nullptr); + if (stats_) { + stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); + } + } + stopped_ = true; } -void AudioRtpSender::Reconfigure() { - if (!provider_) { - return; - } +void AudioRtpSender::SetAudioSend() { + RTC_DCHECK(!stopped_ && can_send_track()); cricket::AudioOptions options; - if (track_->enabled() && track_->GetSource()) { + if (track_->enabled() && track_->GetSource() && + !track_->GetSource()->remote()) { // TODO(xians): Remove this static_cast since we should be able to connect - // a remote audio track to peer connection. + // a remote audio track to a peer connection. options = static_cast<LocalAudioSource*>(track_->GetSource())->options(); } @@ -136,35 +200,42 @@ } VideoRtpSender::VideoRtpSender(VideoTrackInterface* track, - uint32_t ssrc, + const std::string& stream_id, VideoProviderInterface* provider) : id_(track->id()), - track_(track), - ssrc_(ssrc), + stream_id_(stream_id), provider_(provider), + track_(track), cached_track_enabled_(track->enabled()) { + RTC_DCHECK(provider != nullptr); track_->RegisterObserver(this); - VideoSourceInterface* source = track_->GetSource(); - if (source) { - provider_->SetCaptureDevice(ssrc_, source->GetVideoCapturer()); - } - Reconfigure(); } +VideoRtpSender::VideoRtpSender(VideoProviderInterface* provider) + : id_(rtc::CreateRandomUuid()), + stream_id_(rtc::CreateRandomUuid()), + provider_(provider) {} + VideoRtpSender::~VideoRtpSender() { - track_->UnregisterObserver(this); Stop(); } void VideoRtpSender::OnChanged() { + RTC_DCHECK(!stopped_); if (cached_track_enabled_ != track_->enabled()) { cached_track_enabled_ = track_->enabled(); - Reconfigure(); + if (can_send_track()) { + SetVideoSend(); + } } } bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) { - if (track->kind() != "video") { + if (stopped_) { + LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender."; + return false; + } + if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) { LOG(LS_ERROR) << "SetTrack called on video RtpSender with " << track->kind() << " track."; return false; @@ -172,30 +243,72 @@ VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track); // Detach from old track. - track_->UnregisterObserver(this); + if (track_) { + track_->UnregisterObserver(this); + } // Attach to new track. + bool prev_can_send_track = can_send_track(); track_ = video_track; - cached_track_enabled_ = track_->enabled(); - track_->RegisterObserver(this); - Reconfigure(); + if (track_) { + cached_track_enabled_ = track_->enabled(); + track_->RegisterObserver(this); + } + + // Update video provider. + if (can_send_track()) { + VideoSourceInterface* source = track_->GetSource(); + // TODO(deadbeef): If SetTrack is called with a disabled track, and the + // previous track was enabled, this could cause a frame from the new track + // to slip out. Really, what we need is for SetCaptureDevice and + // SetVideoSend + // to be combined into one atomic operation, all the way down to + // WebRtcVideoSendStream. + provider_->SetCaptureDevice(ssrc_, + source ? source->GetVideoCapturer() : nullptr); + SetVideoSend(); + } else if (prev_can_send_track) { + provider_->SetCaptureDevice(ssrc_, nullptr); + provider_->SetVideoSend(ssrc_, false, nullptr); + } return true; } +void VideoRtpSender::SetSsrc(uint32_t ssrc) { + if (stopped_ || ssrc == ssrc_) { + return; + } + // If we are already sending with a particular SSRC, stop sending. + if (can_send_track()) { + provider_->SetCaptureDevice(ssrc_, nullptr); + provider_->SetVideoSend(ssrc_, false, nullptr); + } + ssrc_ = ssrc; + if (can_send_track()) { + VideoSourceInterface* source = track_->GetSource(); + provider_->SetCaptureDevice(ssrc_, + source ? source->GetVideoCapturer() : nullptr); + SetVideoSend(); + } +} + void VideoRtpSender::Stop() { // TODO(deadbeef): Need to do more here to fully stop sending packets. - if (!provider_) { + if (stopped_) { return; } - provider_->SetCaptureDevice(ssrc_, nullptr); - provider_->SetVideoSend(ssrc_, false, nullptr); - provider_ = nullptr; + if (track_) { + track_->UnregisterObserver(this); + } + if (can_send_track()) { + provider_->SetCaptureDevice(ssrc_, nullptr); + provider_->SetVideoSend(ssrc_, false, nullptr); + } + stopped_ = true; } -void VideoRtpSender::Reconfigure() { - if (!provider_) { - return; - } +void VideoRtpSender::SetVideoSend() { + RTC_DCHECK(!stopped_ && can_send_track()); const cricket::VideoOptions* options = nullptr; VideoSourceInterface* source = track_->GetSource(); if (track_->enabled() && source) {
diff --git a/talk/app/webrtc/rtpsender.h b/talk/app/webrtc/rtpsender.h index 3741909..dd846b5 100644 --- a/talk/app/webrtc/rtpsender.h +++ b/talk/app/webrtc/rtpsender.h
@@ -36,6 +36,7 @@ #include "talk/app/webrtc/mediastreamprovider.h" #include "talk/app/webrtc/rtpsenderinterface.h" +#include "talk/app/webrtc/statscollector.h" #include "talk/media/base/audiorenderer.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/criticalsection.h" @@ -56,7 +57,7 @@ void OnData(const void* audio_data, int bits_per_sample, int sample_rate, - int number_of_channels, + size_t number_of_channels, size_t number_of_frames) override; // cricket::AudioRenderer implementation. @@ -70,9 +71,15 @@ class AudioRtpSender : public ObserverInterface, public rtc::RefCountedObject<RtpSenderInterface> { public: + // StatsCollector provided so that Add/RemoveLocalAudioTrack can be called + // at the appropriate times. AudioRtpSender(AudioTrackInterface* track, - uint32_t ssrc, - AudioProviderInterface* provider); + const std::string& stream_id, + AudioProviderInterface* provider, + StatsCollector* stats); + + // Randomly generates id and stream_id. + AudioRtpSender(AudioProviderInterface* provider, StatsCollector* stats); virtual ~AudioRtpSender(); @@ -85,18 +92,37 @@ return track_.get(); } + void SetSsrc(uint32_t ssrc) override; + + uint32_t ssrc() const override { return ssrc_; } + + cricket::MediaType media_type() const override { + return cricket::MEDIA_TYPE_AUDIO; + } + std::string id() const override { return id_; } + void set_stream_id(const std::string& stream_id) override { + stream_id_ = stream_id; + } + std::string stream_id() const override { return stream_id_; } + void Stop() override; private: - void Reconfigure(); + bool can_send_track() const { return track_ && ssrc_; } + // Helper function to construct options for + // AudioProviderInterface::SetAudioSend. + void SetAudioSend(); std::string id_; - rtc::scoped_refptr<AudioTrackInterface> track_; - uint32_t ssrc_; + std::string stream_id_; AudioProviderInterface* provider_; - bool cached_track_enabled_; + StatsCollector* stats_; + rtc::scoped_refptr<AudioTrackInterface> track_; + uint32_t ssrc_ = 0; + bool cached_track_enabled_ = false; + bool stopped_ = false; // Used to pass the data callback from the |track_| to the other end of // cricket::AudioRenderer. @@ -107,9 +133,12 @@ public rtc::RefCountedObject<RtpSenderInterface> { public: VideoRtpSender(VideoTrackInterface* track, - uint32_t ssrc, + const std::string& stream_id, VideoProviderInterface* provider); + // Randomly generates id and stream_id. + explicit VideoRtpSender(VideoProviderInterface* provider); + virtual ~VideoRtpSender(); // ObserverInterface implementation @@ -121,18 +150,36 @@ return track_.get(); } + void SetSsrc(uint32_t ssrc) override; + + uint32_t ssrc() const override { return ssrc_; } + + cricket::MediaType media_type() const override { + return cricket::MEDIA_TYPE_VIDEO; + } + std::string id() const override { return id_; } + void set_stream_id(const std::string& stream_id) override { + stream_id_ = stream_id; + } + std::string stream_id() const override { return stream_id_; } + void Stop() override; private: - void Reconfigure(); + bool can_send_track() const { return track_ && ssrc_; } + // Helper function to construct options for + // VideoProviderInterface::SetVideoSend. + void SetVideoSend(); std::string id_; - rtc::scoped_refptr<VideoTrackInterface> track_; - uint32_t ssrc_; + std::string stream_id_; VideoProviderInterface* provider_; - bool cached_track_enabled_; + rtc::scoped_refptr<VideoTrackInterface> track_; + uint32_t ssrc_ = 0; + bool cached_track_enabled_ = false; + bool stopped_ = false; }; } // namespace webrtc
diff --git a/talk/app/webrtc/rtpsenderinterface.h b/talk/app/webrtc/rtpsenderinterface.h index fca98f2..f54e8ca 100644 --- a/talk/app/webrtc/rtpsenderinterface.h +++ b/talk/app/webrtc/rtpsenderinterface.h
@@ -35,6 +35,7 @@ #include "talk/app/webrtc/proxy.h" #include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/session/media/mediasession.h" #include "webrtc/base/refcount.h" #include "webrtc/base/scoped_ref_ptr.h" @@ -47,10 +48,24 @@ virtual bool SetTrack(MediaStreamTrackInterface* track) = 0; virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0; + // Used to set the SSRC of the sender, once a local description has been set. + // If |ssrc| is 0, this indiates that the sender should disconnect from the + // underlying transport (this occurs if the sender isn't seen in a local + // description). + virtual void SetSsrc(uint32_t ssrc) = 0; + virtual uint32_t ssrc() const = 0; + + // Audio or video sender? + virtual cricket::MediaType media_type() const = 0; + // Not to be confused with "mid", this is a field we can temporarily use // to uniquely identify a receiver until we implement Unified Plan SDP. virtual std::string id() const = 0; + // TODO(deadbeef): Support one sender having multiple stream ids. + virtual void set_stream_id(const std::string& stream_id) = 0; + virtual std::string stream_id() const = 0; + virtual void Stop() = 0; protected: @@ -61,7 +76,12 @@ BEGIN_PROXY_MAP(RtpSender) PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*) PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track) +PROXY_METHOD1(void, SetSsrc, uint32_t) +PROXY_CONSTMETHOD0(uint32_t, ssrc) +PROXY_CONSTMETHOD0(cricket::MediaType, media_type) PROXY_CONSTMETHOD0(std::string, id) +PROXY_METHOD1(void, set_stream_id, const std::string&) +PROXY_CONSTMETHOD0(std::string, stream_id) PROXY_METHOD0(void, Stop) END_PROXY()
diff --git a/talk/app/webrtc/rtpsenderreceiver_unittest.cc b/talk/app/webrtc/rtpsenderreceiver_unittest.cc index c9d7e00..a590e1d 100644 --- a/talk/app/webrtc/rtpsenderreceiver_unittest.cc +++ b/talk/app/webrtc/rtpsenderreceiver_unittest.cc
@@ -26,6 +26,7 @@ */ #include <string> +#include <utility> #include "talk/app/webrtc/audiotrack.h" #include "talk/app/webrtc/mediastream.h" @@ -48,14 +49,17 @@ static const char kVideoTrackId[] = "video_1"; static const char kAudioTrackId[] = "audio_1"; static const uint32_t kVideoSsrc = 98; +static const uint32_t kVideoSsrc2 = 100; static const uint32_t kAudioSsrc = 99; +static const uint32_t kAudioSsrc2 = 101; namespace webrtc { // Helper class to test RtpSender/RtpReceiver. class MockAudioProvider : public AudioProviderInterface { public: - virtual ~MockAudioProvider() {} + ~MockAudioProvider() override {} + MOCK_METHOD2(SetAudioPlayout, void(uint32_t ssrc, bool enable)); @@ -65,6 +69,14 @@ const cricket::AudioOptions& options, cricket::AudioRenderer* renderer)); MOCK_METHOD2(SetAudioPlayoutVolume, void(uint32_t ssrc, double volume)); + + void SetRawAudioSink(uint32_t, + rtc::scoped_ptr<AudioSinkInterface> sink) override { + sink_ = std::move(sink); + } + + private: + rtc::scoped_ptr<AudioSinkInterface> sink_; }; // Helper class to test RtpSender/RtpReceiver. @@ -85,8 +97,8 @@ class FakeVideoSource : public Notifier<VideoSourceInterface> { public: - static rtc::scoped_refptr<FakeVideoSource> Create() { - return new rtc::RefCountedObject<FakeVideoSource>(); + static rtc::scoped_refptr<FakeVideoSource> Create(bool remote) { + return new rtc::RefCountedObject<FakeVideoSource>(remote); } virtual cricket::VideoCapturer* GetVideoCapturer() { return &fake_capturer_; } virtual void Stop() {} @@ -94,16 +106,18 @@ virtual void AddSink(cricket::VideoRenderer* output) {} virtual void RemoveSink(cricket::VideoRenderer* output) {} virtual SourceState state() const { return state_; } + virtual bool remote() const { return remote_; } virtual const cricket::VideoOptions* options() const { return &options_; } virtual cricket::VideoRenderer* FrameInput() { return NULL; } protected: - FakeVideoSource() : state_(kLive) {} + explicit FakeVideoSource(bool remote) : state_(kLive), remote_(remote) {} ~FakeVideoSource() {} private: cricket::FakeVideoCapturer fake_capturer_; SourceState state_; + bool remote_; cricket::VideoOptions options_; }; @@ -111,7 +125,11 @@ public: virtual void SetUp() { stream_ = MediaStream::Create(kStreamLabel1); - rtc::scoped_refptr<VideoSourceInterface> source(FakeVideoSource::Create()); + } + + void AddVideoTrack(bool remote) { + rtc::scoped_refptr<VideoSourceInterface> source( + FakeVideoSource::Create(remote)); video_track_ = VideoTrack::Create(kVideoTrackId, source); EXPECT_TRUE(stream_->AddTrack(video_track_)); } @@ -120,17 +138,21 @@ audio_track_ = AudioTrack::Create(kAudioTrackId, NULL); EXPECT_TRUE(stream_->AddTrack(audio_track_)); EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _)); - audio_rtp_sender_ = new AudioRtpSender(stream_->GetAudioTracks()[0], - kAudioSsrc, &audio_provider_); + audio_rtp_sender_ = + new AudioRtpSender(stream_->GetAudioTracks()[0], stream_->label(), + &audio_provider_, nullptr); + audio_rtp_sender_->SetSsrc(kAudioSsrc); } void CreateVideoRtpSender() { + AddVideoTrack(false); EXPECT_CALL(video_provider_, SetCaptureDevice( kVideoSsrc, video_track_->GetSource()->GetVideoCapturer())); EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, true, _)); video_rtp_sender_ = new VideoRtpSender(stream_->GetVideoTracks()[0], - kVideoSsrc, &video_provider_); + stream_->label(), &video_provider_); + video_rtp_sender_->SetSsrc(kVideoSsrc); } void DestroyAudioRtpSender() { @@ -146,8 +168,8 @@ } void CreateAudioRtpReceiver() { - audio_track_ = - AudioTrack::Create(kAudioTrackId, RemoteAudioSource::Create().get()); + audio_track_ = AudioTrack::Create( + kAudioTrackId, RemoteAudioSource::Create(kAudioSsrc, NULL)); EXPECT_TRUE(stream_->AddTrack(audio_track_)); EXPECT_CALL(audio_provider_, SetAudioPlayout(kAudioSsrc, true)); audio_rtp_receiver_ = new AudioRtpReceiver(stream_->GetAudioTracks()[0], @@ -155,6 +177,7 @@ } void CreateVideoRtpReceiver() { + AddVideoTrack(true); EXPECT_CALL(video_provider_, SetVideoPlayout(kVideoSsrc, true, video_track_->GetSource()->FrameInput())); @@ -280,4 +303,212 @@ DestroyAudioRtpReceiver(); } +// Test that provider methods aren't called without both a track and an SSRC. +TEST_F(RtpSenderReceiverTest, AudioSenderWithoutTrackAndSsrc) { + rtc::scoped_refptr<AudioRtpSender> sender = + new AudioRtpSender(&audio_provider_, nullptr); + rtc::scoped_refptr<AudioTrackInterface> track = + AudioTrack::Create(kAudioTrackId, nullptr); + EXPECT_TRUE(sender->SetTrack(track)); + EXPECT_TRUE(sender->SetTrack(nullptr)); + sender->SetSsrc(kAudioSsrc); + sender->SetSsrc(0); + // Just let it get destroyed and make sure it doesn't call any methods on the + // provider interface. +} + +// Test that provider methods aren't called without both a track and an SSRC. +TEST_F(RtpSenderReceiverTest, VideoSenderWithoutTrackAndSsrc) { + rtc::scoped_refptr<VideoRtpSender> sender = + new VideoRtpSender(&video_provider_); + EXPECT_TRUE(sender->SetTrack(video_track_)); + EXPECT_TRUE(sender->SetTrack(nullptr)); + sender->SetSsrc(kVideoSsrc); + sender->SetSsrc(0); + // Just let it get destroyed and make sure it doesn't call any methods on the + // provider interface. +} + +// Test that an audio sender calls the expected methods on the provider once +// it has a track and SSRC, when the SSRC is set first. +TEST_F(RtpSenderReceiverTest, AudioSenderEarlyWarmupSsrcThenTrack) { + rtc::scoped_refptr<AudioRtpSender> sender = + new AudioRtpSender(&audio_provider_, nullptr); + rtc::scoped_refptr<AudioTrackInterface> track = + AudioTrack::Create(kAudioTrackId, nullptr); + sender->SetSsrc(kAudioSsrc); + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _)); + sender->SetTrack(track); + + // Calls expected from destructor. + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, false, _, _)).Times(1); +} + +// Test that an audio sender calls the expected methods on the provider once +// it has a track and SSRC, when the SSRC is set last. +TEST_F(RtpSenderReceiverTest, AudioSenderEarlyWarmupTrackThenSsrc) { + rtc::scoped_refptr<AudioRtpSender> sender = + new AudioRtpSender(&audio_provider_, nullptr); + rtc::scoped_refptr<AudioTrackInterface> track = + AudioTrack::Create(kAudioTrackId, nullptr); + sender->SetTrack(track); + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _)); + sender->SetSsrc(kAudioSsrc); + + // Calls expected from destructor. + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, false, _, _)).Times(1); +} + +// Test that a video sender calls the expected methods on the provider once +// it has a track and SSRC, when the SSRC is set first. +TEST_F(RtpSenderReceiverTest, VideoSenderEarlyWarmupSsrcThenTrack) { + AddVideoTrack(false); + rtc::scoped_refptr<VideoRtpSender> sender = + new VideoRtpSender(&video_provider_); + sender->SetSsrc(kVideoSsrc); + EXPECT_CALL(video_provider_, + SetCaptureDevice(kVideoSsrc, + video_track_->GetSource()->GetVideoCapturer())); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, true, _)); + sender->SetTrack(video_track_); + + // Calls expected from destructor. + EXPECT_CALL(video_provider_, SetCaptureDevice(kVideoSsrc, nullptr)).Times(1); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, false, _)).Times(1); +} + +// Test that a video sender calls the expected methods on the provider once +// it has a track and SSRC, when the SSRC is set last. +TEST_F(RtpSenderReceiverTest, VideoSenderEarlyWarmupTrackThenSsrc) { + AddVideoTrack(false); + rtc::scoped_refptr<VideoRtpSender> sender = + new VideoRtpSender(&video_provider_); + sender->SetTrack(video_track_); + EXPECT_CALL(video_provider_, + SetCaptureDevice(kVideoSsrc, + video_track_->GetSource()->GetVideoCapturer())); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, true, _)); + sender->SetSsrc(kVideoSsrc); + + // Calls expected from destructor. + EXPECT_CALL(video_provider_, SetCaptureDevice(kVideoSsrc, nullptr)).Times(1); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, false, _)).Times(1); +} + +// Test that the sender is disconnected from the provider when its SSRC is +// set to 0. +TEST_F(RtpSenderReceiverTest, AudioSenderSsrcSetToZero) { + rtc::scoped_refptr<AudioTrackInterface> track = + AudioTrack::Create(kAudioTrackId, nullptr); + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _)); + rtc::scoped_refptr<AudioRtpSender> sender = + new AudioRtpSender(track, kStreamLabel1, &audio_provider_, nullptr); + sender->SetSsrc(kAudioSsrc); + + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, false, _, _)).Times(1); + sender->SetSsrc(0); + + // Make sure it's SetSsrc that called methods on the provider, and not the + // destructor. + EXPECT_CALL(audio_provider_, SetAudioSend(_, _, _, _)).Times(0); +} + +// Test that the sender is disconnected from the provider when its SSRC is +// set to 0. +TEST_F(RtpSenderReceiverTest, VideoSenderSsrcSetToZero) { + AddVideoTrack(false); + EXPECT_CALL(video_provider_, + SetCaptureDevice(kVideoSsrc, + video_track_->GetSource()->GetVideoCapturer())); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, true, _)); + rtc::scoped_refptr<VideoRtpSender> sender = + new VideoRtpSender(video_track_, kStreamLabel1, &video_provider_); + sender->SetSsrc(kVideoSsrc); + + EXPECT_CALL(video_provider_, SetCaptureDevice(kVideoSsrc, nullptr)).Times(1); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, false, _)).Times(1); + sender->SetSsrc(0); + + // Make sure it's SetSsrc that called methods on the provider, and not the + // destructor. + EXPECT_CALL(video_provider_, SetCaptureDevice(_, _)).Times(0); + EXPECT_CALL(video_provider_, SetVideoSend(_, _, _)).Times(0); +} + +TEST_F(RtpSenderReceiverTest, AudioSenderTrackSetToNull) { + rtc::scoped_refptr<AudioTrackInterface> track = + AudioTrack::Create(kAudioTrackId, nullptr); + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _)); + rtc::scoped_refptr<AudioRtpSender> sender = + new AudioRtpSender(track, kStreamLabel1, &audio_provider_, nullptr); + sender->SetSsrc(kAudioSsrc); + + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, false, _, _)).Times(1); + EXPECT_TRUE(sender->SetTrack(nullptr)); + + // Make sure it's SetTrack that called methods on the provider, and not the + // destructor. + EXPECT_CALL(audio_provider_, SetAudioSend(_, _, _, _)).Times(0); +} + +TEST_F(RtpSenderReceiverTest, VideoSenderTrackSetToNull) { + AddVideoTrack(false); + EXPECT_CALL(video_provider_, + SetCaptureDevice(kVideoSsrc, + video_track_->GetSource()->GetVideoCapturer())); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, true, _)); + rtc::scoped_refptr<VideoRtpSender> sender = + new VideoRtpSender(video_track_, kStreamLabel1, &video_provider_); + sender->SetSsrc(kVideoSsrc); + + EXPECT_CALL(video_provider_, SetCaptureDevice(kVideoSsrc, nullptr)).Times(1); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, false, _)).Times(1); + EXPECT_TRUE(sender->SetTrack(nullptr)); + + // Make sure it's SetTrack that called methods on the provider, and not the + // destructor. + EXPECT_CALL(video_provider_, SetCaptureDevice(_, _)).Times(0); + EXPECT_CALL(video_provider_, SetVideoSend(_, _, _)).Times(0); +} + +TEST_F(RtpSenderReceiverTest, AudioSenderSsrcChanged) { + AddVideoTrack(false); + rtc::scoped_refptr<AudioTrackInterface> track = + AudioTrack::Create(kAudioTrackId, nullptr); + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _)); + rtc::scoped_refptr<AudioRtpSender> sender = + new AudioRtpSender(track, kStreamLabel1, &audio_provider_, nullptr); + sender->SetSsrc(kAudioSsrc); + + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, false, _, _)).Times(1); + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc2, true, _, _)).Times(1); + sender->SetSsrc(kAudioSsrc2); + + // Calls expected from destructor. + EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc2, false, _, _)).Times(1); +} + +TEST_F(RtpSenderReceiverTest, VideoSenderSsrcChanged) { + AddVideoTrack(false); + EXPECT_CALL(video_provider_, + SetCaptureDevice(kVideoSsrc, + video_track_->GetSource()->GetVideoCapturer())); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, true, _)); + rtc::scoped_refptr<VideoRtpSender> sender = + new VideoRtpSender(video_track_, kStreamLabel1, &video_provider_); + sender->SetSsrc(kVideoSsrc); + + EXPECT_CALL(video_provider_, SetCaptureDevice(kVideoSsrc, nullptr)).Times(1); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc, false, _)).Times(1); + EXPECT_CALL(video_provider_, + SetCaptureDevice(kVideoSsrc2, + video_track_->GetSource()->GetVideoCapturer())); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc2, true, _)); + sender->SetSsrc(kVideoSsrc2); + + // Calls expected from destructor. + EXPECT_CALL(video_provider_, SetCaptureDevice(kVideoSsrc2, nullptr)).Times(1); + EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc2, false, _)).Times(1); +} + } // namespace webrtc
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc index 347a846..b514b42 100644 --- a/talk/app/webrtc/statscollector.cc +++ b/talk/app/webrtc/statscollector.cc
@@ -115,17 +115,17 @@ report->AddString(StatsReport::kStatsValueNameCodecName, info.codec_name); } -void SetAudioProcessingStats(StatsReport* report, int signal_level, - bool typing_noise_detected, int echo_return_loss, - int echo_return_loss_enhancement, int echo_delay_median_ms, - float aec_quality_min, int echo_delay_std_ms) { +void SetAudioProcessingStats(StatsReport* report, + bool typing_noise_detected, + int echo_return_loss, + int echo_return_loss_enhancement, + int echo_delay_median_ms, + float aec_quality_min, + int echo_delay_std_ms) { report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState, typing_noise_detected); report->AddFloat(StatsReport::kStatsValueNameEchoCancellationQualityMin, aec_quality_min); - // Don't overwrite the previous signal level if it's not available now. - if (signal_level >= 0) - report->AddInt(StatsReport::kStatsValueNameAudioInputLevel, signal_level); const IntForAdd ints[] = { { StatsReport::kStatsValueNameEchoReturnLoss, echo_return_loss }, { StatsReport::kStatsValueNameEchoReturnLossEnhancement, @@ -182,11 +182,14 @@ void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) { ExtractCommonSendProperties(info, report); - SetAudioProcessingStats(report, info.audio_level, info.typing_noise_detected, - info.echo_return_loss, info.echo_return_loss_enhancement, - info.echo_delay_median_ms, info.aec_quality_min, info.echo_delay_std_ms); + SetAudioProcessingStats( + report, info.typing_noise_detected, info.echo_return_loss, + info.echo_return_loss_enhancement, info.echo_delay_median_ms, + info.aec_quality_min, info.echo_delay_std_ms); + RTC_DCHECK_GE(info.audio_level, 0); const IntForAdd ints[] = { + { StatsReport::kStatsValueNameAudioInputLevel, info.audio_level}, { StatsReport::kStatsValueNameJitterReceived, info.jitter_ms }, { StatsReport::kStatsValueNamePacketsLost, info.packets_lost }, { StatsReport::kStatsValueNamePacketsSent, info.packets_sent }, @@ -198,6 +201,8 @@ void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) { ExtractCommonReceiveProperties(info, report); + report->AddString(StatsReport::kStatsValueNameCodecImplementationName, + info.decoder_implementation_name); report->AddInt64(StatsReport::kStatsValueNameBytesReceived, info.bytes_rcvd); report->AddInt64(StatsReport::kStatsValueNameCaptureStartNtpTimeMs, @@ -230,6 +235,8 @@ void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) { ExtractCommonSendProperties(info, report); + report->AddString(StatsReport::kStatsValueNameCodecImplementationName, + info.encoder_implementation_name); report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution, (info.adapt_reason & 0x2) > 0); report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution, @@ -730,17 +737,20 @@ channel_report->AddId(StatsReport::kStatsValueNameRemoteCertificateId, remote_cert_report_id); } - const std::string& srtp_cipher = channel_iter.srtp_cipher; - if (!srtp_cipher.empty()) { - channel_report->AddString(StatsReport::kStatsValueNameSrtpCipher, - srtp_cipher); + int srtp_crypto_suite = channel_iter.srtp_crypto_suite; + if (srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE && + rtc::SrtpCryptoSuiteToName(srtp_crypto_suite).length()) { + channel_report->AddString( + StatsReport::kStatsValueNameSrtpCipher, + rtc::SrtpCryptoSuiteToName(srtp_crypto_suite)); } - int ssl_cipher = channel_iter.ssl_cipher; - if (ssl_cipher && - rtc::SSLStreamAdapter::GetSslCipherSuiteName(ssl_cipher).length()) { + int ssl_cipher_suite = channel_iter.ssl_cipher_suite; + if (ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL && + rtc::SSLStreamAdapter::SslCipherSuiteToName(ssl_cipher_suite) + .length()) { channel_report->AddString( StatsReport::kStatsValueNameDtlsCipher, - rtc::SSLStreamAdapter::GetSslCipherSuiteName(ssl_cipher)); + rtc::SSLStreamAdapter::SslCipherSuiteToName(ssl_cipher_suite)); } int connection_id = 0; @@ -888,21 +898,24 @@ RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent()); RTC_DCHECK(track != NULL); - int signal_level = 0; - if (!track->GetSignalLevel(&signal_level)) - signal_level = -1; + // Don't overwrite report values if they're not available. + int signal_level; + if (track->GetSignalLevel(&signal_level)) { + RTC_DCHECK_GE(signal_level, 0); + report->AddInt(StatsReport::kStatsValueNameAudioInputLevel, signal_level); + } - rtc::scoped_refptr<AudioProcessorInterface> audio_processor( - track->GetAudioProcessor()); + auto audio_processor(track->GetAudioProcessor()); - AudioProcessorInterface::AudioProcessorStats stats; - if (audio_processor.get()) + if (audio_processor.get()) { + AudioProcessorInterface::AudioProcessorStats stats; audio_processor->GetStats(&stats); - SetAudioProcessingStats(report, signal_level, stats.typing_noise_detected, - stats.echo_return_loss, stats.echo_return_loss_enhancement, - stats.echo_delay_median_ms, stats.aec_quality_min, - stats.echo_delay_std_ms); + SetAudioProcessingStats( + report, stats.typing_noise_detected, stats.echo_return_loss, + stats.echo_return_loss_enhancement, stats.echo_delay_median_ms, + stats.aec_quality_min, stats.echo_delay_std_ms); + } } bool StatsCollector::GetTrackIdBySsrc(uint32_t ssrc,
diff --git a/talk/app/webrtc/statscollector.h b/talk/app/webrtc/statscollector.h index 18a345d..56db79d 100644 --- a/talk/app/webrtc/statscollector.h +++ b/talk/app/webrtc/statscollector.h
@@ -36,7 +36,6 @@ #include <vector> #include "talk/app/webrtc/mediastreaminterface.h" -#include "talk/app/webrtc/mediastreamsignaling.h" #include "talk/app/webrtc/peerconnectioninterface.h" #include "talk/app/webrtc/statstypes.h" #include "talk/app/webrtc/webrtcsession.h"
diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc index 9121c69..e7ee911 100644 --- a/talk/app/webrtc/statscollector_unittest.cc +++ b/talk/app/webrtc/statscollector_unittest.cc
@@ -35,7 +35,6 @@ #include "talk/app/webrtc/peerconnectionfactory.h" #include "talk/app/webrtc/mediastream.h" #include "talk/app/webrtc/mediastreaminterface.h" -#include "talk/app/webrtc/mediastreamsignaling.h" #include "talk/app/webrtc/mediastreamtrack.h" #include "talk/app/webrtc/test/fakedatachannelprovider.h" #include "talk/app/webrtc/videotrack.h" @@ -683,8 +682,8 @@ // Fake stats to process. cricket::TransportChannelStats channel_stats; channel_stats.component = 1; - channel_stats.srtp_cipher = "the-srtp-cipher"; - channel_stats.ssl_cipher = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + channel_stats.srtp_crypto_suite = rtc::SRTP_AES128_CM_SHA1_80; + channel_stats.ssl_cipher_suite = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; cricket::TransportStats transport_stats; transport_stats.transport_name = "audio"; @@ -697,8 +696,7 @@ // Fake certificate to report rtc::scoped_refptr<rtc::RTCCertificate> local_certificate( rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::FakeSSLIdentity>( - new rtc::FakeSSLIdentity(local_cert)) - .Pass())); + new rtc::FakeSSLIdentity(local_cert)))); // Configure MockWebRtcSession EXPECT_CALL(session_, @@ -747,18 +745,17 @@ } // Check negotiated ciphers. - std::string dtls_cipher = ExtractStatsValue( - StatsReport::kStatsReportTypeComponent, - reports, - StatsReport::kStatsValueNameDtlsCipher); - EXPECT_EQ(rtc::SSLStreamAdapter::GetSslCipherSuiteName( + std::string dtls_cipher_suite = + ExtractStatsValue(StatsReport::kStatsReportTypeComponent, reports, + StatsReport::kStatsValueNameDtlsCipher); + EXPECT_EQ(rtc::SSLStreamAdapter::SslCipherSuiteToName( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA), - dtls_cipher); - std::string srtp_cipher = ExtractStatsValue( - StatsReport::kStatsReportTypeComponent, - reports, - StatsReport::kStatsValueNameSrtpCipher); - EXPECT_EQ("the-srtp-cipher", srtp_cipher); + dtls_cipher_suite); + std::string srtp_crypto_suite = + ExtractStatsValue(StatsReport::kStatsReportTypeComponent, reports, + StatsReport::kStatsValueNameSrtpCipher); + EXPECT_EQ(rtc::SrtpCryptoSuiteToName(rtc::SRTP_AES128_CM_SHA1_80), + srtp_crypto_suite); } cricket::FakeMediaEngine* media_engine_; @@ -1407,16 +1404,14 @@ ASSERT_EQ(kNotFound, remote_certificate_id); // Check that the negotiated ciphers are absent. - std::string dtls_cipher = ExtractStatsValue( - StatsReport::kStatsReportTypeComponent, - reports, - StatsReport::kStatsValueNameDtlsCipher); - ASSERT_EQ(kNotFound, dtls_cipher); - std::string srtp_cipher = ExtractStatsValue( - StatsReport::kStatsReportTypeComponent, - reports, - StatsReport::kStatsValueNameSrtpCipher); - ASSERT_EQ(kNotFound, srtp_cipher); + std::string dtls_cipher_suite = + ExtractStatsValue(StatsReport::kStatsReportTypeComponent, reports, + StatsReport::kStatsValueNameDtlsCipher); + ASSERT_EQ(kNotFound, dtls_cipher_suite); + std::string srtp_crypto_suite = + ExtractStatsValue(StatsReport::kStatsReportTypeComponent, reports, + StatsReport::kStatsValueNameSrtpCipher); + ASSERT_EQ(kNotFound, srtp_crypto_suite); } // This test verifies that the stats are generated correctly when the transport
diff --git a/talk/app/webrtc/statstypes.cc b/talk/app/webrtc/statstypes.cc index e45833c..19cb1f5 100644 --- a/talk/app/webrtc/statstypes.cc +++ b/talk/app/webrtc/statstypes.cc
@@ -408,6 +408,8 @@ return "state"; case kStatsValueNameDataChannelId: return "datachannelid"; + case kStatsValueNameCodecImplementationName: + return "codecImplementationName"; // 'goog' prefixed constants. case kStatsValueNameAccelerateRate: @@ -592,9 +594,6 @@ return "googViewLimitedResolution"; case kStatsValueNameWritable: return "googWritable"; - default: - RTC_DCHECK(false); - break; } return nullptr;
diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h index 7fa9f32..60439b9 100644 --- a/talk/app/webrtc/statstypes.h +++ b/talk/app/webrtc/statstypes.h
@@ -120,6 +120,7 @@ kStatsValueNameAudioOutputLevel, kStatsValueNameBytesReceived, kStatsValueNameBytesSent, + kStatsValueNameCodecImplementationName, kStatsValueNameDataChannelId, kStatsValueNamePacketsLost, kStatsValueNamePacketsReceived,
diff --git a/talk/app/webrtc/test/DEPS b/talk/app/webrtc/test/DEPS new file mode 100644 index 0000000..a814b15 --- /dev/null +++ b/talk/app/webrtc/test/DEPS
@@ -0,0 +1,5 @@ +include_rules = [ + # Allow include of Chrome base/android to allow inclusion of headers needed + # for accessing the JVM and Application context in gtest. + "+base/android", +]
diff --git a/talk/app/webrtc/test/androidtestinitializer.cc b/talk/app/webrtc/test/androidtestinitializer.cc new file mode 100644 index 0000000..883c2d8 --- /dev/null +++ b/talk/app/webrtc/test/androidtestinitializer.cc
@@ -0,0 +1,74 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/app/webrtc/test/androidtestinitializer.h" + +#include <pthread.h> + +// Note: this dependency is dangerous since it reaches into Chromium's base. +// There's a risk of e.g. macro clashes. This file may only be used in tests. +// Since we use Chromes build system for creating the gtest binary, this should +// be fine. +#include "base/android/context_utils.h" +#include "base/android/jni_android.h" + +#include "talk/app/webrtc/java/jni/classreferenceholder.h" +#include "talk/app/webrtc/java/jni/jni_helpers.h" +#include "webrtc/base/checks.h" +#include "webrtc/base/ssladapter.h" +#include "webrtc/voice_engine/include/voe_base.h" + +namespace webrtc { + +namespace { + +static pthread_once_t g_initialize_once = PTHREAD_ONCE_INIT; + +// There can only be one JNI_OnLoad in each binary. So since this is a GTEST +// C++ runner binary, we want to initialize the same global objects we normally +// do if this had been a Java binary. +void EnsureInitializedOnce() { + RTC_CHECK(::base::android::IsVMInitialized()); + JNIEnv* jni = ::base::android::AttachCurrentThread(); + JavaVM* jvm = NULL; + RTC_CHECK_EQ(0, jni->GetJavaVM(&jvm)); + jobject context = ::base::android::GetApplicationContext(); + + RTC_CHECK_GE(webrtc_jni::InitGlobalJniVariables(jvm), 0); + RTC_CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()"; + webrtc_jni::LoadGlobalClassReferenceHolder(); + + webrtc::VoiceEngine::SetAndroidObjects(jvm, context); +} + +} // anonymous namespace + +void InitializeAndroidObjects() { + RTC_CHECK_EQ(0, pthread_once(&g_initialize_once, &EnsureInitializedOnce)); +} + +} // namespace webrtc
diff --git a/talk/app/webrtc/test/androidtestinitializer.h b/talk/app/webrtc/test/androidtestinitializer.h new file mode 100644 index 0000000..e699282 --- /dev/null +++ b/talk/app/webrtc/test/androidtestinitializer.h
@@ -0,0 +1,37 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TALK_APP_WEBRTC_TEST_ANDROIDTESTINITIALIZER_H_ +#define TALK_APP_WEBRTC_TEST_ANDROIDTESTINITIALIZER_H_ + +namespace webrtc { + +void InitializeAndroidObjects(); + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_TEST_ANDROIDTESTINITIALIZER_H_
diff --git a/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc b/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc index e2dc123..6b675a9 100644 --- a/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc +++ b/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc
@@ -58,7 +58,7 @@ int32_t RecordedDataIsAvailable(const void* audioSamples, const size_t nSamples, const size_t nBytesPerSample, - const uint8_t nChannels, + const size_t nChannels, const uint32_t samplesPerSec, const uint32_t totalDelayMS, const int32_t clockDrift, @@ -82,7 +82,7 @@ // ADM is pulling data. int32_t NeedMorePlayData(const size_t nSamples, const size_t nBytesPerSample, - const uint8_t nChannels, + const size_t nChannels, const uint32_t samplesPerSec, void* audioSamples, size_t& nSamplesOut,
diff --git a/talk/app/webrtc/test/fakedtlsidentitystore.h b/talk/app/webrtc/test/fakedtlsidentitystore.h index 0f9bdb9..98074c7 100644 --- a/talk/app/webrtc/test/fakedtlsidentitystore.h +++ b/talk/app/webrtc/test/fakedtlsidentitystore.h
@@ -29,41 +29,73 @@ #define TALK_APP_WEBRTC_TEST_FAKEDTLSIDENTITYSERVICE_H_ #include <string> +#include <utility> #include "talk/app/webrtc/dtlsidentitystore.h" #include "talk/app/webrtc/peerconnectioninterface.h" #include "webrtc/base/rtccertificate.h" -static const char kRSA_PRIVATE_KEY_PEM[] = - "-----BEGIN RSA PRIVATE KEY-----\n" - "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n" - "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n" - "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n" - "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n" - "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n" - "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n" - "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n" - "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n" - "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n" - "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n" - "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n" - "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n" - "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n" - "UCXiYxSsu20QNVw=\n" - "-----END RSA PRIVATE KEY-----\n"; - -static const char kCERT_PEM[] = - "-----BEGIN CERTIFICATE-----\n" - "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n" - "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n" - "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n" - "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n" - "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n" - "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n" - "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n" - "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n" - "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n" - "-----END CERTIFICATE-----\n"; +static const struct { + const char* rsa_private_key_pem; + const char* cert_pem; +} kKeysAndCerts[] = { + {"-----BEGIN RSA PRIVATE KEY-----\n" + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n" + "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n" + "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n" + "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n" + "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n" + "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n" + "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n" + "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n" + "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n" + "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n" + "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n" + "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n" + "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n" + "UCXiYxSsu20QNVw=\n" + "-----END RSA PRIVATE KEY-----\n", + "-----BEGIN CERTIFICATE-----\n" + "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n" + "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n" + "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n" + "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n" + "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n" + "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n" + "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n" + "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n" + "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n" + "-----END CERTIFICATE-----\n"}, + {"-----BEGIN RSA PRIVATE KEY-----\n" + "MIICXQIBAAKBgQDeYqlyJ1wuiMsi905e3X81/WA/G3ym50PIDZBVtSwZi7JVQPgj\n" + "Bl8CPZMvDh9EwB4Ji9ytA8dZZbQ4WbJWPr73zPpJSCvQqz6sOXSlenBRi72acNaQ\n" + "sOR/qPvviJx5I6Hqo4qemfnjZhAW85a5BpgrAwKgMLIQTHCTLWwVSyrDrwIDAQAB\n" + "AoGARni9eY8/hv+SX+I+05EdXt6MQXNUbQ+cSykBNCfVccLzIFEWUQMT2IHqwl6X\n" + "ShIXcq7/n1QzOAEiuzixauM3YHg4xZ1Um2Ha9a7ig5Xg4v6b43bmMkNE6LkoAtYs\n" + "qnQdfMh442b1liDud6IMb1Qk0amt3fSrgRMc547TZQVx4QECQQDxUeDm94r3p4ng\n" + "5rCLLC1K5/6HSTZsh7jatKPlz7GfP/IZlYV7iE5784/n0wRiCjZOS7hQRy/8m2Gp\n" + "pf4aZq+DAkEA6+np4d36FYikydvUrupLT3FkdRHGn/v83qOll/VmeNh+L1xMZlIP\n" + "tM26hAXCcQb7O5+J9y3cx2CAQsBS11ZXZQJAfGgTo76WG9p5UEJdXUInD2jOZPwv\n" + "XIATolxh6kXKcijLLLlSmT7KB0inNYIpzkkpee+7U1d/u6B3FriGaSHq9QJBAM/J\n" + "ICnDdLCgwNvWVraVQC3BpwSB2pswvCFwq7py94V60XFvbw80Ogc6qIv98qvQxVlX\n" + "hJIEgA/PjEi+0ng94Q0CQQDm8XSDby35gmjO+6eRmJtAjtB7nguLvrPXM6CPXRmD\n" + "sRoBocpHw6j9UdzZ6qYG0FkdXZghezXFY58ro2BYYRR3\n" + "-----END RSA PRIVATE KEY-----\n", + "-----BEGIN CERTIFICATE-----\n" + "MIICWDCCAcGgAwIBAgIJALgDjxMbBOhbMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n" + "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n" + "aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTEzMjIzMjEzWhcNMTYxMTEyMjIzMjEzWjBF\n" + "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + "gQDeYqlyJ1wuiMsi905e3X81/WA/G3ym50PIDZBVtSwZi7JVQPgjBl8CPZMvDh9E\n" + "wB4Ji9ytA8dZZbQ4WbJWPr73zPpJSCvQqz6sOXSlenBRi72acNaQsOR/qPvviJx5\n" + "I6Hqo4qemfnjZhAW85a5BpgrAwKgMLIQTHCTLWwVSyrDrwIDAQABo1AwTjAdBgNV\n" + "HQ4EFgQUx2tbJdlcSTCepn09UdYORXKuSTAwHwYDVR0jBBgwFoAUx2tbJdlcSTCe\n" + "pn09UdYORXKuSTAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAmp9Id\n" + "E716gHMqeBG4S2FCgVFCr0a0ugkaneQAN/c2L9CbMemEN9W6jvucUIVOtYd90dDW\n" + "lXuowWmT/JctPe3D2qt4yvYW3puECHk2tVQmrJOZiZiTRtWm6HxkmoUYHYp/DtaS\n" + "1Xe29gSTnZtI5sQCrGMzk3SGRSSs7ejLKiVDBQ==\n" + "-----END CERTIFICATE-----\n"}}; class FakeDtlsIdentityStore : public webrtc::DtlsIdentityStoreInterface, public rtc::MessageHandler { @@ -77,6 +109,9 @@ should_fail_ = should_fail; } + void use_original_key() { key_index_ = 0; } + void use_alternate_key() { key_index_ = 1; } + void RequestIdentity( rtc::KeyType key_type, const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& @@ -92,8 +127,9 @@ static rtc::scoped_refptr<rtc::RTCCertificate> GenerateCertificate() { std::string cert; std::string key; - rtc::SSLIdentity::PemToDer("CERTIFICATE", kCERT_PEM, &cert); - rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", kRSA_PRIVATE_KEY_PEM, &key); + rtc::SSLIdentity::PemToDer("CERTIFICATE", kKeysAndCerts[0].cert_pem, &cert); + rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", + kKeysAndCerts[0].rsa_private_key_pem, &key); std::string pem_cert = rtc::SSLIdentity::DerToPem( rtc::kPemTypeCertificate, @@ -106,7 +142,7 @@ rtc::scoped_ptr<rtc::SSLIdentity> identity( rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert)); - return rtc::RTCCertificate::Create(identity.Pass()); + return rtc::RTCCertificate::Create(std::move(identity)); } private: @@ -115,6 +151,11 @@ MSG_FAILURE, }; + const char* get_key() { + return kKeysAndCerts[key_index_].rsa_private_key_pem; + } + const char* get_cert() { return kKeysAndCerts[key_index_].cert_pem; } + // rtc::MessageHandler implementation. void OnMessage(rtc::Message* msg) { MessageData* message_data = static_cast<MessageData*>(msg->pdata); @@ -124,9 +165,8 @@ case MSG_SUCCESS: { std::string cert; std::string key; - rtc::SSLIdentity::PemToDer("CERTIFICATE", kCERT_PEM, &cert); - rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", kRSA_PRIVATE_KEY_PEM, - &key); + rtc::SSLIdentity::PemToDer("CERTIFICATE", get_cert(), &cert); + rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", get_key(), &key); observer->OnSuccess(cert, key); break; } @@ -138,6 +178,7 @@ } bool should_fail_; + int key_index_ = 0; }; #endif // TALK_APP_WEBRTC_TEST_FAKEDTLSIDENTITYSERVICE_H_
diff --git a/talk/app/webrtc/test/fakemediastreamsignaling.h b/talk/app/webrtc/test/fakemediastreamsignaling.h deleted file mode 100644 index 562c4ad..0000000 --- a/talk/app/webrtc/test/fakemediastreamsignaling.h +++ /dev/null
@@ -1,140 +0,0 @@ -/* - * libjingle - * Copyright 2013 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_APP_WEBRTC_TEST_FAKEMEDIASTREAMSIGNALING_H_ -#define TALK_APP_WEBRTC_TEST_FAKEMEDIASTREAMSIGNALING_H_ - -#include "talk/app/webrtc/audiotrack.h" -#include "talk/app/webrtc/mediastreamsignaling.h" -#include "talk/app/webrtc/videotrack.h" - -static const char kStream1[] = "stream1"; -static const char kVideoTrack1[] = "video1"; -static const char kAudioTrack1[] = "audio1"; - -static const char kStream2[] = "stream2"; -static const char kVideoTrack2[] = "video2"; -static const char kAudioTrack2[] = "audio2"; - -class FakeMediaStreamSignaling : public webrtc::MediaStreamSignaling, - public webrtc::MediaStreamSignalingObserver { - public: - explicit FakeMediaStreamSignaling(cricket::ChannelManager* channel_manager) : - webrtc::MediaStreamSignaling(rtc::Thread::Current(), this, - channel_manager) { - } - - void SendAudioVideoStream1() { - ClearLocalStreams(); - AddLocalStream(CreateStream(kStream1, kAudioTrack1, kVideoTrack1)); - } - - void SendAudioVideoStream2() { - ClearLocalStreams(); - AddLocalStream(CreateStream(kStream2, kAudioTrack2, kVideoTrack2)); - } - - void SendAudioVideoStream1And2() { - ClearLocalStreams(); - AddLocalStream(CreateStream(kStream1, kAudioTrack1, kVideoTrack1)); - AddLocalStream(CreateStream(kStream2, kAudioTrack2, kVideoTrack2)); - } - - void SendNothing() { - ClearLocalStreams(); - } - - void UseOptionsAudioOnly() { - ClearLocalStreams(); - AddLocalStream(CreateStream(kStream2, kAudioTrack2, "")); - } - - void UseOptionsVideoOnly() { - ClearLocalStreams(); - AddLocalStream(CreateStream(kStream2, "", kVideoTrack2)); - } - - void ClearLocalStreams() { - while (local_streams()->count() != 0) { - RemoveLocalStream(local_streams()->at(0)); - } - } - - // Implements MediaStreamSignalingObserver. - virtual void OnAddRemoteStream(webrtc::MediaStreamInterface* stream) {} - virtual void OnRemoveRemoteStream(webrtc::MediaStreamInterface* stream) {} - virtual void OnAddDataChannel(webrtc::DataChannelInterface* data_channel) {} - virtual void OnAddLocalAudioTrack(webrtc::MediaStreamInterface* stream, - webrtc::AudioTrackInterface* audio_track, - uint32_t ssrc) {} - virtual void OnAddLocalVideoTrack(webrtc::MediaStreamInterface* stream, - webrtc::VideoTrackInterface* video_track, - uint32_t ssrc) {} - virtual void OnAddRemoteAudioTrack(webrtc::MediaStreamInterface* stream, - webrtc::AudioTrackInterface* audio_track, - uint32_t ssrc) {} - virtual void OnAddRemoteVideoTrack(webrtc::MediaStreamInterface* stream, - webrtc::VideoTrackInterface* video_track, - uint32_t ssrc) {} - virtual void OnRemoveRemoteAudioTrack( - webrtc::MediaStreamInterface* stream, - webrtc::AudioTrackInterface* audio_track) {} - virtual void OnRemoveRemoteVideoTrack( - webrtc::MediaStreamInterface* stream, - webrtc::VideoTrackInterface* video_track) {} - virtual void OnRemoveLocalAudioTrack(webrtc::MediaStreamInterface* stream, - webrtc::AudioTrackInterface* audio_track, - uint32_t ssrc) {} - virtual void OnRemoveLocalVideoTrack( - webrtc::MediaStreamInterface* stream, - webrtc::VideoTrackInterface* video_track) {} - virtual void OnRemoveLocalStream(webrtc::MediaStreamInterface* stream) {} - - private: - rtc::scoped_refptr<webrtc::MediaStreamInterface> CreateStream( - const std::string& stream_label, - const std::string& audio_track_id, - const std::string& video_track_id) { - rtc::scoped_refptr<webrtc::MediaStreamInterface> stream( - webrtc::MediaStream::Create(stream_label)); - - if (!audio_track_id.empty()) { - rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( - webrtc::AudioTrack::Create(audio_track_id, NULL)); - stream->AddTrack(audio_track); - } - - if (!video_track_id.empty()) { - rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track( - webrtc::VideoTrack::Create(video_track_id, NULL)); - stream->AddTrack(video_track); - } - return stream; - } -}; - -#endif // TALK_APP_WEBRTC_TEST_FAKEMEDIASTREAMSIGNALING_H_
diff --git a/talk/app/webrtc/test/peerconnectiontestwrapper.cc b/talk/app/webrtc/test/peerconnectiontestwrapper.cc index 2eb24d9..86b7842 100644 --- a/talk/app/webrtc/test/peerconnectiontestwrapper.cc +++ b/talk/app/webrtc/test/peerconnectiontestwrapper.cc
@@ -25,13 +25,15 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "talk/app/webrtc/fakeportallocatorfactory.h" +#include <utility> + #include "talk/app/webrtc/test/fakedtlsidentitystore.h" #include "talk/app/webrtc/test/fakeperiodicvideocapturer.h" #include "talk/app/webrtc/test/mockpeerconnectionobservers.h" #include "talk/app/webrtc/test/peerconnectiontestwrapper.h" #include "talk/app/webrtc/videosourceinterface.h" #include "webrtc/base/gunit.h" +#include "webrtc/p2p/client/fakeportallocator.h" static const char kStreamLabelBase[] = "stream_label"; static const char kVideoTrackLabelBase[] = "video_track"; @@ -70,10 +72,8 @@ bool PeerConnectionTestWrapper::CreatePc( const MediaConstraintsInterface* constraints) { - allocator_factory_ = webrtc::FakePortAllocatorFactory::Create(); - if (!allocator_factory_) { - return false; - } + rtc::scoped_ptr<cricket::PortAllocator> port_allocator( + new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr)); fake_audio_capture_module_ = FakeAudioCaptureModule::Create(); if (fake_audio_capture_module_ == NULL) { @@ -87,17 +87,17 @@ return false; } - // CreatePeerConnection with IceServers. - webrtc::PeerConnectionInterface::IceServers ice_servers; + // CreatePeerConnection with RTCConfiguration. + webrtc::PeerConnectionInterface::RTCConfiguration config; webrtc::PeerConnectionInterface::IceServer ice_server; ice_server.uri = "stun:stun.l.google.com:19302"; - ice_servers.push_back(ice_server); + config.servers.push_back(ice_server); rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store( rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeDtlsIdentityStore() : nullptr); peer_connection_ = peer_connection_factory_->CreatePeerConnection( - ice_servers, constraints, allocator_factory_.get(), - dtls_identity_store.Pass(), this); + config, constraints, std::move(port_allocator), + std::move(dtls_identity_store), this); return peer_connection_.get() != NULL; }
diff --git a/talk/app/webrtc/test/peerconnectiontestwrapper.h b/talk/app/webrtc/test/peerconnectiontestwrapper.h index b654263..883f2f2 100644 --- a/talk/app/webrtc/test/peerconnectiontestwrapper.h +++ b/talk/app/webrtc/test/peerconnectiontestwrapper.h
@@ -34,11 +34,6 @@ #include "talk/app/webrtc/test/fakevideotrackrenderer.h" #include "webrtc/base/sigslot.h" -namespace webrtc { -class DtlsIdentityStoreInterface; -class PortAllocatorFactoryInterface; -} - class PeerConnectionTestWrapper : public webrtc::PeerConnectionObserver, public webrtc::CreateSessionDescriptionObserver, @@ -110,8 +105,6 @@ bool video, const webrtc::FakeConstraints& video_constraints); std::string name_; - rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface> - allocator_factory_; rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_; rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory_;
diff --git a/talk/app/webrtc/videosource.cc b/talk/app/webrtc/videosource.cc index b33f5f9..4b371e3 100644 --- a/talk/app/webrtc/videosource.cc +++ b/talk/app/webrtc/videosource.cc
@@ -32,6 +32,7 @@ #include "talk/app/webrtc/mediaconstraintsinterface.h" #include "talk/session/media/channelmanager.h" +#include "webrtc/base/arraysize.h" using cricket::CaptureState; using webrtc::MediaConstraintsInterface; @@ -267,11 +268,12 @@ // Set |option| to the highest-priority value of |key| in the constraints. // Return false if the key is mandatory, and the value is invalid. bool ExtractOption(const MediaConstraintsInterface* all_constraints, - const std::string& key, cricket::Settable<bool>* option) { + const std::string& key, + rtc::Optional<bool>* option) { size_t mandatory = 0; bool value; if (FindConstraint(all_constraints, key, &value, &mandatory)) { - option->Set(value); + *option = rtc::Optional<bool>(value); return true; } @@ -302,8 +304,6 @@ virtual ~FrameInputWrapper() {} // VideoRenderer implementation. - bool SetSize(int width, int height, int reserved) override { return true; } - bool RenderFrame(const cricket::VideoFrame* frame) override { if (!capturer_->IsRunning()) { return true; @@ -329,21 +329,23 @@ rtc::scoped_refptr<VideoSource> VideoSource::Create( cricket::ChannelManager* channel_manager, cricket::VideoCapturer* capturer, - const webrtc::MediaConstraintsInterface* constraints) { + const webrtc::MediaConstraintsInterface* constraints, + bool remote) { ASSERT(channel_manager != NULL); ASSERT(capturer != NULL); - rtc::scoped_refptr<VideoSource> source( - new rtc::RefCountedObject<VideoSource>(channel_manager, - capturer)); + rtc::scoped_refptr<VideoSource> source(new rtc::RefCountedObject<VideoSource>( + channel_manager, capturer, remote)); source->Initialize(constraints); return source; } VideoSource::VideoSource(cricket::ChannelManager* channel_manager, - cricket::VideoCapturer* capturer) + cricket::VideoCapturer* capturer, + bool remote) : channel_manager_(channel_manager), video_capturer_(capturer), - state_(kInitializing) { + state_(kInitializing), + remote_(remote) { channel_manager_->SignalVideoCaptureStateChange.connect( this, &VideoSource::OnStateChange); } @@ -368,7 +370,7 @@ } else { // The VideoCapturer implementation doesn't support capability // enumeration. We need to guess what the camera supports. - for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) { + for (int i = 0; i < arraysize(kVideoFormats); ++i) { formats.push_back(cricket::VideoFormat(kVideoFormats[i])); } } @@ -460,7 +462,9 @@ } void VideoSource::SetState(SourceState new_state) { - if (VERIFY(state_ != new_state)) { + // TODO(hbos): Temporarily disabled VERIFY due to webrtc:4776. + // if (VERIFY(state_ != new_state)) { + if (state_ != new_state) { state_ = new_state; FireOnChanged(); }
diff --git a/talk/app/webrtc/videosource.h b/talk/app/webrtc/videosource.h index 8253cba..98c1e08 100644 --- a/talk/app/webrtc/videosource.h +++ b/talk/app/webrtc/videosource.h
@@ -66,9 +66,12 @@ static rtc::scoped_refptr<VideoSource> Create( cricket::ChannelManager* channel_manager, cricket::VideoCapturer* capturer, - const webrtc::MediaConstraintsInterface* constraints); + const webrtc::MediaConstraintsInterface* constraints, + bool remote); - virtual SourceState state() const { return state_; } + SourceState state() const override { return state_; } + bool remote() const override { return remote_; } + virtual const cricket::VideoOptions* options() const { return &options_; } virtual cricket::VideoRenderer* FrameInput(); @@ -86,7 +89,8 @@ protected: VideoSource(cricket::ChannelManager* channel_manager, - cricket::VideoCapturer* capturer); + cricket::VideoCapturer* capturer, + bool remote); virtual ~VideoSource(); void Initialize(const webrtc::MediaConstraintsInterface* constraints); @@ -104,6 +108,7 @@ cricket::VideoFormat format_; cricket::VideoOptions options_; SourceState state_; + const bool remote_; }; } // namespace webrtc
diff --git a/talk/app/webrtc/videosource_unittest.cc b/talk/app/webrtc/videosource_unittest.cc index 2efcc1d..6f1df34 100644 --- a/talk/app/webrtc/videosource_unittest.cc +++ b/talk/app/webrtc/videosource_unittest.cc
@@ -144,9 +144,9 @@ void CreateVideoSource( const webrtc::MediaConstraintsInterface* constraints) { // VideoSource take ownership of |capturer_| - source_ = VideoSource::Create(channel_manager_.get(), - capturer_cleanup_.release(), - constraints); + source_ = + VideoSource::Create(channel_manager_.get(), capturer_cleanup_.release(), + constraints, false); ASSERT_TRUE(source_.get() != NULL); EXPECT_EQ(capturer_, source_->GetVideoCapturer()); @@ -210,8 +210,7 @@ // RemoteVideoCapturer and takes video frames from FrameInput. TEST_F(VideoSourceTest, StartStopRemote) { source_ = VideoSource::Create(channel_manager_.get(), - new webrtc::RemoteVideoCapturer(), - NULL); + new webrtc::RemoteVideoCapturer(), NULL, true); ASSERT_TRUE(source_.get() != NULL); EXPECT_TRUE(NULL != source_->GetVideoCapturer()); @@ -392,16 +391,14 @@ CreateVideoSource(&constraints); - bool value = true; - EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value)); - EXPECT_FALSE(value); + EXPECT_EQ(rtc::Optional<bool>(false), + source_->options()->video_noise_reduction); } TEST_F(VideoSourceTest, OptionNotSet) { FakeConstraints constraints; CreateVideoSource(&constraints); - bool value; - EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value)); + EXPECT_EQ(rtc::Optional<bool>(), source_->options()->video_noise_reduction); } TEST_F(VideoSourceTest, MandatoryOptionOverridesOptional) { @@ -413,9 +410,8 @@ CreateVideoSource(&constraints); - bool value = false; - EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value)); - EXPECT_TRUE(value); + EXPECT_EQ(rtc::Optional<bool>(true), + source_->options()->video_noise_reduction); } TEST_F(VideoSourceTest, InvalidOptionKeyOptional) { @@ -428,9 +424,8 @@ EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), kMaxWaitMs); - bool value = true; - EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value)); - EXPECT_FALSE(value); + EXPECT_EQ(rtc::Optional<bool>(false), + source_->options()->video_noise_reduction); } TEST_F(VideoSourceTest, InvalidOptionKeyMandatory) { @@ -443,8 +438,7 @@ EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), kMaxWaitMs); - bool value; - EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value)); + EXPECT_EQ(rtc::Optional<bool>(), source_->options()->video_noise_reduction); } TEST_F(VideoSourceTest, InvalidOptionValueOptional) { @@ -456,8 +450,7 @@ EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), kMaxWaitMs); - bool value = false; - EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value)); + EXPECT_EQ(rtc::Optional<bool>(), source_->options()->video_noise_reduction); } TEST_F(VideoSourceTest, InvalidOptionValueMandatory) { @@ -473,8 +466,7 @@ EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), kMaxWaitMs); - bool value; - EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value)); + EXPECT_EQ(rtc::Optional<bool>(), source_->options()->video_noise_reduction); } TEST_F(VideoSourceTest, MixedOptionsAndConstraints) { @@ -497,9 +489,8 @@ EXPECT_EQ(288, format->height); EXPECT_EQ(30, format->framerate()); - bool value = true; - EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value)); - EXPECT_FALSE(value); + EXPECT_EQ(rtc::Optional<bool>(false), + source_->options()->video_noise_reduction); } // Tests that the source starts video with the default resolution for
diff --git a/talk/app/webrtc/videosourceproxy.h b/talk/app/webrtc/videosourceproxy.h index 677fa9c..ce96e8e 100644 --- a/talk/app/webrtc/videosourceproxy.h +++ b/talk/app/webrtc/videosourceproxy.h
@@ -38,6 +38,7 @@ // signaling thread. BEGIN_PROXY_MAP(VideoSource) PROXY_CONSTMETHOD0(SourceState, state) + PROXY_CONSTMETHOD0(bool, remote) PROXY_METHOD0(cricket::VideoCapturer*, GetVideoCapturer) PROXY_METHOD0(void, Stop) PROXY_METHOD0(void, Restart)
diff --git a/talk/app/webrtc/videotrack.cc b/talk/app/webrtc/videotrack.cc index 7c78aea..f138240 100644 --- a/talk/app/webrtc/videotrack.cc +++ b/talk/app/webrtc/videotrack.cc
@@ -31,7 +31,7 @@ namespace webrtc { -static const char kVideoTrackKind[] = "video"; +const char MediaStreamTrackInterface::kVideoKind[] = "video"; VideoTrack::VideoTrack(const std::string& label, VideoSourceInterface* video_source) @@ -47,7 +47,7 @@ } std::string VideoTrack::kind() const { - return kVideoTrackKind; + return kVideoKind; } void VideoTrack::AddRenderer(VideoRendererInterface* renderer) {
diff --git a/talk/app/webrtc/videotrack_unittest.cc b/talk/app/webrtc/videotrack_unittest.cc index 609ee80..013d925 100644 --- a/talk/app/webrtc/videotrack_unittest.cc +++ b/talk/app/webrtc/videotrack_unittest.cc
@@ -62,7 +62,7 @@ video_track_ = VideoTrack::Create( kVideoTrackId, VideoSource::Create(channel_manager_.get(), - new webrtc::RemoteVideoCapturer(), NULL)); + new webrtc::RemoteVideoCapturer(), NULL, true)); } protected:
diff --git a/talk/app/webrtc/videotrackrenderers.cc b/talk/app/webrtc/videotrackrenderers.cc index 3c47c6e..3f9301b 100644 --- a/talk/app/webrtc/videotrackrenderers.cc +++ b/talk/app/webrtc/videotrackrenderers.cc
@@ -54,10 +54,6 @@ enabled_ = enable; } -bool VideoTrackRenderers::SetSize(int width, int height, int reserved) { - return true; -} - bool VideoTrackRenderers::RenderFrame(const cricket::VideoFrame* frame) { rtc::CritScope cs(&critical_section_); if (!enabled_) {
diff --git a/talk/app/webrtc/videotrackrenderers.h b/talk/app/webrtc/videotrackrenderers.h index 15274a1..3262e22 100644 --- a/talk/app/webrtc/videotrackrenderers.h +++ b/talk/app/webrtc/videotrackrenderers.h
@@ -48,7 +48,6 @@ ~VideoTrackRenderers(); // Implements cricket::VideoRenderer - virtual bool SetSize(int width, int height, int reserved); virtual bool RenderFrame(const cricket::VideoFrame* frame); void AddRenderer(VideoRendererInterface* renderer);
diff --git a/talk/app/webrtc/webrtcsdp.cc b/talk/app/webrtc/webrtcsdp.cc index 3fa9a7d..e287e90 100644 --- a/talk/app/webrtc/webrtcsdp.cc +++ b/talk/app/webrtc/webrtcsdp.cc
@@ -45,6 +45,7 @@ #include "webrtc/p2p/base/constants.h" #include "webrtc/p2p/base/port.h" #include "talk/session/media/mediasession.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" #include "webrtc/base/messagedigest.h" @@ -121,6 +122,7 @@ static const char kAttributeGroup[] = "group"; static const char kAttributeMid[] = "mid"; static const char kAttributeRtcpMux[] = "rtcp-mux"; +static const char kAttributeRtcpReducedSize[] = "rtcp-rsize"; static const char kAttributeSsrc[] = "ssrc"; static const char kSsrcAttributeCname[] = "cname"; static const char kAttributeExtmap[] = "extmap"; @@ -138,8 +140,8 @@ static const char kAttributeCandidateTyp[] = "typ"; static const char kAttributeCandidateRaddr[] = "raddr"; static const char kAttributeCandidateRport[] = "rport"; -static const char kAttributeCandidateUsername[] = "username"; -static const char kAttributeCandidatePassword[] = "password"; +static const char kAttributeCandidateUfrag[] = "ufrag"; +static const char kAttributeCandidatePwd[] = "pwd"; static const char kAttributeCandidateGeneration[] = "generation"; static const char kAttributeFingerprint[] = "fingerprint"; static const char kAttributeSetup[] = "setup"; @@ -260,6 +262,7 @@ const MediaType media_type, std::string* message); static void BuildCandidate(const std::vector<Candidate>& candidates, + bool include_ufrag, std::string* message); static void BuildIceOptions(const std::vector<std::string>& transport_options, std::string* message); @@ -876,7 +879,7 @@ std::string message; std::vector<cricket::Candidate> candidates; candidates.push_back(candidate.candidate()); - BuildCandidate(candidates, &message); + BuildCandidate(candidates, true, &message); // From WebRTC draft section 4.8.1.1 candidate-attribute will be // just candidate:<candidate> not a=candidate:<blah>CRLF ASSERT(message.find("a=") == 0); @@ -1070,10 +1073,9 @@ } // Extension - // Empty string as the candidate username and password. - // Will be updated later with the ice-ufrag and ice-pwd. - // TODO: Remove the username/password extension, which is currently - // kept for backwards compatibility. + // Though non-standard, we support the ICE ufrag and pwd being signaled on + // the candidate to avoid issues with confusing which generation a candidate + // belongs to when trickling multiple generations at the same time. std::string username; std::string password; uint32_t generation = 0; @@ -1084,9 +1086,9 @@ if (!GetValueFromString(first_line, fields[++i], &generation, error)) { return false; } - } else if (fields[i] == kAttributeCandidateUsername) { + } else if (fields[i] == kAttributeCandidateUfrag) { username = fields[++i]; - } else if (fields[i] == kAttributeCandidatePassword) { + } else if (fields[i] == kAttributeCandidatePwd) { password = fields[++i]; } else { // Skip the unknown extension. @@ -1283,8 +1285,9 @@ } } - // Build the a=candidate lines. - BuildCandidate(candidates, message); + // Build the a=candidate lines. We don't include ufrag and pwd in the + // candidates in the SDP to avoid redundancy. + BuildCandidate(candidates, false, message); // Use the transport_info to build the media level ice-ufrag and ice-pwd. if (transport_info) { @@ -1292,13 +1295,17 @@ // ice-pwd-att = "ice-pwd" ":" password // ice-ufrag-att = "ice-ufrag" ":" ufrag // ice-ufrag - InitAttrLine(kAttributeIceUfrag, &os); - os << kSdpDelimiterColon << transport_info->description.ice_ufrag; - AddLine(os.str(), message); + if (!transport_info->description.ice_ufrag.empty()) { + InitAttrLine(kAttributeIceUfrag, &os); + os << kSdpDelimiterColon << transport_info->description.ice_ufrag; + AddLine(os.str(), message); + } // ice-pwd - InitAttrLine(kAttributeIcePwd, &os); - os << kSdpDelimiterColon << transport_info->description.ice_pwd; - AddLine(os.str(), message); + if (!transport_info->description.ice_pwd.empty()) { + InitAttrLine(kAttributeIcePwd, &os); + os << kSdpDelimiterColon << transport_info->description.ice_pwd; + AddLine(os.str(), message); + } // draft-petithuguenin-mmusic-ice-attributes-level-03 BuildIceOptions(transport_info->description.transport_options, message); @@ -1399,6 +1406,13 @@ AddLine(os.str(), message); } + // RFC 5506 + // a=rtcp-rsize + if (media_desc->rtcp_reduced_size()) { + InitAttrLine(kAttributeRtcpReducedSize, &os); + AddLine(os.str(), message); + } + // RFC 4568 // a=crypto:<tag> <crypto-suite> <key-params> [<session-params>] for (std::vector<CryptoParams>::const_iterator it = @@ -1525,7 +1539,7 @@ kCodecParamMaxAverageBitrate, kCodecParamMaxPlaybackRate, kCodecParamAssociatedPayloadType }; - for (size_t i = 0; i < ARRAY_SIZE(kFmtpParams); ++i) { + for (size_t i = 0; i < arraysize(kFmtpParams); ++i) { if (_stricmp(name.c_str(), kFmtpParams[i]) == 0) { return true; } @@ -1708,6 +1722,7 @@ } void BuildCandidate(const std::vector<Candidate>& candidates, + bool include_ufrag, std::string* message) { std::ostringstream os; @@ -1757,6 +1772,9 @@ // Extensions os << kAttributeCandidateGeneration << " " << it->generation(); + if (include_ufrag && !it->username().empty()) { + os << " " << kAttributeCandidateUfrag << " " << it->username(); + } AddLine(os.str(), message); } @@ -2046,7 +2064,7 @@ struct StaticPayloadAudioCodec { const char* name; int clockrate; - int channels; + size_t channels; }; static const StaticPayloadAudioCodec kStaticPayloadAudioCodecs[] = { { "PCMU", 8000, 1 }, @@ -2082,10 +2100,10 @@ int payload_type = *it; if (!media_desc->HasCodec(payload_type) && payload_type >= 0 && - payload_type < ARRAY_SIZE(kStaticPayloadAudioCodecs)) { + payload_type < arraysize(kStaticPayloadAudioCodecs)) { std::string encoding_name = kStaticPayloadAudioCodecs[payload_type].name; int clock_rate = kStaticPayloadAudioCodecs[payload_type].clockrate; - int channels = kStaticPayloadAudioCodecs[payload_type].channels; + size_t channels = kStaticPayloadAudioCodecs[payload_type].channels; media_desc->AddCodec(cricket::AudioCodec(payload_type, encoding_name, clock_rate, 0, channels, preference)); @@ -2552,6 +2570,8 @@ // if (HasAttribute(line, kAttributeRtcpMux)) { media_desc->set_rtcp_mux(true); + } else if (HasAttribute(line, kAttributeRtcpReducedSize)) { + media_desc->set_rtcp_reduced_size(true); } else if (HasAttribute(line, kAttributeSsrcGroup)) { if (!ParseSsrcGroupAttribute(line, &ssrc_groups, error)) { return false; @@ -2666,7 +2686,8 @@ // Update the candidates with the media level "ice-pwd" and "ice-ufrag". for (Candidates::iterator it = candidates_orig.begin(); it != candidates_orig.end(); ++it) { - ASSERT((*it).username().empty()); + ASSERT((*it).username().empty() || + (*it).username() == transport->ice_ufrag); (*it).set_username(transport->ice_ufrag); ASSERT((*it).password().empty()); (*it).set_password(transport->ice_pwd); @@ -2817,7 +2838,7 @@ // Updates or creates a new codec entry in the audio description with according // to |name|, |clockrate|, |bitrate|, |channels| and |preference|. void UpdateCodec(int payload_type, const std::string& name, int clockrate, - int bitrate, int channels, int preference, + int bitrate, size_t channels, int preference, AudioContentDescription* audio_desc) { // Codec may already be populated with (only) optional parameters // (from an fmtp). @@ -2916,7 +2937,7 @@ // of audio channels. This parameter is OPTIONAL and may be // omitted if the number of channels is one, provided that no // additional parameters are needed. - int channels = 1; + size_t channels = 1; if (codec_params.size() == 3) { if (!GetValueFromString(line, codec_params[2], &channels, error)) { return false;
diff --git a/talk/app/webrtc/webrtcsdp_unittest.cc b/talk/app/webrtc/webrtcsdp_unittest.cc index cb6a392..15fc808 100644 --- a/talk/app/webrtc/webrtcsdp_unittest.cc +++ b/talk/app/webrtc/webrtcsdp_unittest.cc
@@ -30,6 +30,9 @@ #include <vector> #include "talk/app/webrtc/jsepsessiondescription.h" +#ifdef WEBRTC_ANDROID +#include "talk/app/webrtc/test/androidtestinitializer.h" +#endif #include "talk/app/webrtc/webrtcsdp.h" #include "talk/media/base/constants.h" #include "webrtc/p2p/base/constants.h" @@ -80,11 +83,13 @@ static const uint32_t kCandidatePriority = 2130706432U; // pref = 1.0 static const char kCandidateUfragVoice[] = "ufrag_voice"; static const char kCandidatePwdVoice[] = "pwd_voice"; +static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n"; static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n"; static const char kCandidateUfragVideo[] = "ufrag_video"; static const char kCandidatePwdVideo[] = "pwd_video"; static const char kCandidateUfragData[] = "ufrag_data"; static const char kCandidatePwdData[] = "pwd_data"; +static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n"; static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n"; static const uint32_t kCandidateGeneration = 2; static const char kCandidateFoundation1[] = "a0+B/1"; @@ -153,6 +158,7 @@ "a=mid:audio_content_name\r\n" "a=sendrecv\r\n" "a=rtcp-mux\r\n" + "a=rtcp-rsize\r\n" "a=crypto:1 AES_CM_128_HMAC_SHA1_32 " "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 " "dummy_session_params\r\n" @@ -220,6 +226,7 @@ "a=mid:audio_content_name\r\n" "a=sendrecv\r\n" "a=rtcp-mux\r\n" + "a=rtcp-rsize\r\n" "a=crypto:1 AES_CM_128_HMAC_SHA1_32 " "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 " "dummy_session_params\r\n" @@ -394,9 +401,9 @@ "abcd::abcd::abcd::abcd::abcd::abcd::abcd::abcd 1234 typ host generation 2"; // One candidate reference string. -static const char kSdpOneCandidateOldFormat[] = +static const char kSdpOneCandidateWithUfragPwd[] = "a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name" - " eth0 username user_rtp password password_rtp generation 2\r\n"; + " eth0 ufrag user_rtp pwd password_rtp generation 2\r\n"; // Session id and version static const char kSessionId[] = "18446744069414584320"; @@ -523,10 +530,14 @@ static void ReplaceRejected(bool audio_rejected, bool video_rejected, std::string* message) { if (audio_rejected) { - Replace("m=audio 2345", "m=audio 0", message); + Replace("m=audio 9", "m=audio 0", message); + Replace(kAttributeIceUfragVoice, "", message); + Replace(kAttributeIcePwdVoice, "", message); } if (video_rejected) { - Replace("m=video 3457", "m=video 0", message); + Replace("m=video 9", "m=video 0", message); + Replace(kAttributeIceUfragVideo, "", message); + Replace(kAttributeIcePwdVideo, "", message); } } @@ -536,6 +547,9 @@ public: WebRtcSdpTest() : jdesc_(kDummyString) { +#ifdef WEBRTC_ANDROID + webrtc::InitializeAndroidObjects(); +#endif // AudioContentDescription audio_desc_ = CreateAudioContentDescription(); AudioCodec opus(111, "opus", 48000, 0, 2, 3); @@ -704,6 +718,7 @@ AudioContentDescription* CreateAudioContentDescription() { AudioContentDescription* audio = new AudioContentDescription(); audio->set_rtcp_mux(true); + audio->set_rtcp_reduced_size(true); StreamParams audio_stream1; audio_stream1.id = kAudioTrackId1; audio_stream1.cname = kStream1Cname; @@ -735,6 +750,9 @@ // rtcp_mux EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux()); + // rtcp_reduced_size + EXPECT_EQ(cd1->rtcp_reduced_size(), cd2->rtcp_reduced_size()); + // cryptos EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size()); if (cd1->cryptos().size() != cd2->cryptos().size()) { @@ -979,6 +997,18 @@ desc_.AddTransportInfo(transport_info); } + void SetIceUfragPwd(const std::string& content_name, + const std::string& ice_ufrag, + const std::string& ice_pwd) { + ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL); + cricket::TransportInfo transport_info = + *(desc_.GetTransportInfoByName(content_name)); + desc_.RemoveTransportInfoByName(content_name); + transport_info.description.ice_ufrag = ice_ufrag; + transport_info.description.ice_pwd = ice_pwd; + desc_.AddTransportInfo(transport_info); + } + void AddFingerprint() { desc_.RemoveTransportInfoByName(kAudioContentName); desc_.RemoveTransportInfoByName(kVideoContentName); @@ -1050,15 +1080,22 @@ audio_desc_); desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected, video_desc_); - std::string new_sdp = kSdpFullString; + SetIceUfragPwd(kAudioContentName, + audio_rejected ? "" : kCandidateUfragVoice, + audio_rejected ? "" : kCandidatePwdVoice); + SetIceUfragPwd(kVideoContentName, + video_rejected ? "" : kCandidateUfragVideo, + video_rejected ? "" : kCandidatePwdVideo); + + std::string new_sdp = kSdpString; ReplaceRejected(audio_rejected, video_rejected, &new_sdp); - if (!jdesc_.Initialize(desc_.Copy(), - jdesc_.session_id(), - jdesc_.session_version())) { + JsepSessionDescription jdesc_no_candidates(kDummyString); + if (!jdesc_no_candidates.Initialize(desc_.Copy(), kSessionId, + kSessionVersion)) { return false; } - std::string message = webrtc::SdpSerialize(jdesc_); + std::string message = webrtc::SdpSerialize(jdesc_no_candidates); EXPECT_EQ(new_sdp, message); return true; } @@ -1121,11 +1158,11 @@ } bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) { - std::string new_sdp = kSdpFullString; + std::string new_sdp = kSdpString; ReplaceRejected(audio_rejected, video_rejected, &new_sdp); JsepSessionDescription new_jdesc(JsepSessionDescription::kOffer); - EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc)); + audio_desc_ = static_cast<AudioContentDescription*>( audio_desc_->Copy()); video_desc_ = static_cast<VideoContentDescription*>( @@ -1136,12 +1173,18 @@ audio_desc_); desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected, video_desc_); - if (!jdesc_.Initialize(desc_.Copy(), - jdesc_.session_id(), - jdesc_.session_version())) { + SetIceUfragPwd(kAudioContentName, + audio_rejected ? "" : kCandidateUfragVoice, + audio_rejected ? "" : kCandidatePwdVoice); + SetIceUfragPwd(kVideoContentName, + video_rejected ? "" : kCandidateUfragVideo, + video_rejected ? "" : kCandidatePwdVideo); + JsepSessionDescription jdesc_no_candidates(kDummyString); + if (!jdesc_no_candidates.Initialize(desc_.Copy(), jdesc_.session_id(), + jdesc_.session_version())) { return false; } - EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc)); + EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc)); return true; } @@ -1540,8 +1583,8 @@ TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) { // JsepSessionDescription with desc but without candidates. JsepSessionDescription jdesc_no_candidates(kDummyString); - ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(), - kSessionId, kSessionVersion)); + ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(), kSessionId, + kSessionVersion)); std::string message = webrtc::SdpSerialize(jdesc_no_candidates); EXPECT_EQ(std::string(kSdpString), message); } @@ -1721,6 +1764,13 @@ TEST_F(WebRtcSdpTest, SerializeCandidates) { std::string message = webrtc::SdpSerializeCandidate(*jcandidate_); EXPECT_EQ(std::string(kRawCandidate), message); + + Candidate candidate_with_ufrag(candidates_.front()); + candidate_with_ufrag.set_username("ABC"); + jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"), 0, + candidate_with_ufrag)); + message = webrtc::SdpSerializeCandidate(*jcandidate_); + EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message); } // TODO(mallinath) : Enable this test once WebRTCSdp capable of parsing @@ -2317,9 +2367,10 @@ EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate())); } -TEST_F(WebRtcSdpTest, DeserializeCandidateOldFormat) { +TEST_F(WebRtcSdpTest, DeserializeCandidateWithUfragPwd) { JsepIceCandidate jcandidate(kDummyMid, kDummyIndex); - EXPECT_TRUE(SdpDeserializeCandidate(kSdpOneCandidateOldFormat,&jcandidate)); + EXPECT_TRUE( + SdpDeserializeCandidate(kSdpOneCandidateWithUfragPwd, &jcandidate)); EXPECT_EQ(kDummyMid, jcandidate.sdp_mid()); EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index()); Candidate ref_candidate = jcandidate_->candidate();
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc index 95abeab..d8f7637 100644 --- a/talk/app/webrtc/webrtcsession.cc +++ b/talk/app/webrtc/webrtcsession.cc
@@ -30,13 +30,13 @@ #include <limits.h> #include <algorithm> -#include <vector> #include <set> +#include <utility> +#include <vector> #include "talk/app/webrtc/jsepicecandidate.h" #include "talk/app/webrtc/jsepsessiondescription.h" #include "talk/app/webrtc/mediaconstraintsinterface.h" -#include "talk/app/webrtc/mediastreamsignaling.h" #include "talk/app/webrtc/peerconnectioninterface.h" #include "talk/app/webrtc/sctputils.h" #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" @@ -45,6 +45,7 @@ #include "talk/session/media/channel.h" #include "talk/session/media/channelmanager.h" #include "talk/session/media/mediasession.h" +#include "webrtc/audio/audio_sink.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/checks.h" #include "webrtc/base/helpers.h" @@ -441,10 +442,11 @@ // Set |option| to the highest-priority value of |key| in the optional // constraints if the key is found and has a valid value. -template<typename T> +template <typename T> static void SetOptionFromOptionalConstraint( const MediaConstraintsInterface* constraints, - const std::string& key, cricket::Settable<T>* option) { + const std::string& key, + rtc::Optional<T>* option) { if (!constraints) { return; } @@ -452,7 +454,7 @@ T value; if (constraints->GetOptional().FindFirst(key, &string_value)) { if (rtc::FromString(string_value, &value)) { - option->Set(value); + *option = rtc::Optional<T>(value); } } } @@ -492,9 +494,13 @@ } } + // This method has two purposes: 1. Return whether |new_desc| requests + // an ICE restart (i.e., new ufrag/pwd). 2. If it requests an ICE restart + // and it is an OFFER, remember this in |ice_restart_| so that the next + // Local Answer will be created with new ufrag and pwd. bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc, const SessionDescriptionInterface* new_desc) { - if (!old_desc || new_desc->type() != SessionDescriptionInterface::kOffer) { + if (!old_desc) { return false; } const SessionDescription* new_sd = new_desc->description(); @@ -520,7 +526,9 @@ new_transport_desc->ice_ufrag, new_transport_desc->ice_pwd)) { LOG(LS_INFO) << "Remote peer request ice restart."; - ice_restart_ = true; + if (new_desc->type() == SessionDescriptionInterface::kOffer) { + ice_restart_ = true; + } return true; } } @@ -593,6 +601,8 @@ const PeerConnectionInterface::RTCConfiguration& rtc_configuration) { bundle_policy_ = rtc_configuration.bundle_policy; rtcp_mux_policy_ = rtc_configuration.rtcp_mux_policy; + video_options_.disable_prerenderer_smoothing = + rtc::Optional<bool>(rtc_configuration.disable_prerenderer_smoothing); transport_controller_->SetSslMaxProtocolVersion(options.ssl_max_version); // Obtain a certificate from RTCConfiguration if any were provided (optional). @@ -644,8 +654,8 @@ constraints, MediaConstraintsInterface::kEnableDscp, &value, NULL)) { - audio_options_.dscp.Set(value); - video_options_.dscp.Set(value); + audio_options_.dscp = rtc::Optional<bool>(value); + video_options_.dscp = rtc::Optional<bool>(value); } // Find Suspend Below Min Bitrate constraint. @@ -654,7 +664,7 @@ MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate, &value, NULL)) { - video_options_.suspend_below_min_bitrate.Set(value); + video_options_.suspend_below_min_bitrate = rtc::Optional<bool>(value); } SetOptionFromOptionalConstraint(constraints, @@ -684,12 +694,10 @@ SetOptionFromOptionalConstraint(constraints, MediaConstraintsInterface::kNumUnsignalledRecvStreams, &video_options_.unsignalled_recv_stream_limit); - if (video_options_.unsignalled_recv_stream_limit.IsSet()) { - int stream_limit; - video_options_.unsignalled_recv_stream_limit.Get(&stream_limit); - stream_limit = std::min(kMaxUnsignalledRecvStreams, stream_limit); - stream_limit = std::max(0, stream_limit); - video_options_.unsignalled_recv_stream_limit.Set(stream_limit); + if (video_options_.unsignalled_recv_stream_limit) { + video_options_.unsignalled_recv_stream_limit = rtc::Optional<int>( + std::max(0, std::min(kMaxUnsignalledRecvStreams, + *video_options_.unsignalled_recv_stream_limit))); } SetOptionFromOptionalConstraint(constraints, @@ -700,22 +708,12 @@ MediaConstraintsInterface::kCombinedAudioVideoBwe, &audio_options_.combined_audio_video_bwe); - audio_options_.audio_jitter_buffer_max_packets.Set( - rtc_configuration.audio_jitter_buffer_max_packets); + audio_options_.audio_jitter_buffer_max_packets = + rtc::Optional<int>(rtc_configuration.audio_jitter_buffer_max_packets); - audio_options_.audio_jitter_buffer_fast_accelerate.Set( + audio_options_.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>( rtc_configuration.audio_jitter_buffer_fast_accelerate); - const cricket::VideoCodec default_codec( - JsepSessionDescription::kDefaultVideoCodecId, - JsepSessionDescription::kDefaultVideoCodecName, - JsepSessionDescription::kMaxVideoCodecWidth, - JsepSessionDescription::kMaxVideoCodecHeight, - JsepSessionDescription::kDefaultVideoCodecFramerate, - JsepSessionDescription::kDefaultVideoCodecPreference); - channel_manager_->SetDefaultVideoEncoderConfig( - cricket::VideoEncoderConfig(default_codec)); - if (!dtls_enabled_) { // Construct with DTLS disabled. webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory( @@ -726,7 +724,7 @@ // Use the |dtls_identity_store| to generate a certificate. RTC_DCHECK(dtls_identity_store); webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory( - signaling_thread(), channel_manager_, dtls_identity_store.Pass(), + signaling_thread(), channel_manager_, std::move(dtls_identity_store), this, id())); } else { // Use the already generated certificate. @@ -744,12 +742,6 @@ port_allocator()->set_candidate_filter( ConvertIceTransportTypeToCandidateFilter(rtc_configuration.type)); - if (rtc_configuration.enable_localhost_ice_candidate) { - port_allocator()->set_flags( - port_allocator()->flags() | - cricket::PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE); - } - return true; } @@ -769,14 +761,20 @@ return webrtc_session_desc_factory_->SdesPolicy(); } -bool WebRtcSession::GetSslRole(rtc::SSLRole* role) { +bool WebRtcSession::GetSslRole(const std::string& transport_name, + rtc::SSLRole* role) { if (!local_desc_ || !remote_desc_) { LOG(LS_INFO) << "Local and Remote descriptions must be applied to get " << "SSL Role of the session."; return false; } - return transport_controller_->GetSslRole(role); + return transport_controller_->GetSslRole(transport_name, role); +} + +bool WebRtcSession::GetSslRole(const cricket::BaseChannel* channel, + rtc::SSLRole* role) { + return channel && GetSslRole(channel->transport_name(), role); } void WebRtcSession::CreateOffer( @@ -978,15 +976,12 @@ return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc); } } else if (action == kAnswer) { - if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) { - return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc); - } const cricket::ContentGroup* local_bundle = local_desc_->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); const cricket::ContentGroup* remote_bundle = remote_desc_->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); if (local_bundle && remote_bundle) { - // The answerer decides the transport to bundle on + // The answerer decides the transport to bundle on. const cricket::ContentGroup* answer_bundle = (source == cricket::CS_LOCAL ? local_bundle : remote_bundle); if (!EnableBundle(*answer_bundle)) { @@ -994,6 +989,11 @@ return BadAnswerSdp(source, kEnableBundleFailed, err_desc); } } + // Only push down the transport description after enabling BUNDLE; we don't + // want to push down a description on a transport about to be destroyed. + if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) { + return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc); + } EnableChannels(); SetState(STATE_INPROGRESS); if (!PushdownMediaDescription(cricket::CA_ANSWER, source, err_desc)) { @@ -1250,6 +1250,8 @@ const PeerConnectionInterface::RTCConfiguration& config) const { cricket::IceConfig ice_config; ice_config.receiving_timeout_ms = config.ice_connection_receiving_timeout; + ice_config.backup_connection_ping_interval = + config.ice_backup_candidate_pair_ping_interval; ice_config.gather_continually = (config.continual_gathering_policy == PeerConnectionInterface::GATHER_CONTINUALLY); return ice_config; @@ -1326,6 +1328,15 @@ } } +void WebRtcSession::SetRawAudioSink(uint32_t ssrc, + rtc::scoped_ptr<AudioSinkInterface> sink) { + ASSERT(signaling_thread()->IsCurrent()); + if (!voice_channel_) + return; + + voice_channel_->SetRawAudioSink(ssrc, std::move(sink)); +} + bool WebRtcSession::SetCaptureDevice(uint32_t ssrc, cricket::VideoCapturer* camera) { ASSERT(signaling_thread()->IsCurrent()); @@ -1409,8 +1420,7 @@ LOG(LS_ERROR) << "InsertDtmf: Track does not exist: " << track_id; return false; } - if (!voice_channel_->InsertDtmf(send_ssrc, code, duration, - cricket::DF_SEND)) { + if (!voice_channel_->InsertDtmf(send_ssrc, code, duration)) { LOG(LS_ERROR) << "Failed to insert DTMF to channel."; return false; } @@ -1747,7 +1757,6 @@ cricket::GetFirstVideoContent(desc); if ((!video_info || video_info->rejected) && video_channel_) { SignalVideoChannelDestroyed(); - const std::string content_name = video_channel_->content_name(); channel_manager_->DestroyVideoChannel(video_channel_.release()); } @@ -1755,7 +1764,6 @@ cricket::GetFirstAudioContent(desc); if ((!voice_info || voice_info->rejected) && voice_channel_) { SignalVoiceChannelDestroyed(); - const std::string content_name = voice_channel_->content_name(); channel_manager_->DestroyVoiceChannel(voice_channel_.release()); } @@ -1763,7 +1771,6 @@ cricket::GetFirstDataContent(desc); if ((!data_info || data_info->rejected) && data_channel_) { SignalDataChannelDestroyed(); - const std::string content_name = data_channel_->content_name(); channel_manager_->DestroyDataChannel(data_channel_.release()); } } @@ -2164,9 +2171,10 @@ return; } - const std::string& srtp_cipher = stats.channel_stats[0].srtp_cipher; - int ssl_cipher = stats.channel_stats[0].ssl_cipher; - if (srtp_cipher.empty() && !ssl_cipher) { + int srtp_crypto_suite = stats.channel_stats[0].srtp_crypto_suite; + int ssl_cipher_suite = stats.channel_stats[0].ssl_cipher_suite; + if (srtp_crypto_suite == rtc::SRTP_INVALID_CRYPTO_SUITE && + ssl_cipher_suite == rtc::TLS_NULL_WITH_NULL_NULL) { return; } @@ -2186,12 +2194,13 @@ return; } - if (!srtp_cipher.empty()) { - metrics_observer_->IncrementSparseEnumCounter( - srtp_counter_type, rtc::GetSrtpCryptoSuiteFromName(srtp_cipher)); + if (srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE) { + metrics_observer_->IncrementSparseEnumCounter(srtp_counter_type, + srtp_crypto_suite); } - if (ssl_cipher) { - metrics_observer_->IncrementSparseEnumCounter(ssl_counter_type, ssl_cipher); + if (ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL) { + metrics_observer_->IncrementSparseEnumCounter(ssl_counter_type, + ssl_cipher_suite); } }
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h index d9c40d1..b79e0ec 100644 --- a/talk/app/webrtc/webrtcsession.h +++ b/talk/app/webrtc/webrtcsession.h
@@ -38,11 +38,11 @@ #include "talk/app/webrtc/peerconnectioninterface.h" #include "talk/app/webrtc/statstypes.h" #include "talk/media/base/mediachannel.h" -#include "webrtc/p2p/base/transportcontroller.h" #include "talk/session/media/mediasession.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/sslidentity.h" #include "webrtc/base/thread.h" +#include "webrtc/p2p/base/transportcontroller.h" namespace cricket { @@ -204,7 +204,11 @@ cricket::SecurePolicy SdesPolicy() const; // Get current ssl role from transport. - bool GetSslRole(rtc::SSLRole* role); + bool GetSslRole(const std::string& transport_name, rtc::SSLRole* role); + + // Get current SSL role for this channel's transport. + // If |transport| is null, returns false. + bool GetSslRole(const cricket::BaseChannel* channel, rtc::SSLRole* role); void CreateOffer( CreateSessionDescriptionObserver* observer, @@ -250,6 +254,8 @@ const cricket::AudioOptions& options, cricket::AudioRenderer* renderer) override; void SetAudioPlayoutVolume(uint32_t ssrc, double volume) override; + void SetRawAudioSink(uint32_t ssrc, + rtc::scoped_ptr<AudioSinkInterface> sink) override; // Implements VideoMediaProviderInterface. bool SetCaptureDevice(uint32_t ssrc, cricket::VideoCapturer* camera) override;
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc index 3eb46f1..e81b8b5 100644 --- a/talk/app/webrtc/webrtcsession_unittest.cc +++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -25,6 +25,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <utility> #include <vector> #include "talk/app/webrtc/audiotrack.h" @@ -33,7 +34,6 @@ #include "talk/app/webrtc/jsepicecandidate.h" #include "talk/app/webrtc/jsepsessiondescription.h" #include "talk/app/webrtc/peerconnection.h" -#include "talk/app/webrtc/mediastreamsignaling.h" #include "talk/app/webrtc/sctputils.h" #include "talk/app/webrtc/streamcollection.h" #include "talk/app/webrtc/streamcollection.h" @@ -72,8 +72,6 @@ return; \ } -using cricket::DF_PLAY; -using cricket::DF_SEND; using cricket::FakeVoiceMediaChannel; using cricket::TransportInfo; using rtc::SocketAddress; @@ -173,15 +171,6 @@ enum RTCCertificateGenerationMethod { ALREADY_GENERATED, DTLS_IDENTITY_STORE }; -// Add some extra |newlines| to the |message| after |line|. -static void InjectAfter(const std::string& line, - const std::string& newlines, - std::string* message) { - const std::string tmp = line + newlines; - rtc::replace_substrs(line.c_str(), line.length(), tmp.c_str(), tmp.length(), - message); -} - class MockIceObserver : public webrtc::IceObserver { public: MockIceObserver() @@ -428,7 +417,7 @@ observer_.ice_gathering_state_); EXPECT_TRUE(session_->Initialize(options_, constraints_.get(), - dtls_identity_store.Pass(), + std::move(dtls_identity_store), rtc_configuration)); session_->set_metrics_observer(metrics_observer_); } @@ -479,7 +468,7 @@ } else { RTC_CHECK(false); } - Init(dtls_identity_store.Pass(), configuration); + Init(std::move(dtls_identity_store), configuration); } // Init with DTLS with a store that will fail to generate a certificate. @@ -488,7 +477,7 @@ new FakeDtlsIdentityStore()); dtls_identity_store->set_should_fail(true); PeerConnectionInterface::RTCConfiguration configuration; - Init(dtls_identity_store.Pass(), configuration); + Init(std::move(dtls_identity_store), configuration); } void InitWithDtmfCodec() { @@ -726,9 +715,9 @@ std::string identity_name = "WebRTC" + rtc::ToString(rtc::CreateRandomId()); // Confirmed to work with KT_RSA and KT_ECDSA. - tdesc_factory_->set_certificate(rtc::RTCCertificate::Create( - rtc::scoped_ptr<rtc::SSLIdentity>(rtc::SSLIdentity::Generate( - identity_name, rtc::KT_DEFAULT)).Pass())); + tdesc_factory_->set_certificate( + rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>( + rtc::SSLIdentity::Generate(identity_name, rtc::KT_DEFAULT)))); tdesc_factory_->set_secure(cricket::SEC_REQUIRED); } @@ -789,7 +778,7 @@ ASSERT_TRUE(video_channel_ != NULL); const cricket::VideoOptions& video_options = video_channel_->options(); EXPECT_EQ(value_expected, - video_options.unsignalled_recv_stream_limit.GetWithDefaultIfUnset(-1)); + video_options.unsignalled_recv_stream_limit.value_or(-1)); } void CompareIceUfragAndPassword(const cricket::SessionDescription* desc1, @@ -1442,12 +1431,12 @@ } void ConfigureAllocatorWithTurn() { - cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); + cricket::RelayServerConfig turn_server(cricket::RELAY_TURN); cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); - relay_server.credentials = credentials; - relay_server.ports.push_back(cricket::ProtocolAddress( - kTurnUdpIntAddr, cricket::PROTO_UDP, false)); - allocator_->AddRelay(relay_server); + turn_server.credentials = credentials; + turn_server.ports.push_back( + cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP, false)); + allocator_->AddTurnServer(turn_server); allocator_->set_step_delay(cricket::kMinimumStepDelay); allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP); } @@ -1968,6 +1957,67 @@ SetLocalDescriptionWithoutError(answer); } +// Test that we can create and set an answer correctly when different +// SSL roles have been negotiated for different transports. +// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525 +TEST_P(WebRtcSessionTest, TestCreateAnswerWithDifferentSslRoles) { + SendAudioVideoStream1(); + InitWithDtls(GetParam()); + SetFactoryDtlsSrtp(); + + SessionDescriptionInterface* offer = CreateOffer(); + SetLocalDescriptionWithoutError(offer); + + cricket::MediaSessionOptions options; + options.recv_video = true; + + // First, negotiate different SSL roles. + SessionDescriptionInterface* answer = + CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED); + TransportInfo* audio_transport_info = + answer->description()->GetTransportInfoByName("audio"); + audio_transport_info->description.connection_role = + cricket::CONNECTIONROLE_ACTIVE; + TransportInfo* video_transport_info = + answer->description()->GetTransportInfoByName("video"); + video_transport_info->description.connection_role = + cricket::CONNECTIONROLE_PASSIVE; + SetRemoteDescriptionWithoutError(answer); + + // Now create an offer in the reverse direction, and ensure the initial + // offerer responds with an answer with correct SSL roles. + offer = CreateRemoteOfferWithVersion(options, cricket::SEC_DISABLED, + kSessionVersion, + session_->remote_description()); + SetRemoteDescriptionWithoutError(offer); + + answer = CreateAnswer(nullptr); + audio_transport_info = answer->description()->GetTransportInfoByName("audio"); + EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE, + audio_transport_info->description.connection_role); + video_transport_info = answer->description()->GetTransportInfoByName("video"); + EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE, + video_transport_info->description.connection_role); + SetLocalDescriptionWithoutError(answer); + + // Lastly, start BUNDLE-ing on "audio", expecting that the "passive" role of + // audio is transferred over to video in the answer that completes the BUNDLE + // negotiation. + options.bundle_enabled = true; + offer = CreateRemoteOfferWithVersion(options, cricket::SEC_DISABLED, + kSessionVersion, + session_->remote_description()); + SetRemoteDescriptionWithoutError(offer); + answer = CreateAnswer(nullptr); + audio_transport_info = answer->description()->GetTransportInfoByName("audio"); + EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE, + audio_transport_info->description.connection_role); + video_transport_info = answer->description()->GetTransportInfoByName("video"); + EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE, + video_transport_info->description.connection_role); + SetLocalDescriptionWithoutError(answer); +} + TEST_F(WebRtcSessionTest, TestSetLocalOfferTwice) { Init(); SendNothing(); @@ -2809,10 +2859,9 @@ EXPECT_FALSE(session_->SetRemoteDescription(modified_offer, &error)); } -// Test that if the remote description indicates the peer requested ICE restart -// (via a new ufrag or pwd), the old ICE candidates are not copied, -// and vice versa. -TEST_F(WebRtcSessionTest, TestSetRemoteDescriptionWithIceRestart) { +// Test that if the remote offer indicates the peer requested ICE restart (via +// a new ufrag or pwd), the old ICE candidates are not copied, and vice versa. +TEST_F(WebRtcSessionTest, TestSetRemoteOfferWithIceRestart) { Init(); scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer()); @@ -2866,6 +2915,64 @@ EXPECT_EQ(0, session_->remote_description()->candidates(0)->count()); } +// Test that if the remote answer indicates the peer requested ICE restart (via +// a new ufrag or pwd), the old ICE candidates are not copied, and vice versa. +TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithIceRestart) { + Init(); + SessionDescriptionInterface* offer = CreateOffer(); + SetLocalDescriptionWithoutError(offer); + scoped_ptr<SessionDescriptionInterface> answer(CreateRemoteAnswer(offer)); + + // Create the first answer. + std::string sdp; + ModifyIceUfragPwdLines(answer.get(), "0123456789012345", + "abcdefghijklmnopqrstuvwx", &sdp); + SessionDescriptionInterface* answer1 = + CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); + cricket::Candidate candidate1(1, "udp", rtc::SocketAddress("1.1.1.1", 5000), + 0, "", "", "relay", 0, ""); + JsepIceCandidate ice_candidate1(kMediaContentName0, kMediaContentIndex0, + candidate1); + EXPECT_TRUE(answer1->AddCandidate(&ice_candidate1)); + SetRemoteDescriptionWithoutError(answer1); + EXPECT_EQ(1, session_->remote_description()->candidates(0)->count()); + + // The second answer has the same ufrag and pwd but different address. + sdp.clear(); + ModifyIceUfragPwdLines(answer.get(), "0123456789012345", + "abcdefghijklmnopqrstuvwx", &sdp); + SessionDescriptionInterface* answer2 = + CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); + candidate1.set_address(rtc::SocketAddress("1.1.1.1", 6000)); + JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0, + candidate1); + EXPECT_TRUE(answer2->AddCandidate(&ice_candidate2)); + SetRemoteDescriptionWithoutError(answer2); + EXPECT_EQ(2, session_->remote_description()->candidates(0)->count()); + + // The third answer has a different ufrag and different address. + sdp.clear(); + ModifyIceUfragPwdLines(answer.get(), "0123456789012333", + "abcdefghijklmnopqrstuvwx", &sdp); + SessionDescriptionInterface* answer3 = + CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); + candidate1.set_address(rtc::SocketAddress("1.1.1.1", 7000)); + JsepIceCandidate ice_candidate3(kMediaContentName0, kMediaContentIndex0, + candidate1); + EXPECT_TRUE(answer3->AddCandidate(&ice_candidate3)); + SetRemoteDescriptionWithoutError(answer3); + EXPECT_EQ(1, session_->remote_description()->candidates(0)->count()); + + // The fourth answer has no candidate but a different ufrag/pwd. + sdp.clear(); + ModifyIceUfragPwdLines(answer.get(), "0123456789012444", + "abcdefghijklmnopqrstuvyz", &sdp); + SessionDescriptionInterface* offer4 = + CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); + SetRemoteDescriptionWithoutError(offer4); + EXPECT_EQ(0, session_->remote_description()->candidates(0)->count()); +} + // Test that candidates sent to the "video" transport do not get pushed down to // the "audio" transport channel when bundling. TEST_F(WebRtcSessionTest, TestIgnoreCandidatesForUnusedTransportWhenBundling) { @@ -3297,20 +3404,18 @@ EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); cricket::AudioOptions options; - options.echo_cancellation.Set(true); + options.echo_cancellation = rtc::Optional<bool>(true); rtc::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer()); session_->SetAudioSend(send_ssrc, false, options, renderer.get()); EXPECT_TRUE(channel->IsStreamMuted(send_ssrc)); - EXPECT_FALSE(channel->options().echo_cancellation.IsSet()); + EXPECT_EQ(rtc::Optional<bool>(), channel->options().echo_cancellation); EXPECT_TRUE(renderer->sink() != NULL); // This will trigger SetSink(NULL) to the |renderer|. session_->SetAudioSend(send_ssrc, true, options, NULL); EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); - bool value; - EXPECT_TRUE(channel->options().echo_cancellation.Get(&value)); - EXPECT_TRUE(value); + EXPECT_EQ(rtc::Optional<bool>(true), channel->options().echo_cancellation); EXPECT_TRUE(renderer->sink() == NULL); } @@ -3387,7 +3492,6 @@ EXPECT_EQ(0U, channel->dtmf_info_queue().size()); // Insert DTMF - const int expected_flags = DF_SEND; const int expected_duration = 90; session_->InsertDtmf(kAudioTrack1, 0, expected_duration); session_->InsertDtmf(kAudioTrack1, 1, expected_duration); @@ -3397,11 +3501,11 @@ ASSERT_EQ(3U, channel->dtmf_info_queue().size()); const uint32_t send_ssrc = channel->send_streams()[0].first_ssrc(); EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[0], send_ssrc, 0, - expected_duration, expected_flags)); + expected_duration)); EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[1], send_ssrc, 1, - expected_duration, expected_flags)); + expected_duration)); EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[2], send_ssrc, 2, - expected_duration, expected_flags)); + expected_duration)); } // This test verifies the |initial_offerer| flag when session initiates the @@ -3582,7 +3686,9 @@ SetLocalDescriptionWithoutError(answer.release()); // Receive an offer with new ufrag and password. - options.transport_options.ice_restart = true; + options.audio_transport_options.ice_restart = true; + options.video_transport_options.ice_restart = true; + options.data_transport_options.ice_restart = true; rtc::scoped_ptr<JsepSessionDescription> updated_offer1( CreateRemoteOffer(options, session_->remote_description())); SetRemoteDescriptionWithoutError(updated_offer1.release()); @@ -3613,7 +3719,9 @@ SetLocalDescriptionWithoutError(answer.release()); // Receive an offer without changed ufrag or password. - options.transport_options.ice_restart = false; + options.audio_transport_options.ice_restart = false; + options.video_transport_options.ice_restart = false; + options.data_transport_options.ice_restart = false; rtc::scoped_ptr<JsepSessionDescription> updated_offer2( CreateRemoteOffer(options, session_->remote_description())); SetRemoteDescriptionWithoutError(updated_offer2.release()); @@ -3993,10 +4101,8 @@ ASSERT_TRUE(voice_channel_ != NULL); const cricket::AudioOptions& audio_options = voice_channel_->options(); const cricket::VideoOptions& video_options = video_channel_->options(); - EXPECT_TRUE(audio_options.dscp.IsSet()); - EXPECT_TRUE(audio_options.dscp.GetWithDefaultIfUnset(false)); - EXPECT_TRUE(video_options.dscp.IsSet()); - EXPECT_TRUE(video_options.dscp.GetWithDefaultIfUnset(false)); + EXPECT_EQ(rtc::Optional<bool>(true), audio_options.dscp); + EXPECT_EQ(rtc::Optional<bool>(true), video_options.dscp); } TEST_F(WebRtcSessionTest, TestSuspendBelowMinBitrateConstraint) { @@ -4014,8 +4120,7 @@ ASSERT_TRUE(video_channel_ != NULL); const cricket::VideoOptions& video_options = video_channel_->options(); - EXPECT_TRUE( - video_options.suspend_below_min_bitrate.GetWithDefaultIfUnset(false)); + EXPECT_EQ(rtc::Optional<bool>(true), video_options.suspend_below_min_bitrate); } TEST_F(WebRtcSessionTest, TestNumUnsignalledRecvStreamsConstraint) { @@ -4042,8 +4147,7 @@ ASSERT_TRUE(voice_channel_ != NULL); const cricket::AudioOptions& audio_options = voice_channel_->options(); - EXPECT_TRUE( - audio_options.combined_audio_video_bwe.GetWithDefaultIfUnset(false)); + EXPECT_EQ(rtc::Optional<bool>(true), audio_options.combined_audio_video_bwe); } // Tests that we can renegotiate new media content with ICE candidates in the
diff --git a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc index 25965af..f08b77e 100644 --- a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc +++ b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
@@ -27,6 +27,8 @@ #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" +#include <utility> + #include "talk/app/webrtc/dtlsidentitystore.h" #include "talk/app/webrtc/jsep.h" #include "talk/app/webrtc/jsepsessiondescription.h" @@ -99,12 +101,12 @@ der_private_key.length()); rtc::scoped_ptr<rtc::SSLIdentity> identity( rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert)); - SignalCertificateReady(rtc::RTCCertificate::Create(identity.Pass())); + SignalCertificateReady(rtc::RTCCertificate::Create(std::move(identity))); } void WebRtcIdentityRequestObserver::OnSuccess( rtc::scoped_ptr<rtc::SSLIdentity> identity) { - SignalCertificateReady(rtc::RTCCertificate::Create(identity.Pass())); + SignalCertificateReady(rtc::RTCCertificate::Create(std::move(identity))); } // static @@ -143,7 +145,7 @@ // to just use a random number as session id and start version from // |kInitSessionVersion|. session_version_(kInitSessionVersion), - dtls_identity_store_(dtls_identity_store.Pass()), + dtls_identity_store_(std::move(dtls_identity_store)), identity_request_observer_(identity_request_observer), session_(session), session_id_(session_id), @@ -177,7 +179,7 @@ : WebRtcSessionDescriptionFactory( signaling_thread, channel_manager, - dtls_identity_store.Pass(), + std::move(dtls_identity_store), new rtc::RefCountedObject<WebRtcIdentityRequestObserver>(), session, session_id, @@ -390,7 +392,9 @@ return; } if (session_->local_description() && - !request.options.transport_options.ice_restart) { + !request.options.audio_transport_options.ice_restart && + !request.options.video_transport_options.ice_restart && + !request.options.data_transport_options.ice_restart) { // Include all local ice candidates in the SessionDescription unless // the an ice restart has been requested. CopyCandidatesFromSessionDescription(session_->local_description(), offer); @@ -403,12 +407,25 @@ // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1 // an answer should also contain new ice ufrag and password if an offer has // been received with new ufrag and password. - request.options.transport_options.ice_restart = session_->IceRestartPending(); + request.options.audio_transport_options.ice_restart = + session_->IceRestartPending(); + request.options.video_transport_options.ice_restart = + session_->IceRestartPending(); + request.options.data_transport_options.ice_restart = + session_->IceRestartPending(); // We should pass current ssl role to the transport description factory, if // there is already an existing ongoing session. rtc::SSLRole ssl_role; - if (session_->GetSslRole(&ssl_role)) { - request.options.transport_options.prefer_passive_role = + if (session_->GetSslRole(session_->voice_channel(), &ssl_role)) { + request.options.audio_transport_options.prefer_passive_role = + (rtc::SSL_SERVER == ssl_role); + } + if (session_->GetSslRole(session_->video_channel(), &ssl_role)) { + request.options.video_transport_options.prefer_passive_role = + (rtc::SSL_SERVER == ssl_role); + } + if (session_->GetSslRole(session_->data_channel(), &ssl_role)) { + request.options.data_transport_options.prefer_passive_role = (rtc::SSL_SERVER == ssl_role); } @@ -437,7 +454,9 @@ return; } if (session_->local_description() && - !request.options.transport_options.ice_restart) { + !request.options.audio_transport_options.ice_restart && + !request.options.video_transport_options.ice_restart && + !request.options.data_transport_options.ice_restart) { // Include all local ice candidates in the SessionDescription unless // the remote peer has requested an ice restart. CopyCandidatesFromSessionDescription(session_->local_description(), answer);
diff --git a/talk/build/common.gypi b/talk/build/common.gypi index 36a96c5..061b06b 100644 --- a/talk/build/common.gypi +++ b/talk/build/common.gypi
@@ -41,7 +41,6 @@ ], # Disable these to not build components which can be externally provided. 'build_expat%': 1, - 'build_icu%': 1, 'build_json%': 1, 'build_libsrtp%': 1, 'build_libyuv%': 1, @@ -61,17 +60,9 @@ '../../webrtc', ], 'defines': [ - 'EXPAT_RELATIVE_PATH', - 'FEATURE_ENABLE_VOICEMAIL', - 'GTEST_RELATIVE_PATH', - 'JSONCPP_RELATIVE_PATH', - 'LOGGING=1', 'SRTP_RELATIVE_PATH', # Feature selection - 'FEATURE_ENABLE_SSL', - 'FEATURE_ENABLE_VOICEMAIL', - 'FEATURE_ENABLE_PSTN', 'HAVE_SCTP', 'HAVE_SRTP', 'HAVE_WEBRTC_VIDEO', @@ -80,7 +71,6 @@ 'conditions': [ ['OS=="linux"', { 'defines': [ - 'LINUX', 'WEBRTC_LINUX', ], # Remove Chromium's disabling of the -Wformat warning. @@ -112,7 +102,6 @@ }], ['OS=="mac"', { 'defines': [ - 'OSX', 'WEBRTC_MAC', ], }], @@ -129,7 +118,6 @@ }], ['OS=="ios"', { 'defines': [ - 'IOS', 'WEBRTC_MAC', 'WEBRTC_IOS', ],
diff --git a/talk/build/merge_ios_libs.gyp b/talk/build/merge_ios_libs.gyp index 0c7114d..f7e4875 100644 --- a/talk/build/merge_ios_libs.gyp +++ b/talk/build/merge_ios_libs.gyp
@@ -27,7 +27,7 @@ { 'includes': ['common.gypi',], 'conditions': [ - ['OS=="ios" or (OS=="mac" and mac_sdk>="10.8")', { + ['OS=="ios" or OS=="mac"', { 'targets': [ { 'target_name': 'libjingle_peerconnection_objc_no_op',
diff --git a/talk/codereview.settings b/talk/codereview.settings index 97bee14..c441cc6 100644 --- a/talk/codereview.settings +++ b/talk/codereview.settings
@@ -1,4 +1,5 @@ -Creating CLs from this location is not supported! -Please create a full WebRTC checkout using 'fetch webrtc' -or by cloning https://chromium.googlesource.com/external/webrtc +Creating CLs from this location is not supported! Please make sure the current +working directory is the parent directory of this directory. +If you're working with a Chromium checkout, you'll have to create a full WebRTC +checkout and upload a CL from that. See http://www.webrtc.org for instructions.
diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp index 81d723a..6e0f8a3 100755 --- a/talk/libjingle.gyp +++ b/talk/libjingle.gyp
@@ -43,8 +43,8 @@ ['OS=="linux" or OS=="android"', { 'targets': [ { - 'target_name': 'libjingle_peerconnection_so', - 'type': 'shared_library', + 'target_name': 'libjingle_peerconnection_jni', + 'type': 'static_library', 'dependencies': [ '<(webrtc_root)/system_wrappers/system_wrappers.gyp:field_trial_default', 'libjingle_peerconnection', @@ -62,11 +62,55 @@ '<(libyuv_dir)/include', ], 'conditions': [ - ['build_icu==1', { - 'dependencies': [ - '<(DEPTH)/third_party/icu/icu.gyp:icuuc', + ['OS=="linux"', { + 'include_dirs': [ + '<(java_home)/include', + '<(java_home)/include/linux', ], }], + ['build_json==1', { + 'dependencies': [ + '<(DEPTH)/third_party/jsoncpp/jsoncpp.gyp:jsoncpp', + ], + 'export_dependent_settings': [ + '<(DEPTH)/third_party/jsoncpp/jsoncpp.gyp:jsoncpp', + ], + }], + ['OS=="android"', { + 'sources': [ + 'app/webrtc/androidvideocapturer.cc', + 'app/webrtc/androidvideocapturer.h', + 'app/webrtc/java/jni/androidmediacodeccommon.h', + 'app/webrtc/java/jni/androidmediadecoder_jni.cc', + 'app/webrtc/java/jni/androidmediadecoder_jni.h', + 'app/webrtc/java/jni/androidmediaencoder_jni.cc', + 'app/webrtc/java/jni/androidmediaencoder_jni.h', + 'app/webrtc/java/jni/androidnetworkmonitor_jni.cc', + 'app/webrtc/java/jni/androidnetworkmonitor_jni.h', + 'app/webrtc/java/jni/androidvideocapturer_jni.cc', + 'app/webrtc/java/jni/androidvideocapturer_jni.h', + 'app/webrtc/java/jni/surfacetexturehelper_jni.cc', + 'app/webrtc/java/jni/surfacetexturehelper_jni.h', + ] + }], + ], + }, + { + 'target_name': 'libjingle_peerconnection_so', + 'type': 'shared_library', + 'dependencies': [ + 'libjingle_peerconnection', + 'libjingle_peerconnection_jni', + ], + 'sources': [ + 'app/webrtc/java/jni/jni_onload.cc', + ], + 'variables': { + # This library uses native JNI exports; tell GYP so that the + # required symbols will be kept. + 'use_native_jni_exports': 1, + }, + 'conditions': [ ['OS=="linux"', { 'defines': [ 'HAVE_GTK', @@ -86,30 +130,6 @@ }], ], }], - ['OS=="android"', { - 'sources': [ - 'app/webrtc/java/jni/androidvideocapturer_jni.cc', - 'app/webrtc/java/jni/androidvideocapturer_jni.h', - ], - 'variables': { - # This library uses native JNI exports; tell GYP so that the - # required symbols will be kept. - 'use_native_jni_exports': 1, - }, - }], - ['OS=="android" and build_with_chromium==0', { - 'sources': [ - 'app/webrtc/java/jni/androidmediacodeccommon.h', - 'app/webrtc/java/jni/androidmediadecoder_jni.cc', - 'app/webrtc/java/jni/androidmediadecoder_jni.h', - 'app/webrtc/java/jni/androidmediaencoder_jni.cc', - 'app/webrtc/java/jni/androidmediaencoder_jni.h', - 'app/webrtc/java/jni/androidnetworkmonitor_jni.cc', - 'app/webrtc/java/jni/androidnetworkmonitor_jni.h', - 'app/webrtc/java/jni/surfacetexturehelper_jni.cc', - 'app/webrtc/java/jni/surfacetexturehelper_jni.h', - ] - }], ], }, { @@ -154,6 +174,8 @@ 'app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java', 'app/webrtc/java/android/org/webrtc/CameraEnumerator.java', 'app/webrtc/java/android/org/webrtc/EglBase.java', + 'app/webrtc/java/android/org/webrtc/EglBase10.java', + 'app/webrtc/java/android/org/webrtc/EglBase14.java', 'app/webrtc/java/android/org/webrtc/GlRectDrawer.java', 'app/webrtc/java/android/org/webrtc/GlShader.java', 'app/webrtc/java/android/org/webrtc/GlUtil.java', @@ -232,6 +254,12 @@ 'libjingle_peerconnection_so', ], 'variables': { + # Designate as Chromium code and point to our lint settings to + # enable linting of the WebRTC code (this is the only way to make + # lint_action invoke the Android linter). + 'android_manifest_path': '<(webrtc_root)/build/android/AndroidManifest.xml', + 'suppressions_file': '<(webrtc_root)/build/android/suppressions.xml', + 'chromium_code': 1, 'java_in_dir': 'app/webrtc/java', 'webrtc_base_dir': '<(webrtc_root)/base', 'webrtc_modules_dir': '<(webrtc_root)/modules', @@ -246,7 +274,7 @@ }, # libjingle_peerconnection_java ] }], - ['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.7")', { + ['OS=="ios" or (OS=="mac" and target_arch!="ia32")', { # The >= 10.7 above is required for ARC. 'targets': [ { @@ -354,6 +382,9 @@ # common.gypi enables this for mac but we want this to be disabled # like it is for ios. 'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO', + # Disabled due to failing when compiled with -Wall, see + # https://bugs.chromium.org/p/webrtc/issues/detail?id=5397 + 'WARNING_CFLAGS': ['-Wno-unused-property-ivar'], }, 'conditions': [ ['OS=="ios"', { @@ -366,6 +397,9 @@ 'app/webrtc/objc/public/RTCEAGLVideoView.h', 'app/webrtc/objc/public/RTCAVFoundationVideoSource.h', ], + 'dependencies': [ + '<(webrtc_root)/base/base.gyp:rtc_base_objc', + ], 'link_settings': { 'xcode_settings': { 'OTHER_LDFLAGS': [ @@ -534,7 +568,7 @@ 'include_dirs': [ # TODO(jiayl): move this into the direct_dependent_settings of # usrsctp.gyp. - '<(DEPTH)/third_party/usrsctp', + '<(DEPTH)/third_party/usrsctp/usrsctplib', ], 'dependencies': [ '<(DEPTH)/third_party/usrsctp/usrsctp.gyp:usrsctplib', @@ -678,10 +712,16 @@ 'include_dirs': [ '<(DEPTH)/testing/gtest/include', ], + 'include_dirs!': [ + '<(DEPTH)/webrtc', + ], 'direct_dependent_settings': { 'include_dirs': [ '<(DEPTH)/testing/gtest/include', ], + 'include_dirs!': [ + '<(DEPTH)/webrtc', + ], }, 'sources': [ 'session/media/audiomonitor.cc', @@ -725,7 +765,6 @@ 'app/webrtc/dtmfsender.cc', 'app/webrtc/dtmfsender.h', 'app/webrtc/dtmfsenderinterface.h', - 'app/webrtc/fakeportallocatorfactory.h', 'app/webrtc/jsep.h', 'app/webrtc/jsepicecandidate.cc', 'app/webrtc/jsepicecandidate.h', @@ -740,10 +779,10 @@ 'app/webrtc/mediastream.cc', 'app/webrtc/mediastream.h', 'app/webrtc/mediastreaminterface.h', + 'app/webrtc/mediastreamobserver.cc', + 'app/webrtc/mediastreamobserver.h', 'app/webrtc/mediastreamprovider.h', 'app/webrtc/mediastreamproxy.h', - 'app/webrtc/mediastreamsignaling.cc', - 'app/webrtc/mediastreamsignaling.h', 'app/webrtc/mediastreamtrack.h', 'app/webrtc/mediastreamtrackproxy.h', 'app/webrtc/notifier.h', @@ -754,8 +793,6 @@ 'app/webrtc/peerconnectionfactoryproxy.h', 'app/webrtc/peerconnectioninterface.h', 'app/webrtc/peerconnectionproxy.h', - 'app/webrtc/portallocatorfactory.cc', - 'app/webrtc/portallocatorfactory.h', 'app/webrtc/proxy.h', 'app/webrtc/remoteaudiosource.cc', 'app/webrtc/remoteaudiosource.h', @@ -789,14 +826,6 @@ 'app/webrtc/webrtcsessiondescriptionfactory.cc', 'app/webrtc/webrtcsessiondescriptionfactory.h', ], - 'conditions': [ - ['OS=="android" and build_with_chromium==0', { - 'sources': [ - 'app/webrtc/androidvideocapturer.h', - 'app/webrtc/androidvideocapturer.cc', - ], - }], - ], }, # target libjingle_peerconnection ], }
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp index 41b38b3..1dc3649 100755 --- a/talk/libjingle_tests.gyp +++ b/talk/libjingle_tests.gyp
@@ -91,15 +91,15 @@ 'media/base/videocapturer_unittest.cc', 'media/base/videocommon_unittest.cc', 'media/base/videoengine_unittest.h', + 'media/base/videoframe_unittest.h', 'media/devices/dummydevicemanager_unittest.cc', 'media/devices/filevideocapturer_unittest.cc', 'media/sctp/sctpdataengine_unittest.cc', 'media/webrtc/simulcast_unittest.cc', + 'media/webrtc/webrtcmediaengine_unittest.cc', 'media/webrtc/webrtcvideocapturer_unittest.cc', - 'media/base/videoframe_unittest.h', 'media/webrtc/webrtcvideoframe_unittest.cc', 'media/webrtc/webrtcvideoframefactory_unittest.cc', - # Disabled because some tests fail. # TODO(ronghuawu): Reenable these tests. # 'media/devices/devicemanager_unittest.cc', @@ -128,6 +128,17 @@ }, }, }], + ['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-unused-function', + ], + }, + }, + },], ['OS=="ios"', { 'sources!': [ 'media/sctp/sctpdataengine_unittest.cc', @@ -176,7 +187,7 @@ }, # target libjingle_p2p_unittest { 'target_name': 'libjingle_peerconnection_unittest', - 'type': 'executable', + 'type': '<(gtest_target_type)', 'dependencies': [ '<(DEPTH)/testing/gmock.gyp:gmock', '<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils', @@ -207,7 +218,6 @@ # 'app/webrtc/peerconnectionproxy_unittest.cc', 'app/webrtc/remotevideocapturer_unittest.cc', 'app/webrtc/rtpsenderreceiver_unittest.cc', - 'app/webrtc/sctputils.cc', 'app/webrtc/statscollector_unittest.cc', 'app/webrtc/test/fakeaudiocapturemodule.cc', 'app/webrtc/test/fakeaudiocapturemodule.h', @@ -215,7 +225,6 @@ 'app/webrtc/test/fakeconstraints.h', 'app/webrtc/test/fakedatachannelprovider.h', 'app/webrtc/test/fakedtlsidentitystore.h', - 'app/webrtc/test/fakemediastreamsignaling.h', 'app/webrtc/test/fakeperiodicvideocapturer.h', 'app/webrtc/test/fakevideotrackrenderer.h', 'app/webrtc/test/mockpeerconnectionobservers.h', @@ -229,17 +238,25 @@ ], 'conditions': [ ['OS=="android"', { - # We want gmock features that use tr1::tuple, but we currently - # don't support the variadic templates used by libstdc++'s - # implementation. gmock supports this scenario by providing its - # own implementation but we must opt in to it. - 'defines': [ - 'GTEST_USE_OWN_TR1_TUPLE=1', - # GTEST_USE_OWN_TR1_TUPLE only works if GTEST_HAS_TR1_TUPLE is set. - # gmock r625 made it so that GTEST_HAS_TR1_TUPLE is set to 0 - # automatically on android, so it has to be set explicitly here. - 'GTEST_HAS_TR1_TUPLE=1', - ], + 'sources': [ + 'app/webrtc/test/androidtestinitializer.cc', + 'app/webrtc/test/androidtestinitializer.h', + ], + 'dependencies': [ + '<(DEPTH)/testing/android/native_test.gyp:native_test_native_code', + 'libjingle.gyp:libjingle_peerconnection_jni', + ], + }], + ['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-unused-function', + ], + }, + }, }], ], }, # target libjingle_peerconnection_unittest @@ -333,7 +350,7 @@ }, ], # targets }], # OS=="android" - ['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.7")', { + ['OS=="ios" or (OS=="mac" and target_arch!="ia32")', { # The >=10.7 above is required to make ARC link cleanly (e.g. as # opposed to _compile_ cleanly, which the library under test # does just fine on 10.6 too). @@ -378,7 +395,7 @@ '<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils', '<(webrtc_root)/system_wrappers/system_wrappers.gyp:field_trial_default', '<(DEPTH)/third_party/ocmock/ocmock.gyp:ocmock', - '<(webrtc_root)/libjingle_examples.gyp:apprtc_signaling', + '<(webrtc_root)/webrtc_examples.gyp:apprtc_signaling', ], 'sources': [ 'app/webrtc/objctests/mac/main.mm', @@ -394,6 +411,17 @@ }, # target apprtc_signaling_gunit_test ], }], + ['OS=="android"', { + 'targets': [ + { + 'target_name': 'libjingle_peerconnection_unittest_apk_target', + 'type': 'none', + 'dependencies': [ + '<(DEPTH)/webrtc/build/apk_tests.gyp:libjingle_peerconnection_unittest_apk', + ], + }, + ], + }], ['test_isolation_mode != "noop"', { 'targets': [ {
diff --git a/talk/media/base/audiorenderer.h b/talk/media/base/audiorenderer.h index 229c36e..a42cd7d 100644 --- a/talk/media/base/audiorenderer.h +++ b/talk/media/base/audiorenderer.h
@@ -41,7 +41,7 @@ virtual void OnData(const void* audio_data, int bits_per_sample, int sample_rate, - int number_of_channels, + size_t number_of_channels, size_t number_of_frames) = 0; // Called when the AudioRenderer is going away.
diff --git a/talk/media/base/capturemanager_unittest.cc b/talk/media/base/capturemanager_unittest.cc index e990342..84086ab 100644 --- a/talk/media/base/capturemanager_unittest.cc +++ b/talk/media/base/capturemanager_unittest.cc
@@ -29,6 +29,7 @@ #include "talk/media/base/fakevideocapturer.h" #include "talk/media/base/fakevideorenderer.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/gunit.h" #include "webrtc/base/sigslot.h" @@ -57,7 +58,7 @@ } void PopulateSupportedFormats() { std::vector<cricket::VideoFormat> formats; - for (int i = 0; i < ARRAY_SIZE(kCameraFormats); ++i) { + for (int i = 0; i < arraysize(kCameraFormats); ++i) { formats.push_back(cricket::VideoFormat(kCameraFormats[i])); } video_capturer_.ResetSupportedFormats(formats);
diff --git a/talk/media/base/codec.cc b/talk/media/base/codec.cc index 5b747d1..59708b3 100644 --- a/talk/media/base/codec.cc +++ b/talk/media/base/codec.cc
@@ -163,13 +163,15 @@ feedback_params.Intersect(other.feedback_params); } -AudioCodec::AudioCodec(int pt, - const std::string& nm, - int cr, - int br, - int cs, - int pr) - : Codec(pt, nm, cr, pr), bitrate(br), channels(cs) { +AudioCodec::AudioCodec(int id, + const std::string& name, + int clockrate, + int bitrate, + size_t channels, + int preference) + : Codec(id, name, clockrate, preference), + bitrate(bitrate), + channels(channels) { } AudioCodec::AudioCodec() : Codec(), bitrate(0), channels(0) { @@ -219,20 +221,20 @@ return os.str(); } -VideoCodec::VideoCodec(int pt, - const std::string& nm, - int w, - int h, - int fr, - int pr) - : Codec(pt, nm, kVideoCodecClockrate, pr), - width(w), - height(h), - framerate(fr) { +VideoCodec::VideoCodec(int id, + const std::string& name, + int width, + int height, + int framerate, + int preference) + : Codec(id, name, kVideoCodecClockrate, preference), + width(width), + height(height), + framerate(framerate) { } -VideoCodec::VideoCodec(int pt, const std::string& nm) - : Codec(pt, nm, kVideoCodecClockrate, 0), +VideoCodec::VideoCodec(int id, const std::string& name) + : Codec(id, name, kVideoCodecClockrate, 0), width(0), height(0), framerate(0) { @@ -334,6 +336,11 @@ FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); } +bool HasTransportCc(const VideoCodec& codec) { + return codec.HasFeedbackParam( + FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); +} + bool CodecNamesEq(const std::string& name1, const std::string& name2) { return _stricmp(name1.c_str(), name2.c_str()) == 0; }
diff --git a/talk/media/base/codec.h b/talk/media/base/codec.h index 3bb08e7..da78e1c 100644 --- a/talk/media/base/codec.h +++ b/talk/media/base/codec.h
@@ -128,10 +128,15 @@ struct AudioCodec : public Codec { int bitrate; - int channels; + size_t channels; // Creates a codec with the given parameters. - AudioCodec(int pt, const std::string& nm, int cr, int br, int cs, int pr); + AudioCodec(int id, + const std::string& name, + int clockrate, + int bitrate, + size_t channels, + int preference); // Creates an empty codec. AudioCodec(); AudioCodec(const AudioCodec& c); @@ -161,8 +166,13 @@ int framerate; // Creates a codec with the given parameters. - VideoCodec(int pt, const std::string& nm, int w, int h, int fr, int pr); - VideoCodec(int pt, const std::string& nm); + VideoCodec(int id, + const std::string& name, + int width, + int height, + int framerate, + int preference); + VideoCodec(int id, const std::string& name); // Creates an empty codec. VideoCodec(); VideoCodec(const VideoCodec& c); @@ -209,50 +219,6 @@ std::string ToString() const; }; -struct VideoEncoderConfig { - static const int kDefaultMaxThreads = -1; - static const int kDefaultCpuProfile = -1; - - VideoEncoderConfig() - : max_codec(), - num_threads(kDefaultMaxThreads), - cpu_profile(kDefaultCpuProfile) { - } - - VideoEncoderConfig(const VideoCodec& c) - : max_codec(c), - num_threads(kDefaultMaxThreads), - cpu_profile(kDefaultCpuProfile) { - } - - VideoEncoderConfig(const VideoCodec& c, int t, int p) - : max_codec(c), - num_threads(t), - cpu_profile(p) { - } - - VideoEncoderConfig& operator=(const VideoEncoderConfig& config) { - max_codec = config.max_codec; - num_threads = config.num_threads; - cpu_profile = config.cpu_profile; - return *this; - } - - bool operator==(const VideoEncoderConfig& config) const { - return max_codec == config.max_codec && - num_threads == config.num_threads && - cpu_profile == config.cpu_profile; - } - - bool operator!=(const VideoEncoderConfig& config) const { - return !(*this == config); - } - - VideoCodec max_codec; - int num_threads; - int cpu_profile; -}; - // Get the codec setting associated with |payload_type|. If there // is no codec associated with that payload type it returns false. template <class Codec> @@ -271,6 +237,7 @@ bool CodecNamesEq(const std::string& name1, const std::string& name2); bool HasNack(const VideoCodec& codec); bool HasRemb(const VideoCodec& codec); +bool HasTransportCc(const VideoCodec& codec); } // namespace cricket
diff --git a/talk/media/base/codec_unittest.cc b/talk/media/base/codec_unittest.cc index 7bd3735..b2aff50 100644 --- a/talk/media/base/codec_unittest.cc +++ b/talk/media/base/codec_unittest.cc
@@ -33,7 +33,6 @@ using cricket::DataCodec; using cricket::FeedbackParam; using cricket::VideoCodec; -using cricket::VideoEncoderConfig; using cricket::kCodecParamAssociatedPayloadType; using cricket::kCodecParamMaxBitrate; using cricket::kCodecParamMinBitrate; @@ -214,54 +213,6 @@ EXPECT_FALSE(c1.Matches(VideoCodec(95, "V", 640, 400, 15, 0))); } -TEST_F(CodecTest, TestVideoEncoderConfigOperators) { - VideoEncoderConfig c1(VideoCodec( - 96, "SVC", 320, 200, 30, 3), 1, 2); - VideoEncoderConfig c2(VideoCodec( - 95, "SVC", 320, 200, 30, 3), 1, 2); - VideoEncoderConfig c3(VideoCodec( - 96, "xxx", 320, 200, 30, 3), 1, 2); - VideoEncoderConfig c4(VideoCodec( - 96, "SVC", 120, 200, 30, 3), 1, 2); - VideoEncoderConfig c5(VideoCodec( - 96, "SVC", 320, 100, 30, 3), 1, 2); - VideoEncoderConfig c6(VideoCodec( - 96, "SVC", 320, 200, 10, 3), 1, 2); - VideoEncoderConfig c7(VideoCodec( - 96, "SVC", 320, 200, 30, 1), 1, 2); - VideoEncoderConfig c8(VideoCodec( - 96, "SVC", 320, 200, 30, 3), 0, 2); - VideoEncoderConfig c9(VideoCodec( - 96, "SVC", 320, 200, 30, 3), 1, 1); - EXPECT_TRUE(c1 != c2); - EXPECT_TRUE(c1 != c2); - EXPECT_TRUE(c1 != c3); - EXPECT_TRUE(c1 != c4); - EXPECT_TRUE(c1 != c5); - EXPECT_TRUE(c1 != c6); - EXPECT_TRUE(c1 != c7); - EXPECT_TRUE(c1 != c8); - EXPECT_TRUE(c1 != c9); - - VideoEncoderConfig c10; - VideoEncoderConfig c11(VideoCodec( - 0, "", 0, 0, 0, 0)); - VideoEncoderConfig c12(VideoCodec( - 0, "", 0, 0, 0, 0), - VideoEncoderConfig::kDefaultMaxThreads, - VideoEncoderConfig::kDefaultCpuProfile); - VideoEncoderConfig c13 = c1; - VideoEncoderConfig c14(VideoCodec( - 0, "", 0, 0, 0, 0), 0, 0); - - EXPECT_TRUE(c11 == c10); - EXPECT_TRUE(c12 == c10); - EXPECT_TRUE(c13 != c10); - EXPECT_TRUE(c13 == c1); - EXPECT_TRUE(c14 != c11); - EXPECT_TRUE(c14 != c12); -} - TEST_F(CodecTest, TestDataCodecMatches) { // Test a codec with a static payload type. DataCodec c0(95, "D", 0);
diff --git a/talk/media/base/constants.cc b/talk/media/base/constants.cc index 4063004..2361be6 100644 --- a/talk/media/base/constants.cc +++ b/talk/media/base/constants.cc
@@ -90,6 +90,7 @@ const char kRtcpFbParamNack[] = "nack"; const char kRtcpFbNackParamPli[] = "pli"; const char kRtcpFbParamRemb[] = "goog-remb"; +const char kRtcpFbParamTransportCc[] = "transport-cc"; const char kRtcpFbParamCcm[] = "ccm"; const char kRtcpFbCcmParamFir[] = "fir";
diff --git a/talk/media/base/constants.h b/talk/media/base/constants.h index b6a9e56..706a7bd 100644 --- a/talk/media/base/constants.h +++ b/talk/media/base/constants.h
@@ -107,6 +107,9 @@ // rtcp-fb messages according to // http://tools.ietf.org/html/draft-alvestrand-rmcat-remb-00 extern const char kRtcpFbParamRemb[]; +// rtcp-fb messages according to +// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 +extern const char kRtcpFbParamTransportCc[]; // ccm submessages according to RFC 5104 extern const char kRtcpFbParamCcm[]; extern const char kRtcpFbCcmParamFir[];
diff --git a/talk/media/base/cryptoparams.h b/talk/media/base/cryptoparams.h index 9dd1db5..589953d 100644 --- a/talk/media/base/cryptoparams.h +++ b/talk/media/base/cryptoparams.h
@@ -35,8 +35,10 @@ // Parameters for SRTP negotiation, as described in RFC 4568. struct CryptoParams { CryptoParams() : tag(0) {} - CryptoParams(int t, const std::string& cs, - const std::string& kp, const std::string& sp) + CryptoParams(int t, + const std::string& cs, + const std::string& kp, + const std::string& sp) : tag(t), cipher_suite(cs), key_params(kp), session_params(sp) {} bool Matches(const CryptoParams& params) const {
diff --git a/talk/media/base/executablehelpers.h b/talk/media/base/executablehelpers.h index 401890f..dd165c2 100644 --- a/talk/media/base/executablehelpers.h +++ b/talk/media/base/executablehelpers.h
@@ -28,7 +28,7 @@ #ifndef TALK_MEDIA_BASE_EXECUTABLEHELPERS_H_ #define TALK_MEDIA_BASE_EXECUTABLEHELPERS_H_ -#ifdef OSX +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) #include <mach-o/dyld.h> #endif @@ -62,15 +62,15 @@ #else // UNICODE rtc::Pathname path(exe_path_buffer); #endif // UNICODE -#elif defined(OSX) || defined(LINUX) +#elif (defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)) || defined(WEBRTC_LINUX) char exe_path_buffer[kMaxExePathSize]; -#ifdef OSX +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) uint32_t copied_length = kMaxExePathSize - 1; if (_NSGetExecutablePath(exe_path_buffer, &copied_length) == -1) { LOG(LS_ERROR) << "Buffer too small"; return rtc::Pathname(); } -#elif defined LINUX +#elif defined WEBRTC_LINUX int32_t copied_length = kMaxExePathSize - 1; const char* kProcExeFmt = "/proc/%d/exe"; char proc_exe_link[40]; @@ -86,11 +86,11 @@ return rtc::Pathname(); } exe_path_buffer[copied_length] = '\0'; -#endif // LINUX +#endif // WEBRTC_LINUX rtc::Pathname path(exe_path_buffer); -#else // Android || IOS +#else // Android || iOS rtc::Pathname path; -#endif // OSX || LINUX +#endif // Mac || Linux return path; }
diff --git a/talk/media/base/fakemediaengine.h b/talk/media/base/fakemediaengine.h index a6fa960..149704f 100644 --- a/talk/media/base/fakemediaengine.h +++ b/talk/media/base/fakemediaengine.h
@@ -38,9 +38,10 @@ #include "talk/media/base/mediaengine.h" #include "talk/media/base/rtputils.h" #include "talk/media/base/streamparams.h" -#include "webrtc/p2p/base/sessiondescription.h" +#include "webrtc/audio/audio_sink.h" #include "webrtc/base/buffer.h" #include "webrtc/base/stringutils.h" +#include "webrtc/p2p/base/sessiondescription.h" namespace cricket { @@ -229,15 +230,13 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> { public: struct DtmfInfo { - DtmfInfo(uint32_t ssrc, int event_code, int duration, int flags) + DtmfInfo(uint32_t ssrc, int event_code, int duration) : ssrc(ssrc), event_code(event_code), - duration(duration), - flags(flags) {} + duration(duration) {} uint32_t ssrc; int event_code; int duration; - int flags; }; explicit FakeVoiceMediaChannel(FakeVoiceEngine* engine, const AudioOptions& options) @@ -321,9 +320,8 @@ } virtual bool InsertDtmf(uint32_t ssrc, int event_code, - int duration, - int flags) { - dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration, flags)); + int duration) { + dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration)); return true; } @@ -349,6 +347,12 @@ virtual bool GetStats(VoiceMediaInfo* info) { return false; } + virtual void SetRawAudioSink( + uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) { + sink_ = std::move(sink); + } + private: class VoiceChannelAudioSink : public AudioRenderer::Sink { public: @@ -364,7 +368,7 @@ void OnData(const void* audio_data, int bits_per_sample, int sample_rate, - int number_of_channels, + size_t number_of_channels, size_t number_of_frames) override {} void OnClose() override { renderer_ = NULL; } AudioRenderer* renderer() const { return renderer_; } @@ -421,16 +425,16 @@ int time_since_last_typing_; AudioOptions options_; std::map<uint32_t, VoiceChannelAudioSink*> local_renderers_; + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink_; }; // A helper function to compare the FakeVoiceMediaChannel::DtmfInfo. inline bool CompareDtmfInfo(const FakeVoiceMediaChannel::DtmfInfo& info, uint32_t ssrc, int event_code, - int duration, - int flags) { + int duration) { return (info.duration == duration && info.event_code == event_code && - info.flags == flags && info.ssrc == ssrc); + info.ssrc == ssrc); } class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> { @@ -694,33 +698,23 @@ class FakeBaseEngine { public: FakeBaseEngine() - : loglevel_(-1), - options_changed_(false), + : options_changed_(false), fail_create_channel_(false) {} - void SetLogging(int level, const char* filter) { - loglevel_ = level; - logfilter_ = filter; - } - void set_fail_create_channel(bool fail) { fail_create_channel_ = fail; } - const std::vector<RtpHeaderExtension>& rtp_header_extensions() const { - return rtp_header_extensions_; - } + RtpCapabilities GetCapabilities() const { return capabilities_; } void set_rtp_header_extensions( const std::vector<RtpHeaderExtension>& extensions) { - rtp_header_extensions_ = extensions; + capabilities_.header_extensions = extensions; } protected: - int loglevel_; - std::string logfilter_; // Flag used by optionsmessagehandler_unittest for checking whether any // relevant setting has been updated. // TODO(thaloun): Replace with explicit checks of before & after values. bool options_changed_; bool fail_create_channel_; - std::vector<RtpHeaderExtension> rtp_header_extensions_; + RtpCapabilities capabilities_; }; class FakeVoiceEngine : public FakeBaseEngine { @@ -733,14 +727,8 @@ } bool Init(rtc::Thread* worker_thread) { return true; } void Terminate() {} - webrtc::VoiceEngine* GetVoE() { return nullptr; } - AudioOptions GetOptions() const { - return options_; - } - bool SetOptions(const AudioOptions& options) { - options_ = options; - options_changed_ = true; - return true; + rtc::scoped_refptr<webrtc::AudioState> GetAudioState() const { + return rtc::scoped_refptr<webrtc::AudioState>(); } VoiceMediaChannel* CreateChannel(webrtc::Call* call, @@ -763,21 +751,12 @@ const std::vector<AudioCodec>& codecs() { return codecs_; } void SetCodecs(const std::vector<AudioCodec> codecs) { codecs_ = codecs; } - bool SetDevices(const Device* in_device, const Device* out_device) { - in_device_ = (in_device) ? in_device->name : ""; - out_device_ = (out_device) ? out_device->name : ""; - options_changed_ = true; - return true; - } - bool GetOutputVolume(int* level) { *level = output_volume_; return true; } - bool SetOutputVolume(int level) { output_volume_ = level; - options_changed_ = true; return true; } @@ -795,9 +774,6 @@ std::vector<FakeVoiceMediaChannel*> channels_; std::vector<AudioCodec> codecs_; int output_volume_; - std::string in_device_; - std::string out_device_; - AudioOptions options_; friend class FakeMediaEngine; }; @@ -815,13 +791,6 @@ options_changed_ = true; return true; } - bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { - default_encoder_config_ = config; - return true; - } - const VideoEncoderConfig& default_encoder_config() const { - return default_encoder_config_; - } VideoMediaChannel* CreateChannel(webrtc::Call* call, const VideoOptions& options) { @@ -864,7 +833,6 @@ private: std::vector<FakeVideoMediaChannel*> channels_; std::vector<VideoCodec> codecs_; - VideoEncoderConfig default_encoder_config_; std::string in_device_; bool capture_; VideoOptions options_; @@ -875,10 +843,7 @@ class FakeMediaEngine : public CompositeMediaEngine<FakeVoiceEngine, FakeVideoEngine> { public: - FakeMediaEngine() { - voice_ = FakeVoiceEngine(); - video_ = FakeVideoEngine(); - } + FakeMediaEngine() {} virtual ~FakeMediaEngine() {} void SetAudioCodecs(const std::vector<AudioCodec>& codecs) { @@ -904,24 +869,13 @@ return video_.GetChannel(index); } - AudioOptions audio_options() const { return voice_.options_; } int output_volume() const { return voice_.output_volume_; } - const VideoEncoderConfig& default_video_encoder_config() const { - return video_.default_encoder_config_; - } - const std::string& audio_in_device() const { return voice_.in_device_; } - const std::string& audio_out_device() const { return voice_.out_device_; } - int voice_loglevel() const { return voice_.loglevel_; } - const std::string& voice_logfilter() const { return voice_.logfilter_; } - int video_loglevel() const { return video_.loglevel_; } - const std::string& video_logfilter() const { return video_.logfilter_; } bool capture() const { return video_.capture_; } bool options_changed() const { - return voice_.options_changed_ || video_.options_changed_; + return video_.options_changed_; } void clear_options_changed() { video_.options_changed_ = false; - voice_.options_changed_ = false; } void set_fail_create_channel(bool fail) { voice_.set_fail_create_channel(fail);
diff --git a/talk/media/base/fakemediaprocessor.h b/talk/media/base/fakemediaprocessor.h deleted file mode 100644 index 8de2678..0000000 --- a/talk/media/base/fakemediaprocessor.h +++ /dev/null
@@ -1,29 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// TODO(solenberg): Remove this file once Chromium's libjingle.gyp/.gn are -// updated.
diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h index 1466084..f6fb77d 100644 --- a/talk/media/base/mediachannel.h +++ b/talk/media/base/mediachannel.h
@@ -38,6 +38,7 @@ #include "webrtc/base/buffer.h" #include "webrtc/base/dscp.h" #include "webrtc/base/logging.h" +#include "webrtc/base/optional.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/socket.h" #include "webrtc/base/window.h" @@ -50,88 +51,30 @@ class Timing; } +namespace webrtc { +class AudioSinkInterface; +} + namespace cricket { class AudioRenderer; -struct RtpHeader; class ScreencastId; -struct VideoFormat; class VideoCapturer; class VideoRenderer; +struct RtpHeader; +struct VideoFormat; const int kMinRtpHeaderExtensionId = 1; const int kMaxRtpHeaderExtensionId = 255; const int kScreencastDefaultFps = 5; -// Used in AudioOptions and VideoOptions to signify "unset" values. template <class T> -class Settable { - public: - Settable() : set_(false), val_() {} - explicit Settable(T val) : set_(true), val_(val) {} - - bool IsSet() const { - return set_; - } - - bool Get(T* out) const { - *out = val_; - return set_; - } - - T GetWithDefaultIfUnset(const T& default_value) const { - return set_ ? val_ : default_value; - } - - void Set(T val) { - set_ = true; - val_ = val; - } - - void Clear() { - Set(T()); - set_ = false; - } - - void SetFrom(const Settable<T>& o) { - // Set this value based on the value of o, iff o is set. If this value is - // set and o is unset, the current value will be unchanged. - T val; - if (o.Get(&val)) { - Set(val); - } - } - - std::string ToString() const { - return set_ ? rtc::ToString(val_) : ""; - } - - bool operator==(const Settable<T>& o) const { - // Equal if both are unset with any value or both set with the same value. - return (set_ == o.set_) && (!set_ || (val_ == o.val_)); - } - - bool operator!=(const Settable<T>& o) const { - return !operator==(o); - } - - protected: - void InitializeValue(const T &val) { - val_ = val; - } - - private: - bool set_; - T val_; -}; - -template <class T> -static std::string ToStringIfSet(const char* key, const Settable<T>& val) { +static std::string ToStringIfSet(const char* key, const rtc::Optional<T>& val) { std::string str; - if (val.IsSet()) { + if (val) { str = key; str += ": "; - str += val.ToString(); + str += val ? rtc::ToString(*val) : ""; str += ", "; } return str; @@ -157,32 +100,32 @@ // but some things currently still use flags. struct AudioOptions { void SetAll(const AudioOptions& change) { - echo_cancellation.SetFrom(change.echo_cancellation); - auto_gain_control.SetFrom(change.auto_gain_control); - noise_suppression.SetFrom(change.noise_suppression); - highpass_filter.SetFrom(change.highpass_filter); - stereo_swapping.SetFrom(change.stereo_swapping); - audio_jitter_buffer_max_packets.SetFrom( - change.audio_jitter_buffer_max_packets); - audio_jitter_buffer_fast_accelerate.SetFrom( - change.audio_jitter_buffer_fast_accelerate); - typing_detection.SetFrom(change.typing_detection); - aecm_generate_comfort_noise.SetFrom(change.aecm_generate_comfort_noise); - conference_mode.SetFrom(change.conference_mode); - adjust_agc_delta.SetFrom(change.adjust_agc_delta); - experimental_agc.SetFrom(change.experimental_agc); - extended_filter_aec.SetFrom(change.extended_filter_aec); - delay_agnostic_aec.SetFrom(change.delay_agnostic_aec); - experimental_ns.SetFrom(change.experimental_ns); - aec_dump.SetFrom(change.aec_dump); - tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov); - tx_agc_digital_compression_gain.SetFrom( - change.tx_agc_digital_compression_gain); - tx_agc_limiter.SetFrom(change.tx_agc_limiter); - recording_sample_rate.SetFrom(change.recording_sample_rate); - playout_sample_rate.SetFrom(change.playout_sample_rate); - dscp.SetFrom(change.dscp); - combined_audio_video_bwe.SetFrom(change.combined_audio_video_bwe); + SetFrom(&echo_cancellation, change.echo_cancellation); + SetFrom(&auto_gain_control, change.auto_gain_control); + SetFrom(&noise_suppression, change.noise_suppression); + SetFrom(&highpass_filter, change.highpass_filter); + SetFrom(&stereo_swapping, change.stereo_swapping); + SetFrom(&audio_jitter_buffer_max_packets, + change.audio_jitter_buffer_max_packets); + SetFrom(&audio_jitter_buffer_fast_accelerate, + change.audio_jitter_buffer_fast_accelerate); + SetFrom(&typing_detection, change.typing_detection); + SetFrom(&aecm_generate_comfort_noise, change.aecm_generate_comfort_noise); + SetFrom(&conference_mode, change.conference_mode); + SetFrom(&adjust_agc_delta, change.adjust_agc_delta); + SetFrom(&experimental_agc, change.experimental_agc); + SetFrom(&extended_filter_aec, change.extended_filter_aec); + SetFrom(&delay_agnostic_aec, change.delay_agnostic_aec); + SetFrom(&experimental_ns, change.experimental_ns); + SetFrom(&aec_dump, change.aec_dump); + SetFrom(&tx_agc_target_dbov, change.tx_agc_target_dbov); + SetFrom(&tx_agc_digital_compression_gain, + change.tx_agc_digital_compression_gain); + SetFrom(&tx_agc_limiter, change.tx_agc_limiter); + SetFrom(&recording_sample_rate, change.recording_sample_rate); + SetFrom(&playout_sample_rate, change.playout_sample_rate); + SetFrom(&dscp, change.dscp); + SetFrom(&combined_audio_video_bwe, change.combined_audio_video_bwe); } bool operator==(const AudioOptions& o) const { @@ -247,39 +190,47 @@ // Audio processing that attempts to filter away the output signal from // later inbound pickup. - Settable<bool> echo_cancellation; + rtc::Optional<bool> echo_cancellation; // Audio processing to adjust the sensitivity of the local mic dynamically. - Settable<bool> auto_gain_control; + rtc::Optional<bool> auto_gain_control; // Audio processing to filter out background noise. - Settable<bool> noise_suppression; + rtc::Optional<bool> noise_suppression; // Audio processing to remove background noise of lower frequencies. - Settable<bool> highpass_filter; + rtc::Optional<bool> highpass_filter; // Audio processing to swap the left and right channels. - Settable<bool> stereo_swapping; + rtc::Optional<bool> stereo_swapping; // Audio receiver jitter buffer (NetEq) max capacity in number of packets. - Settable<int> audio_jitter_buffer_max_packets; + rtc::Optional<int> audio_jitter_buffer_max_packets; // Audio receiver jitter buffer (NetEq) fast accelerate mode. - Settable<bool> audio_jitter_buffer_fast_accelerate; + rtc::Optional<bool> audio_jitter_buffer_fast_accelerate; // Audio processing to detect typing. - Settable<bool> typing_detection; - Settable<bool> aecm_generate_comfort_noise; - Settable<bool> conference_mode; - Settable<int> adjust_agc_delta; - Settable<bool> experimental_agc; - Settable<bool> extended_filter_aec; - Settable<bool> delay_agnostic_aec; - Settable<bool> experimental_ns; - Settable<bool> aec_dump; + rtc::Optional<bool> typing_detection; + rtc::Optional<bool> aecm_generate_comfort_noise; + rtc::Optional<bool> conference_mode; + rtc::Optional<int> adjust_agc_delta; + rtc::Optional<bool> experimental_agc; + rtc::Optional<bool> extended_filter_aec; + rtc::Optional<bool> delay_agnostic_aec; + rtc::Optional<bool> experimental_ns; + rtc::Optional<bool> aec_dump; // Note that tx_agc_* only applies to non-experimental AGC. - Settable<uint16_t> tx_agc_target_dbov; - Settable<uint16_t> tx_agc_digital_compression_gain; - Settable<bool> tx_agc_limiter; - Settable<uint32_t> recording_sample_rate; - Settable<uint32_t> playout_sample_rate; + rtc::Optional<uint16_t> tx_agc_target_dbov; + rtc::Optional<uint16_t> tx_agc_digital_compression_gain; + rtc::Optional<bool> tx_agc_limiter; + rtc::Optional<uint32_t> recording_sample_rate; + rtc::Optional<uint32_t> playout_sample_rate; // Set DSCP value for packet sent from audio channel. - Settable<bool> dscp; + rtc::Optional<bool> dscp; // Enable combined audio+bandwidth BWE. - Settable<bool> combined_audio_video_bwe; + rtc::Optional<bool> combined_audio_video_bwe; + + private: + template <typename T> + static void SetFrom(rtc::Optional<T>* s, const rtc::Optional<T>& o) { + if (o) { + *s = o; + } + } }; // Options that can be applied to a VideoMediaChannel or a VideoMediaEngine. @@ -287,38 +238,41 @@ // We are moving all of the setting of options to structs like this, // but some things currently still use flags. struct VideoOptions { - VideoOptions() { - process_adaptation_threshhold.Set(kProcessCpuThreshold); - system_low_adaptation_threshhold.Set(kLowSystemCpuThreshold); - system_high_adaptation_threshhold.Set(kHighSystemCpuThreshold); - unsignalled_recv_stream_limit.Set(kNumDefaultUnsignalledVideoRecvStreams); - } + VideoOptions() + : process_adaptation_threshhold(kProcessCpuThreshold), + system_low_adaptation_threshhold(kLowSystemCpuThreshold), + system_high_adaptation_threshhold(kHighSystemCpuThreshold), + unsignalled_recv_stream_limit(kNumDefaultUnsignalledVideoRecvStreams) {} void SetAll(const VideoOptions& change) { - adapt_input_to_cpu_usage.SetFrom(change.adapt_input_to_cpu_usage); - adapt_cpu_with_smoothing.SetFrom(change.adapt_cpu_with_smoothing); - video_adapt_third.SetFrom(change.video_adapt_third); - video_noise_reduction.SetFrom(change.video_noise_reduction); - video_start_bitrate.SetFrom(change.video_start_bitrate); - cpu_overuse_detection.SetFrom(change.cpu_overuse_detection); - cpu_underuse_threshold.SetFrom(change.cpu_underuse_threshold); - cpu_overuse_threshold.SetFrom(change.cpu_overuse_threshold); - cpu_underuse_encode_rsd_threshold.SetFrom( - change.cpu_underuse_encode_rsd_threshold); - cpu_overuse_encode_rsd_threshold.SetFrom( - change.cpu_overuse_encode_rsd_threshold); - cpu_overuse_encode_usage.SetFrom(change.cpu_overuse_encode_usage); - conference_mode.SetFrom(change.conference_mode); - process_adaptation_threshhold.SetFrom(change.process_adaptation_threshhold); - system_low_adaptation_threshhold.SetFrom( - change.system_low_adaptation_threshhold); - system_high_adaptation_threshhold.SetFrom( - change.system_high_adaptation_threshhold); - dscp.SetFrom(change.dscp); - suspend_below_min_bitrate.SetFrom(change.suspend_below_min_bitrate); - unsignalled_recv_stream_limit.SetFrom(change.unsignalled_recv_stream_limit); - use_simulcast_adapter.SetFrom(change.use_simulcast_adapter); - screencast_min_bitrate.SetFrom(change.screencast_min_bitrate); + SetFrom(&adapt_input_to_cpu_usage, change.adapt_input_to_cpu_usage); + SetFrom(&adapt_cpu_with_smoothing, change.adapt_cpu_with_smoothing); + SetFrom(&video_adapt_third, change.video_adapt_third); + SetFrom(&video_noise_reduction, change.video_noise_reduction); + SetFrom(&video_start_bitrate, change.video_start_bitrate); + SetFrom(&cpu_overuse_detection, change.cpu_overuse_detection); + SetFrom(&cpu_underuse_threshold, change.cpu_underuse_threshold); + SetFrom(&cpu_overuse_threshold, change.cpu_overuse_threshold); + SetFrom(&cpu_underuse_encode_rsd_threshold, + change.cpu_underuse_encode_rsd_threshold); + SetFrom(&cpu_overuse_encode_rsd_threshold, + change.cpu_overuse_encode_rsd_threshold); + SetFrom(&cpu_overuse_encode_usage, change.cpu_overuse_encode_usage); + SetFrom(&conference_mode, change.conference_mode); + SetFrom(&process_adaptation_threshhold, + change.process_adaptation_threshhold); + SetFrom(&system_low_adaptation_threshhold, + change.system_low_adaptation_threshhold); + SetFrom(&system_high_adaptation_threshhold, + change.system_high_adaptation_threshhold); + SetFrom(&dscp, change.dscp); + SetFrom(&suspend_below_min_bitrate, change.suspend_below_min_bitrate); + SetFrom(&unsignalled_recv_stream_limit, + change.unsignalled_recv_stream_limit); + SetFrom(&use_simulcast_adapter, change.use_simulcast_adapter); + SetFrom(&screencast_min_bitrate, change.screencast_min_bitrate); + SetFrom(&disable_prerenderer_smoothing, + change.disable_prerenderer_smoothing); } bool operator==(const VideoOptions& o) const { @@ -345,7 +299,8 @@ suspend_below_min_bitrate == o.suspend_below_min_bitrate && unsignalled_recv_stream_limit == o.unsignalled_recv_stream_limit && use_simulcast_adapter == o.use_simulcast_adapter && - screencast_min_bitrate == o.screencast_min_bitrate; + screencast_min_bitrate == o.screencast_min_bitrate && + disable_prerenderer_smoothing == o.disable_prerenderer_smoothing; } std::string ToString() const { @@ -381,56 +336,71 @@ } // Enable CPU adaptation? - Settable<bool> adapt_input_to_cpu_usage; + rtc::Optional<bool> adapt_input_to_cpu_usage; // Enable CPU adaptation smoothing? - Settable<bool> adapt_cpu_with_smoothing; + rtc::Optional<bool> adapt_cpu_with_smoothing; // Enable video adapt third? - Settable<bool> video_adapt_third; + rtc::Optional<bool> video_adapt_third; // Enable denoising? - Settable<bool> video_noise_reduction; + rtc::Optional<bool> video_noise_reduction; // Experimental: Enable WebRtc higher start bitrate? - Settable<int> video_start_bitrate; + rtc::Optional<int> video_start_bitrate; // Enable WebRTC Cpu Overuse Detection, which is a new version of the CPU // adaptation algorithm. So this option will override the // |adapt_input_to_cpu_usage|. - Settable<bool> cpu_overuse_detection; + rtc::Optional<bool> cpu_overuse_detection; // Low threshold (t1) for cpu overuse adaptation. (Adapt up) // Metric: encode usage (m1). m1 < t1 => underuse. - Settable<int> cpu_underuse_threshold; + rtc::Optional<int> cpu_underuse_threshold; // High threshold (t1) for cpu overuse adaptation. (Adapt down) // Metric: encode usage (m1). m1 > t1 => overuse. - Settable<int> cpu_overuse_threshold; + rtc::Optional<int> cpu_overuse_threshold; // Low threshold (t2) for cpu overuse adaptation. (Adapt up) // Metric: relative standard deviation of encode time (m2). // Optional threshold. If set, (m1 < t1 && m2 < t2) => underuse. // Note: t2 will have no effect if t1 is not set. - Settable<int> cpu_underuse_encode_rsd_threshold; + rtc::Optional<int> cpu_underuse_encode_rsd_threshold; // High threshold (t2) for cpu overuse adaptation. (Adapt down) // Metric: relative standard deviation of encode time (m2). // Optional threshold. If set, (m1 > t1 || m2 > t2) => overuse. // Note: t2 will have no effect if t1 is not set. - Settable<int> cpu_overuse_encode_rsd_threshold; + rtc::Optional<int> cpu_overuse_encode_rsd_threshold; // Use encode usage for cpu detection. - Settable<bool> cpu_overuse_encode_usage; + rtc::Optional<bool> cpu_overuse_encode_usage; // Use conference mode? - Settable<bool> conference_mode; + rtc::Optional<bool> conference_mode; // Threshhold for process cpu adaptation. (Process limit) - Settable<float> process_adaptation_threshhold; + rtc::Optional<float> process_adaptation_threshhold; // Low threshhold for cpu adaptation. (Adapt up) - Settable<float> system_low_adaptation_threshhold; + rtc::Optional<float> system_low_adaptation_threshhold; // High threshhold for cpu adaptation. (Adapt down) - Settable<float> system_high_adaptation_threshhold; + rtc::Optional<float> system_high_adaptation_threshhold; // Set DSCP value for packet sent from video channel. - Settable<bool> dscp; + rtc::Optional<bool> dscp; // Enable WebRTC suspension of video. No video frames will be sent when the // bitrate is below the configured minimum bitrate. - Settable<bool> suspend_below_min_bitrate; + rtc::Optional<bool> suspend_below_min_bitrate; // Limit on the number of early receive channels that can be created. - Settable<int> unsignalled_recv_stream_limit; + rtc::Optional<int> unsignalled_recv_stream_limit; // Enable use of simulcast adapter. - Settable<bool> use_simulcast_adapter; + rtc::Optional<bool> use_simulcast_adapter; // Force screencast to use a minimum bitrate - Settable<int> screencast_min_bitrate; + rtc::Optional<int> screencast_min_bitrate; + // Set to true if the renderer has an algorithm of frame selection. + // If the value is true, then WebRTC will hand over a frame as soon as + // possible without delay, and rendering smoothness is completely the duty + // of the renderer; + // If the value is false, then WebRTC is responsible to delay frame release + // in order to increase rendering smoothness. + rtc::Optional<bool> disable_prerenderer_smoothing; + + private: + template <typename T> + static void SetFrom(rtc::Optional<T>* s, const rtc::Optional<T>& o) { + if (o) { + *s = o; + } + } }; struct RtpHeaderExtension { @@ -447,8 +417,8 @@ std::string ToString() const { std::ostringstream ost; ost << "{"; - ost << "id: , " << id; ost << "uri: " << uri; + ost << ", id: " << id; ost << "}"; return ost.str(); } @@ -481,12 +451,6 @@ OPT_AGC_MINUS_10DB = 0x80000000 }; -// DTMF flags to control if a DTMF tone should be played and/or sent. -enum DtmfFlags { - DF_PLAY = 0x01, - DF_SEND = 0x02, -}; - class MediaChannel : public sigslot::has_slots<> { public: class NetworkInterface { @@ -593,7 +557,6 @@ enum SendFlags { SEND_NOTHING, - SEND_RINGBACKTONE, SEND_MICROPHONE }; @@ -820,6 +783,7 @@ } std::vector<SsrcGroup> ssrc_groups; + std::string encoder_implementation_name; int packets_cached; int firs_rcvd; int plis_rcvd; @@ -865,6 +829,7 @@ } std::vector<SsrcGroup> ssrc_groups; + std::string decoder_implementation_name; int packets_concealed; int firs_sent; int plis_sent; @@ -968,9 +933,13 @@ std::vector<DataReceiverInfo> receivers; }; +struct RtcpParameters { + bool reduced_size = false; +}; + template <class Codec> struct RtpParameters { - virtual std::string ToString() { + virtual std::string ToString() const { std::ostringstream ost; ost << "{"; ost << "codecs: " << VectorToString(codecs) << ", "; @@ -982,11 +951,12 @@ std::vector<Codec> codecs; std::vector<RtpHeaderExtension> extensions; // TODO(pthatcher): Add streams. + RtcpParameters rtcp; }; template <class Codec, class Options> struct RtpSendParameters : RtpParameters<Codec> { - std::string ToString() override { + std::string ToString() const override { std::ostringstream ost; ost << "{"; ost << "codecs: " << VectorToString(this->codecs) << ", "; @@ -1056,18 +1026,18 @@ // Set speaker output volume of the specified ssrc. virtual bool SetOutputVolume(uint32_t ssrc, double volume) = 0; // Returns if the telephone-event has been negotiated. - virtual bool CanInsertDtmf() { return false; } - // Send and/or play a DTMF |event| according to the |flags|. - // The DTMF out-of-band signal will be used on sending. + virtual bool CanInsertDtmf() = 0; + // Send a DTMF |event|. The DTMF out-of-band signal will be used. // The |ssrc| should be either 0 or a valid send stream ssrc. // The valid value for the |event| are 0 to 15 which corresponding to // DTMF event 0-9, *, #, A-D. - virtual bool InsertDtmf(uint32_t ssrc, - int event, - int duration, - int flags) = 0; + virtual bool InsertDtmf(uint32_t ssrc, int event, int duration) = 0; // Gets quality stats for the channel. virtual bool GetStats(VoiceMediaInfo* info) = 0; + + virtual void SetRawAudioSink( + uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) = 0; }; struct VideoSendParameters : RtpSendParameters<VideoCodec, VideoOptions> { @@ -1194,13 +1164,13 @@ enum SendDataResult { SDR_SUCCESS, SDR_ERROR, SDR_BLOCK }; struct DataOptions { - std::string ToString() { + std::string ToString() const { return "{}"; } }; struct DataSendParameters : RtpSendParameters<DataCodec, DataOptions> { - std::string ToString() { + std::string ToString() const { std::ostringstream ost; // Options and extensions aren't used. ost << "{";
diff --git a/talk/media/base/mediaengine.h b/talk/media/base/mediaengine.h index 1a992d7..467614b 100644 --- a/talk/media/base/mediaengine.h +++ b/talk/media/base/mediaengine.h
@@ -28,7 +28,7 @@ #ifndef TALK_MEDIA_BASE_MEDIAENGINE_H_ #define TALK_MEDIA_BASE_MEDIAENGINE_H_ -#ifdef OSX +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) #include <CoreAudio/CoreAudio.h> #endif @@ -40,8 +40,8 @@ #include "talk/media/base/mediacommon.h" #include "talk/media/base/videocapturer.h" #include "talk/media/base/videocommon.h" -#include "talk/media/base/voiceprocessor.h" #include "talk/media/devices/devicemanager.h" +#include "webrtc/audio_state.h" #include "webrtc/base/fileutils.h" #include "webrtc/base/sigslotrepeater.h" @@ -51,13 +51,16 @@ namespace webrtc { class Call; -class VoiceEngine; } namespace cricket { class VideoCapturer; +struct RtpCapabilities { + std::vector<RtpHeaderExtension> header_extensions; +}; + // MediaEngineInterface is an abstraction of a media engine which can be // subclassed to support different media componentry backends. // It supports voice and video operations in the same class to facilitate @@ -72,7 +75,7 @@ // Shuts down the engine. virtual void Terminate() = 0; // TODO(solenberg): Remove once VoE API refactoring is done. - virtual webrtc::VoiceEngine* GetVoE() = 0; + virtual rtc::scoped_refptr<webrtc::AudioState> GetAudioState() const = 0; // MediaChannel creation // Creates a voice media channel. Returns NULL on failure. @@ -85,20 +88,6 @@ webrtc::Call* call, const VideoOptions& options) = 0; - // Configuration - // Gets global audio options. - virtual AudioOptions GetAudioOptions() const = 0; - // Sets global audio options. "options" are from AudioOptions, above. - virtual bool SetAudioOptions(const AudioOptions& options) = 0; - // Sets the default (maximum) codec/resolution and encoder option to capture - // and encode video. - virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) - = 0; - - // Device selection - virtual bool SetSoundDevices(const Device* in_device, - const Device* out_device) = 0; - // Device configuration // Gets the current speaker volume, as a value between 0 and 255. virtual bool GetOutputVolume(int* level) = 0; @@ -109,15 +98,9 @@ virtual int GetInputLevel() = 0; virtual const std::vector<AudioCodec>& audio_codecs() = 0; - virtual const std::vector<RtpHeaderExtension>& - audio_rtp_header_extensions() = 0; + virtual RtpCapabilities GetAudioCapabilities() = 0; virtual const std::vector<VideoCodec>& video_codecs() = 0; - virtual const std::vector<RtpHeaderExtension>& - video_rtp_header_extensions() = 0; - - // Logging control - virtual void SetVoiceLogging(int min_sev, const char* filter) = 0; - virtual void SetVideoLogging(int min_sev, const char* filter) = 0; + virtual RtpCapabilities GetVideoCapabilities() = 0; // Starts AEC dump using existing file. virtual bool StartAecDump(rtc::PlatformFile file) = 0; @@ -167,8 +150,8 @@ voice_.Terminate(); } - virtual webrtc::VoiceEngine* GetVoE() { - return voice_.GetVoE(); + virtual rtc::scoped_refptr<webrtc::AudioState> GetAudioState() const { + return voice_.GetAudioState(); } virtual VoiceMediaChannel* CreateChannel(webrtc::Call* call, const AudioOptions& options) { @@ -179,21 +162,6 @@ return video_.CreateChannel(call, options); } - virtual AudioOptions GetAudioOptions() const { - return voice_.GetOptions(); - } - virtual bool SetAudioOptions(const AudioOptions& options) { - return voice_.SetOptions(options); - } - virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) { - return video_.SetDefaultEncoderConfig(config); - } - - virtual bool SetSoundDevices(const Device* in_device, - const Device* out_device) { - return voice_.SetDevices(in_device, out_device); - } - virtual bool GetOutputVolume(int* level) { return voice_.GetOutputVolume(level); } @@ -207,21 +175,14 @@ virtual const std::vector<AudioCodec>& audio_codecs() { return voice_.codecs(); } - virtual const std::vector<RtpHeaderExtension>& audio_rtp_header_extensions() { - return voice_.rtp_header_extensions(); + virtual RtpCapabilities GetAudioCapabilities() { + return voice_.GetCapabilities(); } virtual const std::vector<VideoCodec>& video_codecs() { return video_.codecs(); } - virtual const std::vector<RtpHeaderExtension>& video_rtp_header_extensions() { - return video_.rtp_header_extensions(); - } - - virtual void SetVoiceLogging(int min_sev, const char* filter) { - voice_.SetLogging(min_sev, filter); - } - virtual void SetVideoLogging(int min_sev, const char* filter) { - video_.SetLogging(min_sev, filter); + virtual RtpCapabilities GetVideoCapabilities() { + return video_.GetCapabilities(); } virtual bool StartAecDump(rtc::PlatformFile file) { @@ -243,70 +204,6 @@ VIDEO video_; }; -// NullVoiceEngine can be used with CompositeMediaEngine in the case where only -// a video engine is desired. -class NullVoiceEngine { - public: - bool Init(rtc::Thread* worker_thread) { return true; } - void Terminate() {} - // If you need this to return an actual channel, use FakeMediaEngine instead. - VoiceMediaChannel* CreateChannel(const AudioOptions& options) { - return nullptr; - } - AudioOptions GetOptions() const { return AudioOptions(); } - bool SetOptions(const AudioOptions& options) { return true; } - bool SetDevices(const Device* in_device, const Device* out_device) { - return true; - } - bool GetOutputVolume(int* level) { - *level = 0; - return true; - } - bool SetOutputVolume(int level) { return true; } - int GetInputLevel() { return 0; } - const std::vector<AudioCodec>& codecs() { return codecs_; } - const std::vector<RtpHeaderExtension>& rtp_header_extensions() { - return rtp_header_extensions_; - } - void SetLogging(int min_sev, const char* filter) {} - bool StartAecDump(rtc::PlatformFile file) { return false; } - bool StartRtcEventLog(rtc::PlatformFile file) { return false; } - void StopRtcEventLog() {} - - private: - std::vector<AudioCodec> codecs_; - std::vector<RtpHeaderExtension> rtp_header_extensions_; -}; - -// NullVideoEngine can be used with CompositeMediaEngine in the case where only -// a voice engine is desired. -class NullVideoEngine { - public: - bool Init(rtc::Thread* worker_thread) { return true; } - void Terminate() {} - // If you need this to return an actual channel, use FakeMediaEngine instead. - VideoMediaChannel* CreateChannel( - const VideoOptions& options, - VoiceMediaChannel* voice_media_channel) { - return NULL; - } - bool SetOptions(const VideoOptions& options) { return true; } - bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { - return true; - } - const std::vector<VideoCodec>& codecs() { return codecs_; } - const std::vector<RtpHeaderExtension>& rtp_header_extensions() { - return rtp_header_extensions_; - } - void SetLogging(int min_sev, const char* filter) {} - - private: - std::vector<VideoCodec> codecs_; - std::vector<RtpHeaderExtension> rtp_header_extensions_; -}; - -typedef CompositeMediaEngine<NullVoiceEngine, NullVideoEngine> NullMediaEngine; - enum DataChannelType { DCT_NONE = 0, DCT_RTP = 1,
diff --git a/talk/media/base/streamparams_unittest.cc b/talk/media/base/streamparams_unittest.cc index a9e1ce3..a016473 100644 --- a/talk/media/base/streamparams_unittest.cc +++ b/talk/media/base/streamparams_unittest.cc
@@ -27,6 +27,7 @@ #include "talk/media/base/streamparams.h" #include "talk/media/base/testutils.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/gunit.h" static const uint32_t kSsrcs1[] = {1}; @@ -54,8 +55,8 @@ cricket::SsrcGroup("abc", MAKE_VECTOR(kSsrcs2)), }; - for (size_t i = 0; i < ARRAY_SIZE(ssrc_groups); ++i) { - for (size_t j = 0; j < ARRAY_SIZE(ssrc_groups); ++j) { + for (size_t i = 0; i < arraysize(ssrc_groups); ++i) { + for (size_t j = 0; j < arraysize(ssrc_groups); ++j) { EXPECT_EQ((ssrc_groups[i] == ssrc_groups[j]), (i == j)); EXPECT_EQ((ssrc_groups[i] != ssrc_groups[j]), (i != j)); } @@ -92,7 +93,7 @@ TEST(StreamParams, HasSsrcGroup) { cricket::StreamParams sp = - CreateStreamParamsWithSsrcGroup("XYZ", kSsrcs2, ARRAY_SIZE(kSsrcs2)); + CreateStreamParamsWithSsrcGroup("XYZ", kSsrcs2, arraysize(kSsrcs2)); EXPECT_EQ(2U, sp.ssrcs.size()); EXPECT_EQ(kSsrcs2[0], sp.first_ssrc()); EXPECT_TRUE(sp.has_ssrcs()); @@ -107,7 +108,7 @@ TEST(StreamParams, GetSsrcGroup) { cricket::StreamParams sp = - CreateStreamParamsWithSsrcGroup("XYZ", kSsrcs2, ARRAY_SIZE(kSsrcs2)); + CreateStreamParamsWithSsrcGroup("XYZ", kSsrcs2, arraysize(kSsrcs2)); EXPECT_EQ(NULL, sp.get_ssrc_group("xyz")); EXPECT_EQ(&sp.ssrc_groups[0], sp.get_ssrc_group("XYZ")); } @@ -116,17 +117,17 @@ cricket::StreamParams l1 = cricket::StreamParams::CreateLegacy(1); cricket::StreamParams l2 = cricket::StreamParams::CreateLegacy(2); cricket::StreamParams sg1 = - CreateStreamParamsWithSsrcGroup("ABC", kSsrcs1, ARRAY_SIZE(kSsrcs1)); + CreateStreamParamsWithSsrcGroup("ABC", kSsrcs1, arraysize(kSsrcs1)); cricket::StreamParams sg2 = - CreateStreamParamsWithSsrcGroup("ABC", kSsrcs2, ARRAY_SIZE(kSsrcs2)); + CreateStreamParamsWithSsrcGroup("ABC", kSsrcs2, arraysize(kSsrcs2)); cricket::StreamParams sg3 = - CreateStreamParamsWithSsrcGroup("Abc", kSsrcs2, ARRAY_SIZE(kSsrcs2)); + CreateStreamParamsWithSsrcGroup("Abc", kSsrcs2, arraysize(kSsrcs2)); cricket::StreamParams sg4 = - CreateStreamParamsWithSsrcGroup("abc", kSsrcs2, ARRAY_SIZE(kSsrcs2)); + CreateStreamParamsWithSsrcGroup("abc", kSsrcs2, arraysize(kSsrcs2)); cricket::StreamParams sps[] = {l1, l2, sg1, sg2, sg3, sg4}; - for (size_t i = 0; i < ARRAY_SIZE(sps); ++i) { - for (size_t j = 0; j < ARRAY_SIZE(sps); ++j) { + for (size_t i = 0; i < arraysize(sps); ++i) { + for (size_t j = 0; j < arraysize(sps); ++j) { EXPECT_EQ((sps[i] == sps[j]), (i == j)); EXPECT_EQ((sps[i] != sps[j]), (i != j)); } @@ -195,7 +196,7 @@ TEST(StreamParams, ToString) { cricket::StreamParams sp = - CreateStreamParamsWithSsrcGroup("XYZ", kSsrcs2, ARRAY_SIZE(kSsrcs2)); + CreateStreamParamsWithSsrcGroup("XYZ", kSsrcs2, arraysize(kSsrcs2)); EXPECT_STREQ("{ssrcs:[1,2];ssrc_groups:{semantics:XYZ;ssrcs:[1,2]};}", sp.ToString().c_str()); }
diff --git a/talk/media/base/testutils.cc b/talk/media/base/testutils.cc index 3b1fcf0..49a78e6 100644 --- a/talk/media/base/testutils.cc +++ b/talk/media/base/testutils.cc
@@ -132,8 +132,8 @@ }; size_t RtpTestUtility::GetTestPacketCount() { - return std::min(ARRAY_SIZE(kTestRawRtpPackets), - ARRAY_SIZE(kTestRawRtcpPackets)); + return std::min(arraysize(kTestRawRtpPackets), + arraysize(kTestRawRtcpPackets)); } bool RtpTestUtility::WriteTestPackets(size_t count,
diff --git a/talk/media/base/testutils.h b/talk/media/base/testutils.h index cb4146d..20c0d62 100644 --- a/talk/media/base/testutils.h +++ b/talk/media/base/testutils.h
@@ -35,6 +35,7 @@ #include "talk/media/base/mediachannel.h" #include "talk/media/base/videocapturer.h" #include "talk/media/base/videocommon.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/window.h" @@ -54,7 +55,7 @@ template <class T> inline std::vector<T> MakeVector(const T a[], size_t s) { return std::vector<T>(a, a + s); } -#define MAKE_VECTOR(a) cricket::MakeVector(a, ARRAY_SIZE(a)) +#define MAKE_VECTOR(a) cricket::MakeVector(a, arraysize(a)) struct RtpDumpPacket; class RtpDumpWriter;
diff --git a/talk/media/base/videocapturer.cc b/talk/media/base/videocapturer.cc index ca4b906..d525a41 100644 --- a/talk/media/base/videocapturer.cc +++ b/talk/media/base/videocapturer.cc
@@ -59,7 +59,7 @@ }; static const int64_t kMaxDistance = ~(static_cast<int64_t>(1) << 63); -#ifdef LINUX +#ifdef WEBRTC_LINUX static const int kYU12Penalty = 16; // Needs to be higher than MJPG index. #endif static const int kDefaultScreencastFps = 5; @@ -82,7 +82,7 @@ pixel_height(0), time_stamp(0), data_size(0), - rotation(0), + rotation(webrtc::kVideoRotation_0), data(NULL) {} // TODO(fbarchard): Remove this function once lmimediaengine stops using it. @@ -94,11 +94,6 @@ return true; } -webrtc::VideoRotation CapturedFrame::GetRotation() const { - ASSERT(rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270); - return static_cast<webrtc::VideoRotation>(rotation); -} - ///////////////////////////////////////////////////////////////////// // Implementation of class VideoCapturer ///////////////////////////////////////////////////////////////////// @@ -126,7 +121,6 @@ SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured); scaled_width_ = 0; scaled_height_ = 0; - screencast_max_pixels_ = 0; muted_ = false; black_frame_count_down_ = kNumBlackFramesOnMute; enable_video_adapter_ = true; @@ -365,16 +359,11 @@ if (IsScreencast()) { int scaled_width, scaled_height; - if (screencast_max_pixels_ > 0) { - ComputeScaleMaxPixels(captured_frame->width, captured_frame->height, - screencast_max_pixels_, &scaled_width, &scaled_height); - } else { - int desired_screencast_fps = capture_format_.get() ? - VideoFormat::IntervalToFps(capture_format_->interval) : - kDefaultScreencastFps; - ComputeScale(captured_frame->width, captured_frame->height, - desired_screencast_fps, &scaled_width, &scaled_height); - } + int desired_screencast_fps = capture_format_.get() ? + VideoFormat::IntervalToFps(capture_format_->interval) : + kDefaultScreencastFps; + ComputeScale(captured_frame->width, captured_frame->height, + desired_screencast_fps, &scaled_width, &scaled_height); if (FOURCC_ARGB == captured_frame->fourcc && (scaled_width != captured_frame->width || @@ -605,7 +594,7 @@ for (size_t i = 0; i < preferred_fourccs.size(); ++i) { if (supported_fourcc == CanonicalFourCC(preferred_fourccs[i])) { delta_fourcc = i; -#ifdef LINUX +#ifdef WEBRTC_LINUX // For HD avoid YU12 which is a software conversion and has 2 bugs // b/7326348 b/6960899. Reenable when fixed. if (supported.height >= 720 && (supported_fourcc == FOURCC_YU12 ||
diff --git a/talk/media/base/videocapturer.h b/talk/media/base/videocapturer.h index 0a11ed0..a13c201 100644 --- a/talk/media/base/videocapturer.h +++ b/talk/media/base/videocapturer.h
@@ -78,10 +78,6 @@ // fourcc. Return true if succeeded. bool GetDataSize(uint32_t* size) const; - // TODO(guoweis): Change the type of |rotation| from int to - // webrtc::VideoRotation once chromium gets the code. - webrtc::VideoRotation GetRotation() const; - // The width and height of the captured frame could be different from those // of VideoFormat. Once the first frame is captured, the width, height, // fourcc, pixel_width, and pixel_height should keep the same over frames. @@ -90,15 +86,11 @@ uint32_t fourcc; // compression uint32_t pixel_width; // width of a pixel, default is 1 uint32_t pixel_height; // height of a pixel, default is 1 - // TODO(magjed): |elapsed_time| is deprecated - remove once not used anymore. - int64_t elapsed_time; int64_t time_stamp; // timestamp of when the frame was captured, in unix // time with nanosecond units. uint32_t data_size; // number of bytes of the frame data - // TODO(guoweis): This can't be converted to VideoRotation yet as it's - // used by chrome now. - int rotation; // rotation in degrees of the frame (0, 90, 180, 270) + webrtc::VideoRotation rotation; // rotation in degrees of the frame. void* data; // pointer to the frame data. This object allocates the // memory or points to an existing memory. @@ -270,17 +262,6 @@ sigslot::signal2<VideoCapturer*, const VideoFrame*, sigslot::multi_threaded_local> SignalVideoFrame; - // If 'screencast_max_pixels' is set greater than zero, screencasts will be - // scaled to be no larger than this value. - // If set to zero, the max pixels will be limited to - // Retina MacBookPro 15" resolution of 2880 x 1800. - // For high fps, maximum pixels limit is set based on common 24" monitor - // resolution of 2048 x 1280. - int screencast_max_pixels() const { return screencast_max_pixels_; } - void set_screencast_max_pixels(int p) { - screencast_max_pixels_ = std::max(0, p); - } - // If true, run video adaptation. By default, video adaptation is enabled // and users must call video_adapter()->OnOutputFormatRequest() // to receive frames. @@ -377,7 +358,6 @@ bool square_pixel_aspect_ratio_; // Enable scaling to square pixels. int scaled_width_; // Current output size from ComputeScale. int scaled_height_; - int screencast_max_pixels_; // Downscale screencasts further if requested. bool muted_; int black_frame_count_down_;
diff --git a/talk/media/base/videocapturer_unittest.cc b/talk/media/base/videocapturer_unittest.cc index 359fe95..6d1d8aa 100644 --- a/talk/media/base/videocapturer_unittest.cc +++ b/talk/media/base/videocapturer_unittest.cc
@@ -196,39 +196,6 @@ EXPECT_EQ(33, video_frames_received()); } -TEST_F(VideoCapturerTest, ScreencastScaledMaxPixels) { - capturer_.SetScreencast(true); - - int kWidth = 1280; - int kHeight = 720; - - // Screencasts usually have large weird dimensions and are ARGB. - std::vector<cricket::VideoFormat> formats; - formats.push_back(cricket::VideoFormat(kWidth, kHeight, - cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB)); - formats.push_back(cricket::VideoFormat(2 * kWidth, 2 * kHeight, - cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB)); - capturer_.ResetSupportedFormats(formats); - - - EXPECT_EQ(0, capturer_.screencast_max_pixels()); - EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat( - 2 * kWidth, - 2 * kHeight, - cricket::VideoFormat::FpsToInterval(30), - cricket::FOURCC_ARGB))); - EXPECT_TRUE(capturer_.IsRunning()); - EXPECT_EQ(0, renderer_.num_rendered_frames()); - renderer_.SetSize(2 * kWidth, 2 * kHeight, 0); - EXPECT_TRUE(capturer_.CaptureFrame()); - EXPECT_EQ(1, renderer_.num_rendered_frames()); - - capturer_.set_screencast_max_pixels(kWidth * kHeight); - renderer_.SetSize(kWidth, kHeight, 0); - EXPECT_TRUE(capturer_.CaptureFrame()); - EXPECT_EQ(2, renderer_.num_rendered_frames()); -} - TEST_F(VideoCapturerTest, ScreencastScaledOddWidth) { capturer_.SetScreencast(true);
diff --git a/talk/media/base/videocommon.cc b/talk/media/base/videocommon.cc index 7b6aac2..faf6450 100644 --- a/talk/media/base/videocommon.cc +++ b/talk/media/base/videocommon.cc
@@ -31,6 +31,7 @@ #include <math.h> #include <sstream> +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" namespace cricket { @@ -58,7 +59,7 @@ }; uint32_t CanonicalFourCC(uint32_t fourcc) { - for (int i = 0; i < ARRAY_SIZE(kFourCCAliases); ++i) { + for (int i = 0; i < arraysize(kFourCCAliases); ++i) { if (kFourCCAliases[i].alias == fourcc) { return kFourCCAliases[i].canonical; } @@ -75,7 +76,7 @@ 1.f / 16.f // 1/16 scale. }; -static const int kNumScaleFactors = ARRAY_SIZE(kScaleFactors); +static const int kNumScaleFactors = arraysize(kScaleFactors); // Finds the scale factor that, when applied to width and height, produces // fewer than num_pixels. @@ -106,9 +107,6 @@ ASSERT(scaled_width != NULL); ASSERT(scaled_height != NULL); ASSERT(max_pixels > 0); - // For VP8 the values for max width and height can be found here - // webrtc/src/video_engine/vie_defines.h (kViEMaxCodecWidth and - // kViEMaxCodecHeight) const int kMaxWidth = 4096; const int kMaxHeight = 3072; int new_frame_width = frame_width;
diff --git a/talk/media/base/videoengine_unittest.h b/talk/media/base/videoengine_unittest.h index d89b3e6..d7fa00d 100644 --- a/talk/media/base/videoengine_unittest.h +++ b/talk/media/base/videoengine_unittest.h
@@ -126,327 +126,6 @@ } }; -template<class E> -class VideoEngineTest : public testing::Test { - protected: - // Tests starting and stopping the engine, and creating a channel. - void StartupShutdown() { - EXPECT_TRUE(engine_.Init(rtc::Thread::Current())); - cricket::VideoMediaChannel* channel = engine_.CreateChannel(NULL); - EXPECT_TRUE(channel != NULL); - delete channel; - engine_.Terminate(); - } - - void ConstrainNewCodecBody() { - cricket::VideoCodec empty, in, out; - cricket::VideoCodec max_settings(engine_.codecs()[0].id, - engine_.codecs()[0].name, - 1280, 800, 30, 0); - - // set max settings of 1280x800x30 - EXPECT_TRUE(engine_.SetDefaultEncoderConfig( - cricket::VideoEncoderConfig(max_settings))); - - // don't constrain the max resolution - in = max_settings; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // constrain resolution greater than the max and wider aspect, - // picking best aspect (16:10) - in.width = 1380; - in.height = 800; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); - - // constrain resolution greater than the max and narrow aspect, - // picking best aspect (16:9) - in.width = 1280; - in.height = 740; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); - - // constrain resolution greater than the max, picking equal aspect (4:3) - in.width = 1280; - in.height = 960; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); - - // constrain resolution greater than the max, picking equal aspect (16:10) - in.width = 1280; - in.height = 800; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); - - // reduce max settings to 640x480x30 - max_settings.width = 640; - max_settings.height = 480; - EXPECT_TRUE(engine_.SetDefaultEncoderConfig( - cricket::VideoEncoderConfig(max_settings))); - - // don't constrain the max resolution - in = max_settings; - in.width = 640; - in.height = 480; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // keep 16:10 if they request it - in.height = 400; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // don't constrain lesser 4:3 resolutions - in.width = 320; - in.height = 240; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // don't constrain lesser 16:10 resolutions - in.width = 320; - in.height = 200; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // requested resolution of 0x0 succeeds - in.width = 0; - in.height = 0; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // constrain resolution lesser than the max and wider aspect, - // picking best aspect (16:9) - in.width = 350; - in.height = 201; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 320, 180, 30); - - // constrain resolution greater than the max and narrow aspect, - // picking best aspect (4:3) - in.width = 350; - in.height = 300; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 320, 240, 30); - - // constrain resolution greater than the max and wider aspect, - // picking best aspect (16:9) - in.width = 1380; - in.height = 800; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 360, 30); - - // constrain resolution greater than the max and narrow aspect, - // picking best aspect (4:3) - in.width = 1280; - in.height = 900; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 480, 30); - - // constrain resolution greater than the max, picking equal aspect (4:3) - in.width = 1280; - in.height = 960; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 480, 30); - - // constrain resolution greater than the max, picking equal aspect (16:10) - in.width = 1280; - in.height = 800; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); - - // constrain res & fps greater than the max - in.framerate = 50; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); - - // reduce max settings to 160x100x10 - max_settings.width = 160; - max_settings.height = 100; - max_settings.framerate = 10; - EXPECT_TRUE(engine_.SetDefaultEncoderConfig( - cricket::VideoEncoderConfig(max_settings))); - - // constrain res & fps to new max - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 160, 100, 10); - - // allow 4:3 "comparable" resolutions - in.width = 160; - in.height = 120; - in.framerate = 10; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 160, 120, 10); - } - - // This is the new way of constraining codec size, where we no longer maintain - // a list of the supported formats. Instead, CanSendCodec will just downscale - // the resolution by 2 until the width is below clamp. - void ConstrainNewCodec2Body() { - cricket::VideoCodec empty, in, out; - cricket::VideoCodec max_settings(engine_.codecs()[0].id, - engine_.codecs()[0].name, - 1280, 800, 30, 0); - - // Set max settings of 1280x800x30 - EXPECT_TRUE(engine_.SetDefaultEncoderConfig( - cricket::VideoEncoderConfig(max_settings))); - - // Don't constrain the max resolution - in = max_settings; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // Constrain resolution greater than the max width. - in.width = 1380; - in.height = 800; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 690, 400, 30); - - // Don't constrain resolution when only the height is greater than max. - in.width = 960; - in.height = 1280; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 960, 1280, 30); - - // Don't constrain smaller format. - in.width = 640; - in.height = 480; - EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 480, 30); - } - - void ConstrainRunningCodecBody() { - cricket::VideoCodec in, out, current; - cricket::VideoCodec max_settings(engine_.codecs()[0].id, - engine_.codecs()[0].name, - 1280, 800, 30, 0); - - // set max settings of 1280x960x30 - EXPECT_TRUE(engine_.SetDefaultEncoderConfig( - cricket::VideoEncoderConfig(max_settings))); - - // establish current call at 1280x800x30 (16:10) - current = max_settings; - current.height = 800; - - // Don't constrain current resolution - in = current; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // requested resolution of 0x0 succeeds - in.width = 0; - in.height = 0; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // Reduce an intermediate resolution down to the next lowest one, preserving - // aspect ratio. - in.width = 800; - in.height = 600; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); - - // Clamping by aspect ratio, but still never return a dimension higher than - // requested. - in.width = 1280; - in.height = 720; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); - - in.width = 1279; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 960, 600, 30); - - in.width = 1281; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); - - // Clamp large resolutions down, always preserving aspect - in.width = 1920; - in.height = 1080; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); - - in.width = 1921; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); - - in.width = 1919; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); - - // reduce max settings to 640x480x30 - max_settings.width = 640; - max_settings.height = 480; - EXPECT_TRUE(engine_.SetDefaultEncoderConfig( - cricket::VideoEncoderConfig(max_settings))); - - // establish current call at 640x400x30 (16:10) - current = max_settings; - current.height = 400; - - // Don't constrain current resolution - in = current; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // requested resolution of 0x0 succeeds - in.width = 0; - in.height = 0; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED2(IsEqualCodec, out, in); - - // Reduce an intermediate resolution down to the next lowest one, preserving - // aspect ratio. - in.width = 400; - in.height = 300; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 320, 200, 30); - - // Clamping by aspect ratio, but still never return a dimension higher than - // requested. - in.width = 640; - in.height = 360; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 360, 30); - - in.width = 639; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 480, 300, 30); - - in.width = 641; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 360, 30); - - // Clamp large resolutions down, always preserving aspect - in.width = 1280; - in.height = 800; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); - - in.width = 1281; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); - - in.width = 1279; - EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); - EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); - - // Should fail for any that are smaller than our supported formats - in.width = 80; - in.height = 80; - EXPECT_FALSE(engine_.CanSendCodec(in, current, &out)); - - in.height = 50; - EXPECT_FALSE(engine_.CanSendCodec(in, current, &out)); - } - - VideoEngineOverride<E> engine_; - rtc::scoped_ptr<cricket::FakeVideoCapturer> video_capturer_; -}; - template<class E, class C> class VideoMediaChannelTest : public testing::Test, public sigslot::has_slots<> { @@ -875,7 +554,7 @@ EXPECT_TRUE(SetOneCodec(DefaultCodec())); cricket::VideoSendParameters parameters; parameters.codecs.push_back(DefaultCodec()); - parameters.options.conference_mode.Set(true); + parameters.options.conference_mode = rtc::Optional<bool>(true); EXPECT_TRUE(channel_->SetSendParameters(parameters)); EXPECT_TRUE(SetSend(true)); EXPECT_TRUE(channel_->AddRecvStream( @@ -926,7 +605,7 @@ EXPECT_TRUE(SetOneCodec(DefaultCodec())); cricket::VideoSendParameters parameters; parameters.codecs.push_back(DefaultCodec()); - parameters.options.conference_mode.Set(true); + parameters.options.conference_mode = rtc::Optional<bool>(true); EXPECT_TRUE(channel_->SetSendParameters(parameters)); EXPECT_TRUE(channel_->AddRecvStream( cricket::StreamParams::CreateLegacy(kSsrc))); @@ -1009,8 +688,10 @@ rtc::scoped_ptr<const rtc::Buffer> p(GetRtpPacket(0)); ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); EXPECT_EQ(kSsrc, ssrc); - EXPECT_EQ(NumRtpPackets(), NumRtpPackets(ssrc)); - EXPECT_EQ(NumRtpBytes(), NumRtpBytes(ssrc)); + // Packets are being paced out, so these can mismatch between the first and + // second call to NumRtpPackets until pending packets are paced out. + EXPECT_EQ_WAIT(NumRtpPackets(), NumRtpPackets(ssrc), kTimeout); + EXPECT_EQ_WAIT(NumRtpBytes(), NumRtpBytes(ssrc), kTimeout); EXPECT_EQ(1, NumSentSsrcs()); EXPECT_EQ(0, NumRtpPackets(kSsrc - 1)); EXPECT_EQ(0, NumRtpBytes(kSsrc - 1)); @@ -1031,8 +712,10 @@ rtc::scoped_ptr<const rtc::Buffer> p(GetRtpPacket(0)); ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); EXPECT_EQ(999u, ssrc); - EXPECT_EQ(NumRtpPackets(), NumRtpPackets(ssrc)); - EXPECT_EQ(NumRtpBytes(), NumRtpBytes(ssrc)); + // Packets are being paced out, so these can mismatch between the first and + // second call to NumRtpPackets until pending packets are paced out. + EXPECT_EQ_WAIT(NumRtpPackets(), NumRtpPackets(ssrc), kTimeout); + EXPECT_EQ_WAIT(NumRtpBytes(), NumRtpBytes(ssrc), kTimeout); EXPECT_EQ(1, NumSentSsrcs()); EXPECT_EQ(0, NumRtpPackets(kSsrc)); EXPECT_EQ(0, NumRtpBytes(kSsrc)); @@ -1236,7 +919,7 @@ EXPECT_TRUE(SetDefaultCodec()); cricket::VideoSendParameters parameters; parameters.codecs.push_back(DefaultCodec()); - parameters.options.conference_mode.Set(true); + parameters.options.conference_mode = rtc::Optional<bool>(true); EXPECT_TRUE(channel_->SetSendParameters(parameters)); EXPECT_TRUE(SetSend(true)); EXPECT_TRUE(channel_->AddRecvStream( @@ -1746,8 +1429,8 @@ // Tests that we can send and receive frames with early receive. void TwoStreamsSendAndUnsignalledRecv(const cricket::VideoCodec& codec) { cricket::VideoSendParameters parameters; - parameters.options.conference_mode.Set(true); - parameters.options.unsignalled_recv_stream_limit.Set(1); + parameters.options.conference_mode = rtc::Optional<bool>(true); + parameters.options.unsignalled_recv_stream_limit = rtc::Optional<int>(1); EXPECT_TRUE(channel_->SetSendParameters(parameters)); SetUpSecondStreamWithNoRecv(); // Test sending and receiving on first stream. @@ -1780,8 +1463,8 @@ void TwoStreamsAddAndRemoveUnsignalledRecv( const cricket::VideoCodec& codec) { cricket::VideoOptions vmo; - vmo.conference_mode.Set(true); - vmo.unsignalled_recv_stream_limit.Set(1); + vmo.conference_mode = rtc::Optional<bool>(true); + vmo.unsignalled_recv_stream_limit = rtc::Optional<int>(1); EXPECT_TRUE(channel_->SetOptions(vmo)); SetUpSecondStreamWithNoRecv(); // Sending and receiving on first stream.
diff --git a/talk/media/base/videoframe.cc b/talk/media/base/videoframe.cc index 2b604b0..3e4d60a 100644 --- a/talk/media/base/videoframe.cc +++ b/talk/media/base/videoframe.cc
@@ -33,6 +33,7 @@ #include "libyuv/planar_functions.h" #include "libyuv/scale.h" #include "talk/media/base/videocommon.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" @@ -318,7 +319,7 @@ } // TODO(fbarchard): Make function to dump information about frames. uint8_t four_samples[4] = {0, 0, 0, 0}; - for (size_t i = 0; i < ARRAY_SIZE(four_samples) && i < sample_size; ++i) { + for (size_t i = 0; i < arraysize(four_samples) && i < sample_size; ++i) { four_samples[i] = sample[i]; } if (sample_size < expected_size) {
diff --git a/talk/media/base/videoframe.h b/talk/media/base/videoframe.h index 217732f..f81c678 100644 --- a/talk/media/base/videoframe.h +++ b/talk/media/base/videoframe.h
@@ -30,7 +30,7 @@ #include "webrtc/base/basictypes.h" #include "webrtc/base/stream.h" -#include "webrtc/common_video/interface/video_frame_buffer.h" +#include "webrtc/common_video/include/video_frame_buffer.h" #include "webrtc/common_video/rotation.h" namespace cricket {
diff --git a/talk/media/base/videoframefactory.cc b/talk/media/base/videoframefactory.cc index dfd97c6..fb81096 100644 --- a/talk/media/base/videoframefactory.cc +++ b/talk/media/base/videoframefactory.cc
@@ -51,8 +51,8 @@ // If the frame is rotated, we need to switch the width and height. if (apply_rotation_ && - (input_frame->GetRotation() == webrtc::kVideoRotation_90 || - input_frame->GetRotation() == webrtc::kVideoRotation_270)) { + (input_frame->rotation == webrtc::kVideoRotation_90 || + input_frame->rotation == webrtc::kVideoRotation_270)) { std::swap(output_width, output_height); }
diff --git a/talk/media/base/videorenderer.h b/talk/media/base/videorenderer.h index 0a0ee51..a18c4e3 100644 --- a/talk/media/base/videorenderer.h +++ b/talk/media/base/videorenderer.h
@@ -42,11 +42,12 @@ class VideoRenderer { public: virtual ~VideoRenderer() {} - // Called when the video has changed size. This is also used as an - // initialization method to set the UI size before any video frame - // rendered. webrtc::ExternalRenderer's FrameSizeChange will invoke this when - // it's called or later when a VideoRenderer is attached. - virtual bool SetSize(int width, int height, int reserved) = 0; + // Called when the video has changed size. + // TODO(nisse): This method is not really used, and should be + // deleted. Provide a default do-nothing implementation, to easy the + // transition as the method is deleted in subclasses, in particular, + // chrome's MockVideoRenderer class. + virtual bool SetSize(int width, int height, int reserved) { return true; }; // Called when a new frame is available for display. virtual bool RenderFrame(const VideoFrame *frame) = 0;
diff --git a/talk/media/base/voiceprocessor.h b/talk/media/base/voiceprocessor.h deleted file mode 100755 index 8de2678..0000000 --- a/talk/media/base/voiceprocessor.h +++ /dev/null
@@ -1,29 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// TODO(solenberg): Remove this file once Chromium's libjingle.gyp/.gn are -// updated.
diff --git a/talk/media/devices/carbonvideorenderer.cc b/talk/media/devices/carbonvideorenderer.cc index 846135d..b711ae4 100644 --- a/talk/media/devices/carbonvideorenderer.cc +++ b/talk/media/devices/carbonvideorenderer.cc
@@ -40,7 +40,6 @@ image_height_(0), x_(x), y_(y), - image_ref_(NULL), window_ref_(NULL) { }
diff --git a/talk/media/devices/carbonvideorenderer.h b/talk/media/devices/carbonvideorenderer.h index 52c9740..e8329ea 100644 --- a/talk/media/devices/carbonvideorenderer.h +++ b/talk/media/devices/carbonvideorenderer.h
@@ -65,7 +65,6 @@ int image_height_; int x_; int y_; - CGImageRef image_ref_; WindowRef window_ref_; };
diff --git a/talk/media/devices/devicemanager.cc b/talk/media/devices/devicemanager.cc index 1d7ac5b..eca14a5 100644 --- a/talk/media/devices/devicemanager.cc +++ b/talk/media/devices/devicemanager.cc
@@ -123,7 +123,7 @@ bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) { devices->clear(); -#if defined(ANDROID) || defined(IOS) +#if defined(ANDROID) || defined(WEBRTC_IOS) // On Android and iOS, we treat the camera(s) as a single device. Even if // there are multiple cameras, that's abstracted away at a higher level. Device dev("camera", "1"); // name and ID
diff --git a/talk/media/devices/devicemanager_unittest.cc b/talk/media/devices/devicemanager_unittest.cc index f259c7d..606a05e 100644 --- a/talk/media/devices/devicemanager_unittest.cc +++ b/talk/media/devices/devicemanager_unittest.cc
@@ -39,6 +39,7 @@ #include "talk/media/base/videocapturerfactory.h" #include "talk/media/devices/filevideocapturer.h" #include "talk/media/devices/v4llookup.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/fileutils.h" #include "webrtc/base/gunit.h" #include "webrtc/base/logging.h" @@ -47,10 +48,10 @@ #include "webrtc/base/stream.h" #include "webrtc/base/windowpickerfactory.h" -#ifdef LINUX +#ifdef WEBRTC_LINUX // TODO(juberti): Figure out why this doesn't compile on Windows. #include "webrtc/base/fileutils_mock.h" -#endif // LINUX +#endif // WEBRTC_LINUX using rtc::Pathname; using rtc::FileTimeType; @@ -269,22 +270,22 @@ "device5", }; std::vector<Device> devices; - for (int i = 0; i < ARRAY_SIZE(kTotalDevicesName); ++i) { + for (int i = 0; i < arraysize(kTotalDevicesName); ++i) { devices.push_back(Device(kTotalDevicesName[i], i)); } EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName, - ARRAY_SIZE(kTotalDevicesName))); + arraysize(kTotalDevicesName))); // Return false if given NULL as the exclusion list. EXPECT_TRUE(DeviceManager::FilterDevices(&devices, NULL)); // The devices should not change. EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName, - ARRAY_SIZE(kTotalDevicesName))); + arraysize(kTotalDevicesName))); EXPECT_TRUE(DeviceManager::FilterDevices(&devices, kFilteredDevicesName)); EXPECT_TRUE(CompareDeviceList(devices, kDevicesName, - ARRAY_SIZE(kDevicesName))); + arraysize(kDevicesName))); } -#ifdef LINUX +#ifdef WEBRTC_LINUX class FakeV4LLookup : public cricket::V4LLookup { public: explicit FakeV4LLookup(std::vector<std::string> device_paths) @@ -376,7 +377,7 @@ EXPECT_EQ("/dev/video0", video_ins.at(0).name); EXPECT_EQ("/dev/video5", video_ins.at(1).name); } -#endif // LINUX +#endif // WEBRTC_LINUX // TODO(noahric): These are flaky on windows on headless machines. #ifndef WIN32
diff --git a/talk/media/devices/fakedevicemanager.h b/talk/media/devices/fakedevicemanager.h index a4b2b86..77a8342 100644 --- a/talk/media/devices/fakedevicemanager.h +++ b/talk/media/devices/fakedevicemanager.h
@@ -156,7 +156,7 @@ return true; } -#ifdef OSX +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) bool QtKitToSgDevice(const std::string& qtkit_name, Device* out) { out->name = qtkit_name; out->id = "sg:" + qtkit_name;
diff --git a/talk/media/devices/mobiledevicemanager.cc b/talk/media/devices/mobiledevicemanager.cc index 2a886a3..5739c7e 100644 --- a/talk/media/devices/mobiledevicemanager.cc +++ b/talk/media/devices/mobiledevicemanager.cc
@@ -27,7 +27,7 @@ #include "talk/media/devices/devicemanager.h" #include "webrtc/base/arraysize.h" -#include "webrtc/modules/video_capture/include/video_capture_factory.h" +#include "webrtc/modules/video_capture/video_capture_factory.h" namespace cricket {
diff --git a/talk/media/devices/v4llookup.h b/talk/media/devices/v4llookup.h index 1bed90b6..5c53ede 100644 --- a/talk/media/devices/v4llookup.h +++ b/talk/media/devices/v4llookup.h
@@ -37,7 +37,7 @@ #include <string> -#ifdef LINUX +#ifdef WEBRTC_LINUX namespace cricket { class V4LLookup { public: @@ -66,5 +66,5 @@ } // namespace cricket -#endif // LINUX +#endif // WEBRTC_LINUX #endif // TALK_MEDIA_DEVICES_V4LLOOKUP_H_
diff --git a/talk/media/devices/videorendererfactory.h b/talk/media/devices/videorendererfactory.h index 416f05b..b7128f6 100644 --- a/talk/media/devices/videorendererfactory.h +++ b/talk/media/devices/videorendererfactory.h
@@ -32,9 +32,9 @@ #define TALK_MEDIA_DEVICES_VIDEORENDERERFACTORY_H_ #include "talk/media/base/videorenderer.h" -#if defined(LINUX) && defined(HAVE_GTK) +#if defined(WEBRTC_LINUX) && defined(HAVE_GTK) #include "talk/media/devices/gtkvideorenderer.h" -#elif defined(OSX) && !defined(CARBON_DEPRECATED) +#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && !defined(CARBON_DEPRECATED) #include "talk/media/devices/carbonvideorenderer.h" #elif defined(WIN32) #include "talk/media/devices/gdivideorenderer.h" @@ -45,9 +45,10 @@ class VideoRendererFactory { public: static VideoRenderer* CreateGuiVideoRenderer(int x, int y) { - #if defined(LINUX) && defined(HAVE_GTK) + #if defined(WEBRTC_LINUX) && defined(HAVE_GTK) return new GtkVideoRenderer(x, y); - #elif defined(OSX) && !defined(CARBON_DEPRECATED) + #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && \ + !defined(CARBON_DEPRECATED) CarbonVideoRenderer* renderer = new CarbonVideoRenderer(x, y); // Needs to be initialized on the main thread. if (renderer->Initialize()) {
diff --git a/talk/media/devices/win32devicemanager.cc b/talk/media/devices/win32devicemanager.cc index 1b9e9d8..f34e3c4 100644 --- a/talk/media/devices/win32devicemanager.cc +++ b/talk/media/devices/win32devicemanager.cc
@@ -48,6 +48,7 @@ } }, 4 }; +#include "webrtc/base/arraysize.h" #include "webrtc/base/logging.h" #include "webrtc/base/stringutils.h" #include "webrtc/base/thread.h" @@ -148,7 +149,7 @@ *device = devices[0]; for (size_t i = 0; i < devices.size(); ++i) { if (strnicmp(devices[i].id.c_str(), kUsbDevicePathPrefix, - ARRAY_SIZE(kUsbDevicePathPrefix) - 1) == 0) { + arraysize(kUsbDevicePathPrefix) - 1) == 0) { *device = devices[i]; break; }
diff --git a/talk/media/sctp/sctpdataengine.cc b/talk/media/sctp/sctpdataengine.cc index c88882d..3753cd2 100644 --- a/talk/media/sctp/sctpdataengine.cc +++ b/talk/media/sctp/sctpdataengine.cc
@@ -36,6 +36,7 @@ #include "talk/media/base/constants.h" #include "talk/media/base/streamparams.h" #include "usrsctplib/usrsctp.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/buffer.h" #include "webrtc/base/helpers.h" #include "webrtc/base/logging.h" @@ -76,7 +77,7 @@ MAKEFLAG(SCTP_STREAM_CHANGE_DENIED) }; #undef MAKEFLAG - for (int i = 0; i < ARRAY_SIZE(flaginfo); ++i) { + for (int i = 0; i < arraysize(flaginfo); ++i) { if (flags & flaginfo[i].value) { if (!first) result << " | "; result << flaginfo[i].name; @@ -473,7 +474,7 @@ struct sctp_event event = {0}; event.se_assoc_id = SCTP_ALL_ASSOC; event.se_on = 1; - for (size_t i = 0; i < ARRAY_SIZE(event_types); i++) { + for (size_t i = 0; i < arraysize(event_types); i++) { event.se_type = event_types[i]; if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) { @@ -728,7 +729,13 @@ } const uint32_t ssrc = stream.first_ssrc(); - if (open_streams_.find(ssrc) != open_streams_.end()) { + if (ssrc >= cricket::kMaxSctpSid) { + LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " + << "Not adding data stream '" << stream.id + << "' with ssrc=" << ssrc + << " because stream ssrc is too high."; + return false; + } else if (open_streams_.find(ssrc) != open_streams_.end()) { LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " << "Not adding data stream '" << stream.id << "' with ssrc=" << ssrc
diff --git a/talk/media/sctp/sctpdataengine_unittest.cc b/talk/media/sctp/sctpdataengine_unittest.cc index 4706368..d673c69 100644 --- a/talk/media/sctp/sctpdataengine_unittest.cc +++ b/talk/media/sctp/sctpdataengine_unittest.cc
@@ -270,12 +270,14 @@ ProcessMessagesUntilIdle(); } - void AddStream(int ssrc) { + bool AddStream(int ssrc) { + bool ret = true; cricket::StreamParams p(cricket::StreamParams::CreateLegacy(ssrc)); - chan1_->AddSendStream(p); - chan1_->AddRecvStream(p); - chan2_->AddSendStream(p); - chan2_->AddRecvStream(p); + ret = ret && chan1_->AddSendStream(p); + ret = ret && chan1_->AddRecvStream(p); + ret = ret && chan2_->AddSendStream(p); + ret = ret && chan2_->AddRecvStream(p); + return ret; } cricket::SctpDataMediaChannel* CreateChannel( @@ -504,6 +506,12 @@ EXPECT_GT(channel1_ready_to_send_count(), prior_count); } +TEST_F(SctpDataMediaChannelTest, RefusesHighNumberedChannels) { + SetupConnectedChannels(); + EXPECT_TRUE(AddStream(1022)); + EXPECT_FALSE(AddStream(1023)); +} + // Flaky on Linux and Windows. See webrtc:4453. #if defined(WEBRTC_WIN) || defined(WEBRTC_LINUX) #define MAYBE_ReusesAStream DISABLED_ReusesAStream
diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc index d86bfb5..d50a53c 100644 --- a/talk/media/webrtc/fakewebrtccall.cc +++ b/talk/media/webrtc/fakewebrtccall.cc
@@ -28,10 +28,12 @@ #include "talk/media/webrtc/fakewebrtccall.h" #include <algorithm> +#include <utility> #include "talk/media/base/rtputils.h" #include "webrtc/base/checks.h" #include "webrtc/base/gunit.h" +#include "webrtc/audio/audio_sink.h" namespace cricket { FakeAudioSendStream::FakeAudioSendStream( @@ -39,14 +41,27 @@ RTC_DCHECK(config.voe_channel_id != -1); } +const webrtc::AudioSendStream::Config& + FakeAudioSendStream::GetConfig() const { + return config_; +} + void FakeAudioSendStream::SetStats( const webrtc::AudioSendStream::Stats& stats) { stats_ = stats; } -const webrtc::AudioSendStream::Config& - FakeAudioSendStream::GetConfig() const { - return config_; +FakeAudioSendStream::TelephoneEvent + FakeAudioSendStream::GetLatestTelephoneEvent() const { + return latest_telephone_event_; +} + +bool FakeAudioSendStream::SendTelephoneEvent(int payload_type, uint8_t event, + uint32_t duration_ms) { + latest_telephone_event_.payload_type = payload_type; + latest_telephone_event_.event_code = event; + latest_telephone_event_.duration_ms = duration_ms; + return true; } webrtc::AudioSendStream::Stats FakeAudioSendStream::GetStats() const { @@ -77,6 +92,11 @@ return stats_; } +void FakeAudioReceiveStream::SetSink( + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) { + sink_ = std::move(sink); +} + FakeVideoSendStream::FakeVideoSendStream( const webrtc::VideoSendStream::Config& config, const webrtc::VideoEncoderConfig& encoder_config)
diff --git a/talk/media/webrtc/fakewebrtccall.h b/talk/media/webrtc/fakewebrtccall.h index 88edc60..3528c7a 100644 --- a/talk/media/webrtc/fakewebrtccall.h +++ b/talk/media/webrtc/fakewebrtccall.h
@@ -47,14 +47,19 @@ #include "webrtc/video_send_stream.h" namespace cricket { - -class FakeAudioSendStream : public webrtc::AudioSendStream { +class FakeAudioSendStream final : public webrtc::AudioSendStream { public: - explicit FakeAudioSendStream( - const webrtc::AudioSendStream::Config& config); + struct TelephoneEvent { + int payload_type = -1; + uint8_t event_code = 0; + uint32_t duration_ms = 0; + }; + + explicit FakeAudioSendStream(const webrtc::AudioSendStream::Config& config); const webrtc::AudioSendStream::Config& GetConfig() const; void SetStats(const webrtc::AudioSendStream::Stats& stats); + TelephoneEvent GetLatestTelephoneEvent() const; private: // webrtc::SendStream implementation. @@ -66,13 +71,16 @@ } // webrtc::AudioSendStream implementation. + bool SendTelephoneEvent(int payload_type, uint8_t event, + uint32_t duration_ms) override; webrtc::AudioSendStream::Stats GetStats() const override; + TelephoneEvent latest_telephone_event_; webrtc::AudioSendStream::Config config_; webrtc::AudioSendStream::Stats stats_; }; -class FakeAudioReceiveStream : public webrtc::AudioReceiveStream { +class FakeAudioReceiveStream final : public webrtc::AudioReceiveStream { public: explicit FakeAudioReceiveStream( const webrtc::AudioReceiveStream::Config& config); @@ -98,14 +106,16 @@ // webrtc::AudioReceiveStream implementation. webrtc::AudioReceiveStream::Stats GetStats() const override; + void SetSink(rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) override; webrtc::AudioReceiveStream::Config config_; webrtc::AudioReceiveStream::Stats stats_; int received_packets_; + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink_; }; -class FakeVideoSendStream : public webrtc::VideoSendStream, - public webrtc::VideoCaptureInput { +class FakeVideoSendStream final : public webrtc::VideoSendStream, + public webrtc::VideoCaptureInput { public: FakeVideoSendStream(const webrtc::VideoSendStream::Config& config, const webrtc::VideoEncoderConfig& encoder_config); @@ -153,7 +163,7 @@ webrtc::VideoSendStream::Stats stats_; }; -class FakeVideoReceiveStream : public webrtc::VideoReceiveStream { +class FakeVideoReceiveStream final : public webrtc::VideoReceiveStream { public: explicit FakeVideoReceiveStream( const webrtc::VideoReceiveStream::Config& config); @@ -188,7 +198,7 @@ webrtc::VideoReceiveStream::Stats stats_; }; -class FakeCall : public webrtc::Call, public webrtc::PacketReceiver { +class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver { public: explicit FakeCall(const webrtc::Call::Config& config); ~FakeCall() override;
diff --git a/talk/media/webrtc/fakewebrtcvideoengine.h b/talk/media/webrtc/fakewebrtcvideoengine.h index 8e4c7c8..e0d4db5 100644 --- a/talk/media/webrtc/fakewebrtcvideoengine.h +++ b/talk/media/webrtc/fakewebrtcvideoengine.h
@@ -41,7 +41,7 @@ #include "webrtc/base/gunit.h" #include "webrtc/base/stringutils.h" #include "webrtc/base/thread_annotations.h" -#include "webrtc/modules/video_coding/codecs/interface/video_error_codes.h" +#include "webrtc/modules/video_coding/include/video_error_codes.h" #include "webrtc/video_decoder.h" #include "webrtc/video_encoder.h"
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index 2405e07..65ba927 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -41,19 +41,11 @@ #include "webrtc/base/gunit.h" #include "webrtc/base/stringutils.h" #include "webrtc/config.h" +#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" namespace cricket { -static const char kFakeDefaultDeviceName[] = "Fake Default"; -static const int kFakeDefaultDeviceId = -1; -static const char kFakeDeviceName[] = "Fake Device"; -#ifdef WIN32 -static const int kFakeDeviceId = 0; -#else -static const int kFakeDeviceId = 1; -#endif - static const int kOpusBandwidthNb = 4000; static const int kOpusBandwidthMb = 6000; static const int kOpusBandwidthWb = 8000; @@ -63,18 +55,6 @@ #define WEBRTC_CHECK_CHANNEL(channel) \ if (channels_.find(channel) == channels_.end()) return -1; -#define WEBRTC_ASSERT_CHANNEL(channel) \ - RTC_DCHECK(channels_.find(channel) != channels_.end()); - -// Verify the header extension ID, if enabled, is within the bounds specified in -// [RFC5285]: 1-14 inclusive. -#define WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id) \ - do { \ - if (enable && (id < 1 || id > 14)) { \ - return -1; \ - } \ - } while (0); - class FakeAudioProcessing : public webrtc::AudioProcessing { public: FakeAudioProcessing() : experimental_ns_enabled_(false) {} @@ -94,11 +74,13 @@ experimental_ns_enabled_ = config.Get<webrtc::ExperimentalNs>().enabled; } + WEBRTC_STUB_CONST(input_sample_rate_hz, ()); WEBRTC_STUB_CONST(proc_sample_rate_hz, ()); WEBRTC_STUB_CONST(proc_split_sample_rate_hz, ()); - WEBRTC_STUB_CONST(num_input_channels, ()); - WEBRTC_STUB_CONST(num_output_channels, ()); - WEBRTC_STUB_CONST(num_reverse_channels, ()); + size_t num_input_channels() const override { return 0; } + size_t num_proc_channels() const override { return 0; } + size_t num_output_channels() const override { return 0; } + size_t num_reverse_channels() const override { return 0; } WEBRTC_VOID_STUB(set_output_will_be_muted, (bool muted)); WEBRTC_STUB(ProcessStream, (webrtc::AudioFrame* frame)); WEBRTC_STUB(ProcessStream, ( @@ -156,20 +138,11 @@ class FakeWebRtcVoiceEngine : public webrtc::VoEAudioProcessing, - public webrtc::VoEBase, public webrtc::VoECodec, public webrtc::VoEDtmf, + public webrtc::VoEBase, public webrtc::VoECodec, public webrtc::VoEHardware, public webrtc::VoENetwork, public webrtc::VoERTP_RTCP, public webrtc::VoEVolumeControl { public: - struct DtmfInfo { - DtmfInfo() - : dtmf_event_code(-1), - dtmf_out_of_band(false), - dtmf_length_ms(-1) {} - int dtmf_event_code; - bool dtmf_out_of_band; - int dtmf_length_ms; - }; struct Channel { explicit Channel() : external_transport(false), @@ -184,15 +157,11 @@ nack(false), cn8_type(13), cn16_type(105), - dtmf_type(106), red_type(117), nack_max_packets(0), send_ssrc(0), - send_audio_level_ext_(-1), - receive_audio_level_ext_(-1), - send_absolute_sender_time_ext_(-1), - receive_absolute_sender_time_ext_(-1), associate_send_channel(-1), + recv_codecs(), neteq_capacity(-1), neteq_fast_accelerate(false) { memset(&send_codec, 0, sizeof(send_codec)); @@ -209,16 +178,10 @@ bool nack; int cn8_type; int cn16_type; - int dtmf_type; int red_type; int nack_max_packets; uint32_t send_ssrc; - int send_audio_level_ext_; - int receive_audio_level_ext_; - int send_absolute_sender_time_ext_; - int receive_absolute_sender_time_ext_; int associate_send_channel; - DtmfInfo dtmf_info; std::vector<webrtc::CodecInst> recv_codecs; webrtc::CodecInst send_codec; webrtc::PacketTime last_rtp_packet_time; @@ -227,13 +190,10 @@ bool neteq_fast_accelerate; }; - FakeWebRtcVoiceEngine(const cricket::AudioCodec* const* codecs, - int num_codecs) + FakeWebRtcVoiceEngine() : inited_(false), last_channel_(-1), fail_create_channel_(false), - codecs_(codecs), - num_codecs_(num_codecs), num_set_send_codecs_(0), ec_enabled_(false), ec_metrics_enabled_(false), @@ -255,26 +215,13 @@ memset(&agc_config_, 0, sizeof(agc_config_)); } ~FakeWebRtcVoiceEngine() { - // Ought to have all been deleted by the WebRtcVoiceMediaChannel - // destructors, but just in case ... - for (std::map<int, Channel*>::const_iterator i = channels_.begin(); - i != channels_.end(); ++i) { - delete i->second; - } + RTC_CHECK(channels_.empty()); } bool ec_metrics_enabled() const { return ec_metrics_enabled_; } bool IsInited() const { return inited_; } int GetLastChannel() const { return last_channel_; } - int GetChannelFromLocalSsrc(uint32_t local_ssrc) const { - for (std::map<int, Channel*>::const_iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - if (local_ssrc == iter->second->send_ssrc) - return iter->first; - } - return -1; - } int GetNumChannels() const { return static_cast<int>(channels_.size()); } uint32_t GetLocalSSRC(int channel) { return channels_[channel]->send_ssrc; @@ -307,7 +254,7 @@ return channels_[channel]->nack_max_packets; } const webrtc::PacketTime& GetLastRtpPacketTime(int channel) { - WEBRTC_ASSERT_CHANNEL(channel); + RTC_DCHECK(channels_.find(channel) != channels_.end()); return channels_[channel]->last_rtp_packet_time; } int GetSendCNPayloadType(int channel, bool wideband) { @@ -315,9 +262,6 @@ channels_[channel]->cn16_type : channels_[channel]->cn8_type; } - int GetSendTelephoneEventPayloadType(int channel) { - return channels_[channel]->dtmf_type; - } int GetSendREDPayloadType(int channel) { return channels_[channel]->red_type; } @@ -351,11 +295,8 @@ return -1; } Channel* ch = new Channel(); - for (int i = 0; i < NumOfCodecs(); ++i) { - webrtc::CodecInst codec; - GetCodec(i, codec); - ch->recv_codecs.push_back(codec); - } + auto db = webrtc::acm2::RentACodec::Database(); + ch->recv_codecs.assign(db.begin(), db.end()); if (config.Get<webrtc::NetEqCapacityConfig>().enabled) { ch->neteq_capacity = config.Get<webrtc::NetEqCapacityConfig>().capacity; } @@ -364,24 +305,6 @@ channels_[++last_channel_] = ch; return last_channel_; } - int GetSendRtpExtensionId(int channel, const std::string& extension) { - WEBRTC_ASSERT_CHANNEL(channel); - if (extension == kRtpAudioLevelHeaderExtension) { - return channels_[channel]->send_audio_level_ext_; - } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) { - return channels_[channel]->send_absolute_sender_time_ext_; - } - return -1; - } - int GetReceiveRtpExtensionId(int channel, const std::string& extension) { - WEBRTC_ASSERT_CHANNEL(channel); - if (extension == kRtpAudioLevelHeaderExtension) { - return channels_[channel]->receive_audio_level_ext_; - } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) { - return channels_[channel]->receive_absolute_sender_time_ext_; - } - return -1; - } int GetNumSetSendCodecs() const { return num_set_send_codecs_; } @@ -473,22 +396,8 @@ webrtc::RtcEventLog* GetEventLog() { return nullptr; } // webrtc::VoECodec - WEBRTC_FUNC(NumOfCodecs, ()) { - return num_codecs_; - } - WEBRTC_FUNC(GetCodec, (int index, webrtc::CodecInst& codec)) { - if (index < 0 || index >= NumOfCodecs()) { - return -1; - } - const cricket::AudioCodec& c(*codecs_[index]); - codec.pltype = c.id; - rtc::strcpyn(codec.plname, sizeof(codec.plname), c.name.c_str()); - codec.plfreq = c.clockrate; - codec.pacsize = 0; - codec.channels = c.channels; - codec.rate = c.bitrate; - return 0; - } + WEBRTC_STUB(NumOfCodecs, ()); + WEBRTC_STUB(GetCodec, (int index, webrtc::CodecInst& codec)); WEBRTC_FUNC(SetSendCodec, (int channel, const webrtc::CodecInst& codec)) { WEBRTC_CHECK_CHANNEL(channel); // To match the behavior of the real implementation. @@ -526,16 +435,17 @@ } } // Otherwise try to find this codec and update its payload type. + int result = -1; // not found for (std::vector<webrtc::CodecInst>::iterator it = ch->recv_codecs.begin(); it != ch->recv_codecs.end(); ++it) { if (strcmp(it->plname, codec.plname) == 0 && - it->plfreq == codec.plfreq) { + it->plfreq == codec.plfreq && + it->channels == codec.channels) { it->pltype = codec.pltype; - it->channels = codec.channels; - return 0; + result = 0; } } - return -1; // not found + return result; } WEBRTC_FUNC(SetSendCNPayloadType, (int channel, int type, webrtc::PayloadFrequencies frequency)) { @@ -620,46 +530,11 @@ return 0; } - // webrtc::VoEDtmf - WEBRTC_FUNC(SendTelephoneEvent, (int channel, int event_code, - bool out_of_band = true, int length_ms = 160, int attenuation_db = 10)) { - channels_[channel]->dtmf_info.dtmf_event_code = event_code; - channels_[channel]->dtmf_info.dtmf_out_of_band = out_of_band; - channels_[channel]->dtmf_info.dtmf_length_ms = length_ms; - return 0; - } - - WEBRTC_FUNC(SetSendTelephoneEventPayloadType, - (int channel, unsigned char type)) { - channels_[channel]->dtmf_type = type; - return 0; - }; - WEBRTC_STUB(GetSendTelephoneEventPayloadType, - (int channel, unsigned char& type)); - - WEBRTC_STUB(SetDtmfFeedbackStatus, (bool enable, bool directFeedback)); - WEBRTC_STUB(GetDtmfFeedbackStatus, (bool& enabled, bool& directFeedback)); - - WEBRTC_FUNC(PlayDtmfTone, - (int event_code, int length_ms = 200, int attenuation_db = 10)) { - dtmf_info_.dtmf_event_code = event_code; - dtmf_info_.dtmf_length_ms = length_ms; - return 0; - } - // webrtc::VoEHardware - WEBRTC_FUNC(GetNumOfRecordingDevices, (int& num)) { - return GetNumDevices(num); - } - WEBRTC_FUNC(GetNumOfPlayoutDevices, (int& num)) { - return GetNumDevices(num); - } - WEBRTC_FUNC(GetRecordingDeviceName, (int i, char* name, char* guid)) { - return GetDeviceName(i, name, guid); - } - WEBRTC_FUNC(GetPlayoutDeviceName, (int i, char* name, char* guid)) { - return GetDeviceName(i, name, guid); - } + WEBRTC_STUB(GetNumOfRecordingDevices, (int& num)); + WEBRTC_STUB(GetNumOfPlayoutDevices, (int& num)); + WEBRTC_STUB(GetRecordingDeviceName, (int i, char* name, char* guid)); + WEBRTC_STUB(GetPlayoutDeviceName, (int i, char* name, char* guid)); WEBRTC_STUB(SetRecordingDevice, (int, webrtc::StereoChannel)); WEBRTC_STUB(SetPlayoutDevice, (int)); WEBRTC_STUB(SetAudioDeviceLayer, (webrtc::AudioLayers)); @@ -729,35 +604,14 @@ } WEBRTC_STUB(GetLocalSSRC, (int channel, unsigned int& ssrc)); WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc)); - WEBRTC_FUNC(SetSendAudioLevelIndicationStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->send_audio_level_ext_ = (enable) ? id : -1; - return 0; - } - WEBRTC_FUNC(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->receive_audio_level_ext_ = (enable) ? id : -1; - return 0; - } - WEBRTC_FUNC(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->send_absolute_sender_time_ext_ = (enable) ? id : -1; - return 0; - } - WEBRTC_FUNC(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->receive_absolute_sender_time_ext_ = (enable) ? id : -1; - return 0; - } - + WEBRTC_STUB(SetSendAudioLevelIndicationStatus, (int channel, bool enable, + unsigned char id)); + WEBRTC_STUB(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable, + unsigned char id)); + WEBRTC_STUB(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable, + unsigned char id)); + WEBRTC_STUB(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable, + unsigned char id)); WEBRTC_STUB(SetRTCPStatus, (int channel, bool enable)); WEBRTC_STUB(GetRTCPStatus, (int channel, bool& enabled)); WEBRTC_STUB(SetRTCP_CNAME, (int channel, const char cname[256])); @@ -776,22 +630,12 @@ unsigned int& discardedPackets)); WEBRTC_STUB(GetRTCPStatistics, (int channel, webrtc::CallStatistics& stats)); WEBRTC_FUNC(SetREDStatus, (int channel, bool enable, int redPayloadtype)) { - return SetFECStatus(channel, enable, redPayloadtype); - } - // TODO(minyue): remove the below function when transition to SetREDStatus - // is finished. - WEBRTC_FUNC(SetFECStatus, (int channel, bool enable, int redPayloadtype)) { WEBRTC_CHECK_CHANNEL(channel); channels_[channel]->red = enable; channels_[channel]->red_type = redPayloadtype; return 0; } WEBRTC_FUNC(GetREDStatus, (int channel, bool& enable, int& redPayloadtype)) { - return GetFECStatus(channel, enable, redPayloadtype); - } - // TODO(minyue): remove the below function when transition to GetREDStatus - // is finished. - WEBRTC_FUNC(GetFECStatus, (int channel, bool& enable, int& redPayloadtype)) { WEBRTC_CHECK_CHANNEL(channel); enable = channels_[channel]->red; redPayloadtype = channels_[channel]->red_type; @@ -937,15 +781,6 @@ void EnableStereoChannelSwapping(bool enable) { stereo_swapping_enabled_ = enable; } - bool WasSendTelephoneEventCalled(int channel, int event_code, int length_ms) { - return (channels_[channel]->dtmf_info.dtmf_event_code == event_code && - channels_[channel]->dtmf_info.dtmf_out_of_band == true && - channels_[channel]->dtmf_info.dtmf_length_ms == length_ms); - } - bool WasPlayDtmfToneCalled(int event_code, int length_ms) { - return (dtmf_info_.dtmf_event_code == event_code && - dtmf_info_.dtmf_length_ms == length_ms); - } int GetNetEqCapacity() const { auto ch = channels_.find(last_channel_); ASSERT(ch != channels_.end()); @@ -958,47 +793,10 @@ } private: - int GetNumDevices(int& num) { -#ifdef WIN32 - num = 1; -#else - // On non-Windows platforms VE adds a special entry for the default device, - // so if there is one physical device then there are two entries in the - // list. - num = 2; -#endif - return 0; - } - - int GetDeviceName(int i, char* name, char* guid) { - const char *s; -#ifdef WIN32 - if (0 == i) { - s = kFakeDeviceName; - } else { - return -1; - } -#else - // See comment above. - if (0 == i) { - s = kFakeDefaultDeviceName; - } else if (1 == i) { - s = kFakeDeviceName; - } else { - return -1; - } -#endif - strcpy(name, s); - guid[0] = '\0'; - return 0; - } - bool inited_; int last_channel_; std::map<int, Channel*> channels_; bool fail_create_channel_; - const cricket::AudioCodec* const* codecs_; - int num_codecs_; int num_set_send_codecs_; // how many times we call SetSendCodec(). bool ec_enabled_; bool ec_metrics_enabled_; @@ -1018,12 +816,9 @@ int send_fail_channel_; int recording_sample_rate_; int playout_sample_rate_; - DtmfInfo dtmf_info_; FakeAudioProcessing audio_processing_; }; -#undef WEBRTC_CHECK_HEADER_EXTENSION_ID - } // namespace cricket #endif // TALK_SESSION_PHONE_FAKEWEBRTCVOICEENGINE_H_
diff --git a/talk/media/webrtc/simulcast.cc b/talk/media/webrtc/simulcast.cc index f55d960..b67a363 100755 --- a/talk/media/webrtc/simulcast.cc +++ b/talk/media/webrtc/simulcast.cc
@@ -29,9 +29,11 @@ #include "talk/media/base/streamparams.h" #include "talk/media/webrtc/simulcast.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" #include "webrtc/system_wrappers/include/field_trial.h" + namespace cricket { struct SimulcastFormat { @@ -93,7 +95,7 @@ int FindSimulcastFormatIndex(int width, int height) { MaybeExchangeWidthHeight(&width, &height); - for (int i = 0; i < ARRAY_SIZE(kSimulcastFormats); ++i) { + for (int i = 0; i < arraysize(kSimulcastFormats); ++i) { if (width >= kSimulcastFormats[i].width && height >= kSimulcastFormats[i].height) { return i; @@ -105,7 +107,7 @@ int FindSimulcastFormatIndex(int width, int height, size_t max_layers) { MaybeExchangeWidthHeight(&width, &height); - for (int i = 0; i < ARRAY_SIZE(kSimulcastFormats); ++i) { + for (int i = 0; i < arraysize(kSimulcastFormats); ++i) { if (width >= kSimulcastFormats[i].width && height >= kSimulcastFormats[i].height && max_layers == kSimulcastFormats[i].max_layers) {
diff --git a/talk/media/webrtc/webrtcmediaengine.cc b/talk/media/webrtc/webrtcmediaengine.cc index af202bd..31e5025 100644 --- a/talk/media/webrtc/webrtcmediaengine.cc +++ b/talk/media/webrtc/webrtcmediaengine.cc
@@ -26,6 +26,9 @@ */ #include "talk/media/webrtc/webrtcmediaengine.h" + +#include <algorithm> + #include "talk/media/webrtc/webrtcvideoengine2.h" #include "talk/media/webrtc/webrtcvoiceengine.h" @@ -68,44 +71,85 @@ return CreateWebRtcMediaEngine(adm, encoder_factory, decoder_factory); } -const char* kBweExtensionPriorities[] = { - kRtpTransportSequenceNumberHeaderExtension, - kRtpAbsoluteSenderTimeHeaderExtension, kRtpTimestampOffsetHeaderExtension}; - -const size_t kBweExtensionPrioritiesLength = - ARRAY_SIZE(kBweExtensionPriorities); - -int GetPriority(const RtpHeaderExtension& extension, - const char* extension_prios[], - size_t extension_prios_length) { - for (size_t i = 0; i < extension_prios_length; ++i) { - if (extension.uri == extension_prios[i]) - return static_cast<int>(i); - } - return -1; -} - -std::vector<RtpHeaderExtension> FilterRedundantRtpExtensions( - const std::vector<RtpHeaderExtension>& extensions, - const char* extension_prios[], - size_t extension_prios_length) { - if (extensions.empty()) - return std::vector<RtpHeaderExtension>(); - std::vector<RtpHeaderExtension> filtered; - std::map<int, const RtpHeaderExtension*> sorted; - for (auto& extension : extensions) { - int priority = - GetPriority(extension, extension_prios, extension_prios_length); - if (priority == -1) { - filtered.push_back(extension); - continue; - } else { - sorted[priority] = &extension; +namespace { +// Remove mutually exclusive extensions with lower priority. +void DiscardRedundantExtensions( + std::vector<webrtc::RtpExtension>* extensions, + rtc::ArrayView<const char*> extensions_decreasing_prio) { + RTC_DCHECK(extensions); + bool found = false; + for (const char* name : extensions_decreasing_prio) { + auto it = std::find_if(extensions->begin(), extensions->end(), + [name](const webrtc::RtpExtension& rhs) { + return rhs.name == name; + }); + if (it != extensions->end()) { + if (found) { + extensions->erase(it); + } + found = true; } } - if (!sorted.empty()) - filtered.push_back(*sorted.begin()->second); - return filtered; +} +} // namespace + +bool ValidateRtpExtensions(const std::vector<RtpHeaderExtension>& extensions) { + bool id_used[14] = {false}; + for (const auto& extension : extensions) { + if (extension.id <= 0 || extension.id >= 15) { + LOG(LS_ERROR) << "Bad RTP extension ID: " << extension.ToString(); + return false; + } + if (id_used[extension.id - 1]) { + LOG(LS_ERROR) << "Duplicate RTP extension ID: " << extension.ToString(); + return false; + } + id_used[extension.id - 1] = true; + } + return true; } +std::vector<webrtc::RtpExtension> FilterRtpExtensions( + const std::vector<RtpHeaderExtension>& extensions, + bool (*supported)(const std::string&), + bool filter_redundant_extensions) { + RTC_DCHECK(ValidateRtpExtensions(extensions)); + RTC_DCHECK(supported); + std::vector<webrtc::RtpExtension> result; + + // Ignore any extensions that we don't recognize. + for (const auto& extension : extensions) { + if (supported(extension.uri)) { + result.push_back({extension.uri, extension.id}); + } else { + LOG(LS_WARNING) << "Unsupported RTP extension: " << extension.ToString(); + } + } + + // Sort by name, ascending, so that we don't reset extensions if they were + // specified in a different order (also allows us to use std::unique below). + std::sort(result.begin(), result.end(), + [](const webrtc::RtpExtension& rhs, const webrtc::RtpExtension& lhs) { + return rhs.name < lhs.name; + }); + + // Remove unnecessary extensions (used on send side). + if (filter_redundant_extensions) { + auto it = std::unique(result.begin(), result.end(), + [](const webrtc::RtpExtension& rhs, const webrtc::RtpExtension& lhs) { + return rhs.name == lhs.name; + }); + result.erase(it, result.end()); + + // Keep just the highest priority extension of any in the following list. + static const char* kBweExtensionPriorities[] = { + kRtpTransportSequenceNumberHeaderExtension, + kRtpAbsoluteSenderTimeHeaderExtension, + kRtpTimestampOffsetHeaderExtension + }; + DiscardRedundantExtensions(&result, kBweExtensionPriorities); + } + + return result; +} } // namespace cricket
diff --git a/talk/media/webrtc/webrtcmediaengine.h b/talk/media/webrtc/webrtcmediaengine.h index 8d754040..831d072 100644 --- a/talk/media/webrtc/webrtcmediaengine.h +++ b/talk/media/webrtc/webrtcmediaengine.h
@@ -28,7 +28,11 @@ #ifndef TALK_MEDIA_WEBRTCMEDIAENGINE_H_ #define TALK_MEDIA_WEBRTCMEDIAENGINE_H_ +#include <string> +#include <vector> + #include "talk/media/base/mediaengine.h" +#include "webrtc/config.h" namespace webrtc { class AudioDeviceModule; @@ -48,13 +52,18 @@ WebRtcVideoDecoderFactory* decoder_factory); }; -extern const char* kBweExtensionPriorities[]; -extern const size_t kBweExtensionPrioritiesLength; +// Verify that extension IDs are within 1-byte extension range and are not +// overlapping. +bool ValidateRtpExtensions(const std::vector<RtpHeaderExtension>& extensions); -std::vector<RtpHeaderExtension> FilterRedundantRtpExtensions( +// Convert cricket::RtpHeaderExtension:s to webrtc::RtpExtension:s, discarding +// any extensions not validated by the 'supported' predicate. Duplicate +// extensions are removed if 'filter_redundant_extensions' is set, and also any +// mutually exclusive extensions (see implementation for details). +std::vector<webrtc::RtpExtension> FilterRtpExtensions( const std::vector<RtpHeaderExtension>& extensions, - const char* extension_prios[], - size_t extension_prios_length); + bool (*supported)(const std::string&), + bool filter_redundant_extensions); } // namespace cricket
diff --git a/talk/media/webrtc/webrtcmediaengine_unittest.cc b/talk/media/webrtc/webrtcmediaengine_unittest.cc new file mode 100644 index 0000000..7c80e77 --- /dev/null +++ b/talk/media/webrtc/webrtcmediaengine_unittest.cc
@@ -0,0 +1,205 @@ +/* + * libjingle + * Copyright 2015 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "testing/gtest/include/gtest/gtest.h" + +#include "talk/media/webrtc/webrtcmediaengine.h" + +namespace cricket { +namespace { + +std::vector<RtpHeaderExtension> MakeUniqueExtensions() { + std::vector<RtpHeaderExtension> result; + char name[] = "a"; + for (int i = 0; i < 7; ++i) { + result.push_back(RtpHeaderExtension(name, 1 + i)); + name[0]++; + result.push_back(RtpHeaderExtension(name, 14 - i)); + name[0]++; + } + return result; +} + +std::vector<RtpHeaderExtension> MakeRedundantExtensions() { + std::vector<RtpHeaderExtension> result; + char name[] = "a"; + for (int i = 0; i < 7; ++i) { + result.push_back(RtpHeaderExtension(name, 1 + i)); + result.push_back(RtpHeaderExtension(name, 14 - i)); + name[0]++; + } + return result; +} + +bool SupportedExtensions1(const std::string& name) { + return name == "c" || name == "i"; +} + +bool SupportedExtensions2(const std::string& name) { + return name != "a" && name != "n"; +} + +bool IsSorted(const std::vector<webrtc::RtpExtension>& extensions) { + const std::string* last = nullptr; + for (const auto& extension : extensions) { + if (last && *last > extension.name) { + return false; + } + last = &extension.name; + } + return true; +} +} // namespace + +TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_EmptyList) { + std::vector<RtpHeaderExtension> extensions; + EXPECT_TRUE(ValidateRtpExtensions(extensions)); +} + +TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_AllGood) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + EXPECT_TRUE(ValidateRtpExtensions(extensions)); +} + +TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OutOfRangeId_Low) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + extensions.push_back(RtpHeaderExtension("foo", 0)); + EXPECT_FALSE(ValidateRtpExtensions(extensions)); +} + +TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OutOfRangeId_High) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + extensions.push_back(RtpHeaderExtension("foo", 15)); + EXPECT_FALSE(ValidateRtpExtensions(extensions)); +} + +TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OverlappingIds_StartOfSet) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + extensions.push_back(RtpHeaderExtension("foo", 1)); + EXPECT_FALSE(ValidateRtpExtensions(extensions)); +} + +TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OverlappingIds_EndOfSet) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + extensions.push_back(RtpHeaderExtension("foo", 14)); + EXPECT_FALSE(ValidateRtpExtensions(extensions)); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_EmptyList) { + std::vector<RtpHeaderExtension> extensions; + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions1, true); + EXPECT_EQ(0, filtered.size()); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_IncludeOnlySupported) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions1, false); + EXPECT_EQ(2, filtered.size()); + EXPECT_EQ("c", filtered[0].name); + EXPECT_EQ("i", filtered[1].name); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_SortedByName_1) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions2, false); + EXPECT_EQ(12, filtered.size()); + EXPECT_TRUE(IsSorted(filtered)); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_SortedByName_2) { + std::vector<RtpHeaderExtension> extensions = MakeUniqueExtensions(); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions2, true); + EXPECT_EQ(12, filtered.size()); + EXPECT_TRUE(IsSorted(filtered)); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_DontRemoveRedundant) { + std::vector<RtpHeaderExtension> extensions = MakeRedundantExtensions(); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions2, false); + EXPECT_EQ(12, filtered.size()); + EXPECT_TRUE(IsSorted(filtered)); + EXPECT_EQ(filtered[0].name, filtered[1].name); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundant) { + std::vector<RtpHeaderExtension> extensions = MakeRedundantExtensions(); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions2, true); + EXPECT_EQ(6, filtered.size()); + EXPECT_TRUE(IsSorted(filtered)); + EXPECT_NE(filtered[0].name, filtered[1].name); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_1) { + std::vector<RtpHeaderExtension> extensions; + extensions.push_back( + RtpHeaderExtension(kRtpTransportSequenceNumberHeaderExtension, 3)); + extensions.push_back( + RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, 9)); + extensions.push_back( + RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, 6)); + extensions.push_back( + RtpHeaderExtension(kRtpTransportSequenceNumberHeaderExtension, 1)); + extensions.push_back( + RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, 14)); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions2, true); + EXPECT_EQ(1, filtered.size()); + EXPECT_EQ(kRtpTransportSequenceNumberHeaderExtension, filtered[0].name); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_2) { + std::vector<RtpHeaderExtension> extensions; + extensions.push_back( + RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, 1)); + extensions.push_back( + RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, 14)); + extensions.push_back( + RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, 7)); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions2, true); + EXPECT_EQ(1, filtered.size()); + EXPECT_EQ(kRtpAbsoluteSenderTimeHeaderExtension, filtered[0].name); +} + +TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_3) { + std::vector<RtpHeaderExtension> extensions; + extensions.push_back( + RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, 2)); + extensions.push_back( + RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, 14)); + std::vector<webrtc::RtpExtension> filtered = + FilterRtpExtensions(extensions, SupportedExtensions2, true); + EXPECT_EQ(1, filtered.size()); + EXPECT_EQ(kRtpTimestampOffsetHeaderExtension, filtered[0].name); +} +} // namespace cricket
diff --git a/talk/media/webrtc/webrtcvideocapturer.cc b/talk/media/webrtc/webrtcvideocapturer.cc index 7d72128..ee4db5b 100644 --- a/talk/media/webrtc/webrtcvideocapturer.cc +++ b/talk/media/webrtc/webrtcvideocapturer.cc
@@ -34,6 +34,7 @@ #ifdef HAVE_WEBRTC_VIDEO #include "talk/media/webrtc/webrtcvideoframe.h" #include "talk/media/webrtc/webrtcvideoframefactory.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/bind.h" #include "webrtc/base/checks.h" #include "webrtc/base/criticalsection.h" @@ -43,7 +44,7 @@ #include "webrtc/base/timeutils.h" #include "webrtc/base/win32.h" // Need this to #include the impl files. -#include "webrtc/modules/video_capture/include/video_capture_factory.h" +#include "webrtc/modules/video_capture/video_capture_factory.h" #include "webrtc/system_wrappers/include/field_trial.h" namespace cricket { @@ -83,7 +84,7 @@ static bool CapabilityToFormat(const webrtc::VideoCaptureCapability& cap, VideoFormat* format) { uint32_t fourcc = 0; - for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) { + for (size_t i = 0; i < arraysize(kSupportedFourCCs); ++i) { if (kSupportedFourCCs[i].webrtc_type == cap.rawType) { fourcc = kSupportedFourCCs[i].fourcc; break; @@ -103,7 +104,7 @@ static bool FormatToCapability(const VideoFormat& format, webrtc::VideoCaptureCapability* cap) { webrtc::RawVideoType webrtc_type = webrtc::kVideoUnknown; - for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) { + for (size_t i = 0; i < arraysize(kSupportedFourCCs); ++i) { if (kSupportedFourCCs[i].fourcc == format.fourcc) { webrtc_type = kSupportedFourCCs[i].webrtc_type; break; @@ -171,8 +172,8 @@ bool found = false; for (int index = 0; index < num_cams; ++index) { char vcm_name[256]; - if (info->GetDeviceName(index, vcm_name, ARRAY_SIZE(vcm_name), - vcm_id, ARRAY_SIZE(vcm_id)) != -1) { + if (info->GetDeviceName(index, vcm_name, arraysize(vcm_name), vcm_id, + arraysize(vcm_id)) != -1) { if (device.name == reinterpret_cast<char*>(vcm_name)) { found = true; break; @@ -349,6 +350,7 @@ SetCaptureFormat(NULL); start_thread_ = nullptr; + SetCaptureState(CS_STOPPED); } bool WebRtcVideoCapturer::IsRunning() { @@ -361,7 +363,7 @@ } fourccs->clear(); - for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) { + for (size_t i = 0; i < arraysize(kSupportedFourCCs); ++i) { fourccs->push_back(kSupportedFourCCs[i].fourcc); } return true;
diff --git a/talk/media/webrtc/webrtcvideocapturer.h b/talk/media/webrtc/webrtcvideocapturer.h index 0a99884..591e46f 100644 --- a/talk/media/webrtc/webrtcvideocapturer.h +++ b/talk/media/webrtc/webrtcvideocapturer.h
@@ -39,7 +39,7 @@ #include "webrtc/base/messagehandler.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" -#include "webrtc/modules/video_capture/include/video_capture.h" +#include "webrtc/modules/video_capture/video_capture.h" namespace cricket {
diff --git a/talk/media/webrtc/webrtcvideocapturer_unittest.cc b/talk/media/webrtc/webrtcvideocapturer_unittest.cc index d560fc5..85db32e 100644 --- a/talk/media/webrtc/webrtcvideocapturer_unittest.cc +++ b/talk/media/webrtc/webrtcvideocapturer_unittest.cc
@@ -111,6 +111,7 @@ capturer_->Stop(); EXPECT_FALSE(capturer_->IsRunning()); EXPECT_TRUE(capturer_->GetCaptureFormat() == NULL); + EXPECT_EQ_WAIT(cricket::CS_STOPPED, listener_.last_capture_state(), 1000); } TEST_F(WebRtcVideoCapturerTest, TestCaptureVcm) {
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc index bcd513e..55c0742 100644 --- a/talk/media/webrtc/webrtcvideoengine2.cc +++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -152,9 +152,7 @@ return true; } if (CodecNamesEq(codec_name, kVp9CodecName)) { - const std::string group_name = - webrtc::field_trial::FindFullName("WebRTC-SupportVP9"); - return group_name == "Enabled" || group_name == "EnabledByFlag"; + return true; } if (CodecNamesEq(codec_name, kH264CodecName)) { return webrtc::H264Encoder::IsSupported() && @@ -168,6 +166,8 @@ codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty)); codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli)); codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); + codec->AddFeedbackParam( + FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); } static VideoCodec MakeVideoCodecWithDefaultFeedbackParams(int payload_type, @@ -243,20 +243,6 @@ return true; } -static std::string RtpExtensionsToString( - const std::vector<RtpHeaderExtension>& extensions) { - std::stringstream out; - out << '{'; - for (size_t i = 0; i < extensions.size(); ++i) { - out << "{" << extensions[i].uri << ": " << extensions[i].id << "}"; - if (i != extensions.size() - 1) { - out << ", "; - } - } - out << '}'; - return out.str(); -} - inline const webrtc::RtpExtension* FindHeaderExtension( const std::vector<webrtc::RtpExtension>& extensions, const std::string& name) { @@ -303,7 +289,8 @@ // Returns true if the given codec is disallowed from doing simulcast. bool IsCodecBlacklistedForSimulcast(const std::string& codec_name) { - return CodecNamesEq(codec_name, kH264CodecName); + return CodecNamesEq(codec_name, kH264CodecName) || + CodecNamesEq(codec_name, kVp9CodecName); } // The selected thresholds for QVGA and VGA corresponded to a QP around 10. @@ -339,13 +326,13 @@ std::vector<VideoCodec> DefaultVideoCodecList() { std::vector<VideoCodec> codecs; + codecs.push_back(MakeVideoCodecWithDefaultFeedbackParams(kDefaultVp8PlType, + kVp8CodecName)); if (CodecIsInternallySupported(kVp9CodecName)) { codecs.push_back(MakeVideoCodecWithDefaultFeedbackParams(kDefaultVp9PlType, kVp9CodecName)); // TODO(andresp): Add rtx codec for vp9 and verify it works. } - codecs.push_back(MakeVideoCodecWithDefaultFeedbackParams(kDefaultVp8PlType, - kVp8CodecName)); if (CodecIsInternallySupported(kH264CodecName)) { codecs.push_back(MakeVideoCodecWithDefaultFeedbackParams(kDefaultH264PlType, kH264CodecName)); @@ -357,72 +344,6 @@ return codecs; } -static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs, - const VideoCodec& requested_codec, - VideoCodec* matching_codec) { - for (size_t i = 0; i < codecs.size(); ++i) { - if (requested_codec.Matches(codecs[i])) { - *matching_codec = codecs[i]; - return true; - } - } - return false; -} - -static bool ValidateRtpHeaderExtensionIds( - const std::vector<RtpHeaderExtension>& extensions) { - std::set<int> extensions_used; - for (size_t i = 0; i < extensions.size(); ++i) { - if (extensions[i].id <= 0 || extensions[i].id >= 15 || - !extensions_used.insert(extensions[i].id).second) { - LOG(LS_ERROR) << "RTP extensions are with incorrect or duplicate ids."; - return false; - } - } - return true; -} - -static bool CompareRtpHeaderExtensionIds( - const webrtc::RtpExtension& extension1, - const webrtc::RtpExtension& extension2) { - // Sorting on ID is sufficient, more than one extension per ID is unsupported. - return extension1.id > extension2.id; -} - -static std::vector<webrtc::RtpExtension> FilterRtpExtensions( - const std::vector<RtpHeaderExtension>& extensions) { - std::vector<webrtc::RtpExtension> webrtc_extensions; - for (size_t i = 0; i < extensions.size(); ++i) { - // Unsupported extensions will be ignored. - if (webrtc::RtpExtension::IsSupportedForVideo(extensions[i].uri)) { - webrtc_extensions.push_back(webrtc::RtpExtension( - extensions[i].uri, extensions[i].id)); - } else { - LOG(LS_WARNING) << "Unsupported RTP extension: " << extensions[i].uri; - } - } - - // Sort filtered headers to make sure that they can later be compared - // regardless of in which order they were entered. - std::sort(webrtc_extensions.begin(), webrtc_extensions.end(), - CompareRtpHeaderExtensionIds); - return webrtc_extensions; -} - -static bool RtpExtensionsHaveChanged( - const std::vector<webrtc::RtpExtension>& before, - const std::vector<webrtc::RtpExtension>& after) { - if (before.size() != after.size()) - return true; - for (size_t i = 0; i < before.size(); ++i) { - if (before[i].id != after[i].id) - return true; - if (before[i].name != after[i].name) - return true; - } - return false; -} - std::vector<webrtc::VideoStream> WebRtcVideoChannel2::WebRtcVideoSendStream::CreateSimulcastVideoStreams( const VideoCodec& codec, @@ -489,7 +410,8 @@ denoising = false; } else { // Use codec default if video_noise_reduction is unset. - codec_default_denoising = !options.video_noise_reduction.Get(&denoising); + codec_default_denoising = !options.video_noise_reduction; + denoising = options.video_noise_reduction.value_or(false); } if (CodecNamesEq(codec.name, kVp8CodecName)) { @@ -554,20 +476,6 @@ external_encoder_factory_(NULL) { LOG(LS_INFO) << "WebRtcVideoEngine2::WebRtcVideoEngine2()"; video_codecs_ = GetSupportedCodecs(); - rtp_header_extensions_.push_back( - RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, - kRtpTimestampOffsetHeaderExtensionDefaultId)); - rtp_header_extensions_.push_back( - RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, - kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); - rtp_header_extensions_.push_back( - RtpHeaderExtension(kRtpVideoRotationHeaderExtension, - kRtpVideoRotationHeaderExtensionDefaultId)); - if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") { - rtp_header_extensions_.push_back(RtpHeaderExtension( - kRtpTransportSequenceNumberHeaderExtension, - kRtpTransportSequenceNumberHeaderExtensionDefaultId)); - } } WebRtcVideoEngine2::~WebRtcVideoEngine2() { @@ -579,29 +487,6 @@ initialized_ = true; } -bool WebRtcVideoEngine2::SetDefaultEncoderConfig( - const VideoEncoderConfig& config) { - const VideoCodec& codec = config.max_codec; - bool supports_codec = false; - for (size_t i = 0; i < video_codecs_.size(); ++i) { - if (CodecNamesEq(video_codecs_[i].name, codec.name)) { - video_codecs_[i].width = codec.width; - video_codecs_[i].height = codec.height; - video_codecs_[i].framerate = codec.framerate; - supports_codec = true; - break; - } - } - - if (!supports_codec) { - LOG(LS_ERROR) << "SetDefaultEncoderConfig, codec not supported: " - << codec.ToString(); - return false; - } - - return true; -} - WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel( webrtc::Call* call, const VideoOptions& options) { @@ -615,19 +500,23 @@ return video_codecs_; } -const std::vector<RtpHeaderExtension>& -WebRtcVideoEngine2::rtp_header_extensions() const { - return rtp_header_extensions_; -} - -void WebRtcVideoEngine2::SetLogging(int min_sev, const char* filter) { - // TODO(pbos): Set up logging. - LOG(LS_VERBOSE) << "SetLogging: " << min_sev << '"' << filter << '"'; - // if min_sev == -1, we keep the current log level. - if (min_sev < 0) { - RTC_DCHECK(min_sev == -1); - return; +RtpCapabilities WebRtcVideoEngine2::GetCapabilities() const { + RtpCapabilities capabilities; + capabilities.header_extensions.push_back( + RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, + kRtpTimestampOffsetHeaderExtensionDefaultId)); + capabilities.header_extensions.push_back( + RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, + kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); + capabilities.header_extensions.push_back( + RtpHeaderExtension(kRtpVideoRotationHeaderExtension, + kRtpVideoRotationHeaderExtensionDefaultId)); + if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") { + capabilities.header_extensions.push_back(RtpHeaderExtension( + kRtpTransportSequenceNumberHeaderExtension, + kRtpTransportSequenceNumberHeaderExtensionDefaultId)); } + return capabilities; } void WebRtcVideoEngine2::SetExternalDecoderFactory( @@ -677,48 +566,6 @@ return false; } -// Tells whether the |requested| codec can be transmitted or not. If it can be -// transmitted |out| is set with the best settings supported. Aspect ratio will -// be set as close to |current|'s as possible. If not set |requested|'s -// dimensions will be used for aspect ratio matching. -bool WebRtcVideoEngine2::CanSendCodec(const VideoCodec& requested, - const VideoCodec& current, - VideoCodec* out) { - RTC_DCHECK(out != NULL); - - if (requested.width != requested.height && - (requested.height == 0 || requested.width == 0)) { - // 0xn and nx0 are invalid resolutions. - return false; - } - - VideoCodec matching_codec; - if (!FindFirstMatchingCodec(video_codecs_, requested, &matching_codec)) { - // Codec not supported. - return false; - } - - out->id = requested.id; - out->name = requested.name; - out->preference = requested.preference; - out->params = requested.params; - out->framerate = std::min(requested.framerate, matching_codec.framerate); - out->params = requested.params; - out->feedback_params = requested.feedback_params; - out->width = requested.width; - out->height = requested.height; - if (requested.width == 0 && requested.height == 0) { - return true; - } - - while (out->width > matching_codec.width) { - out->width /= 2; - out->height /= 2; - } - - return out->width > 0 && out->height > 0; -} - // Ignore spammy trace messages, mostly from the stats API when we haven't // gotten RTCP info yet from the remote side. bool WebRtcVideoEngine2::ShouldIgnoreTrace(const std::string& trace) { @@ -777,7 +624,8 @@ RTC_DCHECK(thread_checker_.CalledOnValidThread()); SetDefaultOptions(); options_.SetAll(options); - options_.cpu_overuse_detection.Get(&signal_cpu_adaptation_); + if (options_.cpu_overuse_detection) + signal_cpu_adaptation_ = *options_.cpu_overuse_detection; rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc; sending_ = false; default_send_ssrc_ = 0; @@ -785,10 +633,10 @@ } void WebRtcVideoChannel2::SetDefaultOptions() { - options_.cpu_overuse_detection.Set(true); - options_.dscp.Set(false); - options_.suspend_below_min_bitrate.Set(false); - options_.screencast_min_bitrate.Set(0); + options_.cpu_overuse_detection = rtc::Optional<bool>(true); + options_.dscp = rtc::Optional<bool>(false); + options_.suspend_below_min_bitrate = rtc::Optional<bool>(false); + options_.screencast_min_bitrate = rtc::Optional<int>(0); } WebRtcVideoChannel2::~WebRtcVideoChannel2() { @@ -863,19 +711,43 @@ } bool WebRtcVideoChannel2::SetSendParameters(const VideoSendParameters& params) { + TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetSendParameters"); + LOG(LS_INFO) << "SetSendParameters: " << params.ToString(); // TODO(pbos): Refactor this to only recreate the send streams once // instead of 4 times. - return (SetSendCodecs(params.codecs) && - SetSendRtpHeaderExtensions(params.extensions) && - SetMaxSendBandwidth(params.max_bandwidth_bps) && - SetOptions(params.options)); + if (!SetSendCodecs(params.codecs) || + !SetSendRtpHeaderExtensions(params.extensions) || + !SetMaxSendBandwidth(params.max_bandwidth_bps) || + !SetOptions(params.options)) { + return false; + } + if (send_params_.rtcp.reduced_size != params.rtcp.reduced_size) { + rtc::CritScope stream_lock(&stream_crit_); + for (auto& kv : send_streams_) { + kv.second->SetSendParameters(params); + } + } + send_params_ = params; + return true; } bool WebRtcVideoChannel2::SetRecvParameters(const VideoRecvParameters& params) { + TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetRecvParameters"); + LOG(LS_INFO) << "SetRecvParameters: " << params.ToString(); // TODO(pbos): Refactor this to only recreate the recv streams once // instead of twice. - return (SetRecvCodecs(params.codecs) && - SetRecvRtpHeaderExtensions(params.extensions)); + if (!SetRecvCodecs(params.codecs) || + !SetRecvRtpHeaderExtensions(params.extensions)) { + return false; + } + if (recv_params_.rtcp.reduced_size != params.rtcp.reduced_size) { + rtc::CritScope stream_lock(&stream_crit_); + for (auto& kv : receive_streams_) { + kv.second->SetRecvParameters(params); + } + } + recv_params_ = params; + return true; } std::string WebRtcVideoChannel2::CodecSettingsVectorToString( @@ -952,15 +824,15 @@ LOG(LS_INFO) << "Using codec: " << supported_codecs.front().codec.ToString(); - VideoCodecSettings old_codec; - if (send_codec_.Get(&old_codec) && supported_codecs.front() == old_codec) { + if (send_codec_ && supported_codecs.front() == *send_codec_) { LOG(LS_INFO) << "Ignore call to SetSendCodecs because first supported " "codec hasn't changed."; // Using same codec, avoid reconfiguring. return true; } - send_codec_.Set(supported_codecs.front()); + send_codec_ = rtc::Optional<WebRtcVideoChannel2::VideoCodecSettings>( + supported_codecs.front()); rtc::CritScope stream_lock(&stream_crit_); LOG(LS_INFO) << "Change the send codec because SetSendCodecs has a different " @@ -969,12 +841,15 @@ RTC_DCHECK(kv.second != nullptr); kv.second->SetCodec(supported_codecs.front()); } - LOG(LS_INFO) << "SetNackAndRemb on all the receive streams because the send " - "codec has changed."; + LOG(LS_INFO) + << "SetFeedbackOptions on all the receive streams because the send " + "codec has changed."; for (auto& kv : receive_streams_) { RTC_DCHECK(kv.second != nullptr); - kv.second->SetNackAndRemb(HasNack(supported_codecs.front().codec), - HasRemb(supported_codecs.front().codec)); + kv.second->SetFeedbackParameters( + HasNack(supported_codecs.front().codec), + HasRemb(supported_codecs.front().codec), + HasTransportCc(supported_codecs.front().codec)); } // TODO(holmer): Changing the codec parameters shouldn't necessarily mean that @@ -1006,12 +881,11 @@ } bool WebRtcVideoChannel2::GetSendCodec(VideoCodec* codec) { - VideoCodecSettings codec_settings; - if (!send_codec_.Get(&codec_settings)) { + if (!send_codec_) { LOG(LS_VERBOSE) << "GetSendCodec: No send codec set."; return false; } - *codec = codec_settings.codec; + *codec = send_codec_->codec; return true; } @@ -1028,7 +902,7 @@ bool WebRtcVideoChannel2::SetSend(bool send) { LOG(LS_VERBOSE) << "SetSend: " << (send ? "true" : "false"); - if (send && !send_codec_.IsSet()) { + if (send && !send_codec_) { LOG(LS_ERROR) << "SetSend(true) called before setting codec."; return false; } @@ -1094,15 +968,10 @@ webrtc::VideoSendStream::Config config(this); config.overuse_callback = this; - WebRtcVideoSendStream* stream = - new WebRtcVideoSendStream(call_, - sp, - config, - external_encoder_factory_, - options_, - bitrate_config_.max_bitrate_bps, - send_codec_, - send_rtp_extensions_); + WebRtcVideoSendStream* stream = new WebRtcVideoSendStream( + call_, sp, config, external_encoder_factory_, options_, + bitrate_config_.max_bitrate_bps, send_codec_, send_rtp_extensions_, + send_params_); uint32_t ssrc = sp.first_ssrc(); RTC_DCHECK(ssrc != 0); @@ -1224,15 +1093,13 @@ // Set up A/V sync group based on sync label. config.sync_group = sp.sync_label; - config.rtp.remb = false; - VideoCodecSettings send_codec; - if (send_codec_.Get(&send_codec)) { - config.rtp.remb = HasRemb(send_codec.codec); - } + config.rtp.remb = send_codec_ ? HasRemb(send_codec_->codec) : false; + config.rtp.transport_cc = + send_codec_ ? HasTransportCc(send_codec_->codec) : false; receive_streams_[ssrc] = new WebRtcVideoReceiveStream( call_, sp, config, external_decoder_factory_, default_stream, - recv_codecs_); + recv_codecs_, options_.disable_prerenderer_smoothing.value_or(false)); return true; } @@ -1246,6 +1113,9 @@ config->rtp.local_ssrc = rtcp_receiver_report_ssrc_; config->rtp.extensions = recv_rtp_extensions_; + config->rtp.rtcp_mode = recv_params_.rtcp.reduced_size + ? webrtc::RtcpMode::kReducedSize + : webrtc::RtcpMode::kCompound; // TODO(pbos): This protection is against setting the same local ssrc as // remote which is not permitted by the lower-level API. RTCP requires a @@ -1482,12 +1352,14 @@ const rtc::PacketTime& packet_time) { const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp, packet_time.not_before); - if (call_->Receiver()->DeliverPacket( - webrtc::MediaType::VIDEO, - reinterpret_cast<const uint8_t*>(packet->data()), packet->size(), - webrtc_packet_time) != webrtc::PacketReceiver::DELIVERY_OK) { - LOG(LS_WARNING) << "Failed to deliver RTCP packet."; - } + // TODO(pbos): Check webrtc::PacketReceiver::DELIVERY_OK once we deliver + // for both audio and video on the same path. Since BundleFilter doesn't + // filter RTCP anymore incoming RTCP packets could've been going to audio (so + // logging failures spam the log). + call_->Receiver()->DeliverPacket( + webrtc::MediaType::VIDEO, + reinterpret_cast<const uint8_t*>(packet->data()), packet->size(), + webrtc_packet_time); } void WebRtcVideoChannel2::OnReadyToSend(bool ready) { @@ -1512,20 +1384,17 @@ bool WebRtcVideoChannel2::SetRecvRtpHeaderExtensions( const std::vector<RtpHeaderExtension>& extensions) { TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetRecvRtpHeaderExtensions"); - LOG(LS_INFO) << "SetRecvRtpHeaderExtensions: " - << RtpExtensionsToString(extensions); - if (!ValidateRtpHeaderExtensionIds(extensions)) + if (!ValidateRtpExtensions(extensions)) { return false; - - std::vector<webrtc::RtpExtension> filtered_extensions = - FilterRtpExtensions(extensions); - if (!RtpExtensionsHaveChanged(recv_rtp_extensions_, filtered_extensions)) { + } + std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions( + extensions, webrtc::RtpExtension::IsSupportedForVideo, false); + if (recv_rtp_extensions_ == filtered_extensions) { LOG(LS_INFO) << "Ignoring call to SetRecvRtpHeaderExtensions because " "header extensions haven't changed."; return true; } - - recv_rtp_extensions_ = filtered_extensions; + recv_rtp_extensions_.swap(filtered_extensions); rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32_t, WebRtcVideoReceiveStream*>::iterator it = @@ -1539,21 +1408,17 @@ bool WebRtcVideoChannel2::SetSendRtpHeaderExtensions( const std::vector<RtpHeaderExtension>& extensions) { TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetSendRtpHeaderExtensions"); - LOG(LS_INFO) << "SetSendRtpHeaderExtensions: " - << RtpExtensionsToString(extensions); - if (!ValidateRtpHeaderExtensionIds(extensions)) + if (!ValidateRtpExtensions(extensions)) { return false; - - std::vector<webrtc::RtpExtension> filtered_extensions = - FilterRtpExtensions(FilterRedundantRtpExtensions( - extensions, kBweExtensionPriorities, kBweExtensionPrioritiesLength)); - if (!RtpExtensionsHaveChanged(send_rtp_extensions_, filtered_extensions)) { - LOG(LS_INFO) << "Ignoring call to SetSendRtpHeaderExtensions because " + } + std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions( + extensions, webrtc::RtpExtension::IsSupportedForVideo, true); + if (send_rtp_extensions_ == filtered_extensions) { + LOG(LS_INFO) << "Ignoring call to SetRecvRtpHeaderExtensions because " "header extensions haven't changed."; return true; } - - send_rtp_extensions_ = filtered_extensions; + send_rtp_extensions_.swap(filtered_extensions); const webrtc::RtpExtension* cvo_extension = FindHeaderExtension( send_rtp_extensions_, kRtpVideoRotationHeaderExtension); @@ -1612,11 +1477,11 @@ } { rtc::CritScope lock(&capturer_crit_); - options_.cpu_overuse_detection.Get(&signal_cpu_adaptation_); + if (options_.cpu_overuse_detection) + signal_cpu_adaptation_ = *options_.cpu_overuse_detection; } - rtc::DiffServCodePoint dscp = options_.dscp.GetWithDefaultIfUnset(false) - ? rtc::DSCP_AF41 - : rtc::DSCP_DEFAULT; + rtc::DiffServCodePoint dscp = + options_.dscp.value_or(false) ? rtc::DSCP_AF41 : rtc::DSCP_DEFAULT; MediaChannel::SetDscp(dscp); rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32_t, WebRtcVideoSendStream*>::iterator it = @@ -1708,12 +1573,11 @@ const webrtc::VideoSendStream::Config& config, const VideoOptions& options, int max_bitrate_bps, - const Settable<VideoCodecSettings>& codec_settings) + const rtc::Optional<VideoCodecSettings>& codec_settings) : config(config), options(options), max_bitrate_bps(max_bitrate_bps), - codec_settings(codec_settings) { -} + codec_settings(codec_settings) {} WebRtcVideoChannel2::WebRtcVideoSendStream::AllocatedEncoder::AllocatedEncoder( webrtc::VideoEncoder* encoder, @@ -1737,8 +1601,11 @@ WebRtcVideoEncoderFactory* external_encoder_factory, const VideoOptions& options, int max_bitrate_bps, - const Settable<VideoCodecSettings>& codec_settings, - const std::vector<webrtc::RtpExtension>& rtp_extensions) + const rtc::Optional<VideoCodecSettings>& codec_settings, + const std::vector<webrtc::RtpExtension>& rtp_extensions, + // TODO(deadbeef): Don't duplicate information between send_params, + // rtp_extensions, options, etc. + const VideoSendParameters& send_params) : ssrcs_(sp.ssrcs), ssrc_groups_(sp.ssrc_groups), call_(call), @@ -1759,10 +1626,12 @@ ¶meters_.config.rtp.rtx.ssrcs); parameters_.config.rtp.c_name = sp.cname; parameters_.config.rtp.extensions = rtp_extensions; + parameters_.config.rtp.rtcp_mode = send_params.rtcp.reduced_size + ? webrtc::RtcpMode::kReducedSize + : webrtc::RtcpMode::kCompound; - VideoCodecSettings params; - if (codec_settings.Get(¶ms)) { - SetCodec(params); + if (codec_settings) { + SetCodec(*codec_settings); } } @@ -1940,11 +1809,10 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetOptions( const VideoOptions& options) { rtc::CritScope cs(&lock_); - VideoCodecSettings codec_settings; - if (parameters_.codec_settings.Get(&codec_settings)) { + if (parameters_.codec_settings) { LOG(LS_INFO) << "SetCodecAndOptions because of SetOptions; options=" << options.ToString(); - SetCodecAndOptions(codec_settings, options); + SetCodecAndOptions(*parameters_.codec_settings, options); } else { parameters_.options = options; } @@ -2049,10 +1917,12 @@ parameters_.config.rtp.nack.rtp_history_ms = HasNack(codec_settings.codec) ? kNackHistoryMs : 0; - options.suspend_below_min_bitrate.Get( - ¶meters_.config.suspend_below_min_bitrate); + RTC_CHECK(options.suspend_below_min_bitrate); + parameters_.config.suspend_below_min_bitrate = + *options.suspend_below_min_bitrate; - parameters_.codec_settings.Set(codec_settings); + parameters_.codec_settings = + rtc::Optional<WebRtcVideoChannel2::VideoCodecSettings>(codec_settings); parameters_.options = options; LOG(LS_INFO) @@ -2075,17 +1945,27 @@ } } +void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSendParameters( + const VideoSendParameters& send_params) { + rtc::CritScope cs(&lock_); + parameters_.config.rtp.rtcp_mode = send_params.rtcp.reduced_size + ? webrtc::RtcpMode::kReducedSize + : webrtc::RtcpMode::kCompound; + if (stream_ != nullptr) { + LOG(LS_INFO) << "RecreateWebRtcStream (send) because of SetSendParameters"; + RecreateWebRtcStream(); + } +} + webrtc::VideoEncoderConfig WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig( const Dimensions& dimensions, const VideoCodec& codec) const { webrtc::VideoEncoderConfig encoder_config; if (dimensions.is_screencast) { - int screencast_min_bitrate_kbps; - parameters_.options.screencast_min_bitrate.Get( - &screencast_min_bitrate_kbps); + RTC_CHECK(parameters_.options.screencast_min_bitrate); encoder_config.min_transmit_bitrate_bps = - screencast_min_bitrate_kbps * 1000; + *parameters_.options.screencast_min_bitrate * 1000; encoder_config.content_type = webrtc::VideoEncoderConfig::ContentType::kScreen; } else { @@ -2121,7 +2001,7 @@ parameters_.max_bitrate_bps, stream_count); // Conference mode screencast uses 2 temporal layers split at 100kbit. - if (parameters_.options.conference_mode.GetWithDefaultIfUnset(false) && + if (parameters_.options.conference_mode.value_or(false) && dimensions.is_screencast && encoder_config.streams.size() == 1) { ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault(); @@ -2156,8 +2036,8 @@ RTC_DCHECK(!parameters_.encoder_config.streams.empty()); - VideoCodecSettings codec_settings; - parameters_.codec_settings.Get(&codec_settings); + RTC_CHECK(parameters_.codec_settings); + VideoCodecSettings codec_settings = *parameters_.codec_settings; webrtc::VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(last_dimensions_, codec_settings.codec); @@ -2202,9 +2082,8 @@ for (uint32_t ssrc : parameters_.config.rtp.ssrcs) info.add_ssrc(ssrc); - VideoCodecSettings codec_settings; - if (parameters_.codec_settings.Get(&codec_settings)) - info.codec_name = codec_settings.codec.name; + if (parameters_.codec_settings) + info.codec_name = parameters_.codec_settings->codec.name; for (size_t i = 0; i < parameters_.encoder_config.streams.size(); ++i) { if (i == parameters_.encoder_config.streams.size() - 1) { info.preferred_bitrate += @@ -2238,6 +2117,15 @@ } } } + + // Get bandwidth limitation info from stream_->GetStats(). + // Input resolution (output from video_adapter) can be further scaled down or + // higher video layer(s) can be dropped due to bitrate constraints. + // Note, adapt_changes only include changes from the video_adapter. + if (stats.bw_limited_resolution) + info.adapt_reason |= CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH; + + info.encoder_implementation_name = stats.encoder_implementation_name; info.ssrc_groups = ssrc_groups_; info.framerate_input = stats.input_frame_rate; info.framerate_sent = stats.encode_frame_rate; @@ -2316,11 +2204,10 @@ call_->DestroyVideoSendStream(stream_); } - VideoCodecSettings codec_settings; - parameters_.codec_settings.Get(&codec_settings); + RTC_CHECK(parameters_.codec_settings); parameters_.encoder_config.encoder_specific_settings = ConfigureVideoEncoderSettings( - codec_settings.codec, parameters_.options, + parameters_.codec_settings->codec, parameters_.options, parameters_.encoder_config.content_type == webrtc::VideoEncoderConfig::ContentType::kScreen); @@ -2345,7 +2232,8 @@ const webrtc::VideoReceiveStream::Config& config, WebRtcVideoDecoderFactory* external_decoder_factory, bool default_stream, - const std::vector<VideoCodecSettings>& recv_codecs) + const std::vector<VideoCodecSettings>& recv_codecs, + bool disable_prerenderer_smoothing) : call_(call), ssrcs_(sp.ssrcs), ssrc_groups_(sp.ssrc_groups), @@ -2353,6 +2241,7 @@ default_stream_(default_stream), config_(config), external_decoder_factory_(external_decoder_factory), + disable_prerenderer_smoothing_(disable_prerenderer_smoothing), renderer_(NULL), last_width_(-1), last_height_(-1), @@ -2457,10 +2346,10 @@ config_.rtp.nack.rtp_history_ms = HasNack(recv_codecs.begin()->codec) ? kNackHistoryMs : 0; - ClearDecoders(&old_decoders); LOG(LS_INFO) << "RecreateWebRtcStream (recv) because of SetRecvCodecs: " << CodecSettingsVectorToString(recv_codecs); RecreateWebRtcStream(); + ClearDecoders(&old_decoders); } void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetLocalSsrc( @@ -2482,20 +2371,28 @@ RecreateWebRtcStream(); } -void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetNackAndRemb( - bool nack_enabled, bool remb_enabled) { +void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetFeedbackParameters( + bool nack_enabled, + bool remb_enabled, + bool transport_cc_enabled) { int nack_history_ms = nack_enabled ? kNackHistoryMs : 0; if (config_.rtp.nack.rtp_history_ms == nack_history_ms && - config_.rtp.remb == remb_enabled) { - LOG(LS_INFO) << "Ignoring call to SetNackAndRemb because parameters are " - "unchanged; nack=" << nack_enabled - << ", remb=" << remb_enabled; + config_.rtp.remb == remb_enabled && + config_.rtp.transport_cc == transport_cc_enabled) { + LOG(LS_INFO) + << "Ignoring call to SetFeedbackParameters because parameters are " + "unchanged; nack=" + << nack_enabled << ", remb=" << remb_enabled + << ", transport_cc=" << transport_cc_enabled; return; } config_.rtp.remb = remb_enabled; config_.rtp.nack.rtp_history_ms = nack_history_ms; - LOG(LS_INFO) << "RecreateWebRtcStream (recv) because of SetNackAndRemb; nack=" - << nack_enabled << ", remb=" << remb_enabled; + config_.rtp.transport_cc = transport_cc_enabled; + LOG(LS_INFO) + << "RecreateWebRtcStream (recv) because of SetFeedbackParameters; nack=" + << nack_enabled << ", remb=" << remb_enabled + << ", transport_cc=" << transport_cc_enabled; RecreateWebRtcStream(); } @@ -2506,6 +2403,15 @@ RecreateWebRtcStream(); } +void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRecvParameters( + const VideoRecvParameters& recv_params) { + config_.rtp.rtcp_mode = recv_params.rtcp.reduced_size + ? webrtc::RtcpMode::kReducedSize + : webrtc::RtcpMode::kCompound; + LOG(LS_INFO) << "RecreateWebRtcStream (recv) because of SetRecvParameters"; + RecreateWebRtcStream(); +} + void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RecreateWebRtcStream() { if (stream_ != NULL) { call_->DestroyVideoReceiveStream(stream_); @@ -2560,6 +2466,11 @@ return true; } +bool WebRtcVideoChannel2::WebRtcVideoReceiveStream::SmoothsRenderedFrames() + const { + return disable_prerenderer_smoothing_; +} + bool WebRtcVideoChannel2::WebRtcVideoReceiveStream::IsDefaultStream() const { return default_stream_; } @@ -2607,6 +2518,7 @@ info.ssrc_groups = ssrc_groups_; info.add_ssrc(config_.rtp.remote_ssrc); webrtc::VideoReceiveStream::Stats stats = stream_->GetStats(); + info.decoder_implementation_name = stats.decoder_implementation_name; info.bytes_rcvd = stats.rtp_stats.transmitted.payload_bytes + stats.rtp_stats.transmitted.header_bytes + stats.rtp_stats.transmitted.padding_bytes;
diff --git a/talk/media/webrtc/webrtcvideoengine2.h b/talk/media/webrtc/webrtcvideoengine2.h index 7096135..1b8da16 100644 --- a/talk/media/webrtc/webrtcvideoengine2.h +++ b/talk/media/webrtc/webrtcvideoengine2.h
@@ -112,14 +112,11 @@ // Basic video engine implementation. void Init(); - bool SetDefaultEncoderConfig(const VideoEncoderConfig& config); - WebRtcVideoChannel2* CreateChannel(webrtc::Call* call, const VideoOptions& options); const std::vector<VideoCodec>& codecs() const; - const std::vector<RtpHeaderExtension>& rtp_header_extensions() const; - void SetLogging(int min_sev, const char* filter); + RtpCapabilities GetCapabilities() const; // Set a WebRtcVideoDecoderFactory for external decoding. Video engine does // not take the ownership of |decoder_factory|. The caller needs to make sure @@ -134,9 +131,6 @@ bool EnableTimedRender(); bool FindCodec(const VideoCodec& in); - bool CanSendCodec(const VideoCodec& in, - const VideoCodec& current, - VideoCodec* out); // Check whether the supplied trace should be ignored. bool ShouldIgnoreTrace(const std::string& trace); @@ -144,7 +138,6 @@ std::vector<VideoCodec> GetSupportedCodecs() const; std::vector<VideoCodec> video_codecs_; - std::vector<RtpHeaderExtension> rtp_header_extensions_; bool initialized_; @@ -250,14 +243,18 @@ WebRtcVideoEncoderFactory* external_encoder_factory, const VideoOptions& options, int max_bitrate_bps, - const Settable<VideoCodecSettings>& codec_settings, - const std::vector<webrtc::RtpExtension>& rtp_extensions); + const rtc::Optional<VideoCodecSettings>& codec_settings, + const std::vector<webrtc::RtpExtension>& rtp_extensions, + const VideoSendParameters& send_params); ~WebRtcVideoSendStream(); void SetOptions(const VideoOptions& options); void SetCodec(const VideoCodecSettings& codec); void SetRtpExtensions( const std::vector<webrtc::RtpExtension>& rtp_extensions); + // TODO(deadbeef): Move logic from SetCodec/SetRtpExtensions/etc. + // into this method. Currently this method only sets the RTCP mode. + void SetSendParameters(const VideoSendParameters& send_params); void InputFrame(VideoCapturer* capturer, const VideoFrame* frame); bool SetCapturer(VideoCapturer* capturer); @@ -286,11 +283,11 @@ const webrtc::VideoSendStream::Config& config, const VideoOptions& options, int max_bitrate_bps, - const Settable<VideoCodecSettings>& codec_settings); + const rtc::Optional<VideoCodecSettings>& codec_settings); webrtc::VideoSendStream::Config config; VideoOptions options; int max_bitrate_bps; - Settable<VideoCodecSettings> codec_settings; + rtc::Optional<VideoCodecSettings> codec_settings; // Sent resolutions + bitrates etc. by the underlying VideoSendStream, // typically changes when setting a new resolution or reconfiguring // bitrates. @@ -395,19 +392,26 @@ const webrtc::VideoReceiveStream::Config& config, WebRtcVideoDecoderFactory* external_decoder_factory, bool default_stream, - const std::vector<VideoCodecSettings>& recv_codecs); + const std::vector<VideoCodecSettings>& recv_codecs, + bool disable_prerenderer_smoothing); ~WebRtcVideoReceiveStream(); const std::vector<uint32_t>& GetSsrcs() const; void SetLocalSsrc(uint32_t local_ssrc); - void SetNackAndRemb(bool nack_enabled, bool remb_enabled); + void SetFeedbackParameters(bool nack_enabled, + bool remb_enabled, + bool transport_cc_enabled); void SetRecvCodecs(const std::vector<VideoCodecSettings>& recv_codecs); void SetRtpExtensions(const std::vector<webrtc::RtpExtension>& extensions); + // TODO(deadbeef): Move logic from SetRecvCodecs/SetRtpExtensions/etc. + // into this method. Currently this method only sets the RTCP mode. + void SetRecvParameters(const VideoRecvParameters& recv_params); void RenderFrame(const webrtc::VideoFrame& frame, int time_to_render_ms) override; bool IsTextureSupported() const override; + bool SmoothsRenderedFrames() const override; bool IsDefaultStream() const; void SetRenderer(cricket::VideoRenderer* renderer); @@ -448,6 +452,8 @@ WebRtcVideoDecoderFactory* const external_decoder_factory_; std::vector<AllocatedDecoder> allocated_decoders_; + const bool disable_prerenderer_smoothing_; + rtc::CriticalSection renderer_lock_; cricket::VideoRenderer* renderer_ GUARDED_BY(renderer_lock_); int last_width_ GUARDED_BY(renderer_lock_); @@ -512,7 +518,7 @@ std::set<uint32_t> send_ssrcs_ GUARDED_BY(stream_crit_); std::set<uint32_t> receive_ssrcs_ GUARDED_BY(stream_crit_); - Settable<VideoCodecSettings> send_codec_; + rtc::Optional<VideoCodecSettings> send_codec_; std::vector<webrtc::RtpExtension> send_rtp_extensions_; WebRtcVideoEncoderFactory* const external_encoder_factory_; @@ -521,6 +527,10 @@ std::vector<webrtc::RtpExtension> recv_rtp_extensions_; webrtc::Call::Config::BitrateConfig bitrate_config_; VideoOptions options_; + // TODO(deadbeef): Don't duplicate information between + // send_params/recv_params, rtp_extensions, options, etc. + VideoSendParameters send_params_; + VideoRecvParameters recv_params_; }; } // namespace cricket
diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc index c0cd2ff..41e04a9 100644 --- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc +++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -75,6 +75,8 @@ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam( cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty))); EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam( + cricket::kRtcpFbParamTransportCc, cricket::kParamValueEmpty))); + EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam( cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir))); } @@ -205,26 +207,6 @@ EXPECT_TRUE(engine_.FindCodec(rtx)); } -TEST_F(WebRtcVideoEngine2Test, SetDefaultEncoderConfigPreservesFeedbackParams) { - cricket::VideoCodec max_settings( - engine_.codecs()[0].id, engine_.codecs()[0].name, - engine_.codecs()[0].width / 2, engine_.codecs()[0].height / 2, 30, 0); - // This codec shouldn't have NACK by default or the test is pointless. - EXPECT_FALSE(max_settings.HasFeedbackParam( - FeedbackParam(kRtcpFbParamNack, kParamValueEmpty))); - // The engine should by default have it however. - EXPECT_TRUE(engine_.codecs()[0].HasFeedbackParam( - FeedbackParam(kRtcpFbParamNack, kParamValueEmpty))); - - // Set constrained max codec settings. - EXPECT_TRUE(engine_.SetDefaultEncoderConfig( - cricket::VideoEncoderConfig(max_settings))); - - // Verify that feedback parameters are retained. - EXPECT_TRUE(engine_.codecs()[0].HasFeedbackParam( - FeedbackParam(kRtcpFbParamNack, kParamValueEmpty))); -} - TEST_F(WebRtcVideoEngine2Test, DefaultRtxCodecHasAssociatedPayloadTypeSet) { std::vector<VideoCodec> engine_codecs = engine_.codecs(); for (size_t i = 0; i < engine_codecs.size(); ++i) { @@ -240,11 +222,11 @@ } TEST_F(WebRtcVideoEngine2Test, SupportsTimestampOffsetHeaderExtension) { - std::vector<RtpHeaderExtension> extensions = engine_.rtp_header_extensions(); - ASSERT_FALSE(extensions.empty()); - for (size_t i = 0; i < extensions.size(); ++i) { - if (extensions[i].uri == kRtpTimestampOffsetHeaderExtension) { - EXPECT_EQ(kRtpTimestampOffsetHeaderExtensionDefaultId, extensions[i].id); + RtpCapabilities capabilities = engine_.GetCapabilities(); + ASSERT_FALSE(capabilities.header_extensions.empty()); + for (const RtpHeaderExtension& extension : capabilities.header_extensions) { + if (extension.uri == kRtpTimestampOffsetHeaderExtension) { + EXPECT_EQ(kRtpTimestampOffsetHeaderExtensionDefaultId, extension.id); return; } } @@ -252,12 +234,11 @@ } TEST_F(WebRtcVideoEngine2Test, SupportsAbsoluteSenderTimeHeaderExtension) { - std::vector<RtpHeaderExtension> extensions = engine_.rtp_header_extensions(); - ASSERT_FALSE(extensions.empty()); - for (size_t i = 0; i < extensions.size(); ++i) { - if (extensions[i].uri == kRtpAbsoluteSenderTimeHeaderExtension) { - EXPECT_EQ(kRtpAbsoluteSenderTimeHeaderExtensionDefaultId, - extensions[i].id); + RtpCapabilities capabilities = engine_.GetCapabilities(); + ASSERT_FALSE(capabilities.header_extensions.empty()); + for (const RtpHeaderExtension& extension : capabilities.header_extensions) { + if (extension.uri == kRtpAbsoluteSenderTimeHeaderExtension) { + EXPECT_EQ(kRtpAbsoluteSenderTimeHeaderExtensionDefaultId, extension.id); return; } } @@ -272,12 +253,12 @@ TEST_F(WebRtcVideoEngine2WithSendSideBweTest, SupportsTransportSequenceNumberHeaderExtension) { - std::vector<RtpHeaderExtension> extensions = engine_.rtp_header_extensions(); - ASSERT_FALSE(extensions.empty()); - for (size_t i = 0; i < extensions.size(); ++i) { - if (extensions[i].uri == kRtpTransportSequenceNumberHeaderExtension) { + RtpCapabilities capabilities = engine_.GetCapabilities(); + ASSERT_FALSE(capabilities.header_extensions.empty()); + for (const RtpHeaderExtension& extension : capabilities.header_extensions) { + if (extension.uri == kRtpTransportSequenceNumberHeaderExtension) { EXPECT_EQ(kRtpTransportSequenceNumberHeaderExtensionDefaultId, - extensions[i].id); + extension.id); return; } } @@ -285,11 +266,11 @@ } TEST_F(WebRtcVideoEngine2Test, SupportsVideoRotationHeaderExtension) { - std::vector<RtpHeaderExtension> extensions = engine_.rtp_header_extensions(); - ASSERT_FALSE(extensions.empty()); - for (size_t i = 0; i < extensions.size(); ++i) { - if (extensions[i].uri == kRtpVideoRotationHeaderExtension) { - EXPECT_EQ(kRtpVideoRotationHeaderExtensionDefaultId, extensions[i].id); + RtpCapabilities capabilities = engine_.GetCapabilities(); + ASSERT_FALSE(capabilities.header_extensions.empty()); + for (const RtpHeaderExtension& extension : capabilities.header_extensions) { + if (extension.uri == kRtpVideoRotationHeaderExtension) { + EXPECT_EQ(kRtpVideoRotationHeaderExtensionDefaultId, extension.id); return; } } @@ -794,17 +775,6 @@ ASSERT_EQ(1u, decoder_factory.decoders().size()); } -class WebRtcVideoEngine2BaseTest - : public VideoEngineTest<cricket::WebRtcVideoEngine2> { - protected: - typedef VideoEngineTest<cricket::WebRtcVideoEngine2> Base; -}; - -#define WEBRTC_ENGINE_BASE_TEST(test) \ - TEST_F(WebRtcVideoEngine2BaseTest, test) { Base::test##Body(); } - -WEBRTC_ENGINE_BASE_TEST(ConstrainNewCodec2); - class WebRtcVideoChannel2BaseTest : public VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> { protected: @@ -894,7 +864,10 @@ Base::TwoStreamsReUseFirstStream(kVp8Codec); } +//Disabled for TSan: https://bugs.chromium.org/p/webrtc/issues/detail?id=4963 +#if !defined(THREAD_SANITIZER) WEBRTC_BASE_TEST(SendManyResizeOnce); +#endif // THREAD_SANITIZER // TODO(pbos): Enable and figure out why this fails (or should work). TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_SendVp8HdAndReceiveAdaptedVp8Vga) { @@ -1097,7 +1070,7 @@ FakeVideoSendStream* SetDenoisingOption( const cricket::VideoSendParameters& parameters, bool enabled) { cricket::VideoSendParameters params = parameters; - params.options.video_noise_reduction.Set(enabled); + params.options.video_noise_reduction = rtc::Optional<bool>(enabled); channel_->SetSendParameters(params); return fake_call_->GetVideoSendStreams().back(); } @@ -1148,7 +1121,7 @@ parameters.codecs = engine_.codecs(); EXPECT_TRUE(channel_->SetSendParameters(parameters)); EXPECT_TRUE(channel_->SetSend(true)); - parameters.options.conference_mode.Set(true); + parameters.options.conference_mode = rtc::Optional<bool>(true); EXPECT_TRUE(channel_->SetSendParameters(parameters)); // Send side. @@ -1451,6 +1424,11 @@ EXPECT_TRUE(stream->GetConfig().rtp.remb); } +TEST_F(WebRtcVideoChannel2Test, TransportCcIsEnabledByDefault) { + FakeVideoReceiveStream* stream = AddRecvStream(); + EXPECT_TRUE(stream->GetConfig().rtp.transport_cc); +} + TEST_F(WebRtcVideoChannel2Test, RembCanBeEnabledAndDisabled) { FakeVideoReceiveStream* stream = AddRecvStream(); EXPECT_TRUE(stream->GetConfig().rtp.remb); @@ -1471,6 +1449,27 @@ EXPECT_TRUE(stream->GetConfig().rtp.remb); } +TEST_F(WebRtcVideoChannel2Test, TransportCcCanBeEnabledAndDisabled) { + FakeVideoReceiveStream* stream = AddRecvStream(); + EXPECT_TRUE(stream->GetConfig().rtp.transport_cc); + + // Verify that transport cc feedback is turned off when send(!) codecs without + // transport cc feedback are set. + cricket::VideoSendParameters parameters; + parameters.codecs.push_back(kVp8Codec); + EXPECT_TRUE(parameters.codecs[0].feedback_params.params().empty()); + EXPECT_TRUE(channel_->SetSendParameters(parameters)); + stream = fake_call_->GetVideoReceiveStreams()[0]; + EXPECT_FALSE(stream->GetConfig().rtp.transport_cc); + + // Verify that transport cc feedback is turned on when setting default codecs + // since the default codecs have transport cc feedback enabled. + parameters.codecs = engine_.codecs(); + EXPECT_TRUE(channel_->SetSendParameters(parameters)); + stream = fake_call_->GetVideoReceiveStreams()[0]; + EXPECT_TRUE(stream->GetConfig().rtp.transport_cc); +} + TEST_F(WebRtcVideoChannel2Test, NackIsEnabledByDefault) { VerifyCodecHasDefaultFeedbackParams(default_codec_); @@ -1558,7 +1557,8 @@ cricket::VideoCodec codec = kVp8Codec360p; cricket::VideoSendParameters parameters; parameters.codecs.push_back(codec); - parameters.options.screencast_min_bitrate.Set(kScreenshareMinBitrateKbps); + parameters.options.screencast_min_bitrate = + rtc::Optional<int>(kScreenshareMinBitrateKbps); EXPECT_TRUE(channel_->SetSendParameters(parameters)); AddSendStream(); @@ -1612,7 +1612,7 @@ ConferenceModeScreencastConfiguresTemporalLayer) { static const int kConferenceScreencastTemporalBitrateBps = ScreenshareLayerConfig::GetDefault().tl0_bitrate_kbps * 1000; - send_parameters_.options.conference_mode.Set(true); + send_parameters_.options.conference_mode = rtc::Optional<bool>(true); channel_->SetSendParameters(send_parameters_); AddSendStream(); @@ -1659,13 +1659,15 @@ } TEST_F(WebRtcVideoChannel2Test, SetOptionsWithSuspendBelowMinBitrate) { - send_parameters_.options.suspend_below_min_bitrate.Set(true); + send_parameters_.options.suspend_below_min_bitrate = + rtc::Optional<bool>(true); channel_->SetSendParameters(send_parameters_); FakeVideoSendStream* stream = AddSendStream(); EXPECT_TRUE(stream->GetConfig().suspend_below_min_bitrate); - send_parameters_.options.suspend_below_min_bitrate.Set(false); + send_parameters_.options.suspend_below_min_bitrate = + rtc::Optional<bool>(false); channel_->SetSendParameters(send_parameters_); stream = fake_call_->GetVideoSendStreams()[0]; @@ -1853,7 +1855,7 @@ cricket::VideoSendParameters parameters; parameters.codecs.push_back(codec); if (!enable_overuse) { - parameters.options.cpu_overuse_detection.Set(false); + parameters.options.cpu_overuse_detection = rtc::Optional<bool>(false); } EXPECT_TRUE(channel_->SetSendParameters(parameters)); @@ -2375,19 +2377,55 @@ cricket::VideoSendParameters parameters = send_parameters_; EXPECT_TRUE(channel_->SetSendParameters(parameters)); EXPECT_EQ(rtc::DSCP_NO_CHANGE, network_interface->dscp()); - parameters.options.dscp.Set(true); + parameters.options.dscp = rtc::Optional<bool>(true); EXPECT_TRUE(channel_->SetSendParameters(parameters)); EXPECT_EQ(rtc::DSCP_AF41, network_interface->dscp()); // Verify previous value is not modified if dscp option is not set. cricket::VideoSendParameters parameters1 = send_parameters_; EXPECT_TRUE(channel_->SetSendParameters(parameters1)); EXPECT_EQ(rtc::DSCP_AF41, network_interface->dscp()); - parameters1.options.dscp.Set(false); + parameters1.options.dscp = rtc::Optional<bool>(false); EXPECT_TRUE(channel_->SetSendParameters(parameters1)); EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface->dscp()); channel_->SetInterface(NULL); } +// This test verifies that the RTCP reduced size mode is properly applied to +// send video streams. +TEST_F(WebRtcVideoChannel2Test, TestSetSendRtcpReducedSize) { + // Create stream, expecting that default mode is "compound". + FakeVideoSendStream* stream1 = AddSendStream(); + EXPECT_EQ(webrtc::RtcpMode::kCompound, stream1->GetConfig().rtp.rtcp_mode); + + // Now enable reduced size mode. + send_parameters_.rtcp.reduced_size = true; + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); + stream1 = fake_call_->GetVideoSendStreams()[0]; + EXPECT_EQ(webrtc::RtcpMode::kReducedSize, stream1->GetConfig().rtp.rtcp_mode); + + // Create a new stream and ensure it picks up the reduced size mode. + FakeVideoSendStream* stream2 = AddSendStream(); + EXPECT_EQ(webrtc::RtcpMode::kReducedSize, stream2->GetConfig().rtp.rtcp_mode); +} + +// This test verifies that the RTCP reduced size mode is properly applied to +// receive video streams. +TEST_F(WebRtcVideoChannel2Test, TestSetRecvRtcpReducedSize) { + // Create stream, expecting that default mode is "compound". + FakeVideoReceiveStream* stream1 = AddRecvStream(); + EXPECT_EQ(webrtc::RtcpMode::kCompound, stream1->GetConfig().rtp.rtcp_mode); + + // Now enable reduced size mode. + recv_parameters_.rtcp.reduced_size = true; + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + stream1 = fake_call_->GetVideoReceiveStreams()[0]; + EXPECT_EQ(webrtc::RtcpMode::kReducedSize, stream1->GetConfig().rtp.rtcp_mode); + + // Create a new stream and ensure it picks up the reduced size mode. + FakeVideoReceiveStream* stream2 = AddRecvStream(); + EXPECT_EQ(webrtc::RtcpMode::kReducedSize, stream2->GetConfig().rtp.rtcp_mode); +} + TEST_F(WebRtcVideoChannel2Test, OnReadyToSendSignalsNetworkState) { EXPECT_EQ(webrtc::kNetworkUp, fake_call_->GetNetworkState()); @@ -2410,6 +2448,18 @@ EXPECT_EQ(kVp8Codec.name, info.senders[0].codec_name); } +TEST_F(WebRtcVideoChannel2Test, GetStatsReportsEncoderImplementationName) { + FakeVideoSendStream* stream = AddSendStream(); + webrtc::VideoSendStream::Stats stats; + stats.encoder_implementation_name = "encoder_implementation_name"; + stream->SetStats(stats); + + cricket::VideoMediaInfo info; + ASSERT_TRUE(channel_->GetStats(&info)); + EXPECT_EQ(stats.encoder_implementation_name, + info.senders[0].encoder_implementation_name); +} + TEST_F(WebRtcVideoChannel2Test, GetStatsReportsCpuOveruseMetrics) { FakeVideoSendStream* stream = AddSendStream(); webrtc::VideoSendStream::Stats stats; @@ -2460,7 +2510,7 @@ EXPECT_TRUE(channel_->SetSend(true)); // Verify that the CpuOveruseObserver is registered and trigger downgrade. - parameters.options.cpu_overuse_detection.Set(true); + parameters.options.cpu_overuse_detection = rtc::Optional<bool>(true); EXPECT_TRUE(channel_->SetSendParameters(parameters)); // Trigger overuse. @@ -2518,6 +2568,87 @@ EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL)); } +TEST_F(WebRtcVideoChannel2Test, GetStatsTracksAdaptationAndBandwidthStats) { + AddSendStream(cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))); + + // Capture format VGA. + cricket::FakeVideoCapturer video_capturer_vga; + const std::vector<cricket::VideoFormat>* formats = + video_capturer_vga.GetSupportedFormats(); + cricket::VideoFormat capture_format_vga = (*formats)[1]; + EXPECT_EQ(cricket::CS_RUNNING, video_capturer_vga.Start(capture_format_vga)); + EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer_vga)); + EXPECT_TRUE(video_capturer_vga.CaptureFrame()); + + cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0); + cricket::VideoSendParameters parameters; + parameters.codecs.push_back(send_codec); + EXPECT_TRUE(channel_->SetSendParameters(parameters)); + EXPECT_TRUE(channel_->SetSend(true)); + + // Verify that the CpuOveruseObserver is registered and trigger downgrade. + parameters.options.cpu_overuse_detection = rtc::Optional<bool>(true); + EXPECT_TRUE(channel_->SetSendParameters(parameters)); + + // Trigger overuse -> adapt CPU. + ASSERT_EQ(1u, fake_call_->GetVideoSendStreams().size()); + webrtc::LoadObserver* overuse_callback = + fake_call_->GetVideoSendStreams().front()->GetConfig().overuse_callback; + ASSERT_TRUE(overuse_callback != NULL); + overuse_callback->OnLoadUpdate(webrtc::LoadObserver::kOveruse); + EXPECT_TRUE(video_capturer_vga.CaptureFrame()); + cricket::VideoMediaInfo info; + EXPECT_TRUE(channel_->GetStats(&info)); + ASSERT_EQ(1U, info.senders.size()); + EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU, + info.senders[0].adapt_reason); + + // Set bandwidth limitation stats for the stream -> adapt CPU + BW. + webrtc::VideoSendStream::Stats stats; + stats.bw_limited_resolution = true; + fake_call_->GetVideoSendStreams().front()->SetStats(stats); + info.Clear(); + EXPECT_TRUE(channel_->GetStats(&info)); + ASSERT_EQ(1U, info.senders.size()); + EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU + + CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH, + info.senders[0].adapt_reason); + + // Trigger upgrade -> adapt BW. + overuse_callback->OnLoadUpdate(webrtc::LoadObserver::kUnderuse); + EXPECT_TRUE(video_capturer_vga.CaptureFrame()); + info.Clear(); + EXPECT_TRUE(channel_->GetStats(&info)); + ASSERT_EQ(1U, info.senders.size()); + EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH, + info.senders[0].adapt_reason); + + // Reset bandwidth limitation state -> adapt NONE. + stats.bw_limited_resolution = false; + fake_call_->GetVideoSendStreams().front()->SetStats(stats); + info.Clear(); + EXPECT_TRUE(channel_->GetStats(&info)); + ASSERT_EQ(1U, info.senders.size()); + EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_NONE, + info.senders[0].adapt_reason); + + EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL)); +} + +TEST_F(WebRtcVideoChannel2Test, + GetStatsTranslatesBandwidthLimitedResolutionCorrectly) { + FakeVideoSendStream* stream = AddSendStream(); + webrtc::VideoSendStream::Stats stats; + stats.bw_limited_resolution = true; + stream->SetStats(stats); + + cricket::VideoMediaInfo info; + EXPECT_TRUE(channel_->GetStats(&info)); + ASSERT_EQ(1U, info.senders.size()); + EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH, + info.senders[0].adapt_reason); +} + TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesSendRtcpPacketTypesCorrectly) { FakeVideoSendStream* stream = AddSendStream(); @@ -2561,6 +2692,7 @@ TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesDecodeStatsCorrectly) { FakeVideoReceiveStream* stream = AddRecvStream(); webrtc::VideoReceiveStream::Stats stats; + stats.decoder_implementation_name = "decoder_implementation_name"; stats.decode_ms = 2; stats.max_decode_ms = 3; stats.current_delay_ms = 4; @@ -2572,6 +2704,8 @@ cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); + EXPECT_EQ(stats.decoder_implementation_name, + info.receivers[0].decoder_implementation_name); EXPECT_EQ(stats.decode_ms, info.receivers[0].decode_ms); EXPECT_EQ(stats.max_decode_ms, info.receivers[0].max_decode_ms); EXPECT_EQ(stats.current_delay_ms, info.receivers[0].current_delay_ms);
diff --git a/talk/media/webrtc/webrtcvideoframe.cc b/talk/media/webrtc/webrtcvideoframe.cc index 7da7e3b..fcc991c 100644 --- a/talk/media/webrtc/webrtcvideoframe.cc +++ b/talk/media/webrtc/webrtcvideoframe.cc
@@ -56,17 +56,6 @@ rotation_(rotation) { } -WebRtcVideoFrame::WebRtcVideoFrame( - const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, - int64_t elapsed_time_ns, - int64_t time_stamp_ns) - : video_frame_buffer_(buffer), - pixel_width_(1), - pixel_height_(1), - time_stamp_ns_(time_stamp_ns), - rotation_(webrtc::kVideoRotation_0) { -} - WebRtcVideoFrame::~WebRtcVideoFrame() {} bool WebRtcVideoFrame::Init(uint32_t format, @@ -90,13 +79,7 @@ return Reset(frame->fourcc, frame->width, frame->height, dw, dh, static_cast<uint8_t*>(frame->data), frame->data_size, frame->pixel_width, frame->pixel_height, frame->time_stamp, - frame->GetRotation(), apply_rotation); -} - -bool WebRtcVideoFrame::InitToBlack(int w, int h, size_t pixel_width, - size_t pixel_height, int64_t, - int64_t time_stamp_ns) { - return InitToBlack(w, h, pixel_width, pixel_height, time_stamp_ns); + frame->rotation, apply_rotation); } bool WebRtcVideoFrame::InitToBlack(int w, int h, size_t pixel_width,
diff --git a/talk/media/webrtc/webrtcvideoframe.h b/talk/media/webrtc/webrtcvideoframe.h index 0928c59..827cf28 100644 --- a/talk/media/webrtc/webrtcvideoframe.h +++ b/talk/media/webrtc/webrtcvideoframe.h
@@ -33,7 +33,7 @@ #include "webrtc/base/refcount.h" #include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/common_types.h" -#include "webrtc/common_video/interface/video_frame_buffer.h" +#include "webrtc/common_video/include/video_frame_buffer.h" namespace cricket { @@ -46,11 +46,6 @@ int64_t time_stamp_ns, webrtc::VideoRotation rotation); - // TODO(guoweis): Remove this when chrome code base is updated. - WebRtcVideoFrame(const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, - int64_t elapsed_time_ns, - int64_t time_stamp_ns); - ~WebRtcVideoFrame(); // Creates a frame from a raw sample with FourCC "format" and size "w" x "h". @@ -74,10 +69,6 @@ void InitToEmptyBuffer(int w, int h, size_t pixel_width, size_t pixel_height, int64_t time_stamp_ns); - // TODO(magjed): Remove once Chromium is updated. - bool InitToBlack(int w, int h, size_t pixel_width, size_t pixel_height, - int64_t elapsed_time_ns, int64_t time_stamp_ns); - bool InitToBlack(int w, int h, size_t pixel_width, size_t pixel_height, int64_t time_stamp_ns) override;
diff --git a/talk/media/webrtc/webrtcvoe.h b/talk/media/webrtc/webrtcvoe.h index db6a64a..aa705a0 100644 --- a/talk/media/webrtc/webrtcvoe.h +++ b/talk/media/webrtc/webrtcvoe.h
@@ -36,7 +36,6 @@ #include "webrtc/voice_engine/include/voe_audio_processing.h" #include "webrtc/voice_engine/include/voe_base.h" #include "webrtc/voice_engine/include/voe_codec.h" -#include "webrtc/voice_engine/include/voe_dtmf.h" #include "webrtc/voice_engine/include/voe_errors.h" #include "webrtc/voice_engine/include/voe_hardware.h" #include "webrtc/voice_engine/include/voe_network.h" @@ -91,14 +90,13 @@ public: VoEWrapper() : engine_(webrtc::VoiceEngine::Create()), processing_(engine_), - base_(engine_), codec_(engine_), dtmf_(engine_), + base_(engine_), codec_(engine_), hw_(engine_), network_(engine_), rtp_(engine_), volume_(engine_) { } VoEWrapper(webrtc::VoEAudioProcessing* processing, webrtc::VoEBase* base, webrtc::VoECodec* codec, - webrtc::VoEDtmf* dtmf, webrtc::VoEHardware* hw, webrtc::VoENetwork* network, webrtc::VoERTP_RTCP* rtp, @@ -107,7 +105,6 @@ processing_(processing), base_(base), codec_(codec), - dtmf_(dtmf), hw_(hw), network_(network), rtp_(rtp), @@ -118,7 +115,6 @@ webrtc::VoEAudioProcessing* processing() const { return processing_.get(); } webrtc::VoEBase* base() const { return base_.get(); } webrtc::VoECodec* codec() const { return codec_.get(); } - webrtc::VoEDtmf* dtmf() const { return dtmf_.get(); } webrtc::VoEHardware* hw() const { return hw_.get(); } webrtc::VoENetwork* network() const { return network_.get(); } webrtc::VoERTP_RTCP* rtp() const { return rtp_.get(); } @@ -130,29 +126,11 @@ scoped_voe_ptr<webrtc::VoEAudioProcessing> processing_; scoped_voe_ptr<webrtc::VoEBase> base_; scoped_voe_ptr<webrtc::VoECodec> codec_; - scoped_voe_ptr<webrtc::VoEDtmf> dtmf_; scoped_voe_ptr<webrtc::VoEHardware> hw_; scoped_voe_ptr<webrtc::VoENetwork> network_; scoped_voe_ptr<webrtc::VoERTP_RTCP> rtp_; scoped_voe_ptr<webrtc::VoEVolumeControl> volume_; }; - -// Adds indirection to static WebRtc functions, allowing them to be mocked. -class VoETraceWrapper { - public: - virtual ~VoETraceWrapper() {} - - virtual int SetTraceFilter(const unsigned int filter) { - return webrtc::VoiceEngine::SetTraceFilter(filter); - } - virtual int SetTraceFile(const char* fileNameUTF8) { - return webrtc::VoiceEngine::SetTraceFile(fileNameUTF8); - } - virtual int SetTraceCallback(webrtc::TraceCallback* callback) { - return webrtc::VoiceEngine::SetTraceCallback(callback); - } -}; - } // namespace cricket #endif // TALK_MEDIA_WEBRTCVOE_H_
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index 27ca1de..9192b72 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -42,7 +42,10 @@ #include "talk/media/base/audiorenderer.h" #include "talk/media/base/constants.h" #include "talk/media/base/streamparams.h" +#include "talk/media/webrtc/webrtcmediaengine.h" #include "talk/media/webrtc/webrtcvoe.h" +#include "webrtc/audio/audio_sink.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/base64.h" #include "webrtc/base/byteorder.h" #include "webrtc/base/common.h" @@ -52,53 +55,26 @@ #include "webrtc/base/stringutils.h" #include "webrtc/call/rtc_event_log.h" #include "webrtc/common.h" +#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" #include "webrtc/system_wrappers/include/field_trial.h" +#include "webrtc/system_wrappers/include/trace.h" namespace cricket { namespace { -const int kMaxNumPacketSize = 6; -struct CodecPref { - const char* name; - int clockrate; - int channels; - int payload_type; - bool is_multi_rate; - int packet_sizes_ms[kMaxNumPacketSize]; -}; -// Note: keep the supported packet sizes in ascending order. -const CodecPref kCodecPrefs[] = { - { kOpusCodecName, 48000, 2, 111, true, { 10, 20, 40, 60 } }, - { kIsacCodecName, 16000, 1, 103, true, { 30, 60 } }, - { kIsacCodecName, 32000, 1, 104, true, { 30 } }, - // G722 should be advertised as 8000 Hz because of the RFC "bug". - { kG722CodecName, 8000, 1, 9, false, { 10, 20, 30, 40, 50, 60 } }, - { kIlbcCodecName, 8000, 1, 102, false, { 20, 30, 40, 60 } }, - { kPcmuCodecName, 8000, 1, 0, false, { 10, 20, 30, 40, 50, 60 } }, - { kPcmaCodecName, 8000, 1, 8, false, { 10, 20, 30, 40, 50, 60 } }, - { kCnCodecName, 32000, 1, 106, false, { } }, - { kCnCodecName, 16000, 1, 105, false, { } }, - { kCnCodecName, 8000, 1, 13, false, { } }, - { kRedCodecName, 8000, 1, 127, false, { } }, - { kDtmfCodecName, 8000, 1, 126, false, { } }, -}; +const int kDefaultTraceFilter = webrtc::kTraceNone | webrtc::kTraceTerseInfo | + webrtc::kTraceWarning | webrtc::kTraceError | + webrtc::kTraceCritical; +const int kElevatedTraceFilter = kDefaultTraceFilter | webrtc::kTraceStateInfo | + webrtc::kTraceInfo; -// For Linux/Mac, using the default device is done by specifying index 0 for -// VoE 4.0 and not -1 (which was the case for VoE 3.5). -// // On Windows Vista and newer, Microsoft introduced the concept of "Default // Communications Device". This means that there are two types of default // devices (old Wave Audio style default and Default Communications Device). // // On Windows systems which only support Wave Audio style default, uses either // -1 or 0 to select the default device. -// -// On Windows systems which support both "Default Communication Device" and -// old Wave Audio style default, use -1 for Default Communications Device and -// -2 for Wave Audio style default, which is what we want to use for clips. -// It's not clear yet whether the -2 index is handled properly on other OSes. - #ifdef WIN32 const int kDefaultAudioDeviceId = -1; #else @@ -150,6 +126,12 @@ const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; #endif +// Constants from voice_engine_defines.h. +const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1) +const int kMaxTelephoneEventCode = 255; +const int kMinTelephoneEventDuration = 100; +const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16 + bool ValidateStreamParams(const StreamParams& sp) { if (sp.ssrcs.empty()) { LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); @@ -177,32 +159,6 @@ return ss.str(); } -void LogMultiline(rtc::LoggingSeverity sev, char* text) { - const char* delim = "\r\n"; - for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) { - LOG_V(sev) << tok; - } -} - -// Severity is an integer because it comes is assumed to be from command line. -int SeverityToFilter(int severity) { - int filter = webrtc::kTraceNone; - switch (severity) { - case rtc::LS_VERBOSE: - filter |= webrtc::kTraceAll; - FALLTHROUGH(); - case rtc::LS_INFO: - filter |= (webrtc::kTraceStateInfo | webrtc::kTraceInfo); - FALLTHROUGH(); - case rtc::LS_WARNING: - filter |= (webrtc::kTraceTerseInfo | webrtc::kTraceWarning); - FALLTHROUGH(); - case rtc::LS_ERROR: - filter |= (webrtc::kTraceError | webrtc::kTraceCritical); - } - return filter; -} - bool IsCodec(const AudioCodec& codec, const char* ref_name) { return (_stricmp(codec.name.c_str(), ref_name) == 0); } @@ -211,19 +167,9 @@ return (_stricmp(codec.plname, ref_name) == 0); } -bool IsCodecMultiRate(const webrtc::CodecInst& codec) { - for (size_t i = 0; i < ARRAY_SIZE(kCodecPrefs); ++i) { - if (IsCodec(codec, kCodecPrefs[i].name) && - kCodecPrefs[i].clockrate == codec.plfreq) { - return kCodecPrefs[i].is_multi_rate; - } - } - return false; -} - bool FindCodec(const std::vector<AudioCodec>& codecs, - const AudioCodec& codec, - AudioCodec* found_codec) { + const AudioCodec& codec, + AudioCodec* found_codec) { for (const AudioCodec& c : codecs) { if (c.Matches(codec)) { if (found_codec != NULL) { @@ -253,38 +199,8 @@ kParamValueEmpty)); } -int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) { - int selected_packet_size_ms = codec_pref.packet_sizes_ms[0]; - for (int packet_size_ms : codec_pref.packet_sizes_ms) { - if (packet_size_ms && packet_size_ms <= ptime_ms) { - selected_packet_size_ms = packet_size_ms; - } - } - return selected_packet_size_ms; -} - -// If the AudioCodec param kCodecParamPTime is set, then we will set it to codec -// pacsize if it's valid, or we will pick the next smallest value we support. -// TODO(Brave): Query supported packet sizes from ACM when the API is ready. -bool SetPTimeAsPacketSize(webrtc::CodecInst* codec, int ptime_ms) { - for (const CodecPref& codec_pref : kCodecPrefs) { - if ((IsCodec(*codec, codec_pref.name) && - codec_pref.clockrate == codec->plfreq) || - IsCodec(*codec, kG722CodecName)) { - int packet_size_ms = SelectPacketSize(codec_pref, ptime_ms); - if (packet_size_ms) { - // Convert unit from milli-seconds to samples. - codec->pacsize = (codec->plfreq / 1000) * packet_size_ms; - return true; - } - } - } - return false; -} - // Return true if codec.params[feature] == "1", false otherwise. -bool IsCodecFeatureEnabled(const AudioCodec& codec, - const char* feature) { +bool IsCodecFeatureEnabled(const AudioCodec& codec, const char* feature) { int value; return codec.GetParam(feature, &value) && value == 1; } @@ -351,109 +267,29 @@ voe_codec->rate = GetOpusBitrate(codec, *max_playback_rate); } -// Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC -// which says that G722 should be advertised as 8 kHz although it is a 16 kHz -// codec. -void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { - if (IsCodec(*voe_codec, kG722CodecName)) { - // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine - // has changed, and this special case is no longer needed. - RTC_DCHECK(voe_codec->plfreq != new_plfreq); - voe_codec->plfreq = new_plfreq; - } +webrtc::AudioState::Config MakeAudioStateConfig(VoEWrapper* voe_wrapper) { + webrtc::AudioState::Config config; + config.voice_engine = voe_wrapper->engine(); + return config; } -// Gets the default set of options applied to the engine. Historically, these -// were supplied as a combination of flags from the channel manager (ec, agc, -// ns, and highpass) and the rest hardcoded in InitInternal. -AudioOptions GetDefaultEngineOptions() { - AudioOptions options; - options.echo_cancellation.Set(true); - options.auto_gain_control.Set(true); - options.noise_suppression.Set(true); - options.highpass_filter.Set(true); - options.stereo_swapping.Set(false); - options.audio_jitter_buffer_max_packets.Set(50); - options.audio_jitter_buffer_fast_accelerate.Set(false); - options.typing_detection.Set(true); - options.adjust_agc_delta.Set(0); - options.experimental_agc.Set(false); - options.extended_filter_aec.Set(false); - options.delay_agnostic_aec.Set(false); - options.experimental_ns.Set(false); - options.aec_dump.Set(false); - return options; -} - -std::string GetEnableString(bool enable) { - return enable ? "enable" : "disable"; -} -} // namespace { - -WebRtcVoiceEngine::WebRtcVoiceEngine() - : voe_wrapper_(new VoEWrapper()), - tracing_(new VoETraceWrapper()), - adm_(NULL), - log_filter_(SeverityToFilter(kDefaultLogSeverity)), - is_dumping_aec_(false) { - Construct(); -} - -WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper, - VoETraceWrapper* tracing) - : voe_wrapper_(voe_wrapper), - tracing_(tracing), - adm_(NULL), - log_filter_(SeverityToFilter(kDefaultLogSeverity)), - is_dumping_aec_(false) { - Construct(); -} - -void WebRtcVoiceEngine::Construct() { - SetTraceFilter(log_filter_); - initialized_ = false; - LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; - SetTraceOptions(""); - if (tracing_->SetTraceCallback(this) == -1) { - LOG_RTCERR0(SetTraceCallback); - } - if (voe_wrapper_->base()->RegisterVoiceEngineObserver(*this) == -1) { - LOG_RTCERR0(RegisterVoiceEngineObserver); - } - // Clear the default agc state. - memset(&default_agc_config_, 0, sizeof(default_agc_config_)); - - // Load our audio codec list. - ConstructCodecs(); - - // Load our RTP Header extensions. - rtp_header_extensions_.push_back( - RtpHeaderExtension(kRtpAudioLevelHeaderExtension, - kRtpAudioLevelHeaderExtensionDefaultId)); - rtp_header_extensions_.push_back( - RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, - kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); - if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") { - rtp_header_extensions_.push_back(RtpHeaderExtension( - kRtpTransportSequenceNumberHeaderExtension, - kRtpTransportSequenceNumberHeaderExtensionDefaultId)); - } - options_ = GetDefaultEngineOptions(); -} - -void WebRtcVoiceEngine::ConstructCodecs() { - LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; - int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - webrtc::CodecInst voe_codec; - if (GetVoeCodec(i, &voe_codec)) { +class WebRtcVoiceCodecs final { + public: + // TODO(solenberg): Do this filtering once off-line, add a simple AudioCodec + // list and add a test which verifies VoE supports the listed codecs. + static std::vector<AudioCodec> SupportedCodecs() { + LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; + std::vector<AudioCodec> result; + for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { + // Change the sample rate of G722 to 8000 to match SDP. + MaybeFixupG722(&voe_codec, 8000); // Skip uncompressed formats. if (IsCodec(voe_codec, kL16CodecName)) { continue; } const CodecPref* pref = NULL; - for (size_t j = 0; j < ARRAY_SIZE(kCodecPrefs); ++j) { + for (size_t j = 0; j < arraysize(kCodecPrefs); ++j) { if (IsCodec(voe_codec, kCodecPrefs[j].name) && kCodecPrefs[j].clockrate == voe_codec.plfreq && kCodecPrefs[j].channels == voe_codec.channels) { @@ -465,9 +301,10 @@ if (pref) { // Use the payload type that we've configured in our pref table; // use the offset in our pref table to determine the sort order. - AudioCodec codec(pref->payload_type, voe_codec.plname, voe_codec.plfreq, - voe_codec.rate, voe_codec.channels, - ARRAY_SIZE(kCodecPrefs) - (pref - kCodecPrefs)); + AudioCodec codec( + pref->payload_type, voe_codec.plname, voe_codec.plfreq, + voe_codec.rate, voe_codec.channels, + static_cast<int>(arraysize(kCodecPrefs)) - (pref - kCodecPrefs)); LOG(LS_INFO) << ToString(codec); if (IsCodec(codec, kIsacCodecName)) { // Indicate auto-bitrate in signaling. @@ -488,588 +325,21 @@ // TODO(hellner): Add ptime, sprop-stereo, and stereo // when they can be set to values other than the default. } - codecs_.push_back(codec); + result.push_back(codec); } else { LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec); } } - } - // Make sure they are in local preference order. - std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable); -} - -bool WebRtcVoiceEngine::GetVoeCodec(int index, webrtc::CodecInst* codec) { - if (voe_wrapper_->codec()->GetCodec(index, *codec) == -1) { - return false; - } - // Change the sample rate of G722 to 8000 to match SDP. - MaybeFixupG722(codec, 8000); - return true; -} - -WebRtcVoiceEngine::~WebRtcVoiceEngine() { - LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; - if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) { - LOG_RTCERR0(DeRegisterVoiceEngineObserver); - } - if (adm_) { - voe_wrapper_.reset(); - adm_->Release(); - adm_ = NULL; + // Make sure they are in local preference order. + std::sort(result.begin(), result.end(), &AudioCodec::Preferable); + return result; } - tracing_->SetTraceCallback(NULL); -} - -bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) { - RTC_DCHECK(worker_thread == rtc::Thread::Current()); - LOG(LS_INFO) << "WebRtcVoiceEngine::Init"; - bool res = InitInternal(); - if (res) { - LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!"; - } else { - LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed"; - Terminate(); - } - return res; -} - -bool WebRtcVoiceEngine::InitInternal() { - // Temporarily turn logging level up for the Init call - int old_filter = log_filter_; - int extended_filter = log_filter_ | SeverityToFilter(rtc::LS_INFO); - SetTraceFilter(extended_filter); - SetTraceOptions(""); - - // Init WebRtc VoiceEngine. - if (voe_wrapper_->base()->Init(adm_) == -1) { - LOG_RTCERR0_EX(Init, voe_wrapper_->error()); - SetTraceFilter(old_filter); - return false; - } - - SetTraceFilter(old_filter); - SetTraceOptions(log_options_); - - // Log the VoiceEngine version info - char buffer[1024] = ""; - voe_wrapper_->base()->GetVersion(buffer); - LOG(LS_INFO) << "WebRtc VoiceEngine Version:"; - LogMultiline(rtc::LS_INFO, buffer); - - // Save the default AGC configuration settings. This must happen before - // calling SetOptions or the default will be overwritten. - if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) { - LOG_RTCERR0(GetAgcConfig); - return false; - } - - // Set defaults for options, so that ApplyOptions applies them explicitly - // when we clear option (channel) overrides. External clients can still - // modify the defaults via SetOptions (on the media engine). - if (!SetOptions(GetDefaultEngineOptions())) { - return false; - } - - // Print our codec list again for the call diagnostic log - LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; - for (const AudioCodec& codec : codecs_) { - LOG(LS_INFO) << ToString(codec); - } - - // Disable the DTMF playout when a tone is sent. - // PlayDtmfTone will be used if local playout is needed. - if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) { - LOG_RTCERR1(SetDtmfFeedbackStatus, false); - } - - initialized_ = true; - return true; -} - -void WebRtcVoiceEngine::Terminate() { - LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; - initialized_ = false; - - StopAecDump(); - - voe_wrapper_->base()->Terminate(); -} - -VoiceMediaChannel* WebRtcVoiceEngine::CreateChannel(webrtc::Call* call, - const AudioOptions& options) { - return new WebRtcVoiceMediaChannel(this, options, call); -} - -bool WebRtcVoiceEngine::SetOptions(const AudioOptions& options) { - if (!ApplyOptions(options)) { - return false; - } - options_ = options; - return true; -} - -// AudioOptions defaults are set in InitInternal (for options with corresponding -// MediaEngineInterface flags) and in SetOptions(int) for flagless options. -bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { - LOG(LS_INFO) << "ApplyOptions: " << options_in.ToString(); - AudioOptions options = options_in; // The options are modified below. - // kEcConference is AEC with high suppression. - webrtc::EcModes ec_mode = webrtc::kEcConference; - webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone; - webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog; - webrtc::NsModes ns_mode = webrtc::kNsHighSuppression; - bool aecm_comfort_noise = false; - if (options.aecm_generate_comfort_noise.Get(&aecm_comfort_noise)) { - LOG(LS_VERBOSE) << "Comfort noise explicitly set to " - << aecm_comfort_noise << " (default is false)."; - } - -#if defined(IOS) - // On iOS, VPIO provides built-in EC and AGC. - options.echo_cancellation.Set(false); - options.auto_gain_control.Set(false); - LOG(LS_INFO) << "Always disable AEC and AGC on iOS. Use built-in instead."; -#elif defined(ANDROID) - ec_mode = webrtc::kEcAecm; -#endif - -#if defined(IOS) || defined(ANDROID) - // Set the AGC mode for iOS as well despite disabling it above, to avoid - // unsupported configuration errors from webrtc. - agc_mode = webrtc::kAgcFixedDigital; - options.typing_detection.Set(false); - options.experimental_agc.Set(false); - options.extended_filter_aec.Set(false); - options.experimental_ns.Set(false); -#endif - - // Delay Agnostic AEC automatically turns on EC if not set except on iOS - // where the feature is not supported. - bool use_delay_agnostic_aec = false; -#if !defined(IOS) - if (options.delay_agnostic_aec.Get(&use_delay_agnostic_aec)) { - if (use_delay_agnostic_aec) { - options.echo_cancellation.Set(true); - options.extended_filter_aec.Set(true); - ec_mode = webrtc::kEcConference; - } - } -#endif - - webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing(); - - bool echo_cancellation = false; - if (options.echo_cancellation.Get(&echo_cancellation)) { - // Check if platform supports built-in EC. Currently only supported on - // Android and in combination with Java based audio layer. - // TODO(henrika): investigate possibility to support built-in EC also - // in combination with Open SL ES audio. - const bool built_in_aec = voe_wrapper_->hw()->BuiltInAECIsAvailable(); - if (built_in_aec) { - // Built-in EC exists on this device and use_delay_agnostic_aec is not - // overriding it. Enable/Disable it according to the echo_cancellation - // audio option. - const bool enable_built_in_aec = - echo_cancellation && !use_delay_agnostic_aec; - if (voe_wrapper_->hw()->EnableBuiltInAEC(enable_built_in_aec) == 0 && - enable_built_in_aec) { - // Disable internal software EC if built-in EC is enabled, - // i.e., replace the software EC with the built-in EC. - options.echo_cancellation.Set(false); - echo_cancellation = false; - LOG(LS_INFO) << "Disabling EC since built-in EC will be used instead"; - } - } - if (voep->SetEcStatus(echo_cancellation, ec_mode) == -1) { - LOG_RTCERR2(SetEcStatus, echo_cancellation, ec_mode); - return false; - } else { - LOG(LS_INFO) << "Echo control set to " << echo_cancellation - << " with mode " << ec_mode; - } -#if !defined(ANDROID) - // TODO(ajm): Remove the error return on Android from webrtc. - if (voep->SetEcMetricsStatus(echo_cancellation) == -1) { - LOG_RTCERR1(SetEcMetricsStatus, echo_cancellation); - return false; - } -#endif - if (ec_mode == webrtc::kEcAecm) { - if (voep->SetAecmMode(aecm_mode, aecm_comfort_noise) != 0) { - LOG_RTCERR2(SetAecmMode, aecm_mode, aecm_comfort_noise); - return false; - } - } - } - - bool auto_gain_control = false; - if (options.auto_gain_control.Get(&auto_gain_control)) { - const bool built_in_agc = voe_wrapper_->hw()->BuiltInAGCIsAvailable(); - if (built_in_agc) { - if (voe_wrapper_->hw()->EnableBuiltInAGC(auto_gain_control) == 0 && - auto_gain_control) { - // Disable internal software AGC if built-in AGC is enabled, - // i.e., replace the software AGC with the built-in AGC. - options.auto_gain_control.Set(false); - auto_gain_control = false; - LOG(LS_INFO) << "Disabling AGC since built-in AGC will be used instead"; - } - } - if (voep->SetAgcStatus(auto_gain_control, agc_mode) == -1) { - LOG_RTCERR2(SetAgcStatus, auto_gain_control, agc_mode); - return false; - } else { - LOG(LS_INFO) << "Auto gain set to " << auto_gain_control << " with mode " - << agc_mode; - } - } - - if (options.tx_agc_target_dbov.IsSet() || - options.tx_agc_digital_compression_gain.IsSet() || - options.tx_agc_limiter.IsSet()) { - // Override default_agc_config_. Generally, an unset option means "leave - // the VoE bits alone" in this function, so we want whatever is set to be - // stored as the new "default". If we didn't, then setting e.g. - // tx_agc_target_dbov would reset digital compression gain and limiter - // settings. - // Also, if we don't update default_agc_config_, then adjust_agc_delta - // would be an offset from the original values, and not whatever was set - // explicitly. - default_agc_config_.targetLeveldBOv = - options.tx_agc_target_dbov.GetWithDefaultIfUnset( - default_agc_config_.targetLeveldBOv); - default_agc_config_.digitalCompressionGaindB = - options.tx_agc_digital_compression_gain.GetWithDefaultIfUnset( - default_agc_config_.digitalCompressionGaindB); - default_agc_config_.limiterEnable = - options.tx_agc_limiter.GetWithDefaultIfUnset( - default_agc_config_.limiterEnable); - if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) { - LOG_RTCERR3(SetAgcConfig, - default_agc_config_.targetLeveldBOv, - default_agc_config_.digitalCompressionGaindB, - default_agc_config_.limiterEnable); - return false; - } - } - - bool noise_suppression = false; - if (options.noise_suppression.Get(&noise_suppression)) { - const bool built_in_ns = voe_wrapper_->hw()->BuiltInNSIsAvailable(); - if (built_in_ns) { - if (voe_wrapper_->hw()->EnableBuiltInNS(noise_suppression) == 0 && - noise_suppression) { - // Disable internal software NS if built-in NS is enabled, - // i.e., replace the software NS with the built-in NS. - options.noise_suppression.Set(false); - noise_suppression = false; - LOG(LS_INFO) << "Disabling NS since built-in NS will be used instead"; - } - } - if (voep->SetNsStatus(noise_suppression, ns_mode) == -1) { - LOG_RTCERR2(SetNsStatus, noise_suppression, ns_mode); - return false; - } else { - LOG(LS_INFO) << "Noise suppression set to " << noise_suppression - << " with mode " << ns_mode; - } - } - - bool highpass_filter; - if (options.highpass_filter.Get(&highpass_filter)) { - LOG(LS_INFO) << "High pass filter enabled? " << highpass_filter; - if (voep->EnableHighPassFilter(highpass_filter) == -1) { - LOG_RTCERR1(SetHighpassFilterStatus, highpass_filter); - return false; - } - } - - bool stereo_swapping; - if (options.stereo_swapping.Get(&stereo_swapping)) { - LOG(LS_INFO) << "Stereo swapping enabled? " << stereo_swapping; - voep->EnableStereoChannelSwapping(stereo_swapping); - if (voep->IsStereoChannelSwappingEnabled() != stereo_swapping) { - LOG_RTCERR1(EnableStereoChannelSwapping, stereo_swapping); - return false; - } - } - - int audio_jitter_buffer_max_packets; - if (options.audio_jitter_buffer_max_packets.Get( - &audio_jitter_buffer_max_packets)) { - LOG(LS_INFO) << "NetEq capacity is " << audio_jitter_buffer_max_packets; - voe_config_.Set<webrtc::NetEqCapacityConfig>( - new webrtc::NetEqCapacityConfig(audio_jitter_buffer_max_packets)); - } - - bool audio_jitter_buffer_fast_accelerate; - if (options.audio_jitter_buffer_fast_accelerate.Get( - &audio_jitter_buffer_fast_accelerate)) { - LOG(LS_INFO) << "NetEq fast mode? " << audio_jitter_buffer_fast_accelerate; - voe_config_.Set<webrtc::NetEqFastAccelerate>( - new webrtc::NetEqFastAccelerate(audio_jitter_buffer_fast_accelerate)); - } - - bool typing_detection; - if (options.typing_detection.Get(&typing_detection)) { - LOG(LS_INFO) << "Typing detection is enabled? " << typing_detection; - if (voep->SetTypingDetectionStatus(typing_detection) == -1) { - // In case of error, log the info and continue - LOG_RTCERR1(SetTypingDetectionStatus, typing_detection); - } - } - - int adjust_agc_delta; - if (options.adjust_agc_delta.Get(&adjust_agc_delta)) { - LOG(LS_INFO) << "Adjust agc delta is " << adjust_agc_delta; - if (!AdjustAgcLevel(adjust_agc_delta)) { - return false; - } - } - - bool aec_dump; - if (options.aec_dump.Get(&aec_dump)) { - LOG(LS_INFO) << "Aec dump is enabled? " << aec_dump; - if (aec_dump) - StartAecDump(kAecDumpByAudioOptionFilename); - else - StopAecDump(); - } - - webrtc::Config config; - - delay_agnostic_aec_.SetFrom(options.delay_agnostic_aec); - bool delay_agnostic_aec; - if (delay_agnostic_aec_.Get(&delay_agnostic_aec)) { - LOG(LS_INFO) << "Delay agnostic aec is enabled? " << delay_agnostic_aec; - config.Set<webrtc::DelayAgnostic>( - new webrtc::DelayAgnostic(delay_agnostic_aec)); - } - - extended_filter_aec_.SetFrom(options.extended_filter_aec); - bool extended_filter; - if (extended_filter_aec_.Get(&extended_filter)) { - LOG(LS_INFO) << "Extended filter aec is enabled? " << extended_filter; - config.Set<webrtc::ExtendedFilter>( - new webrtc::ExtendedFilter(extended_filter)); - } - - experimental_ns_.SetFrom(options.experimental_ns); - bool experimental_ns; - if (experimental_ns_.Get(&experimental_ns)) { - LOG(LS_INFO) << "Experimental ns is enabled? " << experimental_ns; - config.Set<webrtc::ExperimentalNs>( - new webrtc::ExperimentalNs(experimental_ns)); - } - - // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine - // returns NULL on audio_processing(). - webrtc::AudioProcessing* audioproc = voe_wrapper_->base()->audio_processing(); - if (audioproc) { - audioproc->SetExtraOptions(config); - } - - uint32_t recording_sample_rate; - if (options.recording_sample_rate.Get(&recording_sample_rate)) { - LOG(LS_INFO) << "Recording sample rate is " << recording_sample_rate; - if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) { - LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate); - } - } - - uint32_t playout_sample_rate; - if (options.playout_sample_rate.Get(&playout_sample_rate)) { - LOG(LS_INFO) << "Playout sample rate is " << playout_sample_rate; - if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) { - LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate); - } - } - - return true; -} - -// TODO(juberti): Refactor this so that the core logic can be used to set the -// soundclip device. At that time, reinstate the soundclip pause/resume code. -bool WebRtcVoiceEngine::SetDevices(const Device* in_device, - const Device* out_device) { -#if !defined(IOS) - int in_id = in_device ? rtc::FromString<int>(in_device->id) : - kDefaultAudioDeviceId; - int out_id = out_device ? rtc::FromString<int>(out_device->id) : - kDefaultAudioDeviceId; - // The device manager uses -1 as the default device, which was the case for - // VoE 3.5. VoE 4.0, however, uses 0 as the default in Linux and Mac. -#ifndef WIN32 - if (-1 == in_id) { - in_id = kDefaultAudioDeviceId; - } - if (-1 == out_id) { - out_id = kDefaultAudioDeviceId; - } -#endif - - std::string in_name = (in_id != kDefaultAudioDeviceId) ? - in_device->name : "Default device"; - std::string out_name = (out_id != kDefaultAudioDeviceId) ? - out_device->name : "Default device"; - LOG(LS_INFO) << "Setting microphone to (id=" << in_id << ", name=" << in_name - << ") and speaker to (id=" << out_id << ", name=" << out_name - << ")"; - - // Must also pause all audio playback and capture. - bool ret = true; - for (WebRtcVoiceMediaChannel* channel : channels_) { - if (!channel->PausePlayout()) { - LOG(LS_WARNING) << "Failed to pause playout"; - ret = false; - } - if (!channel->PauseSend()) { - LOG(LS_WARNING) << "Failed to pause send"; - ret = false; - } - } - - // Find the recording device id in VoiceEngine and set recording device. - if (!FindWebRtcAudioDeviceId(true, in_name, in_id, &in_id)) { - ret = false; - } - if (ret) { - if (voe_wrapper_->hw()->SetRecordingDevice(in_id) == -1) { - LOG_RTCERR2(SetRecordingDevice, in_name, in_id); - ret = false; - } - webrtc::AudioProcessing* ap = voe()->base()->audio_processing(); - if (ap) - ap->Initialize(); - } - - // Find the playout device id in VoiceEngine and set playout device. - if (!FindWebRtcAudioDeviceId(false, out_name, out_id, &out_id)) { - LOG(LS_WARNING) << "Failed to find VoiceEngine device id for " << out_name; - ret = false; - } - if (ret) { - if (voe_wrapper_->hw()->SetPlayoutDevice(out_id) == -1) { - LOG_RTCERR2(SetPlayoutDevice, out_name, out_id); - ret = false; - } - } - - // Resume all audio playback and capture. - for (WebRtcVoiceMediaChannel* channel : channels_) { - if (!channel->ResumePlayout()) { - LOG(LS_WARNING) << "Failed to resume playout"; - ret = false; - } - if (!channel->ResumeSend()) { - LOG(LS_WARNING) << "Failed to resume send"; - ret = false; - } - } - - if (ret) { - LOG(LS_INFO) << "Set microphone to (id=" << in_id <<" name=" << in_name - << ") and speaker to (id="<< out_id << " name=" << out_name - << ")"; - } - - return ret; -#else - return true; -#endif // !IOS -} - -bool WebRtcVoiceEngine::FindWebRtcAudioDeviceId( - bool is_input, const std::string& dev_name, int dev_id, int* rtc_id) { - // In Linux, VoiceEngine uses the same device dev_id as the device manager. -#if defined(LINUX) || defined(ANDROID) - *rtc_id = dev_id; - return true; -#else - // In Windows and Mac, we need to find the VoiceEngine device id by name - // unless the input dev_id is the default device id. - if (kDefaultAudioDeviceId == dev_id) { - *rtc_id = dev_id; - return true; - } - - // Get the number of VoiceEngine audio devices. - int count = 0; - if (is_input) { - if (-1 == voe_wrapper_->hw()->GetNumOfRecordingDevices(count)) { - LOG_RTCERR0(GetNumOfRecordingDevices); - return false; - } - } else { - if (-1 == voe_wrapper_->hw()->GetNumOfPlayoutDevices(count)) { - LOG_RTCERR0(GetNumOfPlayoutDevices); - return false; - } - } - - for (int i = 0; i < count; ++i) { - char name[128]; - char guid[128]; - if (is_input) { - voe_wrapper_->hw()->GetRecordingDeviceName(i, name, guid); - LOG(LS_VERBOSE) << "VoiceEngine microphone " << i << ": " << name; - } else { - voe_wrapper_->hw()->GetPlayoutDeviceName(i, name, guid); - LOG(LS_VERBOSE) << "VoiceEngine speaker " << i << ": " << name; - } - - std::string webrtc_name(name); - if (dev_name.compare(0, webrtc_name.size(), webrtc_name) == 0) { - *rtc_id = i; - return true; - } - } - LOG(LS_WARNING) << "VoiceEngine cannot find device: " << dev_name; - return false; -#endif -} - -bool WebRtcVoiceEngine::GetOutputVolume(int* level) { - unsigned int ulevel; - if (voe_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) { - LOG_RTCERR1(GetSpeakerVolume, level); - return false; - } - *level = ulevel; - return true; -} - -bool WebRtcVoiceEngine::SetOutputVolume(int level) { - RTC_DCHECK(level >= 0 && level <= 255); - if (voe_wrapper_->volume()->SetSpeakerVolume(level) == -1) { - LOG_RTCERR1(SetSpeakerVolume, level); - return false; - } - return true; -} - -int WebRtcVoiceEngine::GetInputLevel() { - unsigned int ulevel; - return (voe_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ? - static_cast<int>(ulevel) : -1; -} - -const std::vector<AudioCodec>& WebRtcVoiceEngine::codecs() { - return codecs_; -} - -bool WebRtcVoiceEngine::FindCodec(const AudioCodec& in) { - return FindWebRtcCodec(in, NULL); -} - -// Get the VoiceEngine codec that matches |in|, with the supplied settings. -bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, - webrtc::CodecInst* out) { - int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - webrtc::CodecInst voe_codec; - if (GetVoeCodec(i, &voe_codec)) { + static bool ToCodecInst(const AudioCodec& in, + webrtc::CodecInst* out) { + for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { + // Change the sample rate of G722 to 8000 to match SDP. + MaybeFixupG722(&voe_codec, 8000); AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq, voe_codec.rate, voe_codec.channels, 0); bool multi_rate = IsCodecMultiRate(voe_codec); @@ -1102,84 +372,575 @@ return true; } } + return false; } - return false; -} -const std::vector<RtpHeaderExtension>& -WebRtcVoiceEngine::rtp_header_extensions() const { - return rtp_header_extensions_; -} -void WebRtcVoiceEngine::SetLogging(int min_sev, const char* filter) { - // if min_sev == -1, we keep the current log level. - if (min_sev >= 0) { - SetTraceFilter(SeverityToFilter(min_sev)); + static bool IsCodecMultiRate(const webrtc::CodecInst& codec) { + for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) { + if (IsCodec(codec, kCodecPrefs[i].name) && + kCodecPrefs[i].clockrate == codec.plfreq) { + return kCodecPrefs[i].is_multi_rate; + } + } + return false; } - log_options_ = filter; - SetTraceOptions(initialized_ ? log_options_ : ""); + + // If the AudioCodec param kCodecParamPTime is set, then we will set it to + // codec pacsize if it's valid, or we will pick the next smallest value we + // support. + // TODO(Brave): Query supported packet sizes from ACM when the API is ready. + static bool SetPTimeAsPacketSize(webrtc::CodecInst* codec, int ptime_ms) { + for (const CodecPref& codec_pref : kCodecPrefs) { + if ((IsCodec(*codec, codec_pref.name) && + codec_pref.clockrate == codec->plfreq) || + IsCodec(*codec, kG722CodecName)) { + int packet_size_ms = SelectPacketSize(codec_pref, ptime_ms); + if (packet_size_ms) { + // Convert unit from milli-seconds to samples. + codec->pacsize = (codec->plfreq / 1000) * packet_size_ms; + return true; + } + } + } + return false; + } + + private: + static const int kMaxNumPacketSize = 6; + struct CodecPref { + const char* name; + int clockrate; + size_t channels; + int payload_type; + bool is_multi_rate; + int packet_sizes_ms[kMaxNumPacketSize]; + }; + // Note: keep the supported packet sizes in ascending order. + static const CodecPref kCodecPrefs[12]; + + static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) { + int selected_packet_size_ms = codec_pref.packet_sizes_ms[0]; + for (int packet_size_ms : codec_pref.packet_sizes_ms) { + if (packet_size_ms && packet_size_ms <= ptime_ms) { + selected_packet_size_ms = packet_size_ms; + } + } + return selected_packet_size_ms; + } + + // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC + // which says that G722 should be advertised as 8 kHz although it is a 16 kHz + // codec. + static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { + if (IsCodec(*voe_codec, kG722CodecName)) { + // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine + // has changed, and this special case is no longer needed. + RTC_DCHECK(voe_codec->plfreq != new_plfreq); + voe_codec->plfreq = new_plfreq; + } + } +}; + +const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[12] = { + { kOpusCodecName, 48000, 2, 111, true, { 10, 20, 40, 60 } }, + { kIsacCodecName, 16000, 1, 103, true, { 30, 60 } }, + { kIsacCodecName, 32000, 1, 104, true, { 30 } }, + // G722 should be advertised as 8000 Hz because of the RFC "bug". + { kG722CodecName, 8000, 1, 9, false, { 10, 20, 30, 40, 50, 60 } }, + { kIlbcCodecName, 8000, 1, 102, false, { 20, 30, 40, 60 } }, + { kPcmuCodecName, 8000, 1, 0, false, { 10, 20, 30, 40, 50, 60 } }, + { kPcmaCodecName, 8000, 1, 8, false, { 10, 20, 30, 40, 50, 60 } }, + { kCnCodecName, 32000, 1, 106, false, { } }, + { kCnCodecName, 16000, 1, 105, false, { } }, + { kCnCodecName, 8000, 1, 13, false, { } }, + { kRedCodecName, 8000, 1, 127, false, { } }, + { kDtmfCodecName, 8000, 1, 126, false, { } }, +}; +} // namespace { + +bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in, + webrtc::CodecInst* out) { + return WebRtcVoiceCodecs::ToCodecInst(in, out); } -int WebRtcVoiceEngine::GetLastEngineError() { - return voe_wrapper_->error(); +WebRtcVoiceEngine::WebRtcVoiceEngine() + : voe_wrapper_(new VoEWrapper()), + audio_state_(webrtc::AudioState::Create(MakeAudioStateConfig(voe()))) { + Construct(); } -void WebRtcVoiceEngine::SetTraceFilter(int filter) { - log_filter_ = filter; - tracing_->SetTraceFilter(filter); +WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper) + : voe_wrapper_(voe_wrapper) { + Construct(); } -// We suppport three different logging settings for VoiceEngine: -// 1. Observer callback that goes into talk diagnostic logfile. -// Use --logfile and --loglevel -// -// 2. Encrypted VoiceEngine log for debugging VoiceEngine. -// Use --voice_loglevel --voice_logfilter "tracefile file_name" -// -// 3. EC log and dump for debugging QualityEngine. -// Use --voice_loglevel --voice_logfilter "recordEC file_name" -// -// For more details see: "https://sites.google.com/a/google.com/wavelet/Home/ -// Magic-Flute--RTC-Engine-/Magic-Flute-Command-Line-Parameters" -void WebRtcVoiceEngine::SetTraceOptions(const std::string& options) { - // Set encrypted trace file. - std::vector<std::string> opts; - rtc::tokenize(options, ' ', '"', '"', &opts); - std::vector<std::string>::iterator tracefile = - std::find(opts.begin(), opts.end(), "tracefile"); - if (tracefile != opts.end() && ++tracefile != opts.end()) { - // Write encrypted debug output (at same loglevel) to file - // EncryptedTraceFile no longer supported. - if (tracing_->SetTraceFile(tracefile->c_str()) == -1) { - LOG_RTCERR1(SetTraceFile, *tracefile); +void WebRtcVoiceEngine::Construct() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; + + signal_thread_checker_.DetachFromThread(); + std::memset(&default_agc_config_, 0, sizeof(default_agc_config_)); + voe_config_.Set<webrtc::VoicePacing>(new webrtc::VoicePacing(true)); + + webrtc::Trace::set_level_filter(kDefaultTraceFilter); + webrtc::Trace::SetTraceCallback(this); + + // Load our audio codec list. + codecs_ = WebRtcVoiceCodecs::SupportedCodecs(); +} + +WebRtcVoiceEngine::~WebRtcVoiceEngine() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; + if (adm_) { + voe_wrapper_.reset(); + adm_->Release(); + adm_ = NULL; + } + webrtc::Trace::SetTraceCallback(nullptr); +} + +bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread == rtc::Thread::Current()); + LOG(LS_INFO) << "WebRtcVoiceEngine::Init"; + bool res = InitInternal(); + if (res) { + LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!"; + } else { + LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed"; + Terminate(); + } + return res; +} + +bool WebRtcVoiceEngine::InitInternal() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + // Temporarily turn logging level up for the Init call + webrtc::Trace::set_level_filter(kElevatedTraceFilter); + LOG(LS_INFO) << webrtc::VoiceEngine::GetVersionString(); + if (voe_wrapper_->base()->Init(adm_) == -1) { + LOG_RTCERR0_EX(Init, voe_wrapper_->error()); + return false; + } + webrtc::Trace::set_level_filter(kDefaultTraceFilter); + + // Save the default AGC configuration settings. This must happen before + // calling ApplyOptions or the default will be overwritten. + if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) { + LOG_RTCERR0(GetAgcConfig); + return false; + } + + // Print our codec list again for the call diagnostic log + LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; + for (const AudioCodec& codec : codecs_) { + LOG(LS_INFO) << ToString(codec); + } + + SetDefaultDevices(); + + initialized_ = true; + return true; +} + +void WebRtcVoiceEngine::Terminate() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; + initialized_ = false; + + StopAecDump(); + + voe_wrapper_->base()->Terminate(); +} + +rtc::scoped_refptr<webrtc::AudioState> + WebRtcVoiceEngine::GetAudioState() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + return audio_state_; +} + +VoiceMediaChannel* WebRtcVoiceEngine::CreateChannel(webrtc::Call* call, + const AudioOptions& options) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + return new WebRtcVoiceMediaChannel(this, options, call); +} + +bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_INFO) << "ApplyOptions: " << options_in.ToString(); + + // Default engine options. + AudioOptions options; + options.echo_cancellation = rtc::Optional<bool>(true); + options.auto_gain_control = rtc::Optional<bool>(true); + options.noise_suppression = rtc::Optional<bool>(true); + options.highpass_filter = rtc::Optional<bool>(true); + options.stereo_swapping = rtc::Optional<bool>(false); + options.audio_jitter_buffer_max_packets = rtc::Optional<int>(50); + options.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(false); + options.typing_detection = rtc::Optional<bool>(true); + options.adjust_agc_delta = rtc::Optional<int>(0); + options.experimental_agc = rtc::Optional<bool>(false); + options.extended_filter_aec = rtc::Optional<bool>(false); + options.delay_agnostic_aec = rtc::Optional<bool>(false); + options.experimental_ns = rtc::Optional<bool>(false); + options.aec_dump = rtc::Optional<bool>(false); + + // Apply any given options on top. + options.SetAll(options_in); + + // kEcConference is AEC with high suppression. + webrtc::EcModes ec_mode = webrtc::kEcConference; + webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone; + webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog; + webrtc::NsModes ns_mode = webrtc::kNsHighSuppression; + if (options.aecm_generate_comfort_noise) { + LOG(LS_VERBOSE) << "Comfort noise explicitly set to " + << *options.aecm_generate_comfort_noise + << " (default is false)."; + } + +#if defined(WEBRTC_IOS) + // On iOS, VPIO provides built-in EC and AGC. + options.echo_cancellation = rtc::Optional<bool>(false); + options.auto_gain_control = rtc::Optional<bool>(false); + LOG(LS_INFO) << "Always disable AEC and AGC on iOS. Use built-in instead."; +#elif defined(ANDROID) + ec_mode = webrtc::kEcAecm; +#endif + +#if defined(WEBRTC_IOS) || defined(ANDROID) + // Set the AGC mode for iOS as well despite disabling it above, to avoid + // unsupported configuration errors from webrtc. + agc_mode = webrtc::kAgcFixedDigital; + options.typing_detection = rtc::Optional<bool>(false); + options.experimental_agc = rtc::Optional<bool>(false); + options.extended_filter_aec = rtc::Optional<bool>(false); + options.experimental_ns = rtc::Optional<bool>(false); +#endif + + // Delay Agnostic AEC automatically turns on EC if not set except on iOS + // where the feature is not supported. + bool use_delay_agnostic_aec = false; +#if !defined(WEBRTC_IOS) + if (options.delay_agnostic_aec) { + use_delay_agnostic_aec = *options.delay_agnostic_aec; + if (use_delay_agnostic_aec) { + options.echo_cancellation = rtc::Optional<bool>(true); + options.extended_filter_aec = rtc::Optional<bool>(true); + ec_mode = webrtc::kEcConference; + } + } +#endif + + webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing(); + + if (options.echo_cancellation) { + // Check if platform supports built-in EC. Currently only supported on + // Android and in combination with Java based audio layer. + // TODO(henrika): investigate possibility to support built-in EC also + // in combination with Open SL ES audio. + const bool built_in_aec = voe_wrapper_->hw()->BuiltInAECIsAvailable(); + if (built_in_aec) { + // Built-in EC exists on this device and use_delay_agnostic_aec is not + // overriding it. Enable/Disable it according to the echo_cancellation + // audio option. + const bool enable_built_in_aec = + *options.echo_cancellation && !use_delay_agnostic_aec; + if (voe_wrapper_->hw()->EnableBuiltInAEC(enable_built_in_aec) == 0 && + enable_built_in_aec) { + // Disable internal software EC if built-in EC is enabled, + // i.e., replace the software EC with the built-in EC. + options.echo_cancellation = rtc::Optional<bool>(false); + LOG(LS_INFO) << "Disabling EC since built-in EC will be used instead"; + } + } + if (voep->SetEcStatus(*options.echo_cancellation, ec_mode) == -1) { + LOG_RTCERR2(SetEcStatus, *options.echo_cancellation, ec_mode); + return false; + } else { + LOG(LS_INFO) << "Echo control set to " << *options.echo_cancellation + << " with mode " << ec_mode; + } +#if !defined(ANDROID) + // TODO(ajm): Remove the error return on Android from webrtc. + if (voep->SetEcMetricsStatus(*options.echo_cancellation) == -1) { + LOG_RTCERR1(SetEcMetricsStatus, *options.echo_cancellation); + return false; + } +#endif + if (ec_mode == webrtc::kEcAecm) { + bool cn = options.aecm_generate_comfort_noise.value_or(false); + if (voep->SetAecmMode(aecm_mode, cn) != 0) { + LOG_RTCERR2(SetAecmMode, aecm_mode, cn); + return false; + } } } - // Allow trace options to override the trace filter. We default - // it to log_filter_ (as a translation of libjingle log levels) - // elsewhere, but this allows clients to explicitly set webrtc - // log levels. - std::vector<std::string>::iterator tracefilter = - std::find(opts.begin(), opts.end(), "tracefilter"); - if (tracefilter != opts.end() && ++tracefilter != opts.end()) { - if (!tracing_->SetTraceFilter(rtc::FromString<int>(*tracefilter))) { - LOG_RTCERR1(SetTraceFilter, *tracefilter); + if (options.auto_gain_control) { + const bool built_in_agc = voe_wrapper_->hw()->BuiltInAGCIsAvailable(); + if (built_in_agc) { + if (voe_wrapper_->hw()->EnableBuiltInAGC(*options.auto_gain_control) == + 0 && + *options.auto_gain_control) { + // Disable internal software AGC if built-in AGC is enabled, + // i.e., replace the software AGC with the built-in AGC. + options.auto_gain_control = rtc::Optional<bool>(false); + LOG(LS_INFO) << "Disabling AGC since built-in AGC will be used instead"; + } + } + if (voep->SetAgcStatus(*options.auto_gain_control, agc_mode) == -1) { + LOG_RTCERR2(SetAgcStatus, *options.auto_gain_control, agc_mode); + return false; + } else { + LOG(LS_INFO) << "Auto gain set to " << *options.auto_gain_control + << " with mode " << agc_mode; } } - // Set AEC dump file - std::vector<std::string>::iterator recordEC = - std::find(opts.begin(), opts.end(), "recordEC"); - if (recordEC != opts.end()) { - ++recordEC; - if (recordEC != opts.end()) - StartAecDump(recordEC->c_str()); + if (options.tx_agc_target_dbov || options.tx_agc_digital_compression_gain || + options.tx_agc_limiter) { + // Override default_agc_config_. Generally, an unset option means "leave + // the VoE bits alone" in this function, so we want whatever is set to be + // stored as the new "default". If we didn't, then setting e.g. + // tx_agc_target_dbov would reset digital compression gain and limiter + // settings. + // Also, if we don't update default_agc_config_, then adjust_agc_delta + // would be an offset from the original values, and not whatever was set + // explicitly. + default_agc_config_.targetLeveldBOv = options.tx_agc_target_dbov.value_or( + default_agc_config_.targetLeveldBOv); + default_agc_config_.digitalCompressionGaindB = + options.tx_agc_digital_compression_gain.value_or( + default_agc_config_.digitalCompressionGaindB); + default_agc_config_.limiterEnable = + options.tx_agc_limiter.value_or(default_agc_config_.limiterEnable); + if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) { + LOG_RTCERR3(SetAgcConfig, + default_agc_config_.targetLeveldBOv, + default_agc_config_.digitalCompressionGaindB, + default_agc_config_.limiterEnable); + return false; + } + } + + if (options.noise_suppression) { + const bool built_in_ns = voe_wrapper_->hw()->BuiltInNSIsAvailable(); + if (built_in_ns) { + if (voe_wrapper_->hw()->EnableBuiltInNS(*options.noise_suppression) == + 0 && + *options.noise_suppression) { + // Disable internal software NS if built-in NS is enabled, + // i.e., replace the software NS with the built-in NS. + options.noise_suppression = rtc::Optional<bool>(false); + LOG(LS_INFO) << "Disabling NS since built-in NS will be used instead"; + } + } + if (voep->SetNsStatus(*options.noise_suppression, ns_mode) == -1) { + LOG_RTCERR2(SetNsStatus, *options.noise_suppression, ns_mode); + return false; + } else { + LOG(LS_INFO) << "Noise suppression set to " << *options.noise_suppression + << " with mode " << ns_mode; + } + } + + if (options.highpass_filter) { + LOG(LS_INFO) << "High pass filter enabled? " << *options.highpass_filter; + if (voep->EnableHighPassFilter(*options.highpass_filter) == -1) { + LOG_RTCERR1(SetHighpassFilterStatus, *options.highpass_filter); + return false; + } + } + + if (options.stereo_swapping) { + LOG(LS_INFO) << "Stereo swapping enabled? " << *options.stereo_swapping; + voep->EnableStereoChannelSwapping(*options.stereo_swapping); + if (voep->IsStereoChannelSwappingEnabled() != *options.stereo_swapping) { + LOG_RTCERR1(EnableStereoChannelSwapping, *options.stereo_swapping); + return false; + } + } + + if (options.audio_jitter_buffer_max_packets) { + LOG(LS_INFO) << "NetEq capacity is " + << *options.audio_jitter_buffer_max_packets; + voe_config_.Set<webrtc::NetEqCapacityConfig>( + new webrtc::NetEqCapacityConfig( + *options.audio_jitter_buffer_max_packets)); + } + + if (options.audio_jitter_buffer_fast_accelerate) { + LOG(LS_INFO) << "NetEq fast mode? " + << *options.audio_jitter_buffer_fast_accelerate; + voe_config_.Set<webrtc::NetEqFastAccelerate>( + new webrtc::NetEqFastAccelerate( + *options.audio_jitter_buffer_fast_accelerate)); + } + + if (options.typing_detection) { + LOG(LS_INFO) << "Typing detection is enabled? " + << *options.typing_detection; + if (voep->SetTypingDetectionStatus(*options.typing_detection) == -1) { + // In case of error, log the info and continue + LOG_RTCERR1(SetTypingDetectionStatus, *options.typing_detection); + } + } + + if (options.adjust_agc_delta) { + LOG(LS_INFO) << "Adjust agc delta is " << *options.adjust_agc_delta; + if (!AdjustAgcLevel(*options.adjust_agc_delta)) { + return false; + } + } + + if (options.aec_dump) { + LOG(LS_INFO) << "Aec dump is enabled? " << *options.aec_dump; + if (*options.aec_dump) + StartAecDump(kAecDumpByAudioOptionFilename); else StopAecDump(); } + + webrtc::Config config; + + if (options.delay_agnostic_aec) + delay_agnostic_aec_ = options.delay_agnostic_aec; + if (delay_agnostic_aec_) { + LOG(LS_INFO) << "Delay agnostic aec is enabled? " << *delay_agnostic_aec_; + config.Set<webrtc::DelayAgnostic>( + new webrtc::DelayAgnostic(*delay_agnostic_aec_)); + } + + if (options.extended_filter_aec) { + extended_filter_aec_ = options.extended_filter_aec; + } + if (extended_filter_aec_) { + LOG(LS_INFO) << "Extended filter aec is enabled? " << *extended_filter_aec_; + config.Set<webrtc::ExtendedFilter>( + new webrtc::ExtendedFilter(*extended_filter_aec_)); + } + + if (options.experimental_ns) { + experimental_ns_ = options.experimental_ns; + } + if (experimental_ns_) { + LOG(LS_INFO) << "Experimental ns is enabled? " << *experimental_ns_; + config.Set<webrtc::ExperimentalNs>( + new webrtc::ExperimentalNs(*experimental_ns_)); + } + + // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine + // returns NULL on audio_processing(). + webrtc::AudioProcessing* audioproc = voe_wrapper_->base()->audio_processing(); + if (audioproc) { + audioproc->SetExtraOptions(config); + } + + if (options.recording_sample_rate) { + LOG(LS_INFO) << "Recording sample rate is " + << *options.recording_sample_rate; + if (voe_wrapper_->hw()->SetRecordingSampleRate( + *options.recording_sample_rate)) { + LOG_RTCERR1(SetRecordingSampleRate, *options.recording_sample_rate); + } + } + + if (options.playout_sample_rate) { + LOG(LS_INFO) << "Playout sample rate is " << *options.playout_sample_rate; + if (voe_wrapper_->hw()->SetPlayoutSampleRate( + *options.playout_sample_rate)) { + LOG_RTCERR1(SetPlayoutSampleRate, *options.playout_sample_rate); + } + } + + return true; +} + +void WebRtcVoiceEngine::SetDefaultDevices() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); +#if !defined(WEBRTC_IOS) + int in_id = kDefaultAudioDeviceId; + int out_id = kDefaultAudioDeviceId; + LOG(LS_INFO) << "Setting microphone to (id=" << in_id + << ") and speaker to (id=" << out_id << ")"; + + bool ret = true; + if (voe_wrapper_->hw()->SetRecordingDevice(in_id) == -1) { + LOG_RTCERR1(SetRecordingDevice, in_id); + ret = false; + } + webrtc::AudioProcessing* ap = voe()->base()->audio_processing(); + if (ap) { + ap->Initialize(); + } + + if (voe_wrapper_->hw()->SetPlayoutDevice(out_id) == -1) { + LOG_RTCERR1(SetPlayoutDevice, out_id); + ret = false; + } + + if (ret) { + LOG(LS_INFO) << "Set microphone to (id=" << in_id + << ") and speaker to (id=" << out_id << ")"; + } +#endif // !WEBRTC_IOS +} + +bool WebRtcVoiceEngine::GetOutputVolume(int* level) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + unsigned int ulevel; + if (voe_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) { + LOG_RTCERR1(GetSpeakerVolume, level); + return false; + } + *level = ulevel; + return true; +} + +bool WebRtcVoiceEngine::SetOutputVolume(int level) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(level >= 0 && level <= 255); + if (voe_wrapper_->volume()->SetSpeakerVolume(level) == -1) { + LOG_RTCERR1(SetSpeakerVolume, level); + return false; + } + return true; +} + +int WebRtcVoiceEngine::GetInputLevel() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + unsigned int ulevel; + return (voe_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ? + static_cast<int>(ulevel) : -1; +} + +const std::vector<AudioCodec>& WebRtcVoiceEngine::codecs() { + RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); + return codecs_; +} + +RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const { + RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); + RtpCapabilities capabilities; + capabilities.header_extensions.push_back(RtpHeaderExtension( + kRtpAudioLevelHeaderExtension, kRtpAudioLevelHeaderExtensionDefaultId)); + capabilities.header_extensions.push_back( + RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, + kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); + return capabilities; +} + +int WebRtcVoiceEngine::GetLastEngineError() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + return voe_wrapper_->error(); } void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace, int length) { + // Note: This callback can happen on any thread! rtc::LoggingSeverity sev = rtc::LS_VERBOSE; if (level == webrtc::kTraceError || level == webrtc::kTraceCritical) sev = rtc::LS_ERROR; @@ -1201,34 +962,24 @@ } } -void WebRtcVoiceEngine::CallbackOnError(int channel_id, int err_code) { - RTC_DCHECK(channel_id == -1); - LOG(LS_WARNING) << "VoiceEngine error " << err_code << " reported on channel " - << channel_id << "."; - rtc::CritScope lock(&channels_cs_); - for (WebRtcVoiceMediaChannel* channel : channels_) { - channel->OnError(err_code); - } -} - void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel* channel) { - RTC_DCHECK(channel != NULL); - rtc::CritScope lock(&channels_cs_); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(channel); channels_.push_back(channel); } void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel* channel) { - rtc::CritScope lock(&channels_cs_); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); auto it = std::find(channels_.begin(), channels_.end(), channel); - if (it != channels_.end()) { - channels_.erase(it); - } + RTC_DCHECK(it != channels_.end()); + channels_.erase(it); } // Adjusts the default AGC target level by the specified delta. // NB: If we start messing with other config fields, we'll want // to save the current webrtc::AgcConfig as well. bool WebRtcVoiceEngine::AdjustAgcLevel(int delta) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); webrtc::AgcConfig config = default_agc_config_; config.targetLeveldBOv -= delta; @@ -1244,6 +995,7 @@ } bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); if (initialized_) { LOG(LS_WARNING) << "SetAudioDeviceModule can not be called after Init."; return false; @@ -1260,6 +1012,7 @@ } bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); FILE* aec_dump_file_stream = rtc::FdopenPlatformFileForWriting(file); if (!aec_dump_file_stream) { LOG(LS_ERROR) << "Could not open AEC dump file stream."; @@ -1279,6 +1032,7 @@ } void WebRtcVoiceEngine::StartAecDump(const std::string& filename) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); if (!is_dumping_aec_) { // Start dumping AEC when we are not dumping. if (voe_wrapper_->processing()->StartDebugRecording( @@ -1291,6 +1045,7 @@ } void WebRtcVoiceEngine::StopAecDump() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); if (is_dumping_aec_) { // Stop dumping AEC when we are dumping. if (voe_wrapper_->processing()->StopDebugRecording() != @@ -1302,14 +1057,17 @@ } bool WebRtcVoiceEngine::StartRtcEventLog(rtc::PlatformFile file) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return voe_wrapper_->codec()->GetEventLog()->StartLogging(file); } void WebRtcVoiceEngine::StopRtcEventLog() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); voe_wrapper_->codec()->GetEventLog()->StopLogging(); } int WebRtcVoiceEngine::CreateVoEChannel() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return voe_wrapper_->base()->CreateChannel(voe_config_); } @@ -1317,33 +1075,61 @@ : public AudioRenderer::Sink { public: WebRtcAudioSendStream(int ch, webrtc::AudioTransport* voe_audio_transport, - uint32_t ssrc, webrtc::Call* call) - : channel_(ch), - voe_audio_transport_(voe_audio_transport), - call_(call) { + uint32_t ssrc, const std::string& c_name, + const std::vector<webrtc::RtpExtension>& extensions, + webrtc::Call* call) + : voe_audio_transport_(voe_audio_transport), + call_(call), + config_(nullptr) { RTC_DCHECK_GE(ch, 0); // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore: // RTC_DCHECK(voe_audio_transport); RTC_DCHECK(call); audio_capture_thread_checker_.DetachFromThread(); - webrtc::AudioSendStream::Config config(nullptr); - config.voe_channel_id = channel_; - config.rtp.ssrc = ssrc; - stream_ = call_->CreateAudioSendStream(config); - RTC_DCHECK(stream_); + config_.rtp.ssrc = ssrc; + config_.rtp.c_name = c_name; + config_.voe_channel_id = ch; + RecreateAudioSendStream(extensions); } + ~WebRtcAudioSendStream() override { - RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); Stop(); call_->DestroyAudioSendStream(stream_); } + void RecreateAudioSendStream( + const std::vector<webrtc::RtpExtension>& extensions) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + if (stream_) { + call_->DestroyAudioSendStream(stream_); + stream_ = nullptr; + } + config_.rtp.extensions = extensions; + RTC_DCHECK(!stream_); + stream_ = call_->CreateAudioSendStream(config_); + RTC_CHECK(stream_); + } + + bool SendTelephoneEvent(int payload_type, uint8_t event, + uint32_t duration_ms) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(stream_); + return stream_->SendTelephoneEvent(payload_type, event, duration_ms); + } + + webrtc::AudioSendStream::Stats GetStats() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(stream_); + return stream_->GetStats(); + } + // Starts the rendering by setting a sink to the renderer to get data // callback. // This method is called on the libjingle worker thread. // TODO(xians): Make sure Start() is called only once. void Start(AudioRenderer* renderer) { - RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); RTC_DCHECK(renderer); if (renderer_) { RTC_DCHECK(renderer_ == renderer); @@ -1353,16 +1139,11 @@ renderer_ = renderer; } - webrtc::AudioSendStream::Stats GetStats() const { - RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); - return stream_->GetStats(); - } - // Stops rendering by setting the sink of the renderer to nullptr. No data // callback will be received after this method. // This method is called on the libjingle worker thread. void Stop() { - RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); if (renderer_) { renderer_->SetSink(nullptr); renderer_ = nullptr; @@ -1374,11 +1155,12 @@ void OnData(const void* audio_data, int bits_per_sample, int sample_rate, - int number_of_channels, + size_t number_of_channels, size_t number_of_frames) override { + RTC_DCHECK(!worker_thread_checker_.CalledOnValidThread()); RTC_DCHECK(audio_capture_thread_checker_.CalledOnValidThread()); RTC_DCHECK(voe_audio_transport_); - voe_audio_transport_->OnData(channel_, + voe_audio_transport_->OnData(config_.voe_channel_id, audio_data, bits_per_sample, sample_rate, @@ -1389,7 +1171,7 @@ // Callback from the |renderer_| when it is going away. In case Start() has // never been called, this callback won't be triggered. void OnClose() override { - RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // Set |renderer_| to nullptr to make sure no more callback will get into // the renderer. renderer_ = nullptr; @@ -1397,16 +1179,18 @@ // Accessor to the VoE channel ID. int channel() const { - RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); - return channel_; + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + return config_.voe_channel_id; } private: - rtc::ThreadChecker signal_thread_checker_; + rtc::ThreadChecker worker_thread_checker_; rtc::ThreadChecker audio_capture_thread_checker_; - const int channel_ = -1; webrtc::AudioTransport* const voe_audio_transport_ = nullptr; webrtc::Call* call_ = nullptr; + webrtc::AudioSendStream::Config config_; + // The stream is owned by WebRtcAudioSendStream and may be reallocated if + // configuration changes. webrtc::AudioSendStream* stream_ = nullptr; // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. @@ -1419,80 +1203,163 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { public: - explicit WebRtcAudioReceiveStream(int voe_channel_id) - : channel_(voe_channel_id) {} + WebRtcAudioReceiveStream(int ch, uint32_t remote_ssrc, uint32_t local_ssrc, + bool use_combined_bwe, const std::string& sync_group, + const std::vector<webrtc::RtpExtension>& extensions, + webrtc::Call* call) + : call_(call), + config_() { + RTC_DCHECK_GE(ch, 0); + RTC_DCHECK(call); + config_.rtp.remote_ssrc = remote_ssrc; + config_.rtp.local_ssrc = local_ssrc; + config_.voe_channel_id = ch; + config_.sync_group = sync_group; + RecreateAudioReceiveStream(use_combined_bwe, extensions); + } - int channel() { return channel_; } + ~WebRtcAudioReceiveStream() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + call_->DestroyAudioReceiveStream(stream_); + } + + void RecreateAudioReceiveStream( + const std::vector<webrtc::RtpExtension>& extensions) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RecreateAudioReceiveStream(config_.combined_audio_video_bwe, extensions); + } + void RecreateAudioReceiveStream(bool use_combined_bwe) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.extensions); + } + + webrtc::AudioReceiveStream::Stats GetStats() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(stream_); + return stream_->GetStats(); + } + + int channel() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + return config_.voe_channel_id; + } + + void SetRawAudioSink(rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + stream_->SetSink(std::move(sink)); + } private: - int channel_; + void RecreateAudioReceiveStream(bool use_combined_bwe, + const std::vector<webrtc::RtpExtension>& extensions) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + if (stream_) { + call_->DestroyAudioReceiveStream(stream_); + stream_ = nullptr; + } + config_.rtp.extensions = extensions; + config_.combined_audio_video_bwe = use_combined_bwe; + RTC_DCHECK(!stream_); + stream_ = call_->CreateAudioReceiveStream(config_); + RTC_CHECK(stream_); + } + + rtc::ThreadChecker worker_thread_checker_; + webrtc::Call* call_ = nullptr; + webrtc::AudioReceiveStream::Config config_; + // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if + // configuration changes. + webrtc::AudioReceiveStream* stream_ = nullptr; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioReceiveStream); }; -// WebRtcVoiceMediaChannel WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine, const AudioOptions& options, webrtc::Call* call) - : engine_(engine), - send_bitrate_setting_(false), - send_bitrate_bps_(0), - options_(), - dtmf_allowed_(false), - desired_playout_(false), - nack_enabled_(false), - playout_(false), - typing_noise_detected_(false), - desired_send_(SEND_NOTHING), - send_(SEND_NOTHING), - call_(call) { + : engine_(engine), call_(call) { LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel"; - RTC_DCHECK(nullptr != call); + RTC_DCHECK(call); engine->RegisterChannel(this); SetOptions(options); } WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel"; - - // Remove any remaining send streams. + // TODO(solenberg): Should be able to delete the streams directly, without + // going through RemoveNnStream(), once stream objects handle + // all (de)configuration. while (!send_streams_.empty()) { RemoveSendStream(send_streams_.begin()->first); } - - // Remove any remaining receive streams. - while (!receive_channels_.empty()) { - RemoveRecvStream(receive_channels_.begin()->first); + while (!recv_streams_.empty()) { + RemoveRecvStream(recv_streams_.begin()->first); } - RTC_DCHECK(receive_streams_.empty()); - - // Unregister ourselves from the engine. engine()->UnregisterChannel(this); } bool WebRtcVoiceMediaChannel::SetSendParameters( const AudioSendParameters& params) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendParameters: " + << params.ToString(); // TODO(pthatcher): Refactor this to be more clean now that we have // all the information at once. - return (SetSendCodecs(params.codecs) && - SetSendRtpHeaderExtensions(params.extensions) && - SetMaxSendBandwidth(params.max_bandwidth_bps) && - SetOptions(params.options)); + + if (!SetSendCodecs(params.codecs)) { + return false; + } + + if (!ValidateRtpExtensions(params.extensions)) { + return false; + } + std::vector<webrtc::RtpExtension> filtered_extensions = + FilterRtpExtensions(params.extensions, + webrtc::RtpExtension::IsSupportedForAudio, true); + if (send_rtp_extensions_ != filtered_extensions) { + send_rtp_extensions_.swap(filtered_extensions); + for (auto& it : send_streams_) { + it.second->RecreateAudioSendStream(send_rtp_extensions_); + } + } + + if (!SetMaxSendBandwidth(params.max_bandwidth_bps)) { + return false; + } + return SetOptions(params.options); } bool WebRtcVoiceMediaChannel::SetRecvParameters( const AudioRecvParameters& params) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetRecvParameters: " + << params.ToString(); // TODO(pthatcher): Refactor this to be more clean now that we have // all the information at once. - return (SetRecvCodecs(params.codecs) && - SetRecvRtpHeaderExtensions(params.extensions)); + + if (!SetRecvCodecs(params.codecs)) { + return false; + } + + if (!ValidateRtpExtensions(params.extensions)) { + return false; + } + std::vector<webrtc::RtpExtension> filtered_extensions = + FilterRtpExtensions(params.extensions, + webrtc::RtpExtension::IsSupportedForAudio, false); + if (recv_rtp_extensions_ != filtered_extensions) { + recv_rtp_extensions_.swap(filtered_extensions); + for (auto& it : recv_streams_) { + it.second->RecreateAudioReceiveStream(recv_rtp_extensions_); + } + } + + return true; } bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); LOG(LS_INFO) << "Setting voice channel options: " << options.ToString(); @@ -1503,26 +1370,27 @@ // on top. This means there is no way to "clear" options such that // they go back to the engine default. options_.SetAll(options); - - if (send_ != SEND_NOTHING) { - if (!engine()->ApplyOptions(options_)) { - LOG(LS_WARNING) << - "Failed to apply engine options during channel SetOptions."; - return false; - } + if (!engine()->ApplyOptions(options_)) { + LOG(LS_WARNING) << + "Failed to apply engine options during channel SetOptions."; + return false; } if (dscp_option_changed) { rtc::DiffServCodePoint dscp = rtc::DSCP_DEFAULT; - if (options_.dscp.GetWithDefaultIfUnset(false)) + if (options_.dscp.value_or(false)) { dscp = kAudioDscpValue; + } if (MediaChannel::SetDscp(dscp) != 0) { LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel"; } } // TODO(solenberg): Don't recreate unless options changed. - RecreateAudioReceiveStreams(); + for (auto& it : recv_streams_) { + it.second->RecreateAudioReceiveStream( + options_.combined_audio_video_bwe.value_or(false)); + } LOG(LS_INFO) << "Set voice channel options. Current options: " << options_.ToString(); @@ -1531,7 +1399,7 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs( const std::vector<AudioCodec>& codecs) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // Set the payload types to be used for incoming media. LOG(LS_INFO) << "Setting receive voice codecs."; @@ -1568,7 +1436,26 @@ PausePlayout(); } - bool result = SetRecvCodecsInternal(new_codecs); + bool result = true; + for (const AudioCodec& codec : new_codecs) { + webrtc::CodecInst voe_codec; + if (WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { + LOG(LS_INFO) << ToString(codec); + voe_codec.pltype = codec.id; + for (const auto& ch : recv_streams_) { + if (engine()->voe()->codec()->SetRecPayloadType( + ch.second->channel(), voe_codec) == -1) { + LOG_RTCERR2(SetRecPayloadType, ch.second->channel(), + ToString(voe_codec)); + result = false; + } + } + } else { + LOG(LS_WARNING) << "Unknown codec " << ToString(codec); + result = false; + break; + } + } if (result) { recv_codecs_ = codecs; } @@ -1588,7 +1475,7 @@ engine()->voe()->codec()->SetFECStatus(channel, false); // Scan through the list to figure out the codec to use for sending, along - // with the proper configuration for VAD and DTMF. + // with the proper configuration for VAD. bool found_send_codec = false; webrtc::CodecInst send_codec; memset(&send_codec, 0, sizeof(send_codec)); @@ -1603,7 +1490,7 @@ // Ignore codecs we don't know about. The negotiation step should prevent // this, but double-check to be sure. webrtc::CodecInst voe_codec; - if (!engine()->FindWebRtcCodec(codec, &voe_codec)) { + if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { LOG(LS_WARNING) << "Unknown codec " << ToString(codec); continue; } @@ -1644,7 +1531,7 @@ // Set packet size if the AudioCodec param kCodecParamPTime is set. int ptime_ms = 0; if (codec.GetParam(kCodecParamPTime, &ptime_ms)) { - if (!SetPTimeAsPacketSize(&send_codec, ptime_ms)) { + if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize(&send_codec, ptime_ms)) { LOG(LS_WARNING) << "Failed to set packet size for codec " << send_codec.plname; return false; @@ -1687,7 +1574,7 @@ // Set Opus internal DTX. LOG(LS_INFO) << "Attempt to " - << GetEnableString(enable_opus_dtx) + << (enable_opus_dtx ? "enable" : "disable") << " Opus DTX on channel " << channel; if (engine()->voe()->codec()->SetOpusDtx(channel, enable_opus_dtx)) { @@ -1717,25 +1604,17 @@ SetSendBitrateInternal(send_bitrate_bps_); } - // Loop through the codecs list again to config the telephone-event/CN codec. + // Loop through the codecs list again to config the CN codec. for (const AudioCodec& codec : codecs) { // Ignore codecs we don't know about. The negotiation step should prevent // this, but double-check to be sure. webrtc::CodecInst voe_codec; - if (!engine()->FindWebRtcCodec(codec, &voe_codec)) { + if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { LOG(LS_WARNING) << "Unknown codec " << ToString(codec); continue; } - // Find the DTMF telephone event "codec" and tell VoiceEngine channels - // about it. - if (IsCodec(codec, kDtmfCodecName)) { - if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType( - channel, codec.id) == -1) { - LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, codec.id); - return false; - } - } else if (IsCodec(codec, kCnCodecName)) { + if (IsCodec(codec, kCnCodecName)) { // Turn voice activity detection/comfort noise on if supported. // Set the wideband CN payload type appropriately. // (narrowband always uses the static payload type 13). @@ -1789,13 +1668,17 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( const std::vector<AudioCodec>& codecs) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + // TODO(solenberg): Validate input - that payload types don't overlap, are + // within range, filter out codecs we don't support, + // redundant codecs etc. - dtmf_allowed_ = false; + // Find the DTMF telephone event "codec" payload type. + dtmf_payload_type_ = rtc::Optional<int>(); for (const AudioCodec& codec : codecs) { - // Find the DTMF telephone event "codec". if (IsCodec(codec, kDtmfCodecName)) { - dtmf_allowed_ = true; + dtmf_payload_type_ = rtc::Optional<int>(codec.id); + break; } } @@ -1808,7 +1691,7 @@ } // Set nack status on receive channels and update |nack_enabled_|. - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { SetNack(ch.second->channel(), nack_enabled_); } @@ -1844,106 +1727,6 @@ return true; } -bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions( - const std::vector<RtpHeaderExtension>& extensions) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - if (receive_extensions_ == extensions) { - return true; - } - - for (const auto& ch : receive_channels_) { - if (!SetChannelRecvRtpHeaderExtensions(ch.second->channel(), extensions)) { - return false; - } - } - - receive_extensions_ = extensions; - - // Recreate AudioReceiveStream:s. - { - std::vector<webrtc::RtpExtension> exts; - - const RtpHeaderExtension* audio_level_extension = - FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); - if (audio_level_extension) { - exts.push_back({ - kRtpAudioLevelHeaderExtension, audio_level_extension->id}); - } - - const RtpHeaderExtension* send_time_extension = - FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); - if (send_time_extension) { - exts.push_back({ - kRtpAbsoluteSenderTimeHeaderExtension, send_time_extension->id}); - } - - recv_rtp_extensions_.swap(exts); - RecreateAudioReceiveStreams(); - } - - return true; -} - -bool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions( - int channel_id, const std::vector<RtpHeaderExtension>& extensions) { - const RtpHeaderExtension* audio_level_extension = - FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetReceiveAudioLevelIndicationStatus, channel_id, - audio_level_extension)) { - return false; - } - - const RtpHeaderExtension* send_time_extension = - FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetReceiveAbsoluteSenderTimeStatus, channel_id, - send_time_extension)) { - return false; - } - - return true; -} - -bool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions( - const std::vector<RtpHeaderExtension>& extensions) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - if (send_extensions_ == extensions) { - return true; - } - - for (const auto& ch : send_streams_) { - if (!SetChannelSendRtpHeaderExtensions(ch.second->channel(), extensions)) { - return false; - } - } - - send_extensions_ = extensions; - return true; -} - -bool WebRtcVoiceMediaChannel::SetChannelSendRtpHeaderExtensions( - int channel_id, const std::vector<RtpHeaderExtension>& extensions) { - const RtpHeaderExtension* audio_level_extension = - FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); - - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetSendAudioLevelIndicationStatus, channel_id, - audio_level_extension)) { - return false; - } - - const RtpHeaderExtension* send_time_extension = - FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetSendAbsoluteSenderTimeStatus, channel_id, - send_time_extension)) { - return false; - } - - return true; -} - bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) { desired_playout_ = playout; return ChangePlayout(desired_playout_); @@ -1958,12 +1741,12 @@ } bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); if (playout_ == playout) { return true; } - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { if (!SetPlayout(ch.second->channel(), playout)) { LOG(LS_ERROR) << "SetPlayout " << playout << " on channel " << ch.second->channel() << " failed"; @@ -1995,7 +1778,7 @@ return true; } - // Apply channel specific options. + // Apply channel specific options when channel is enabled for sending. if (send == SEND_MICROPHONE) { engine()->ApplyOptions(options_); } @@ -2007,13 +1790,6 @@ } } - // Clear up the options after stopping sending. Since we may previously have - // applied the channel specific options, now apply the original options stored - // in WebRtcVoiceEngine. - if (send == SEND_NOTHING) { - engine()->ApplyOptions(engine()->GetOptions()); - } - send_ = send; return true; } @@ -2039,7 +1815,7 @@ bool enable, const AudioOptions* options, AudioRenderer* renderer) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // TODO(solenberg): The state change should be fully rolled back if any one of // these calls fail. if (!SetLocalRenderer(ssrc, renderer)) { @@ -2068,7 +1844,7 @@ return id; } -bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) { +bool WebRtcVoiceMediaChannel::DeleteVoEChannel(int channel) { if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) { LOG_RTCERR1(DeRegisterExternalTransport, channel); } @@ -2080,7 +1856,7 @@ } bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); LOG(LS_INFO) << "AddSendStream: " << sp.ToString(); uint32_t ssrc = sp.first_ssrc(); @@ -2097,33 +1873,12 @@ return false; } - // Enable RTCP (for quality stats and feedback messages). - if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) { - LOG_RTCERR2(SetRTCPStatus, channel, 1); - } - - SetChannelSendRtpHeaderExtensions(channel, send_extensions_); - - // Set the local (send) SSRC. - if (engine()->voe()->rtp()->SetLocalSSRC(channel, ssrc) == -1) { - LOG_RTCERR2(SetLocalSSRC, channel, ssrc); - DeleteChannel(channel); - return false; - } - - if (engine()->voe()->rtp()->SetRTCP_CNAME(channel, sp.cname.c_str()) == -1) { - LOG_RTCERR2(SetRTCP_CNAME, channel, sp.cname); - DeleteChannel(channel); - return false; - } - // Save the channel to send_streams_, so that RemoveSendStream() can still // delete the channel in case failure happens below. webrtc::AudioTransport* audio_transport = engine()->voe()->base()->audio_transport(); - send_streams_.insert( - std::make_pair(ssrc, - new WebRtcAudioSendStream(channel, audio_transport, ssrc, call_))); + send_streams_.insert(std::make_pair(ssrc, new WebRtcAudioSendStream( + channel, audio_transport, ssrc, sp.cname, send_rtp_extensions_, call_))); // Set the current codecs to be used for the new channel. We need to do this // after adding the channel to send_channels_, because of how max bitrate is @@ -2138,10 +1893,10 @@ // with the same SSRC in order to send receiver reports. if (send_streams_.size() == 1) { receiver_reports_ssrc_ = ssrc; - for (const auto& ch : receive_channels_) { - int recv_channel = ch.second->channel(); + for (const auto& stream : recv_streams_) { + int recv_channel = stream.second->channel(); if (engine()->voe()->rtp()->SetLocalSSRC(recv_channel, ssrc) != 0) { - LOG_RTCERR2(SetLocalSSRC, ch.second->channel(), ssrc); + LOG_RTCERR2(SetLocalSSRC, recv_channel, ssrc); return false; } engine()->voe()->base()->AssociateSendChannel(recv_channel, channel); @@ -2154,7 +1909,9 @@ } bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_INFO) << "RemoveSendStream: " << ssrc; + auto it = send_streams_.find(ssrc); if (it == send_streams_.end()) { LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc @@ -2165,15 +1922,12 @@ int channel = it->second->channel(); ChangeSend(channel, SEND_NOTHING); - // Delete the WebRtcVoiceChannelRenderer object connected to the channel, - // this will disconnect the audio renderer with the send channel. - delete it->second; - send_streams_.erase(it); - - // Clean up and delete the send channel. + // Clean up and delete the send stream+channel. LOG(LS_INFO) << "Removing audio send stream " << ssrc << " with VoiceEngine channel #" << channel << "."; - if (!DeleteChannel(channel)) { + delete it->second; + send_streams_.erase(it); + if (!DeleteVoEChannel(channel)) { return false; } if (send_streams_.empty()) { @@ -2183,14 +1937,14 @@ } bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); LOG(LS_INFO) << "AddRecvStream: " << sp.ToString(); if (!ValidateStreamParams(sp)) { return false; } - uint32_t ssrc = sp.first_ssrc(); + const uint32_t ssrc = sp.first_ssrc(); if (ssrc == 0) { LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported."; return false; @@ -2202,37 +1956,43 @@ RemoveRecvStream(ssrc); } - if (receive_channels_.find(ssrc) != receive_channels_.end()) { + if (GetReceiveChannelId(ssrc) != -1) { LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc; return false; } - RTC_DCHECK(receive_stream_params_.find(ssrc) == receive_stream_params_.end()); // Create a new channel for receiving audio data. - int channel = CreateVoEChannel(); + const int channel = CreateVoEChannel(); if (channel == -1) { return false; } - if (!ConfigureRecvChannel(channel)) { - DeleteChannel(channel); - return false; + + // Turn off all supported codecs. + // TODO(solenberg): Remove once "no codecs" is the default state of a stream. + for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { + voe_codec.pltype = -1; + if (engine()->voe()->codec()->SetRecPayloadType(channel, voe_codec) == -1) { + LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); + DeleteVoEChannel(channel); + return false; + } } - WebRtcAudioReceiveStream* stream = new WebRtcAudioReceiveStream(channel); - receive_channels_.insert(std::make_pair(ssrc, stream)); - receive_stream_params_[ssrc] = sp; - AddAudioReceiveStream(ssrc); + // Only enable those configured for this channel. + for (const auto& codec : recv_codecs_) { + webrtc::CodecInst voe_codec; + if (WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { + voe_codec.pltype = codec.id; + if (engine()->voe()->codec()->SetRecPayloadType( + channel, voe_codec) == -1) { + LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); + DeleteVoEChannel(channel); + return false; + } + } + } - LOG(LS_INFO) << "New audio stream " << ssrc - << " registered to VoiceEngine channel #" - << channel << "."; - return true; -} - -bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - - int send_channel = GetSendChannelId(receiver_reports_ssrc_); + const int send_channel = GetSendChannelId(receiver_reports_ssrc_); if (send_channel != -1) { // Associate receive channel with first send channel (so the receive channel // can obtain RTT from the send channel) @@ -2240,76 +2000,43 @@ LOG(LS_INFO) << "VoiceEngine channel #" << channel << " is associated with channel #" << send_channel << "."; } - if (engine()->voe()->rtp()->SetLocalSSRC(channel, - receiver_reports_ssrc_) == -1) { - LOG_RTCERR1(SetLocalSSRC, channel); - return false; - } - // Turn off all supported codecs. - int ncodecs = engine()->voe()->codec()->NumOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - webrtc::CodecInst voe_codec; - if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) { - voe_codec.pltype = -1; - if (engine()->voe()->codec()->SetRecPayloadType( - channel, voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); - return false; - } - } - } - - // Only enable those configured for this channel. - for (const auto& codec : recv_codecs_) { - webrtc::CodecInst voe_codec; - if (engine()->FindWebRtcCodec(codec, &voe_codec)) { - voe_codec.pltype = codec.id; - if (engine()->voe()->codec()->SetRecPayloadType( - channel, voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); - return false; - } - } - } + recv_streams_.insert(std::make_pair(ssrc, new WebRtcAudioReceiveStream( + channel, ssrc, receiver_reports_ssrc_, + options_.combined_audio_video_bwe.value_or(false), sp.sync_label, + recv_rtp_extensions_, call_))); SetNack(channel, nack_enabled_); - - // Set RTP header extension for the new channel. - if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) { - return false; - } - SetPlayout(channel, playout_); + return true; } bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); LOG(LS_INFO) << "RemoveRecvStream: " << ssrc; - auto it = receive_channels_.find(ssrc); - if (it == receive_channels_.end()) { + const auto it = recv_streams_.find(ssrc); + if (it == recv_streams_.end()) { LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc << " which doesn't exist."; return false; } - RemoveAudioReceiveStream(ssrc); - receive_stream_params_.erase(ssrc); - - const int channel = it->second->channel(); - delete it->second; - receive_channels_.erase(it); - // Deregister default channel, if that's the one being destroyed. if (IsDefaultRecvStream(ssrc)) { default_recv_ssrc_ = -1; } - LOG(LS_INFO) << "Removing audio stream " << ssrc + const int channel = it->second->channel(); + + // Clean up and delete the receive stream+channel. + LOG(LS_INFO) << "Removing audio receive stream " << ssrc << " with VoiceEngine channel #" << channel << "."; - return DeleteChannel(channel); + it->second->SetRawAudioSink(nullptr); + delete it->second; + recv_streams_.erase(it); + return DeleteVoEChannel(channel); } bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32_t ssrc, @@ -2337,9 +2064,9 @@ bool WebRtcVoiceMediaChannel::GetActiveStreams( AudioInfo::StreamList* actives) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); actives->clear(); - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { int level = GetOutputLevel(ch.second->channel()); if (level > 0) { actives->push_back(std::make_pair(ch.first, level)); @@ -2349,9 +2076,9 @@ } int WebRtcVoiceMediaChannel::GetOutputLevel() { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int highest = 0; - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { highest = std::max(GetOutputLevel(ch.second->channel()), highest); } return highest; @@ -2383,7 +2110,7 @@ } bool WebRtcVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); if (ssrc == 0) { default_recv_volume_ = volume; if (default_recv_ssrc_ == -1) { @@ -2408,64 +2135,48 @@ } bool WebRtcVoiceMediaChannel::CanInsertDtmf() { - return dtmf_allowed_; + return dtmf_payload_type_ ? true : false; } -bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, - int event, - int duration, - int flags) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - if (!dtmf_allowed_) { +bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event, + int duration) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf"; + if (!dtmf_payload_type_) { return false; } - // Send the event. - if (flags & cricket::DF_SEND) { - int channel = -1; - if (ssrc == 0) { - if (send_streams_.size() > 0) { - channel = send_streams_.begin()->second->channel(); - } - } else { - channel = GetSendChannelId(ssrc); - } - if (channel == -1) { - LOG(LS_WARNING) << "InsertDtmf - The specified ssrc " - << ssrc << " is not in use."; - return false; - } - // Send DTMF using out-of-band DTMF. ("true", as 3rd arg) - if (engine()->voe()->dtmf()->SendTelephoneEvent( - channel, event, true, duration) == -1) { - LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration); - return false; - } + // Figure out which WebRtcAudioSendStream to send the event on. + auto it = ssrc != 0 ? send_streams_.find(ssrc) : send_streams_.begin(); + if (it == send_streams_.end()) { + LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use."; + return false; } - - // Play the event. - if (flags & cricket::DF_PLAY) { - // Play DTMF tone locally. - if (engine()->voe()->dtmf()->PlayDtmfTone(event, duration) == -1) { - LOG_RTCERR2(PlayDtmfTone, event, duration); - return false; - } + if (event < kMinTelephoneEventCode || + event > kMaxTelephoneEventCode) { + LOG(LS_WARNING) << "DTMF event code " << event << " out of range."; + return false; } - - return true; + if (duration < kMinTelephoneEventDuration || + duration > kMaxTelephoneEventDuration) { + LOG(LS_WARNING) << "DTMF event duration " << duration << " out of range."; + return false; + } + return it->second->SendTelephoneEvent(*dtmf_payload_type_, event, duration); } void WebRtcVoiceMediaChannel::OnPacketReceived( rtc::Buffer* packet, const rtc::PacketTime& packet_time) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); uint32_t ssrc = 0; if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) { return; } - if (receive_channels_.empty()) { - // Create new channel, which will be the default receive channel. + // If we don't have a default channel, and the SSRC is unknown, create a + // default channel. + if (default_recv_ssrc_ == -1 && GetReceiveChannelId(ssrc) == -1) { StreamParams sp; sp.ssrcs.push_back(ssrc); LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << "."; @@ -2485,7 +2196,13 @@ reinterpret_cast<const uint8_t*>(packet->data()), packet->size(), webrtc_packet_time); if (webrtc::PacketReceiver::DELIVERY_OK != delivery_result) { - return; + // If the SSRC is unknown here, route it to the default channel, if we have + // one. See: https://bugs.chromium.org/p/webrtc/issues/detail?id=5208 + if (default_recv_ssrc_ == -1) { + return; + } else { + ssrc = default_recv_ssrc_; + } } // Find the channel to send this packet to. It must exist since webrtc::Call @@ -2500,7 +2217,7 @@ void WebRtcVoiceMediaChannel::OnRtcpReceived( rtc::Buffer* packet, const rtc::PacketTime& packet_time) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // Forward packet to Call as well. const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp, @@ -2542,7 +2259,7 @@ } bool WebRtcVoiceMediaChannel::MuteStream(uint32_t ssrc, bool muted) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int channel = GetSendChannelId(ssrc); if (channel == -1) { LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use."; @@ -2601,7 +2318,7 @@ return true; webrtc::CodecInst codec = *send_codec_; - bool is_multi_rate = IsCodecMultiRate(codec); + bool is_multi_rate = WebRtcVoiceCodecs::IsCodecMultiRate(codec); if (is_multi_rate) { // If codec is multi-rate then just set the bitrate. @@ -2629,7 +2346,7 @@ } bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); RTC_DCHECK(info); // Get SSRC and stats for each sender. @@ -2652,15 +2369,14 @@ sinfo.echo_delay_std_ms = stats.echo_delay_std_ms; sinfo.echo_return_loss = stats.echo_return_loss; sinfo.echo_return_loss_enhancement = stats.echo_return_loss_enhancement; - sinfo.typing_noise_detected = typing_noise_detected_; - // TODO(solenberg): Move to AudioSendStream. - // sinfo.typing_noise_detected = stats.typing_noise_detected; + sinfo.typing_noise_detected = + (send_ == SEND_NOTHING ? false : stats.typing_noise_detected); info->senders.push_back(sinfo); } // Get SSRC and stats for each receiver. RTC_DCHECK(info->receivers.size() == 0); - for (const auto& stream : receive_streams_) { + for (const auto& stream : recv_streams_) { webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); VoiceReceiverInfo rinfo; rinfo.add_ssrc(stats.remote_ssrc); @@ -2694,15 +2410,17 @@ return true; } -void WebRtcVoiceMediaChannel::OnError(int error) { - if (send_ == SEND_NOTHING) { +void WebRtcVoiceMediaChannel::SetRawAudioSink( + uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::SetRawAudioSink"; + const auto it = recv_streams_.find(ssrc); + if (it == recv_streams_.end()) { + LOG(LS_WARNING) << "SetRawAudioSink: no recv stream" << ssrc; return; } - if (error == VE_TYPING_NOISE_WARNING) { - typing_noise_detected_ = true; - } else if (error == VE_TYPING_NOISE_OFF_WARNING) { - typing_noise_detected_ = false; - } + it->second->SetRawAudioSink(std::move(sink)); } int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) { @@ -2712,16 +2430,16 @@ } int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - const auto it = receive_channels_.find(ssrc); - if (it != receive_channels_.end()) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + const auto it = recv_streams_.find(ssrc); + if (it != recv_streams_.end()) { return it->second->channel(); } return -1; } int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); const auto it = send_streams_.find(ssrc); if (it != send_streams_.end()) { return it->second->channel(); @@ -2762,7 +2480,7 @@ if (codec.id == red_pt) { // If we find the right codec, that will be the codec we pass to // SetSendCodec, with the desired payload type. - if (engine()->FindWebRtcCodec(codec, send_codec)) { + if (WebRtcVoiceEngine::ToCodecInst(codec, send_codec)) { return true; } else { break; @@ -2786,117 +2504,6 @@ } return true; } - -// Convert VoiceEngine error code into VoiceMediaChannel::Error enum. -VoiceMediaChannel::Error - WebRtcVoiceMediaChannel::WebRtcErrorToChannelError(int err_code) { - switch (err_code) { - case 0: - return ERROR_NONE; - case VE_CANNOT_START_RECORDING: - case VE_MIC_VOL_ERROR: - case VE_GET_MIC_VOL_ERROR: - case VE_CANNOT_ACCESS_MIC_VOL: - return ERROR_REC_DEVICE_OPEN_FAILED; - case VE_SATURATION_WARNING: - return ERROR_REC_DEVICE_SATURATION; - case VE_REC_DEVICE_REMOVED: - return ERROR_REC_DEVICE_REMOVED; - case VE_RUNTIME_REC_WARNING: - case VE_RUNTIME_REC_ERROR: - return ERROR_REC_RUNTIME_ERROR; - case VE_CANNOT_START_PLAYOUT: - case VE_SPEAKER_VOL_ERROR: - case VE_GET_SPEAKER_VOL_ERROR: - case VE_CANNOT_ACCESS_SPEAKER_VOL: - return ERROR_PLAY_DEVICE_OPEN_FAILED; - case VE_RUNTIME_PLAY_WARNING: - case VE_RUNTIME_PLAY_ERROR: - return ERROR_PLAY_RUNTIME_ERROR; - case VE_TYPING_NOISE_WARNING: - return ERROR_REC_TYPING_NOISE_DETECTED; - default: - return VoiceMediaChannel::ERROR_OTHER; - } -} - -bool WebRtcVoiceMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter, - int channel_id, const RtpHeaderExtension* extension) { - bool enable = false; - int id = 0; - std::string uri; - if (extension) { - enable = true; - id = extension->id; - uri = extension->uri; - } - if ((engine()->voe()->rtp()->*setter)(channel_id, enable, id) != 0) { - LOG_RTCERR4(*setter, uri, channel_id, enable, id); - return false; - } - return true; -} - -void WebRtcVoiceMediaChannel::RecreateAudioReceiveStreams() { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - for (const auto& it : receive_channels_) { - RemoveAudioReceiveStream(it.first); - } - for (const auto& it : receive_channels_) { - AddAudioReceiveStream(it.first); - } -} - -void WebRtcVoiceMediaChannel::AddAudioReceiveStream(uint32_t ssrc) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - WebRtcAudioReceiveStream* stream = receive_channels_[ssrc]; - RTC_DCHECK(stream != nullptr); - RTC_DCHECK(receive_streams_.find(ssrc) == receive_streams_.end()); - webrtc::AudioReceiveStream::Config config; - config.rtp.remote_ssrc = ssrc; - // Only add RTP extensions if we support combined A/V BWE. - config.rtp.extensions = recv_rtp_extensions_; - config.combined_audio_video_bwe = - options_.combined_audio_video_bwe.GetWithDefaultIfUnset(false); - config.voe_channel_id = stream->channel(); - config.sync_group = receive_stream_params_[ssrc].sync_label; - webrtc::AudioReceiveStream* s = call_->CreateAudioReceiveStream(config); - receive_streams_.insert(std::make_pair(ssrc, s)); -} - -void WebRtcVoiceMediaChannel::RemoveAudioReceiveStream(uint32_t ssrc) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - auto stream_it = receive_streams_.find(ssrc); - if (stream_it != receive_streams_.end()) { - call_->DestroyAudioReceiveStream(stream_it->second); - receive_streams_.erase(stream_it); - } -} - -bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal( - const std::vector<AudioCodec>& new_codecs) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - for (const AudioCodec& codec : new_codecs) { - webrtc::CodecInst voe_codec; - if (engine()->FindWebRtcCodec(codec, &voe_codec)) { - LOG(LS_INFO) << ToString(codec); - voe_codec.pltype = codec.id; - for (const auto& ch : receive_channels_) { - if (engine()->voe()->codec()->SetRecPayloadType( - ch.second->channel(), voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, ch.second->channel(), - ToString(voe_codec)); - return false; - } - } - } else { - LOG(LS_WARNING) << "Unknown codec " << ToString(codec); - return false; - } - } - return true; -} - } // namespace cricket #endif // HAVE_WEBRTC_VOICE
diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h index 1cf05e7..0f2f59e 100644 --- a/talk/media/webrtc/webrtcvoiceengine.h +++ b/talk/media/webrtc/webrtcvoiceengine.h
@@ -29,7 +29,6 @@ #define TALK_MEDIA_WEBRTCVOICEENGINE_H_ #include <map> -#include <set> #include <string> #include <vector> @@ -37,9 +36,8 @@ #include "talk/media/webrtc/webrtccommon.h" #include "talk/media/webrtc/webrtcvoe.h" #include "talk/session/media/channel.h" +#include "webrtc/audio_state.h" #include "webrtc/base/buffer.h" -#include "webrtc/base/byteorder.h" -#include "webrtc/base/logging.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/stream.h" #include "webrtc/base/thread_checker.h" @@ -51,43 +49,34 @@ class AudioDeviceModule; class AudioRenderer; -class VoETraceWrapper; class VoEWrapper; class WebRtcVoiceMediaChannel; // WebRtcVoiceEngine is a class to be used with CompositeMediaEngine. // It uses the WebRtc VoiceEngine library for audio handling. -class WebRtcVoiceEngine - : public webrtc::VoiceEngineObserver, - public webrtc::TraceCallback { +class WebRtcVoiceEngine final : public webrtc::TraceCallback { friend class WebRtcVoiceMediaChannel; - public: + // Exposed for the WVoE/MC unit test. + static bool ToCodecInst(const AudioCodec& in, webrtc::CodecInst* out); + WebRtcVoiceEngine(); // Dependency injection for testing. - WebRtcVoiceEngine(VoEWrapper* voe_wrapper, VoETraceWrapper* tracing); + explicit WebRtcVoiceEngine(VoEWrapper* voe_wrapper); ~WebRtcVoiceEngine(); bool Init(rtc::Thread* worker_thread); void Terminate(); - webrtc::VoiceEngine* GetVoE() { return voe()->engine(); } + rtc::scoped_refptr<webrtc::AudioState> GetAudioState() const; VoiceMediaChannel* CreateChannel(webrtc::Call* call, const AudioOptions& options); - AudioOptions GetOptions() const { return options_; } - bool SetOptions(const AudioOptions& options); - bool SetDevices(const Device* in_device, const Device* out_device); bool GetOutputVolume(int* level); bool SetOutputVolume(int level); int GetInputLevel(); const std::vector<AudioCodec>& codecs(); - bool FindCodec(const AudioCodec& codec); - bool FindWebRtcCodec(const AudioCodec& codec, webrtc::CodecInst* gcodec); - - const std::vector<RtpHeaderExtension>& rtp_header_extensions() const; - - void SetLogging(int min_sev, const char* filter); + RtpCapabilities GetCapabilities() const; // For tracking WebRtc channels. Needed because we have to pause them // all when switching devices. @@ -120,68 +109,49 @@ private: void Construct(); - void ConstructCodecs(); - bool GetVoeCodec(int index, webrtc::CodecInst* codec); bool InitInternal(); - void SetTraceFilter(int filter); - void SetTraceOptions(const std::string& options); // Every option that is "set" will be applied. Every option not "set" will be // ignored. This allows us to selectively turn on and off different options // easily at any time. bool ApplyOptions(const AudioOptions& options); + void SetDefaultDevices(); // webrtc::TraceCallback: void Print(webrtc::TraceLevel level, const char* trace, int length) override; - // webrtc::VoiceEngineObserver: - void CallbackOnError(int channel_id, int errCode) override; - - // Given the device type, name, and id, find device id. Return true and - // set the output parameter rtc_id if successful. - bool FindWebRtcAudioDeviceId( - bool is_input, const std::string& dev_name, int dev_id, int* rtc_id); - void StartAecDump(const std::string& filename); int CreateVoEChannel(); - static const int kDefaultLogSeverity = rtc::LS_WARNING; + rtc::ThreadChecker signal_thread_checker_; + rtc::ThreadChecker worker_thread_checker_; // The primary instance of WebRtc VoiceEngine. rtc::scoped_ptr<VoEWrapper> voe_wrapper_; - rtc::scoped_ptr<VoETraceWrapper> tracing_; + rtc::scoped_refptr<webrtc::AudioState> audio_state_; // The external audio device manager - webrtc::AudioDeviceModule* adm_; - int log_filter_; - std::string log_options_; - bool is_dumping_aec_; + webrtc::AudioDeviceModule* adm_ = nullptr; std::vector<AudioCodec> codecs_; - std::vector<RtpHeaderExtension> rtp_header_extensions_; std::vector<WebRtcVoiceMediaChannel*> channels_; - // channels_ can be read from WebRtc callback thread. We need a lock on that - // callback as well as the RegisterChannel/UnregisterChannel. - rtc::CriticalSection channels_cs_; - webrtc::AgcConfig default_agc_config_; - webrtc::Config voe_config_; + bool initialized_ = false; + bool is_dumping_aec_ = false; - bool initialized_; - AudioOptions options_; - + webrtc::AgcConfig default_agc_config_; // Cache received extended_filter_aec, delay_agnostic_aec and experimental_ns // values, and apply them in case they are missing in the audio options. We // need to do this because SetExtraOptions() will revert to defaults for // options which are not provided. - Settable<bool> extended_filter_aec_; - Settable<bool> delay_agnostic_aec_; - Settable<bool> experimental_ns_; + rtc::Optional<bool> extended_filter_aec_; + rtc::Optional<bool> delay_agnostic_aec_; + rtc::Optional<bool> experimental_ns_; RTC_DISALLOW_COPY_AND_ASSIGN(WebRtcVoiceEngine); }; // WebRtcVoiceMediaChannel is an implementation of VoiceMediaChannel that uses // WebRtc Voice Engine. -class WebRtcVoiceMediaChannel : public VoiceMediaChannel, - public webrtc::Transport { +class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, + public webrtc::Transport { public: WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine, const AudioOptions& options, @@ -217,7 +187,7 @@ bool SetOutputVolume(uint32_t ssrc, double volume) override; bool CanInsertDtmf() override; - bool InsertDtmf(uint32_t ssrc, int event, int duration, int flags) override; + bool InsertDtmf(uint32_t ssrc, int event, int duration) override; void OnPacketReceived(rtc::Buffer* packet, const rtc::PacketTime& packet_time) override; @@ -226,6 +196,10 @@ void OnReadyToSend(bool ready) override {} bool GetStats(VoiceMediaInfo* info) override; + void SetRawAudioSink( + uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) override; + // implements Transport interface bool SendRtp(const uint8_t* data, size_t len, @@ -243,20 +217,14 @@ return VoiceMediaChannel::SendRtcp(&packet, rtc::PacketOptions()); } - void OnError(int error); - int GetReceiveChannelId(uint32_t ssrc) const; int GetSendChannelId(uint32_t ssrc) const; private: bool SetSendCodecs(const std::vector<AudioCodec>& codecs); - bool SetSendRtpHeaderExtensions( - const std::vector<RtpHeaderExtension>& extensions); bool SetOptions(const AudioOptions& options); bool SetMaxSendBandwidth(int bps); bool SetRecvCodecs(const std::vector<AudioCodec>& codecs); - bool SetRecvRtpHeaderExtensions( - const std::vector<RtpHeaderExtension>& extensions); bool SetLocalRenderer(uint32_t ssrc, AudioRenderer* renderer); bool MuteStream(uint32_t ssrc, bool mute); @@ -267,82 +235,55 @@ const std::vector<AudioCodec>& all_codecs, webrtc::CodecInst* send_codec); bool SetPlayout(int channel, bool playout); - static Error WebRtcErrorToChannelError(int err_code); - - typedef int (webrtc::VoERTP_RTCP::* ExtensionSetterFunction)(int, bool, - unsigned char); - void SetNack(int channel, bool nack_enabled); bool SetSendCodec(int channel, const webrtc::CodecInst& send_codec); bool ChangePlayout(bool playout); bool ChangeSend(SendFlags send); bool ChangeSend(int channel, SendFlags send); - bool ConfigureRecvChannel(int channel); int CreateVoEChannel(); - bool DeleteChannel(int channel); + bool DeleteVoEChannel(int channel); bool IsDefaultRecvStream(uint32_t ssrc) { return default_recv_ssrc_ == static_cast<int64_t>(ssrc); } bool SetSendCodecs(int channel, const std::vector<AudioCodec>& codecs); bool SetSendBitrateInternal(int bps); - bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id, - const RtpHeaderExtension* extension); - void RecreateAudioReceiveStreams(); - void AddAudioReceiveStream(uint32_t ssrc); - void RemoveAudioReceiveStream(uint32_t ssrc); - bool SetRecvCodecsInternal(const std::vector<AudioCodec>& new_codecs); + rtc::ThreadChecker worker_thread_checker_; - bool SetChannelRecvRtpHeaderExtensions( - int channel_id, - const std::vector<RtpHeaderExtension>& extensions); - bool SetChannelSendRtpHeaderExtensions( - int channel_id, - const std::vector<RtpHeaderExtension>& extensions); - - rtc::ThreadChecker thread_checker_; - - WebRtcVoiceEngine* const engine_; + WebRtcVoiceEngine* const engine_ = nullptr; std::vector<AudioCodec> recv_codecs_; std::vector<AudioCodec> send_codecs_; rtc::scoped_ptr<webrtc::CodecInst> send_codec_; - bool send_bitrate_setting_; - int send_bitrate_bps_; + bool send_bitrate_setting_ = false; + int send_bitrate_bps_ = 0; AudioOptions options_; - bool dtmf_allowed_; - bool desired_playout_; - bool nack_enabled_; - bool playout_; - bool typing_noise_detected_; - SendFlags desired_send_; - SendFlags send_; - webrtc::Call* const call_; + rtc::Optional<int> dtmf_payload_type_; + bool desired_playout_ = false; + bool nack_enabled_ = false; + bool playout_ = false; + SendFlags desired_send_ = SEND_NOTHING; + SendFlags send_ = SEND_NOTHING; + webrtc::Call* const call_ = nullptr; // SSRC of unsignalled receive stream, or -1 if there isn't one. int64_t default_recv_ssrc_ = -1; // Volume for unsignalled stream, which may be set before the stream exists. double default_recv_volume_ = 1.0; - // SSRC to use for RTCP receiver reports; default to 1 in case of no signaled + // Default SSRC to use for RTCP receiver reports in case of no signaled // send streams. See: https://code.google.com/p/webrtc/issues/detail?id=4740 - uint32_t receiver_reports_ssrc_ = 1; + // and https://code.google.com/p/chromium/issues/detail?id=547661 + uint32_t receiver_reports_ssrc_ = 0xFA17FA17u; class WebRtcAudioSendStream; std::map<uint32_t, WebRtcAudioSendStream*> send_streams_; - std::vector<RtpHeaderExtension> send_extensions_; + std::vector<webrtc::RtpExtension> send_rtp_extensions_; class WebRtcAudioReceiveStream; - std::map<uint32_t, WebRtcAudioReceiveStream*> receive_channels_; - std::map<uint32_t, webrtc::AudioReceiveStream*> receive_streams_; - std::map<uint32_t, StreamParams> receive_stream_params_; - // receive_channels_ can be read from WebRtc callback thread. Access from - // the WebRtc thread must be synchronized with edits on the worker thread. - // Reads on the worker thread are ok. - std::vector<RtpHeaderExtension> receive_extensions_; + std::map<uint32_t, WebRtcAudioReceiveStream*> recv_streams_; std::vector<webrtc::RtpExtension> recv_rtp_extensions_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcVoiceMediaChannel); }; - } // namespace cricket #endif // TALK_MEDIA_WEBRTCVOICEENGINE_H_
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index ce5115c..a62bcb2 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -25,6 +25,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "webrtc/base/arraysize.h" #include "webrtc/base/byteorder.h" #include "webrtc/base/gunit.h" #include "webrtc/call.h" @@ -53,10 +54,6 @@ const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1, 0); const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000, 0, 1, 0); -const cricket::AudioCodec* const kAudioCodecs[] = { - &kPcmuCodec, &kIsacCodec, &kOpusCodec, &kG722CodecVoE, &kRedCodec, - &kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec, -}; const uint32_t kSsrc1 = 0x99; const uint32_t kSsrc2 = 0x98; const uint32_t kSsrcs4[] = { 1, 2, 3, 4 }; @@ -67,37 +64,22 @@ : cricket::VoEWrapper(engine, // processing engine, // base engine, // codec - engine, // dtmf engine, // hw engine, // network engine, // rtp engine) { // volume } }; - -class FakeVoETraceWrapper : public cricket::VoETraceWrapper { - public: - int SetTraceFilter(const unsigned int filter) override { - filter_ = filter; - return 0; - } - int SetTraceFile(const char* fileNameUTF8) override { return 0; } - int SetTraceCallback(webrtc::TraceCallback* callback) override { return 0; } - unsigned int filter_; -}; } // namespace class WebRtcVoiceEngineTestFake : public testing::Test { public: WebRtcVoiceEngineTestFake() : call_(webrtc::Call::Config()), - voe_(kAudioCodecs, ARRAY_SIZE(kAudioCodecs)), - trace_wrapper_(new FakeVoETraceWrapper()), - engine_(new FakeVoEWrapper(&voe_), trace_wrapper_), + engine_(new FakeVoEWrapper(&voe_)), channel_(nullptr) { send_parameters_.codecs.push_back(kPcmuCodec); recv_parameters_.codecs.push_back(kPcmuCodec); - options_adjust_agc_.adjust_agc_delta.Set(-10); } bool SetupEngine() { if (!engine_.Init(rtc::Thread::Current())) { @@ -123,12 +105,10 @@ void SetupForMultiSendStream() { EXPECT_TRUE(SetupEngineWithSendStream()); // Remove stream added in Setup. - int default_channel_num = voe_.GetLastChannel(); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(default_channel_num)); + EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1)); EXPECT_TRUE(channel_->RemoveSendStream(kSsrc1)); - // Verify the channel does not exist. - EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(kSsrc1)); + EXPECT_FALSE(call_.GetAudioSendStream(kSsrc1)); } void DeliverPacket(const void* data, int len) { rtc::Buffer packet(reinterpret_cast<const uint8_t*>(data), len); @@ -139,6 +119,24 @@ engine_.Terminate(); } + const cricket::FakeAudioSendStream& GetSendStream(uint32_t ssrc) { + const auto* send_stream = call_.GetAudioSendStream(ssrc); + EXPECT_TRUE(send_stream); + return *send_stream; + } + + const webrtc::AudioSendStream::Config& GetSendStreamConfig(uint32_t ssrc) { + const auto* send_stream = call_.GetAudioSendStream(ssrc); + EXPECT_TRUE(send_stream); + return send_stream->GetConfig(); + } + + const webrtc::AudioReceiveStream::Config& GetRecvStreamConfig(uint32_t ssrc) { + const auto* recv_stream = call_.GetAudioReceiveStream(ssrc); + EXPECT_TRUE(recv_stream); + return recv_stream->GetConfig(); + } + void TestInsertDtmf(uint32_t ssrc, bool caller) { EXPECT_TRUE(engine_.Init(rtc::Thread::Current())); channel_ = engine_.CreateChannel(&call_, cricket::AudioOptions()); @@ -154,39 +152,30 @@ EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE)); EXPECT_FALSE(channel_->CanInsertDtmf()); - EXPECT_FALSE(channel_->InsertDtmf(ssrc, 1, 111, cricket::DF_SEND)); + EXPECT_FALSE(channel_->InsertDtmf(ssrc, 1, 111)); send_parameters_.codecs.push_back(kTelephoneEventCodec); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); EXPECT_TRUE(channel_->CanInsertDtmf()); if (!caller) { // If this is callee, there's no active send channel yet. - EXPECT_FALSE(channel_->InsertDtmf(ssrc, 2, 123, cricket::DF_SEND)); + EXPECT_FALSE(channel_->InsertDtmf(ssrc, 2, 123)); EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(kSsrc1))); } // Check we fail if the ssrc is invalid. - EXPECT_FALSE(channel_->InsertDtmf(-1, 1, 111, cricket::DF_SEND)); + EXPECT_FALSE(channel_->InsertDtmf(-1, 1, 111)); - // Test send - int channel_id = voe_.GetLastChannel(); - EXPECT_FALSE(voe_.WasSendTelephoneEventCalled(channel_id, 2, 123)); - EXPECT_TRUE(channel_->InsertDtmf(ssrc, 2, 123, cricket::DF_SEND)); - EXPECT_TRUE(voe_.WasSendTelephoneEventCalled(channel_id, 2, 123)); - - // Test play - EXPECT_FALSE(voe_.WasPlayDtmfToneCalled(3, 134)); - EXPECT_TRUE(channel_->InsertDtmf(ssrc, 3, 134, cricket::DF_PLAY)); - EXPECT_TRUE(voe_.WasPlayDtmfToneCalled(3, 134)); - - // Test send and play - EXPECT_FALSE(voe_.WasSendTelephoneEventCalled(channel_id, 4, 145)); - EXPECT_FALSE(voe_.WasPlayDtmfToneCalled(4, 145)); - EXPECT_TRUE(channel_->InsertDtmf(ssrc, 4, 145, - cricket::DF_PLAY | cricket::DF_SEND)); - EXPECT_TRUE(voe_.WasSendTelephoneEventCalled(channel_id, 4, 145)); - EXPECT_TRUE(voe_.WasPlayDtmfToneCalled(4, 145)); + // Test send. + cricket::FakeAudioSendStream::TelephoneEvent telephone_event = + GetSendStream(kSsrc1).GetLatestTelephoneEvent(); + EXPECT_EQ(-1, telephone_event.payload_type); + EXPECT_TRUE(channel_->InsertDtmf(ssrc, 2, 123)); + telephone_event = GetSendStream(kSsrc1).GetLatestTelephoneEvent(); + EXPECT_EQ(kTelephoneEventCodec.id, telephone_event.payload_type); + EXPECT_EQ(2, telephone_event.event_code); + EXPECT_EQ(123, telephone_event.duration_ms); } // Test that send bandwidth is set correctly. @@ -211,81 +200,85 @@ void TestSetSendRtpHeaderExtensions(const std::string& ext) { EXPECT_TRUE(SetupEngineWithSendStream()); - int channel_num = voe_.GetLastChannel(); // Ensure extensions are off by default. - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure unknown extensions won't cause an error. send_parameters_.extensions.push_back(cricket::RtpHeaderExtension( "urn:ietf:params:unknownextention", 1)); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extensions stay off with an empty list of headers. send_parameters_.extensions.clear(); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extension is set properly. const int id = 1; send_parameters_.extensions.push_back(cricket::RtpHeaderExtension(ext, id)); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(id, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(1u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); + EXPECT_EQ(ext, GetSendStreamConfig(kSsrc1).rtp.extensions[0].name); + EXPECT_EQ(id, GetSendStreamConfig(kSsrc1).rtp.extensions[0].id); - // Ensure extension is set properly on new channels. + // Ensure extension is set properly on new stream. EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(kSsrc2))); - int new_channel_num = voe_.GetLastChannel(); - EXPECT_NE(channel_num, new_channel_num); - EXPECT_EQ(id, voe_.GetSendRtpExtensionId(new_channel_num, ext)); + EXPECT_NE(call_.GetAudioSendStream(kSsrc1), + call_.GetAudioSendStream(kSsrc2)); + EXPECT_EQ(1u, GetSendStreamConfig(kSsrc2).rtp.extensions.size()); + EXPECT_EQ(ext, GetSendStreamConfig(kSsrc2).rtp.extensions[0].name); + EXPECT_EQ(id, GetSendStreamConfig(kSsrc2).rtp.extensions[0].id); // Ensure all extensions go back off with an empty list. send_parameters_.codecs.push_back(kPcmuCodec); send_parameters_.extensions.clear(); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(new_channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc2).rtp.extensions.size()); } void TestSetRecvRtpHeaderExtensions(const std::string& ext) { EXPECT_TRUE(SetupEngineWithRecvStream()); - int channel_num = voe_.GetLastChannel(); // Ensure extensions are off by default. - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); - cricket::AudioRecvParameters parameters; // Ensure unknown extensions won't cause an error. - parameters.extensions.push_back(cricket::RtpHeaderExtension( + recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension( "urn:ietf:params:unknownextention", 1)); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extensions stay off with an empty list of headers. - parameters.extensions.clear(); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + recv_parameters_.extensions.clear(); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extension is set properly. const int id = 2; - parameters.extensions.push_back(cricket::RtpHeaderExtension(ext, id)); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension(ext, id)); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); + EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].name); + EXPECT_EQ(id, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].id); - // Ensure extension is set properly on new channel. - // The first stream to occupy the default channel. + // Ensure extension is set properly on new stream. EXPECT_TRUE(channel_->AddRecvStream( cricket::StreamParams::CreateLegacy(kSsrc2))); - int new_channel_num = voe_.GetLastChannel(); - EXPECT_NE(channel_num, new_channel_num); - EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(new_channel_num, ext)); + EXPECT_NE(call_.GetAudioReceiveStream(kSsrc1), + call_.GetAudioReceiveStream(kSsrc2)); + EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size()); + EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].name); + EXPECT_EQ(id, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].id); // Ensure all extensions go back off with an empty list. - parameters.extensions.clear(); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(new_channel_num, ext)); + recv_parameters_.extensions.clear(); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size()); } webrtc::AudioSendStream::Stats GetAudioSendStreamStats() const { @@ -313,7 +306,8 @@ s->SetStats(GetAudioSendStreamStats()); } } - void VerifyVoiceSenderInfo(const cricket::VoiceSenderInfo& info) { + void VerifyVoiceSenderInfo(const cricket::VoiceSenderInfo& info, + bool is_sending) { const auto stats = GetAudioSendStreamStats(); EXPECT_EQ(info.ssrc(), stats.local_ssrc); EXPECT_EQ(info.bytes_sent, stats.bytes_sent); @@ -331,8 +325,8 @@ EXPECT_EQ(info.echo_return_loss, stats.echo_return_loss); EXPECT_EQ(info.echo_return_loss_enhancement, stats.echo_return_loss_enhancement); - // TODO(solenberg): Move typing noise detection into AudioSendStream. - // EXPECT_EQ(info.typing_noise_detected, stats.typing_noise_detected); + EXPECT_EQ(info.typing_noise_detected, + stats.typing_noise_detected && is_sending); } webrtc::AudioReceiveStream::Stats GetAudioReceiveStreamStats() const { @@ -401,13 +395,10 @@ protected: cricket::FakeCall call_; cricket::FakeWebRtcVoiceEngine voe_; - FakeVoETraceWrapper* trace_wrapper_; cricket::WebRtcVoiceEngine engine_; cricket::VoiceMediaChannel* channel_; - cricket::AudioSendParameters send_parameters_; cricket::AudioRecvParameters recv_parameters_; - cricket::AudioOptions options_adjust_agc_; }; // Tests that our stub library "works". @@ -448,32 +439,33 @@ cricket::AudioCodec codec; webrtc::CodecInst codec_inst; // Find PCMU with explicit clockrate and bitrate. - EXPECT_TRUE(engine_.FindWebRtcCodec(kPcmuCodec, &codec_inst)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kPcmuCodec, &codec_inst)); // Find ISAC with explicit clockrate and 0 bitrate. - EXPECT_TRUE(engine_.FindWebRtcCodec(kIsacCodec, &codec_inst)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kIsacCodec, &codec_inst)); // Find telephone-event with explicit clockrate and 0 bitrate. - EXPECT_TRUE(engine_.FindWebRtcCodec(kTelephoneEventCodec, &codec_inst)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kTelephoneEventCodec, + &codec_inst)); // Find ISAC with a different payload id. codec = kIsacCodec; codec.id = 127; - EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst)); EXPECT_EQ(codec.id, codec_inst.pltype); // Find PCMU with a 0 clockrate. codec = kPcmuCodec; codec.clockrate = 0; - EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst)); EXPECT_EQ(codec.id, codec_inst.pltype); EXPECT_EQ(8000, codec_inst.plfreq); // Find PCMU with a 0 bitrate. codec = kPcmuCodec; codec.bitrate = 0; - EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst)); EXPECT_EQ(codec.id, codec_inst.pltype); EXPECT_EQ(64000, codec_inst.rate); // Find ISAC with an explicit bitrate. codec = kIsacCodec; codec.bitrate = 32000; - EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst)); EXPECT_EQ(codec.id, codec_inst.pltype); EXPECT_EQ(32000, codec_inst.rate); } @@ -492,14 +484,13 @@ cricket::StreamParams::CreateLegacy(kSsrc1))); int channel_num = voe_.GetLastChannel(); webrtc::CodecInst gcodec; - rtc::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), "ISAC"); + rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "ISAC"); gcodec.plfreq = 16000; gcodec.channels = 1; EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num, gcodec)); EXPECT_EQ(106, gcodec.pltype); EXPECT_STREQ("ISAC", gcodec.plname); - rtc::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), - "telephone-event"); + rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "telephone-event"); gcodec.plfreq = 8000; EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num, gcodec)); EXPECT_EQ(126, gcodec.pltype); @@ -537,7 +528,7 @@ cricket::StreamParams::CreateLegacy(kSsrc1))); int channel_num = voe_.GetLastChannel(); webrtc::CodecInst opus; - engine_.FindWebRtcCodec(kOpusCodec, &opus); + cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus); // Even without stereo parameters, recv codecs still specify channels = 2. EXPECT_EQ(2, opus.channels); EXPECT_EQ(111, opus.pltype); @@ -560,7 +551,7 @@ cricket::StreamParams::CreateLegacy(kSsrc1))); int channel_num2 = voe_.GetLastChannel(); webrtc::CodecInst opus; - engine_.FindWebRtcCodec(kOpusCodec, &opus); + cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus); // Even when stereo is off, recv codecs still specify channels = 2. EXPECT_EQ(2, opus.channels); EXPECT_EQ(111, opus.pltype); @@ -583,7 +574,7 @@ cricket::StreamParams::CreateLegacy(kSsrc1))); int channel_num2 = voe_.GetLastChannel(); webrtc::CodecInst opus; - engine_.FindWebRtcCodec(kOpusCodec, &opus); + cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus); EXPECT_EQ(2, opus.channels); EXPECT_EQ(111, opus.pltype); EXPECT_STREQ("opus", opus.plname); @@ -606,14 +597,13 @@ cricket::StreamParams::CreateLegacy(kSsrc1))); int channel_num2 = voe_.GetLastChannel(); webrtc::CodecInst gcodec; - rtc::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), "ISAC"); + rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "ISAC"); gcodec.plfreq = 16000; gcodec.channels = 1; EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec)); EXPECT_EQ(106, gcodec.pltype); EXPECT_STREQ("ISAC", gcodec.plname); - rtc::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), - "telephone-event"); + rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "telephone-event"); gcodec.plfreq = 8000; gcodec.channels = 1; EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec)); @@ -630,7 +620,7 @@ int channel_num2 = voe_.GetLastChannel(); webrtc::CodecInst gcodec; - rtc::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), "ISAC"); + rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "ISAC"); gcodec.plfreq = 16000; gcodec.channels = 1; EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec)); @@ -669,7 +659,7 @@ int channel_num = voe_.GetLastChannel(); EXPECT_TRUE(voe_.GetPlayout(channel_num)); webrtc::CodecInst gcodec; - EXPECT_TRUE(engine_.FindWebRtcCodec(kOpusCodec, &gcodec)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &gcodec)); EXPECT_EQ(kOpusCodec.id, gcodec.pltype); } @@ -782,7 +772,7 @@ EXPECT_FALSE(voe_.GetRED(channel_num)); EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false)); EXPECT_EQ(105, voe_.GetSendCNPayloadType(channel_num, true)); - EXPECT_EQ(106, voe_.GetSendTelephoneEventPayloadType(channel_num)); + EXPECT_FALSE(channel_->CanInsertDtmf()); } // Test that VoE Channel doesn't call SetSendCodec again if same codec is tried @@ -1623,7 +1613,7 @@ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec)); EXPECT_EQ(96, gcodec.pltype); EXPECT_STREQ("ISAC", gcodec.plname); - EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num)); + EXPECT_TRUE(channel_->CanInsertDtmf()); } // Test that we can set send codecs even with CN codec as the first @@ -1669,7 +1659,7 @@ EXPECT_FALSE(voe_.GetRED(channel_num)); EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false)); EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true)); - EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num)); + EXPECT_TRUE(channel_->CanInsertDtmf()); } // Test that we set VAD and DTMF types correctly as callee. @@ -1702,7 +1692,7 @@ EXPECT_FALSE(voe_.GetRED(channel_num)); EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false)); EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true)); - EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num)); + EXPECT_TRUE(channel_->CanInsertDtmf()); } // Test that we only apply VAD if we have a CN codec that matches the @@ -1766,7 +1756,7 @@ EXPECT_FALSE(voe_.GetRED(channel_num)); EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false)); EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true)); - EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num)); + EXPECT_TRUE(channel_->CanInsertDtmf()); } // Test that we set up RED correctly as caller. @@ -1976,21 +1966,16 @@ for (uint32_t ssrc : kSsrcs4) { EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(ssrc))); - EXPECT_NE(nullptr, call_.GetAudioSendStream(ssrc)); - // Verify that we are in a sending state for all the created streams. - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); - EXPECT_TRUE(voe_.GetSend(channel_num)); + EXPECT_TRUE(voe_.GetSend(GetSendStreamConfig(ssrc).voe_channel_id)); } - EXPECT_EQ(ARRAY_SIZE(kSsrcs4), call_.GetAudioSendStreams().size()); + EXPECT_EQ(arraysize(kSsrcs4), call_.GetAudioSendStreams().size()); // Delete the send streams. for (uint32_t ssrc : kSsrcs4) { EXPECT_TRUE(channel_->RemoveSendStream(ssrc)); - EXPECT_EQ(nullptr, call_.GetAudioSendStream(ssrc)); - // Stream should already be deleted. + EXPECT_FALSE(call_.GetAudioSendStream(ssrc)); EXPECT_FALSE(channel_->RemoveSendStream(ssrc)); - EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(ssrc)); } EXPECT_EQ(0u, call_.GetAudioSendStreams().size()); } @@ -2015,7 +2000,7 @@ // Verify ISAC and VAD are corrected configured on all send channels. webrtc::CodecInst gcodec; for (uint32_t ssrc : kSsrcs4) { - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec)); EXPECT_STREQ("ISAC", gcodec.plname); EXPECT_TRUE(voe_.GetVAD(channel_num)); @@ -2026,7 +2011,7 @@ parameters.codecs[0] = kPcmuCodec; EXPECT_TRUE(channel_->SetSendParameters(parameters)); for (uint32_t ssrc : kSsrcs4) { - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec)); EXPECT_STREQ("PCMU", gcodec.plname); EXPECT_FALSE(voe_.GetVAD(channel_num)); @@ -2049,7 +2034,7 @@ EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE)); for (uint32_t ssrc : kSsrcs4) { // Verify that we are in a sending state for all the send streams. - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_TRUE(voe_.GetSend(channel_num)); } @@ -2057,7 +2042,7 @@ EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING)); for (uint32_t ssrc : kSsrcs4) { // Verify that we are in a stop state for all the send streams. - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_FALSE(voe_.GetSend(channel_num)); } } @@ -2087,9 +2072,9 @@ EXPECT_EQ(true, channel_->GetStats(&info)); // We have added 4 send streams. We should see empty stats for all. - EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size()); + EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size()); for (const auto& sender : info.senders) { - VerifyVoiceSenderInfo(sender); + VerifyVoiceSenderInfo(sender, false); } // We have added one receive stream. We should see empty stats. @@ -2102,7 +2087,7 @@ cricket::VoiceMediaInfo info; EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2)); EXPECT_EQ(true, channel_->GetStats(&info)); - EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size()); + EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size()); EXPECT_EQ(0u, info.receivers.size()); } @@ -2113,7 +2098,7 @@ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame)); SetAudioReceiveStreamStats(); EXPECT_EQ(true, channel_->GetStats(&info)); - EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size()); + EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size()); EXPECT_EQ(1u, info.receivers.size()); VerifyVoiceReceiverInfo(info.receivers[0]); } @@ -2173,96 +2158,17 @@ EXPECT_FALSE(voe_.GetPlayout(channel_num1)); } -// Test that we can set the devices to use. -TEST_F(WebRtcVoiceEngineTestFake, SetDevices) { - EXPECT_TRUE(SetupEngineWithSendStream()); - int send_channel = voe_.GetLastChannel(); - EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2))); - int recv_channel = voe_.GetLastChannel(); - EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - - cricket::Device default_dev(cricket::kFakeDefaultDeviceName, - cricket::kFakeDefaultDeviceId); - cricket::Device dev(cricket::kFakeDeviceName, - cricket::kFakeDeviceId); - - // Test SetDevices() while not sending or playing. - EXPECT_TRUE(engine_.SetDevices(&default_dev, &default_dev)); - - // Test SetDevices() while sending and playing. - EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE)); - EXPECT_TRUE(channel_->SetPlayout(true)); - EXPECT_TRUE(voe_.GetSend(send_channel)); - EXPECT_TRUE(voe_.GetPlayout(recv_channel)); - - EXPECT_TRUE(engine_.SetDevices(&dev, &dev)); - - EXPECT_TRUE(voe_.GetSend(send_channel)); - EXPECT_TRUE(voe_.GetPlayout(recv_channel)); - - // Test that failure to open newly selected devices does not prevent opening - // ones after that. - voe_.set_playout_fail_channel(recv_channel); - voe_.set_send_fail_channel(send_channel); - - EXPECT_FALSE(engine_.SetDevices(&default_dev, &default_dev)); - - EXPECT_FALSE(voe_.GetSend(send_channel)); - EXPECT_FALSE(voe_.GetPlayout(recv_channel)); - - voe_.set_playout_fail_channel(-1); - voe_.set_send_fail_channel(-1); - - EXPECT_TRUE(engine_.SetDevices(&dev, &dev)); - - EXPECT_TRUE(voe_.GetSend(send_channel)); - EXPECT_TRUE(voe_.GetPlayout(recv_channel)); -} - -// Test that we can set the devices to use even if we failed to -// open the initial ones. -TEST_F(WebRtcVoiceEngineTestFake, SetDevicesWithInitiallyBadDevices) { - EXPECT_TRUE(SetupEngineWithSendStream()); - int send_channel = voe_.GetLastChannel(); - EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2))); - int recv_channel = voe_.GetLastChannel(); - EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - - cricket::Device default_dev(cricket::kFakeDefaultDeviceName, - cricket::kFakeDefaultDeviceId); - cricket::Device dev(cricket::kFakeDeviceName, - cricket::kFakeDeviceId); - - // Test that failure to open devices selected before starting - // send/play does not prevent opening newly selected ones after that. - voe_.set_playout_fail_channel(recv_channel); - voe_.set_send_fail_channel(send_channel); - - EXPECT_TRUE(engine_.SetDevices(&default_dev, &default_dev)); - - EXPECT_FALSE(channel_->SetSend(cricket::SEND_MICROPHONE)); - EXPECT_FALSE(channel_->SetPlayout(true)); - EXPECT_FALSE(voe_.GetSend(send_channel)); - EXPECT_FALSE(voe_.GetPlayout(recv_channel)); - - voe_.set_playout_fail_channel(-1); - voe_.set_send_fail_channel(-1); - - EXPECT_TRUE(engine_.SetDevices(&dev, &dev)); - - EXPECT_TRUE(voe_.GetSend(send_channel)); - EXPECT_TRUE(voe_.GetPlayout(recv_channel)); -} - // Test that we can create a channel configured for Codian bridges, // and start sending on it. TEST_F(WebRtcVoiceEngineTestFake, CodianSend) { EXPECT_TRUE(SetupEngineWithSendStream()); + cricket::AudioOptions options_adjust_agc; + options_adjust_agc.adjust_agc_delta = rtc::Optional<int>(-10); int channel_num = voe_.GetLastChannel(); webrtc::AgcConfig agc_config; EXPECT_EQ(0, voe_.GetAgcConfig(agc_config)); EXPECT_EQ(0, agc_config.targetLeveldBOv); - send_parameters_.options = options_adjust_agc_; + send_parameters_.options = options_adjust_agc; EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE)); EXPECT_TRUE(voe_.GetSend(channel_num)); @@ -2271,7 +2177,6 @@ EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING)); EXPECT_FALSE(voe_.GetSend(channel_num)); EXPECT_EQ(0, voe_.GetAgcConfig(agc_config)); - EXPECT_EQ(0, agc_config.targetLeveldBOv); // level was restored } TEST_F(WebRtcVoiceEngineTestFake, TxAgcConfigViaOptions) { @@ -2279,14 +2184,12 @@ webrtc::AgcConfig agc_config; EXPECT_EQ(0, voe_.GetAgcConfig(agc_config)); EXPECT_EQ(0, agc_config.targetLeveldBOv); - - cricket::AudioOptions options; - options.tx_agc_target_dbov.Set(3); - options.tx_agc_digital_compression_gain.Set(9); - options.tx_agc_limiter.Set(true); - options.auto_gain_control.Set(true); - EXPECT_TRUE(engine_.SetOptions(options)); - + send_parameters_.options.tx_agc_target_dbov = rtc::Optional<uint16_t>(3); + send_parameters_.options.tx_agc_digital_compression_gain = + rtc::Optional<uint16_t>(9); + send_parameters_.options.tx_agc_limiter = rtc::Optional<bool>(true); + send_parameters_.options.auto_gain_control = rtc::Optional<bool>(true); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); EXPECT_EQ(0, voe_.GetAgcConfig(agc_config)); EXPECT_EQ(3, agc_config.targetLeveldBOv); EXPECT_EQ(9, agc_config.digitalCompressionGaindB); @@ -2294,19 +2197,18 @@ // Check interaction with adjust_agc_delta. Both should be respected, for // backwards compatibility. - options.adjust_agc_delta.Set(-10); - EXPECT_TRUE(engine_.SetOptions(options)); - + send_parameters_.options.adjust_agc_delta = rtc::Optional<int>(-10); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); EXPECT_EQ(0, voe_.GetAgcConfig(agc_config)); EXPECT_EQ(13, agc_config.targetLeveldBOv); } TEST_F(WebRtcVoiceEngineTestFake, SampleRatesViaOptions) { EXPECT_TRUE(SetupEngineWithSendStream()); - cricket::AudioOptions options; - options.recording_sample_rate.Set(48000u); - options.playout_sample_rate.Set(44100u); - EXPECT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.recording_sample_rate = + rtc::Optional<uint32_t>(48000); + send_parameters_.options.playout_sample_rate = rtc::Optional<uint32_t>(44100); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); unsigned int recording_sample_rate, playout_sample_rate; EXPECT_EQ(0, voe_.RecordingSampleRate(&recording_sample_rate)); @@ -2315,30 +2217,11 @@ EXPECT_EQ(44100u, playout_sample_rate); } -TEST_F(WebRtcVoiceEngineTestFake, TraceFilterViaTraceOptions) { - EXPECT_TRUE(SetupEngineWithSendStream()); - engine_.SetLogging(rtc::LS_INFO, ""); - EXPECT_EQ( - // Info: - webrtc::kTraceStateInfo | webrtc::kTraceInfo | - // Warning: - webrtc::kTraceTerseInfo | webrtc::kTraceWarning | - // Error: - webrtc::kTraceError | webrtc::kTraceCritical, - static_cast<int>(trace_wrapper_->filter_)); - // Now set it explicitly - std::string filter = - "tracefilter " + rtc::ToString(webrtc::kTraceDefault); - engine_.SetLogging(rtc::LS_VERBOSE, filter.c_str()); - EXPECT_EQ(static_cast<unsigned int>(webrtc::kTraceDefault), - trace_wrapper_->filter_); -} - // Test that we can set the outgoing SSRC properly. // SSRC is set in SetupEngine by calling AddSendStream. TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) { EXPECT_TRUE(SetupEngineWithSendStream()); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel())); + EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1)); } TEST_F(WebRtcVoiceEngineTestFake, GetStats) { @@ -2359,12 +2242,20 @@ // We have added one send stream. We should see the stats we've set. EXPECT_EQ(1u, info.senders.size()); - VerifyVoiceSenderInfo(info.senders[0]); + VerifyVoiceSenderInfo(info.senders[0], false); // We have added one receive stream. We should see empty stats. EXPECT_EQ(info.receivers.size(), 1u); EXPECT_EQ(info.receivers[0].ssrc(), 0); } + // Start sending - this affects some reported stats. + { + cricket::VoiceMediaInfo info; + EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE)); + EXPECT_EQ(true, channel_->GetStats(&info)); + VerifyVoiceSenderInfo(info.senders[0], true); + } + // Remove the kSsrc2 stream. No receiver stats. { cricket::VoiceMediaInfo info; @@ -2391,9 +2282,10 @@ // SSRC is set in SetupEngine by calling AddSendStream. TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) { EXPECT_TRUE(SetupEngineWithSendStream()); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel())); - EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2))); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel())); + EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1)); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(kSsrc2))); + EXPECT_EQ(kSsrc1, GetRecvStreamConfig(kSsrc2).rtp.local_ssrc); } // Test that the local SSRC is the same on sending and receiving channels if the @@ -2406,25 +2298,23 @@ int receive_channel_num = voe_.GetLastChannel(); EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(1234))); - int send_channel_num = voe_.GetLastChannel(); - EXPECT_EQ(1234U, voe_.GetLocalSSRC(send_channel_num)); + EXPECT_TRUE(call_.GetAudioSendStream(1234)); EXPECT_EQ(1234U, voe_.GetLocalSSRC(receive_channel_num)); } // Test that we can properly receive packets. TEST_F(WebRtcVoiceEngineTestFake, Recv) { EXPECT_TRUE(SetupEngine()); + EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1))); DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame)); int channel_num = voe_.GetLastChannel(); - EXPECT_TRUE(voe_.CheckPacket(channel_num, kPcmuFrame, - sizeof(kPcmuFrame))); + EXPECT_TRUE(voe_.CheckPacket(channel_num, kPcmuFrame, sizeof(kPcmuFrame))); } // Test that we can properly receive packets on multiple streams. TEST_F(WebRtcVoiceEngineTestFake, RecvWithMultipleStreams) { - EXPECT_TRUE(SetupEngineWithSendStream()); - EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); + EXPECT_TRUE(SetupEngine()); EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1))); int channel_num1 = voe_.GetLastChannel(); EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2))); @@ -2433,37 +2323,97 @@ int channel_num3 = voe_.GetLastChannel(); // Create packets with the right SSRCs. char packets[4][sizeof(kPcmuFrame)]; - for (size_t i = 0; i < ARRAY_SIZE(packets); ++i) { + for (size_t i = 0; i < arraysize(packets); ++i) { memcpy(packets[i], kPcmuFrame, sizeof(kPcmuFrame)); rtc::SetBE32(packets[i] + 8, static_cast<uint32_t>(i)); } EXPECT_TRUE(voe_.CheckNoPacket(channel_num1)); EXPECT_TRUE(voe_.CheckNoPacket(channel_num2)); EXPECT_TRUE(voe_.CheckNoPacket(channel_num3)); + DeliverPacket(packets[0], sizeof(packets[0])); EXPECT_TRUE(voe_.CheckNoPacket(channel_num1)); EXPECT_TRUE(voe_.CheckNoPacket(channel_num2)); EXPECT_TRUE(voe_.CheckNoPacket(channel_num3)); + DeliverPacket(packets[1], sizeof(packets[1])); - EXPECT_TRUE(voe_.CheckPacket(channel_num1, packets[1], - sizeof(packets[1]))); + EXPECT_TRUE(voe_.CheckPacket(channel_num1, packets[1], sizeof(packets[1]))); EXPECT_TRUE(voe_.CheckNoPacket(channel_num2)); EXPECT_TRUE(voe_.CheckNoPacket(channel_num3)); + DeliverPacket(packets[2], sizeof(packets[2])); EXPECT_TRUE(voe_.CheckNoPacket(channel_num1)); - EXPECT_TRUE(voe_.CheckPacket(channel_num2, packets[2], - sizeof(packets[2]))); + EXPECT_TRUE(voe_.CheckPacket(channel_num2, packets[2], sizeof(packets[2]))); EXPECT_TRUE(voe_.CheckNoPacket(channel_num3)); + DeliverPacket(packets[3], sizeof(packets[3])); EXPECT_TRUE(voe_.CheckNoPacket(channel_num1)); EXPECT_TRUE(voe_.CheckNoPacket(channel_num2)); - EXPECT_TRUE(voe_.CheckPacket(channel_num3, packets[3], - sizeof(packets[3]))); + EXPECT_TRUE(voe_.CheckPacket(channel_num3, packets[3], sizeof(packets[3]))); + EXPECT_TRUE(channel_->RemoveRecvStream(3)); EXPECT_TRUE(channel_->RemoveRecvStream(2)); EXPECT_TRUE(channel_->RemoveRecvStream(1)); } +// Test that receiving on an unsignalled stream works (default channel will be +// created). +TEST_F(WebRtcVoiceEngineTestFake, RecvUnsignalled) { + EXPECT_TRUE(SetupEngine()); + DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame)); + int channel_num = voe_.GetLastChannel(); + EXPECT_TRUE(voe_.CheckPacket(channel_num, kPcmuFrame, sizeof(kPcmuFrame))); +} + +// Test that receiving on an unsignalled stream works (default channel will be +// created), and that packets will be forwarded to the default channel +// regardless of their SSRCs. +TEST_F(WebRtcVoiceEngineTestFake, RecvUnsignalledWithSsrcSwitch) { + EXPECT_TRUE(SetupEngine()); + char packet[sizeof(kPcmuFrame)]; + memcpy(packet, kPcmuFrame, sizeof(kPcmuFrame)); + + // Note that the first unknown SSRC cannot be 0, because we only support + // creating receive streams for SSRC!=0. + DeliverPacket(packet, sizeof(packet)); + int channel_num = voe_.GetLastChannel(); + EXPECT_TRUE(voe_.CheckPacket(channel_num, packet, sizeof(packet))); + // Once we have the default channel, SSRC==0 will be ok. + for (uint32_t ssrc = 0; ssrc < 10; ++ssrc) { + rtc::SetBE32(&packet[8], ssrc); + DeliverPacket(packet, sizeof(packet)); + EXPECT_TRUE(voe_.CheckPacket(channel_num, packet, sizeof(packet))); + } +} + +// Test that a default channel is created even after a signalled stream has been +// added, and that this stream will get any packets for unknown SSRCs. +TEST_F(WebRtcVoiceEngineTestFake, RecvUnsignalledAfterSignalled) { + EXPECT_TRUE(SetupEngine()); + char packet[sizeof(kPcmuFrame)]; + memcpy(packet, kPcmuFrame, sizeof(kPcmuFrame)); + + // Add a known stream, send packet and verify we got it. + EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1))); + int signalled_channel_num = voe_.GetLastChannel(); + DeliverPacket(packet, sizeof(packet)); + EXPECT_TRUE(voe_.CheckPacket(signalled_channel_num, packet, sizeof(packet))); + + // Note that the first unknown SSRC cannot be 0, because we only support + // creating receive streams for SSRC!=0. + rtc::SetBE32(&packet[8], 7011); + DeliverPacket(packet, sizeof(packet)); + int channel_num = voe_.GetLastChannel(); + EXPECT_NE(channel_num, signalled_channel_num); + EXPECT_TRUE(voe_.CheckPacket(channel_num, packet, sizeof(packet))); + // Once we have the default channel, SSRC==0 will be ok. + for (uint32_t ssrc = 0; ssrc < 20; ssrc += 2) { + rtc::SetBE32(&packet[8], ssrc); + DeliverPacket(packet, sizeof(packet)); + EXPECT_TRUE(voe_.CheckPacket(channel_num, packet, sizeof(packet))); + } +} + // Test that we properly handle failures to add a receive stream. TEST_F(WebRtcVoiceEngineTestFake, AddRecvStreamFail) { EXPECT_TRUE(SetupEngine()); @@ -2498,7 +2448,7 @@ cricket::StreamParams::CreateLegacy(kSsrc1))); int channel_num2 = voe_.GetLastChannel(); webrtc::CodecInst gcodec; - rtc::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), "opus"); + rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "opus"); gcodec.plfreq = 48000; gcodec.channels = 2; EXPECT_EQ(-1, voe_.GetRecPayloadType(channel_num2, gcodec)); @@ -2602,10 +2552,12 @@ EXPECT_TRUE(typing_detection_enabled); EXPECT_EQ(ec_mode, webrtc::kEcConference); EXPECT_EQ(ns_mode, webrtc::kNsHighSuppression); + EXPECT_EQ(50, voe_.GetNetEqCapacity()); + EXPECT_FALSE(voe_.GetNetEqFastAccelerate()); - // Nothing set, so all ignored. - cricket::AudioOptions options; - ASSERT_TRUE(engine_.SetOptions(options)); + // Nothing set in AudioOptions, so everything should be as default. + send_parameters_.options = cricket::AudioOptions(); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetEcStatus(ec_enabled, ec_mode); voe_.GetAecmMode(aecm_mode, cng_enabled); voe_.GetAgcStatus(agc_enabled, agc_mode); @@ -2625,20 +2577,19 @@ EXPECT_TRUE(typing_detection_enabled); EXPECT_EQ(ec_mode, webrtc::kEcConference); EXPECT_EQ(ns_mode, webrtc::kNsHighSuppression); - EXPECT_EQ(50, voe_.GetNetEqCapacity()); // From GetDefaultEngineOptions(). - EXPECT_FALSE( - voe_.GetNetEqFastAccelerate()); // From GetDefaultEngineOptions(). + EXPECT_EQ(50, voe_.GetNetEqCapacity()); + EXPECT_FALSE(voe_.GetNetEqFastAccelerate()); // Turn echo cancellation off - options.echo_cancellation.Set(false); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.echo_cancellation = rtc::Optional<bool>(false); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetEcStatus(ec_enabled, ec_mode); EXPECT_FALSE(ec_enabled); // Turn echo cancellation back on, with settings, and make sure // nothing else changed. - options.echo_cancellation.Set(true); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.echo_cancellation = rtc::Optional<bool>(true); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetEcStatus(ec_enabled, ec_mode); voe_.GetAecmMode(aecm_mode, cng_enabled); voe_.GetAgcStatus(agc_enabled, agc_mode); @@ -2660,8 +2611,8 @@ // Turn on delay agnostic aec and make sure nothing change w.r.t. echo // control. - options.delay_agnostic_aec.Set(true); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.delay_agnostic_aec = rtc::Optional<bool>(true); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetEcStatus(ec_enabled, ec_mode); voe_.GetAecmMode(aecm_mode, cng_enabled); EXPECT_TRUE(ec_enabled); @@ -2669,41 +2620,41 @@ EXPECT_EQ(ec_mode, webrtc::kEcConference); // Turn off echo cancellation and delay agnostic aec. - options.delay_agnostic_aec.Set(false); - options.extended_filter_aec.Set(false); - options.echo_cancellation.Set(false); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.delay_agnostic_aec = rtc::Optional<bool>(false); + send_parameters_.options.extended_filter_aec = rtc::Optional<bool>(false); + send_parameters_.options.echo_cancellation = rtc::Optional<bool>(false); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetEcStatus(ec_enabled, ec_mode); EXPECT_FALSE(ec_enabled); // Turning delay agnostic aec back on should also turn on echo cancellation. - options.delay_agnostic_aec.Set(true); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.delay_agnostic_aec = rtc::Optional<bool>(true); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetEcStatus(ec_enabled, ec_mode); EXPECT_TRUE(ec_enabled); EXPECT_TRUE(voe_.ec_metrics_enabled()); EXPECT_EQ(ec_mode, webrtc::kEcConference); // Turn off AGC - options.auto_gain_control.Set(false); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.auto_gain_control = rtc::Optional<bool>(false); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetAgcStatus(agc_enabled, agc_mode); EXPECT_FALSE(agc_enabled); // Turn AGC back on - options.auto_gain_control.Set(true); - options.adjust_agc_delta.Clear(); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.auto_gain_control = rtc::Optional<bool>(true); + send_parameters_.options.adjust_agc_delta = rtc::Optional<int>(); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetAgcStatus(agc_enabled, agc_mode); EXPECT_TRUE(agc_enabled); voe_.GetAgcConfig(agc_config); EXPECT_EQ(0, agc_config.targetLeveldBOv); // Turn off other options (and stereo swapping on). - options.noise_suppression.Set(false); - options.highpass_filter.Set(false); - options.typing_detection.Set(false); - options.stereo_swapping.Set(true); - ASSERT_TRUE(engine_.SetOptions(options)); + send_parameters_.options.noise_suppression = rtc::Optional<bool>(false); + send_parameters_.options.highpass_filter = rtc::Optional<bool>(false); + send_parameters_.options.typing_detection = rtc::Optional<bool>(false); + send_parameters_.options.stereo_swapping = rtc::Optional<bool>(true); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetNsStatus(ns_enabled, ns_mode); highpass_filter_enabled = voe_.IsHighPassFilterEnabled(); stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled(); @@ -2714,7 +2665,7 @@ EXPECT_TRUE(stereo_swapping_enabled); // Set options again to ensure it has no impact. - ASSERT_TRUE(engine_.SetOptions(options)); + EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); voe_.GetEcStatus(ec_enabled, ec_mode); voe_.GetNsStatus(ns_enabled, ns_mode); EXPECT_TRUE(ec_enabled); @@ -2785,9 +2736,9 @@ // AEC and AGC and NS cricket::AudioSendParameters parameters_options_all = send_parameters_; - parameters_options_all.options.echo_cancellation.Set(true); - parameters_options_all.options.auto_gain_control.Set(true); - parameters_options_all.options.noise_suppression.Set(true); + parameters_options_all.options.echo_cancellation = rtc::Optional<bool>(true); + parameters_options_all.options.auto_gain_control = rtc::Optional<bool>(true); + parameters_options_all.options.noise_suppression = rtc::Optional<bool>(true); ASSERT_TRUE(channel1->SetSendParameters(parameters_options_all)); EXPECT_EQ(parameters_options_all.options, channel1->options()); ASSERT_TRUE(channel2->SetSendParameters(parameters_options_all)); @@ -2795,24 +2746,26 @@ // unset NS cricket::AudioSendParameters parameters_options_no_ns = send_parameters_; - parameters_options_no_ns.options.noise_suppression.Set(false); + parameters_options_no_ns.options.noise_suppression = + rtc::Optional<bool>(false); ASSERT_TRUE(channel1->SetSendParameters(parameters_options_no_ns)); cricket::AudioOptions expected_options = parameters_options_all.options; - expected_options.echo_cancellation.Set(true); - expected_options.auto_gain_control.Set(true); - expected_options.noise_suppression.Set(false); + expected_options.echo_cancellation = rtc::Optional<bool>(true); + expected_options.auto_gain_control = rtc::Optional<bool>(true); + expected_options.noise_suppression = rtc::Optional<bool>(false); EXPECT_EQ(expected_options, channel1->options()); // unset AGC cricket::AudioSendParameters parameters_options_no_agc = send_parameters_; - parameters_options_no_agc.options.auto_gain_control.Set(false); + parameters_options_no_agc.options.auto_gain_control = + rtc::Optional<bool>(false); ASSERT_TRUE(channel2->SetSendParameters(parameters_options_no_agc)); - expected_options.echo_cancellation.Set(true); - expected_options.auto_gain_control.Set(false); - expected_options.noise_suppression.Set(true); + expected_options.echo_cancellation = rtc::Optional<bool>(true); + expected_options.auto_gain_control = rtc::Optional<bool>(false); + expected_options.noise_suppression = rtc::Optional<bool>(true); EXPECT_EQ(expected_options, channel2->options()); - ASSERT_TRUE(engine_.SetOptions(parameters_options_all.options)); + ASSERT_TRUE(channel_->SetSendParameters(parameters_options_all)); bool ec_enabled; webrtc::EcModes ec_mode; bool agc_enabled; @@ -2834,14 +2787,6 @@ EXPECT_TRUE(agc_enabled); EXPECT_FALSE(ns_enabled); - channel1->SetSend(cricket::SEND_NOTHING); - voe_.GetEcStatus(ec_enabled, ec_mode); - voe_.GetAgcStatus(agc_enabled, agc_mode); - voe_.GetNsStatus(ns_enabled, ns_mode); - EXPECT_TRUE(ec_enabled); - EXPECT_TRUE(agc_enabled); - EXPECT_TRUE(ns_enabled); - channel2->SetSend(cricket::SEND_MICROPHONE); voe_.GetEcStatus(ec_enabled, ec_mode); voe_.GetAgcStatus(agc_enabled, agc_mode); @@ -2850,25 +2795,19 @@ EXPECT_FALSE(agc_enabled); EXPECT_TRUE(ns_enabled); - channel2->SetSend(cricket::SEND_NOTHING); - voe_.GetEcStatus(ec_enabled, ec_mode); - voe_.GetAgcStatus(agc_enabled, agc_mode); - voe_.GetNsStatus(ns_enabled, ns_mode); - EXPECT_TRUE(ec_enabled); - EXPECT_TRUE(agc_enabled); - EXPECT_TRUE(ns_enabled); - // Make sure settings take effect while we are sending. - ASSERT_TRUE(engine_.SetOptions(parameters_options_all.options)); + ASSERT_TRUE(channel_->SetSendParameters(parameters_options_all)); cricket::AudioSendParameters parameters_options_no_agc_nor_ns = send_parameters_; - parameters_options_no_agc_nor_ns.options.auto_gain_control.Set(false); - parameters_options_no_agc_nor_ns.options.noise_suppression.Set(false); + parameters_options_no_agc_nor_ns.options.auto_gain_control = + rtc::Optional<bool>(false); + parameters_options_no_agc_nor_ns.options.noise_suppression = + rtc::Optional<bool>(false); channel2->SetSend(cricket::SEND_MICROPHONE); channel2->SetSendParameters(parameters_options_no_agc_nor_ns); - expected_options.echo_cancellation.Set(true); - expected_options.auto_gain_control.Set(false); - expected_options.noise_suppression.Set(false); + expected_options.echo_cancellation = rtc::Optional<bool>(true); + expected_options.auto_gain_control = rtc::Optional<bool>(false); + expected_options.noise_suppression = rtc::Optional<bool>(false); EXPECT_EQ(expected_options, channel2->options()); voe_.GetEcStatus(ec_enabled, ec_mode); voe_.GetAgcStatus(agc_enabled, agc_mode); @@ -2887,13 +2826,13 @@ new cricket::FakeNetworkInterface); channel->SetInterface(network_interface.get()); cricket::AudioSendParameters parameters = send_parameters_; - parameters.options.dscp.Set(true); + parameters.options.dscp = rtc::Optional<bool>(true); EXPECT_TRUE(channel->SetSendParameters(parameters)); EXPECT_EQ(rtc::DSCP_EF, network_interface->dscp()); // Verify previous value is not modified if dscp option is not set. EXPECT_TRUE(channel->SetSendParameters(send_parameters_)); EXPECT_EQ(rtc::DSCP_EF, network_interface->dscp()); - parameters.options.dscp.Set(false); + parameters.options.dscp = rtc::Optional<bool>(false); EXPECT_TRUE(channel->SetSendParameters(parameters)); EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface->dscp()); } @@ -3002,7 +2941,7 @@ } // Enable combined BWE option - now it should be set up. - send_parameters_.options.combined_audio_video_bwe.Set(true); + send_parameters_.options.combined_audio_video_bwe = rtc::Optional<bool>(true); EXPECT_TRUE(media_channel->SetSendParameters(send_parameters_)); for (uint32_t ssrc : ssrcs) { const auto* s = call_.GetAudioReceiveStream(ssrc); @@ -3011,7 +2950,8 @@ } // Disable combined BWE option - should be disabled again. - send_parameters_.options.combined_audio_video_bwe.Set(false); + send_parameters_.options.combined_audio_video_bwe = + rtc::Optional<bool>(false); EXPECT_TRUE(media_channel->SetSendParameters(send_parameters_)); for (uint32_t ssrc : ssrcs) { const auto* s = call_.GetAudioReceiveStream(ssrc); @@ -3028,18 +2968,19 @@ EXPECT_TRUE(SetupEngineWithSendStream()); cricket::WebRtcVoiceMediaChannel* media_channel = static_cast<cricket::WebRtcVoiceMediaChannel*>(channel_); - send_parameters_.options.combined_audio_video_bwe.Set(true); + send_parameters_.options.combined_audio_video_bwe = rtc::Optional<bool>(true); EXPECT_TRUE(media_channel->SetSendParameters(send_parameters_)); - static const uint32_t kSsrcs[] = {1, 2, 3, 4}; - for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs); ++i) { + for (uint32_t ssrc : kSsrcs4) { EXPECT_TRUE(media_channel->AddRecvStream( - cricket::StreamParams::CreateLegacy(kSsrcs[i]))); - EXPECT_NE(nullptr, call_.GetAudioReceiveStream(kSsrcs[i])); + cricket::StreamParams::CreateLegacy(ssrc))); + EXPECT_NE(nullptr, call_.GetAudioReceiveStream(ssrc)); } - EXPECT_EQ(ARRAY_SIZE(kSsrcs), call_.GetAudioReceiveStreams().size()); + EXPECT_EQ(arraysize(kSsrcs4), call_.GetAudioReceiveStreams().size()); } +// TODO(solenberg): Remove, once recv streams are configured through Call. +// (This is then covered by TestSetRecvRtpHeaderExtensions.) TEST_F(WebRtcVoiceEngineTestFake, ConfiguresAudioReceiveStreamRtpExtensions) { // Test that setting the header extensions results in the expected state // changes on an associated Call. @@ -3050,7 +2991,7 @@ EXPECT_TRUE(SetupEngineWithSendStream()); cricket::WebRtcVoiceMediaChannel* media_channel = static_cast<cricket::WebRtcVoiceMediaChannel*>(channel_); - send_parameters_.options.combined_audio_video_bwe.Set(true); + send_parameters_.options.combined_audio_video_bwe = rtc::Optional<bool>(true); EXPECT_TRUE(media_channel->SetSendParameters(send_parameters_)); for (uint32_t ssrc : ssrcs) { EXPECT_TRUE(media_channel->AddRecvStream( @@ -3066,17 +3007,17 @@ } // Set up receive extensions. - const auto& e_exts = engine_.rtp_header_extensions(); + cricket::RtpCapabilities capabilities = engine_.GetCapabilities(); cricket::AudioRecvParameters recv_parameters; - recv_parameters.extensions = e_exts; + recv_parameters.extensions = capabilities.header_extensions; channel_->SetRecvParameters(recv_parameters); EXPECT_EQ(2, call_.GetAudioReceiveStreams().size()); for (uint32_t ssrc : ssrcs) { const auto* s = call_.GetAudioReceiveStream(ssrc); EXPECT_NE(nullptr, s); const auto& s_exts = s->GetConfig().rtp.extensions; - EXPECT_EQ(e_exts.size(), s_exts.size()); - for (const auto& e_ext : e_exts) { + EXPECT_EQ(capabilities.header_extensions.size(), s_exts.size()); + for (const auto& e_ext : capabilities.header_extensions) { for (const auto& s_ext : s_exts) { if (e_ext.id == s_ext.id) { EXPECT_EQ(e_ext.uri, s_ext.name); @@ -3109,7 +3050,7 @@ EXPECT_TRUE(SetupEngineWithSendStream()); cricket::WebRtcVoiceMediaChannel* media_channel = static_cast<cricket::WebRtcVoiceMediaChannel*>(channel_); - send_parameters_.options.combined_audio_video_bwe.Set(true); + send_parameters_.options.combined_audio_video_bwe = rtc::Optional<bool>(true); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); EXPECT_TRUE(media_channel->AddRecvStream( cricket::StreamParams::CreateLegacy(kAudioSsrc))); @@ -3164,18 +3105,6 @@ EXPECT_EQ(voe_.GetAssociateSendChannel(recv_ch), -1); } -// Tests for the actual WebRtc VoE library. - -TEST(WebRtcVoiceEngineTest, TestDefaultOptionsBeforeInit) { - cricket::WebRtcVoiceEngine engine; - cricket::AudioOptions options = engine.GetOptions(); - // The default options should have at least a few things set. We purposefully - // don't check the option values here, though. - EXPECT_TRUE(options.echo_cancellation.IsSet()); - EXPECT_TRUE(options.auto_gain_control.IsSet()); - EXPECT_TRUE(options.noise_suppression.IsSet()); -} - // Tests that the library initializes and shuts down properly. TEST(WebRtcVoiceEngineTest, StartupShutdown) { cricket::WebRtcVoiceEngine engine; @@ -3195,54 +3124,60 @@ // Tests that the library is configured with the codecs we want. TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) { - cricket::WebRtcVoiceEngine engine; // Check codecs by name. - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "OPUS", 48000, 0, 2, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "ISAC", 16000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "ISAC", 32000, 0, 1, 0))); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "OPUS", 48000, 0, 2, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "ISAC", 16000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "ISAC", 32000, 0, 1, 0), nullptr)); // Check that name matching is case-insensitive. - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "ILBC", 8000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "iLBC", 8000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "PCMU", 8000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "PCMA", 8000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "G722", 8000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "red", 8000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "CN", 32000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "CN", 16000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "CN", 8000, 0, 1, 0))); - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "telephone-event", 8000, 0, 1, 0))); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "ILBC", 8000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "iLBC", 8000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "PCMU", 8000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "PCMA", 8000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "G722", 8000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "red", 8000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "CN", 32000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "CN", 16000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "CN", 8000, 0, 1, 0), nullptr)); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(96, "telephone-event", 8000, 0, 1, 0), nullptr)); // Check codecs with an id by id. - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(0, "", 8000, 0, 1, 0))); // PCMU - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(8, "", 8000, 0, 1, 0))); // PCMA - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(9, "", 8000, 0, 1, 0))); // G722 - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(13, "", 8000, 0, 1, 0))); // CN + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(0, "", 8000, 0, 1, 0), nullptr)); // PCMU + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(8, "", 8000, 0, 1, 0), nullptr)); // PCMA + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(9, "", 8000, 0, 1, 0), nullptr)); // G722 + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(13, "", 8000, 0, 1, 0), nullptr)); // CN // Check sample/bitrate matching. - EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 0))); + EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 0), nullptr)); // Check that bad codecs fail. - EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(99, "ABCD", 0, 0, 1, 0))); - EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(88, "", 0, 0, 1, 0))); - EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 0, 0, 2, 0))); - EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 5000, 0, 1, 0))); - EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 0, 5000, 1, 0))); + EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(99, "ABCD", 0, 0, 1, 0), nullptr)); + EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(88, "", 0, 0, 1, 0), nullptr)); + EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(0, "", 0, 0, 2, 0), nullptr)); + EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(0, "", 5000, 0, 1, 0), nullptr)); + EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst( + cricket::AudioCodec(0, "", 0, 5000, 1, 0), nullptr)); + // Verify the payload id of common audio codecs, including CN, ISAC, and G722. + cricket::WebRtcVoiceEngine engine; for (std::vector<cricket::AudioCodec>::const_iterator it = engine.codecs().begin(); it != engine.codecs().end(); ++it) { if (it->name == "CN" && it->clockrate == 16000) { @@ -3269,7 +3204,6 @@ EXPECT_EQ("1", it->params.find("useinbandfec")->second); } } - engine.Terminate(); } @@ -3282,7 +3216,7 @@ cricket::VoiceMediaChannel* channels[32]; int num_channels = 0; - while (num_channels < ARRAY_SIZE(channels)) { + while (num_channels < arraysize(channels)) { cricket::VoiceMediaChannel* channel = engine.CreateChannel(call.get(), cricket::AudioOptions()); if (!channel) @@ -3290,7 +3224,7 @@ channels[num_channels++] = channel; } - int expected = ARRAY_SIZE(channels); + int expected = arraysize(channels); EXPECT_EQ(expected, num_channels); while (num_channels > 0) {
diff --git a/talk/session/media/bundlefilter.cc b/talk/session/media/bundlefilter.cc index b47d47f..670befe 100755 --- a/talk/session/media/bundlefilter.cc +++ b/talk/session/media/bundlefilter.cc
@@ -32,78 +32,29 @@ namespace cricket { -static const uint32_t kSsrc01 = 0x01; - BundleFilter::BundleFilter() { } BundleFilter::~BundleFilter() { } -bool BundleFilter::DemuxPacket(const char* data, size_t len, bool rtcp) { - // For rtp packets, we check whether the payload type can be found. - // For rtcp packets, we check whether the ssrc can be found or is the special - // value 1 except for SDES packets which always pass through. Plus, if - // |streams_| is empty, we will allow all rtcp packets pass through provided - // that they are valid rtcp packets in case that they are for early media. - if (!rtcp) { - // It may not be a RTP packet (e.g. SCTP). - if (!IsRtpPacket(data, len)) - return false; - - int payload_type = 0; - if (!GetRtpPayloadType(data, len, &payload_type)) { - return false; - } - return FindPayloadType(payload_type); +bool BundleFilter::DemuxPacket(const uint8_t* data, size_t len) { + // For RTP packets, we check whether the payload type can be found. + if (!IsRtpPacket(data, len)) { + return false; } - // Rtcp packets using ssrc filter. - int pl_type = 0; - uint32_t ssrc = 0; - if (!GetRtcpType(data, len, &pl_type)) return false; - if (pl_type == kRtcpTypeSDES) { - // SDES packet parsing not supported. - LOG(LS_INFO) << "SDES packet received for demux."; - return true; - } else { - if (!GetRtcpSsrc(data, len, &ssrc)) return false; - if (ssrc == kSsrc01) { - // SSRC 1 has a special meaning and indicates generic feedback on - // some systems and should never be dropped. If it is forwarded - // incorrectly it will be ignored by lower layers anyway. - return true; - } + int payload_type = 0; + if (!GetRtpPayloadType(data, len, &payload_type)) { + return false; } - // Pass through if |streams_| is empty to allow early rtcp packets in. - return !HasStreams() || FindStream(ssrc); + return FindPayloadType(payload_type); } void BundleFilter::AddPayloadType(int payload_type) { payload_types_.insert(payload_type); } -bool BundleFilter::AddStream(const StreamParams& stream) { - if (GetStreamBySsrc(streams_, stream.first_ssrc())) { - LOG(LS_WARNING) << "Stream already added to filter"; - return false; - } - streams_.push_back(stream); - return true; -} - -bool BundleFilter::RemoveStream(uint32_t ssrc) { - return RemoveStreamBySsrc(&streams_, ssrc); -} - -bool BundleFilter::HasStreams() const { - return !streams_.empty(); -} - -bool BundleFilter::FindStream(uint32_t ssrc) const { - return ssrc == 0 ? false : GetStreamBySsrc(streams_, ssrc) != nullptr; -} - bool BundleFilter::FindPayloadType(int pl_type) const { return payload_types_.find(pl_type) != payload_types_.end(); }
diff --git a/talk/session/media/bundlefilter.h b/talk/session/media/bundlefilter.h index 3717376..d9d952f 100755 --- a/talk/session/media/bundlefilter.h +++ b/talk/session/media/bundlefilter.h
@@ -28,6 +28,8 @@ #ifndef TALK_SESSION_MEDIA_BUNDLEFILTER_H_ #define TALK_SESSION_MEDIA_BUNDLEFILTER_H_ +#include <stdint.h> + #include <set> #include <vector> @@ -37,42 +39,31 @@ namespace cricket { // In case of single RTP session and single transport channel, all session -// ( or media) channels share a common transport channel. Hence they all get +// (or media) channels share a common transport channel. Hence they all get // SignalReadPacket when packet received on transport channel. This requires // cricket::BaseChannel to know all the valid sources, else media channel // will decode invalid packets. // // This class determines whether a packet is destined for cricket::BaseChannel. -// For rtp packets, this is decided based on the payload type. For rtcp packets, -// this is decided based on the sender ssrc values. +// This is only to be used for RTP packets as RTCP packets are not filtered. +// For RTP packets, this is decided based on the payload type. class BundleFilter { public: BundleFilter(); ~BundleFilter(); - // Determines packet belongs to valid cricket::BaseChannel. - bool DemuxPacket(const char* data, size_t len, bool rtcp); + // Determines if a RTP packet belongs to valid cricket::BaseChannel. + bool DemuxPacket(const uint8_t* data, size_t len); // Adds the supported payload type. void AddPayloadType(int payload_type); - // Adding a valid source to the filter. - bool AddStream(const StreamParams& stream); - - // Removes source from the filter. - bool RemoveStream(uint32_t ssrc); - - // Utility methods added for unitest. - // True if |streams_| is not empty. - bool HasStreams() const; - bool FindStream(uint32_t ssrc) const; + // Public for unittests. bool FindPayloadType(int pl_type) const; void ClearAllPayloadTypes(); - private: std::set<int> payload_types_; - std::vector<StreamParams> streams_; }; } // namespace cricket
diff --git a/talk/session/media/bundlefilter_unittest.cc b/talk/session/media/bundlefilter_unittest.cc index 806d6ba..f2c35fc 100755 --- a/talk/session/media/bundlefilter_unittest.cc +++ b/talk/session/media/bundlefilter_unittest.cc
@@ -30,9 +30,6 @@ using cricket::StreamParams; -static const int kSsrc1 = 0x1111; -static const int kSsrc2 = 0x2222; -static const int kSsrc3 = 0x3333; static const int kPayloadType1 = 0x11; static const int kPayloadType2 = 0x22; static const int kPayloadType3 = 0x33; @@ -55,56 +52,6 @@ 0x22, }; -// PT = 200 = SR, len = 28, SSRC of sender = 0x0001 -// NTP TS = 0, RTP TS = 0, packet count = 0 -static const unsigned char kRtcpPacketSrSsrc01[] = { - 0x80, 0xC8, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -// PT = 200 = SR, len = 28, SSRC of sender = 0x2222 -// NTP TS = 0, RTP TS = 0, packet count = 0 -static const unsigned char kRtcpPacketSrSsrc2[] = { - 0x80, 0xC8, 0x00, 0x1B, 0x00, 0x00, 0x22, 0x22, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -// First packet - SR = PT = 200, len = 0, SSRC of sender = 0x1111 -// NTP TS = 0, RTP TS = 0, packet count = 0 -// second packet - SDES = PT = 202, count = 0, SSRC = 0x1111, cname len = 0 -static const unsigned char kRtcpPacketCompoundSrSdesSsrc1[] = { - 0x80, 0xC8, 0x00, 0x01, 0x00, 0x00, 0x11, 0x11, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x81, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x01, 0x00, -}; - -// SDES = PT = 202, count = 0, SSRC = 0x2222, cname len = 0 -static const unsigned char kRtcpPacketSdesSsrc2[] = { - 0x81, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x01, 0x00, -}; - -// Packet has only mandatory fixed RTCP header -static const unsigned char kRtcpPacketFixedHeaderOnly[] = { - 0x80, 0xC8, 0x00, 0x00, -}; - -// Small packet for SSRC demux. -static const unsigned char kRtcpPacketTooSmall[] = { - 0x80, 0xC8, 0x00, 0x00, 0x00, 0x00, -}; - -// PT = 206, FMT = 1, Sender SSRC = 0x1111, Media SSRC = 0x1111 -// No FCI information is needed for PLI. -static const unsigned char kRtcpPacketNonCompoundRtcpPliFeedback[] = { - 0x81, 0xCE, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, -}; - // An SCTP packet. static const unsigned char kSctpPacket[] = { 0x00, 0x01, 0x00, 0x01, @@ -114,100 +61,29 @@ 0x00, 0x00, 0x00, 0x00, }; -TEST(BundleFilterTest, AddRemoveStreamTest) { - cricket::BundleFilter bundle_filter; - EXPECT_FALSE(bundle_filter.HasStreams()); - EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc1))); - StreamParams stream2; - stream2.ssrcs.push_back(kSsrc2); - stream2.ssrcs.push_back(kSsrc3); - EXPECT_TRUE(bundle_filter.AddStream(stream2)); - - EXPECT_TRUE(bundle_filter.HasStreams()); - EXPECT_TRUE(bundle_filter.FindStream(kSsrc1)); - EXPECT_TRUE(bundle_filter.FindStream(kSsrc2)); - EXPECT_TRUE(bundle_filter.FindStream(kSsrc3)); - EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc1)); - EXPECT_FALSE(bundle_filter.FindStream(kSsrc1)); - EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc3)); - EXPECT_FALSE(bundle_filter.RemoveStream(kSsrc2)); // Already removed. - EXPECT_FALSE(bundle_filter.HasStreams()); -} - TEST(BundleFilterTest, RtpPacketTest) { cricket::BundleFilter bundle_filter; bundle_filter.AddPayloadType(kPayloadType1); - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1), - sizeof(kRtpPacketPt1Ssrc1), false)); + EXPECT_TRUE(bundle_filter.DemuxPacket(kRtpPacketPt1Ssrc1, + sizeof(kRtpPacketPt1Ssrc1))); bundle_filter.AddPayloadType(kPayloadType2); - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtpPacketPt2Ssrc2), - sizeof(kRtpPacketPt2Ssrc2), false)); + EXPECT_TRUE(bundle_filter.DemuxPacket(kRtpPacketPt2Ssrc2, + sizeof(kRtpPacketPt2Ssrc2))); // Payload type 0x33 is not added. - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtpPacketPt3Ssrc2), - sizeof(kRtpPacketPt3Ssrc2), false)); + EXPECT_FALSE(bundle_filter.DemuxPacket(kRtpPacketPt3Ssrc2, + sizeof(kRtpPacketPt3Ssrc2))); // Size is too small. - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1), 11, false)); + EXPECT_FALSE(bundle_filter.DemuxPacket(kRtpPacketPt1Ssrc1, 11)); bundle_filter.ClearAllPayloadTypes(); - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1), - sizeof(kRtpPacketPt1Ssrc1), false)); - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtpPacketPt2Ssrc2), - sizeof(kRtpPacketPt2Ssrc2), false)); -} - -TEST(BundleFilterTest, RtcpPacketTest) { - cricket::BundleFilter bundle_filter; - EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc1))); - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketCompoundSrSdesSsrc1), - sizeof(kRtcpPacketCompoundSrSdesSsrc1), true)); - EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc2))); - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketSrSsrc2), - sizeof(kRtcpPacketSrSsrc2), true)); - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2), - sizeof(kRtcpPacketSdesSsrc2), true)); - EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc2)); - // RTCP Packets other than SR and RR are demuxed regardless of SSRC. - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2), - sizeof(kRtcpPacketSdesSsrc2), true)); - // RTCP Packets with 'special' SSRC 0x01 are demuxed also - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketSrSsrc01), - sizeof(kRtcpPacketSrSsrc01), true)); - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketSrSsrc2), - sizeof(kRtcpPacketSrSsrc2), true)); - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketFixedHeaderOnly), - sizeof(kRtcpPacketFixedHeaderOnly), true)); - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketTooSmall), - sizeof(kRtcpPacketTooSmall), true)); - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketNonCompoundRtcpPliFeedback), - sizeof(kRtcpPacketNonCompoundRtcpPliFeedback), true)); - // If the streams_ is empty, rtcp packet passes through - EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc1)); - EXPECT_FALSE(bundle_filter.HasStreams()); - EXPECT_TRUE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kRtcpPacketSrSsrc2), - sizeof(kRtcpPacketSrSsrc2), true)); + EXPECT_FALSE(bundle_filter.DemuxPacket(kRtpPacketPt1Ssrc1, + sizeof(kRtpPacketPt1Ssrc1))); + EXPECT_FALSE(bundle_filter.DemuxPacket(kRtpPacketPt2Ssrc2, + sizeof(kRtpPacketPt2Ssrc2))); } TEST(BundleFilterTest, InvalidRtpPacket) { cricket::BundleFilter bundle_filter; - EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc1))); - EXPECT_FALSE(bundle_filter.DemuxPacket( - reinterpret_cast<const char*>(kSctpPacket), - sizeof(kSctpPacket), false)); + EXPECT_FALSE(bundle_filter.DemuxPacket(kSctpPacket, sizeof(kSctpPacket))); }
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc index 91a6d8c..a59c3f8 100644 --- a/talk/session/media/channel.cc +++ b/talk/session/media/channel.cc
@@ -25,23 +25,36 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <utility> + #include "talk/session/media/channel.h" #include "talk/media/base/constants.h" #include "talk/media/base/rtputils.h" -#include "webrtc/p2p/base/transportchannel.h" #include "talk/session/media/channelmanager.h" +#include "webrtc/audio/audio_sink.h" #include "webrtc/base/bind.h" #include "webrtc/base/buffer.h" #include "webrtc/base/byteorder.h" #include "webrtc/base/common.h" #include "webrtc/base/dscp.h" #include "webrtc/base/logging.h" +#include "webrtc/base/trace_event.h" +#include "webrtc/p2p/base/transportchannel.h" namespace cricket { - using rtc::Bind; +namespace { +// See comment below for why we need to use a pointer to a scoped_ptr. +bool SetRawAudioSink_w(VoiceMediaChannel* channel, + uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface>* sink) { + channel->SetRawAudioSink(ssrc, std::move(*sink)); + return true; +} +} // namespace + enum { MSG_EARLYMEDIATIMEOUT = 1, MSG_SCREENCASTWINDOWEVENT, @@ -101,15 +114,6 @@ DataMediaChannel::Error error; }; - -struct VideoChannel::ScreencastDetailsData { - explicit ScreencastDetailsData(uint32_t s) - : ssrc(s), fps(0), screencast_max_pixels(0) {} - uint32_t ssrc; - int fps; - int screencast_max_pixels; -}; - static const char* PacketType(bool rtcp) { return (!rtcp) ? "RTP" : "RTCP"; } @@ -151,6 +155,7 @@ if (desc->rtp_header_extensions_set()) { params->extensions = desc->rtp_header_extensions(); } + params->rtcp.reduced_size = desc->rtcp_reduced_size(); } template <class Codec, class Options> @@ -218,11 +223,11 @@ return false; } - if (!SetDtlsSrtpCiphers(transport_channel(), false)) { + if (!SetDtlsSrtpCryptoSuites(transport_channel(), false)) { return false; } if (rtcp_transport_enabled() && - !SetDtlsSrtpCiphers(rtcp_transport_channel(), true)) { + !SetDtlsSrtpCryptoSuites(rtcp_transport_channel(), true)) { return false; } @@ -249,21 +254,43 @@ return true; } - set_transport_channel(transport_controller_->CreateTransportChannel_w( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP)); - if (!transport_channel()) { - return false; + // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport + // changes and wait until the DTLS handshake is complete to set the newly + // negotiated parameters. + if (ShouldSetupDtlsSrtp()) { + // Set |writable_| to false such that UpdateWritableState_w can set up + // DTLS-SRTP when the writable_ becomes true again. + writable_ = false; + srtp_filter_.ResetParams(); } + + // TODO(guoweis): Remove this grossness when we remove non-muxed RTCP. if (rtcp_transport_enabled()) { LOG(LS_INFO) << "Create RTCP TransportChannel for " << content_name() << " on " << transport_name << " transport "; - set_rtcp_transport_channel(transport_controller_->CreateTransportChannel_w( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP)); + set_rtcp_transport_channel( + transport_controller_->CreateTransportChannel_w( + transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP), + false /* update_writablity */); if (!rtcp_transport_channel()) { return false; } } + // We're not updating the writablity during the transition state. + set_transport_channel(transport_controller_->CreateTransportChannel_w( + transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP)); + if (!transport_channel()) { + return false; + } + + // TODO(guoweis): Remove this grossness when we remove non-muxed RTCP. + if (rtcp_transport_enabled()) { + // We can only update the RTCP ready to send after set_transport_channel has + // handled channel writability. + SetReadyToSend( + true, rtcp_transport_channel() && rtcp_transport_channel()->writable()); + } transport_name_ = transport_name; return true; } @@ -299,7 +326,8 @@ SetReadyToSend(false, new_tc && new_tc->writable()); } -void BaseChannel::set_rtcp_transport_channel(TransportChannel* new_tc) { +void BaseChannel::set_rtcp_transport_channel(TransportChannel* new_tc, + bool update_writablity) { ASSERT(worker_thread_ == rtc::Thread::Current()); TransportChannel* old_tc = rtcp_transport_channel_; @@ -318,16 +346,21 @@ rtcp_transport_channel_ = new_tc; if (new_tc) { + RTC_CHECK(!(ShouldSetupDtlsSrtp() && srtp_filter_.IsActive())) + << "Setting RTCP for DTLS/SRTP after SrtpFilter is active " + << "should never happen."; ConnectToTransportChannel(new_tc); for (const auto& pair : rtcp_socket_options_) { new_tc->SetOption(pair.first, pair.second); } } - // Update aggregate writable/ready-to-send state between RTP and RTCP upon - // setting new channel - UpdateWritableState_w(); - SetReadyToSend(true, new_tc && new_tc->writable()); + if (update_writablity) { + // Update aggregate writable/ready-to-send state between RTP and RTCP upon + // setting new channel + UpdateWritableState_w(); + SetReadyToSend(true, new_tc && new_tc->writable()); + } } void BaseChannel::ConnectToTransportChannel(TransportChannel* tc) { @@ -336,6 +369,7 @@ tc->SignalWritableState.connect(this, &BaseChannel::OnWritableState); tc->SignalReadPacket.connect(this, &BaseChannel::OnChannelRead); tc->SignalReadyToSend.connect(this, &BaseChannel::OnReadyToSend); + tc->SignalDtlsState.connect(this, &BaseChannel::OnDtlsState); } void BaseChannel::DisconnectFromTransportChannel(TransportChannel* tc) { @@ -344,6 +378,7 @@ tc->SignalWritableState.disconnect(this); tc->SignalReadPacket.disconnect(this); tc->SignalReadyToSend.disconnect(this); + tc->SignalDtlsState.disconnect(this); } bool BaseChannel::Enable(bool enable) { @@ -374,6 +409,7 @@ bool BaseChannel::SetLocalContent(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "BaseChannel::SetLocalContent"); return InvokeOnWorker(Bind(&BaseChannel::SetLocalContent_w, this, content, action, error_desc)); } @@ -381,6 +417,7 @@ bool BaseChannel::SetRemoteContent(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "BaseChannel::SetRemoteContent"); return InvokeOnWorker(Bind(&BaseChannel::SetRemoteContent_w, this, content, action, error_desc)); } @@ -416,10 +453,10 @@ bool BaseChannel::IsReadyToSend() const { // Send outgoing data if we are enabled, have local and remote content, // and we have had some form of connectivity. - return enabled() && - IsReceiveContentDirection(remote_content_direction_) && + return enabled() && IsReceiveContentDirection(remote_content_direction_) && IsSendContentDirection(local_content_direction_) && - was_ever_writable(); + was_ever_writable() && + (srtp_filter_.IsActive() || !ShouldSetupDtlsSrtp()); } bool BaseChannel::SendPacket(rtc::Buffer* packet, @@ -459,6 +496,7 @@ const char* data, size_t len, const rtc::PacketTime& packet_time, int flags) { + TRACE_EVENT0("webrtc", "BaseChannel::OnChannelRead"); // OnChannelRead gets called from P2PSocket; now pass data to MediaEngine ASSERT(worker_thread_ == rtc::Thread::Current()); @@ -474,6 +512,22 @@ SetReadyToSend(channel == rtcp_transport_channel_, true); } +void BaseChannel::OnDtlsState(TransportChannel* channel, + DtlsTransportState state) { + if (!ShouldSetupDtlsSrtp()) { + return; + } + + // Reset the srtp filter if it's not the CONNECTED state. For the CONNECTED + // state, setting up DTLS-SRTP context is deferred to ChannelWritable_w to + // cover other scenarios like the whole channel is writable (not just this + // TransportChannel) or when TransportChannel is attached after DTLS is + // negotiated. + if (state != DTLS_TRANSPORT_CONNECTED) { + srtp_filter_.ResetParams(); + } +} + void BaseChannel::SetReadyToSend(bool rtcp, bool ready) { if (rtcp) { rtcp_ready_to_send_ = ready; @@ -512,7 +566,7 @@ // Avoid a copy by transferring the ownership of the packet data. int message_id = (!rtcp) ? MSG_RTPPACKET : MSG_RTCPPACKET; PacketMessageData* data = new PacketMessageData; - data->packet = packet->Pass(); + data->packet = std::move(*packet); data->options = options; worker_thread_->Post(this, message_id, data); return true; @@ -628,9 +682,12 @@ << " packet: wrong size=" << packet->size(); return false; } - - // Bundle filter handles both rtp and rtcp packets. - return bundle_filter_.DemuxPacket(packet->data<char>(), packet->size(), rtcp); + if (rtcp) { + // Permit all (seemingly valid) RTCP packets. + return true; + } + // Check whether we handle this payload. + return bundle_filter_.DemuxPacket(packet->data<uint8_t>(), packet->size()); } void BaseChannel::HandlePacket(bool rtcp, rtc::Buffer* packet, @@ -758,8 +815,9 @@ void BaseChannel::ChannelWritable_w() { ASSERT(worker_thread_ == rtc::Thread::Current()); - if (writable_) + if (writable_) { return; + } LOG(LS_INFO) << "Channel writable (" << content_name_ << ")" << (was_ever_writable_ ? "" : " for the first time"); @@ -775,22 +833,8 @@ } } - // If we're doing DTLS-SRTP, now is the time. - if (!was_ever_writable_ && ShouldSetupDtlsSrtp()) { - if (!SetupDtlsSrtp(false)) { - SignalDtlsSetupFailure_w(false); - return; - } - - if (rtcp_transport_channel_) { - if (!SetupDtlsSrtp(true)) { - SignalDtlsSetupFailure_w(true); - return; - } - } - } - was_ever_writable_ = true; + MaybeSetupDtlsSrtp_w(); writable_ = true; ChangeState(); } @@ -806,20 +850,21 @@ SignalDtlsSetupFailure(this, rtcp); } -bool BaseChannel::SetDtlsSrtpCiphers(TransportChannel *tc, bool rtcp) { - std::vector<std::string> ciphers; - // We always use the default SRTP ciphers for RTCP, but we may use different - // ciphers for RTP depending on the media type. +bool BaseChannel::SetDtlsSrtpCryptoSuites(TransportChannel* tc, bool rtcp) { + std::vector<int> crypto_suites; + // We always use the default SRTP crypto suites for RTCP, but we may use + // different crypto suites for RTP depending on the media type. if (!rtcp) { - GetSrtpCryptoSuiteNames(&ciphers); + GetSrtpCryptoSuites(&crypto_suites); } else { - GetDefaultSrtpCryptoSuiteNames(&ciphers); + GetDefaultSrtpCryptoSuites(&crypto_suites); } - return tc->SetSrtpCiphers(ciphers); + return tc->SetSrtpCryptoSuites(crypto_suites); } bool BaseChannel::ShouldSetupDtlsSrtp() const { - return true; + // Since DTLS is applied to all channels, checking RTP should be enough. + return transport_channel_ && transport_channel_->IsDtlsActive(); } // This function returns true if either DTLS-SRTP is not in use @@ -830,14 +875,12 @@ TransportChannel* channel = rtcp_channel ? rtcp_transport_channel_ : transport_channel_; - // No DTLS - if (!channel->IsDtlsActive()) - return true; + RTC_DCHECK(channel->IsDtlsActive()); - std::string selected_cipher; + int selected_crypto_suite; - if (!channel->GetSrtpCryptoSuite(&selected_cipher)) { - LOG(LS_ERROR) << "No DTLS-SRTP selected cipher"; + if (!channel->GetSrtpCryptoSuite(&selected_crypto_suite)) { + LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite"; return false; } @@ -893,21 +936,15 @@ } if (rtcp_channel) { - ret = srtp_filter_.SetRtcpParams( - selected_cipher, - &(*send_key)[0], - static_cast<int>(send_key->size()), - selected_cipher, - &(*recv_key)[0], - static_cast<int>(recv_key->size())); + ret = srtp_filter_.SetRtcpParams(selected_crypto_suite, &(*send_key)[0], + static_cast<int>(send_key->size()), + selected_crypto_suite, &(*recv_key)[0], + static_cast<int>(recv_key->size())); } else { - ret = srtp_filter_.SetRtpParams( - selected_cipher, - &(*send_key)[0], - static_cast<int>(send_key->size()), - selected_cipher, - &(*recv_key)[0], - static_cast<int>(recv_key->size())); + ret = srtp_filter_.SetRtpParams(selected_crypto_suite, &(*send_key)[0], + static_cast<int>(send_key->size()), + selected_crypto_suite, &(*recv_key)[0], + static_cast<int>(recv_key->size())); } if (!ret) @@ -918,6 +955,28 @@ return ret; } +void BaseChannel::MaybeSetupDtlsSrtp_w() { + if (srtp_filter_.IsActive()) { + return; + } + + if (!ShouldSetupDtlsSrtp()) { + return; + } + + if (!SetupDtlsSrtp(false)) { + SignalDtlsSetupFailure_w(false); + return; + } + + if (rtcp_transport_channel_) { + if (!SetupDtlsSrtp(true)) { + SignalDtlsSetupFailure_w(true); + return; + } + } +} + void BaseChannel::ChannelNotWritable_w() { ASSERT(worker_thread_ == rtc::Thread::Current()); if (!writable_) @@ -1022,7 +1081,7 @@ void BaseChannel::ActivateRtcpMux_w() { if (!rtcp_mux_filter_.IsActive()) { rtcp_mux_filter_.SetActive(); - set_rtcp_transport_channel(nullptr); + set_rtcp_transport_channel(nullptr, true); rtcp_transport_enabled_ = false; } } @@ -1045,7 +1104,7 @@ LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name() << " by destroying RTCP transport channel for " << transport_name(); - set_rtcp_transport_channel(nullptr); + set_rtcp_transport_channel(nullptr, true); rtcp_transport_enabled_ = false; } break; @@ -1075,15 +1134,11 @@ bool BaseChannel::AddRecvStream_w(const StreamParams& sp) { ASSERT(worker_thread() == rtc::Thread::Current()); - if (!media_channel()->AddRecvStream(sp)) - return false; - - return bundle_filter_.AddStream(sp); + return media_channel()->AddRecvStream(sp); } bool BaseChannel::RemoveRecvStream_w(uint32_t ssrc) { ASSERT(worker_thread() == rtc::Thread::Current()); - bundle_filter_.RemoveStream(ssrc); return media_channel()->RemoveRecvStream(ssrc); } @@ -1243,6 +1298,7 @@ } void BaseChannel::OnMessage(rtc::Message *pmsg) { + TRACE_EVENT0("webrtc", "BaseChannel::OnMessage"); switch (pmsg->message_id) { case MSG_RTPPACKET: case MSG_RTCPPACKET: { @@ -1324,15 +1380,6 @@ } } -bool VoiceChannel::PressDTMF(int digit, bool playout) { - int flags = DF_SEND; - if (playout) { - flags |= DF_PLAY; - } - int duration_ms = 160; - return InsertDtmf(0, digit, duration_ms, flags); -} - bool VoiceChannel::CanInsertDtmf() { return InvokeOnWorker(Bind(&VoiceMediaChannel::CanInsertDtmf, media_channel())); @@ -1340,10 +1387,9 @@ bool VoiceChannel::InsertDtmf(uint32_t ssrc, int event_code, - int duration, - int flags) { + int duration) { return InvokeOnWorker(Bind(&VoiceChannel::InsertDtmf_w, this, - ssrc, event_code, duration, flags)); + ssrc, event_code, duration)); } bool VoiceChannel::SetOutputVolume(uint32_t ssrc, double volume) { @@ -1351,6 +1397,15 @@ media_channel(), ssrc, volume)); } +void VoiceChannel::SetRawAudioSink( + uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) { + // We need to work around Bind's lack of support for scoped_ptr and ownership + // passing. So we invoke to our own little routine that gets a pointer to + // our local variable. This is OK since we're synchronously invoking. + InvokeOnWorker(Bind(&SetRawAudioSink_w, media_channel(), ssrc, &sink)); +} + bool VoiceChannel::GetStats(VoiceMediaInfo* stats) { return InvokeOnWorker(Bind(&VoiceMediaChannel::GetStats, media_channel(), stats)); @@ -1440,6 +1495,7 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "VoiceChannel::SetLocalContent_w"); ASSERT(worker_thread() == rtc::Thread::Current()); LOG(LS_INFO) << "Setting local voice description"; @@ -1484,6 +1540,7 @@ bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "VoiceChannel::SetRemoteContent_w"); ASSERT(worker_thread() == rtc::Thread::Current()); LOG(LS_INFO) << "Setting remote voice description"; @@ -1502,7 +1559,7 @@ AudioSendParameters send_params = last_send_params_; RtpSendParametersFromMediaDescription(audio, &send_params); if (audio->agc_minus_10db()) { - send_params.options.adjust_agc_delta.Set(kAgcMinus10db); + send_params.options.adjust_agc_delta = rtc::Optional<int>(kAgcMinus10db); } if (!media_channel()->SetSendParameters(send_params)) { SafeSetError("Failed to set remote audio description send parameters.", @@ -1539,13 +1596,11 @@ bool VoiceChannel::InsertDtmf_w(uint32_t ssrc, int event, - int duration, - int flags) { + int duration) { if (!enabled()) { return false; } - - return media_channel()->InsertDtmf(ssrc, event, duration, flags); + return media_channel()->InsertDtmf(ssrc, event, duration); } void VoiceChannel::OnMessage(rtc::Message *pmsg) { @@ -1581,9 +1636,8 @@ SignalAudioMonitor(this, info); } -void VoiceChannel::GetSrtpCryptoSuiteNames( - std::vector<std::string>* ciphers) const { - GetSupportedAudioCryptoSuites(ciphers); +void VoiceChannel::GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const { + GetSupportedAudioCryptoSuites(crypto_suites); } VideoChannel::VideoChannel(rtc::Thread* thread, @@ -1653,20 +1707,6 @@ return InvokeOnWorker(Bind(&VideoChannel::IsScreencasting_w, this)); } -int VideoChannel::GetScreencastFps(uint32_t ssrc) { - ScreencastDetailsData data(ssrc); - worker_thread()->Invoke<void>(Bind( - &VideoChannel::GetScreencastDetails_w, this, &data)); - return data.fps; -} - -int VideoChannel::GetScreencastMaxPixels(uint32_t ssrc) { - ScreencastDetailsData data(ssrc); - worker_thread()->Invoke<void>(Bind( - &VideoChannel::GetScreencastDetails_w, this, &data)); - return data.screencast_max_pixels; -} - bool VideoChannel::SendIntraFrame() { worker_thread()->Invoke<void>(Bind( &VideoMediaChannel::SendIntraFrame, media_channel())); @@ -1726,6 +1766,7 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "VideoChannel::SetLocalContent_w"); ASSERT(worker_thread() == rtc::Thread::Current()); LOG(LS_INFO) << "Setting local video description"; @@ -1770,6 +1811,7 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "VideoChannel::SetRemoteContent_w"); ASSERT(worker_thread() == rtc::Thread::Current()); LOG(LS_INFO) << "Setting remote video description"; @@ -1789,7 +1831,7 @@ VideoSendParameters send_params = last_send_params_; RtpSendParametersFromMediaDescription(video, &send_params); if (video->conference_mode()) { - send_params.options.conference_mode.Set(true); + send_params.options.conference_mode = rtc::Optional<bool>(true); } if (!media_channel()->SetSendParameters(send_params)) { SafeSetError("Failed to set remote video description send parameters.", @@ -1877,18 +1919,6 @@ return !screencast_capturers_.empty(); } -void VideoChannel::GetScreencastDetails_w( - ScreencastDetailsData* data) const { - ScreencastMap::const_iterator iter = screencast_capturers_.find(data->ssrc); - if (iter == screencast_capturers_.end()) { - return; - } - VideoCapturer* capturer = iter->second; - const VideoFormat* video_format = capturer->GetCaptureFormat(); - data->fps = VideoFormat::IntervalToFps(video_format->interval); - data->screencast_max_pixels = capturer->screencast_max_pixels(); -} - void VideoChannel::OnScreencastWindowEvent_s(uint32_t ssrc, rtc::WindowEvent we) { ASSERT(signaling_thread() == rtc::Thread::Current()); @@ -1971,9 +2001,8 @@ return false; } -void VideoChannel::GetSrtpCryptoSuiteNames( - std::vector<std::string>* ciphers) const { - GetSupportedVideoCryptoSuites(ciphers); +void VideoChannel::GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const { + GetSupportedVideoCryptoSuites(crypto_suites); } DataChannel::DataChannel(rtc::Thread* thread, @@ -2067,6 +2096,7 @@ bool DataChannel::SetLocalContent_w(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "DataChannel::SetLocalContent_w"); ASSERT(worker_thread() == rtc::Thread::Current()); LOG(LS_INFO) << "Setting local data description"; @@ -2122,6 +2152,7 @@ bool DataChannel::SetRemoteContent_w(const MediaContentDescription* content, ContentAction action, std::string* error_desc) { + TRACE_EVENT0("webrtc", "DataChannel::SetRemoteContent_w"); ASSERT(worker_thread() == rtc::Thread::Current()); const DataContentDescription* data = @@ -2279,13 +2310,12 @@ new DataChannelReadyToSendMessageData(writable)); } -void DataChannel::GetSrtpCryptoSuiteNames( - std::vector<std::string>* ciphers) const { - GetSupportedDataCryptoSuites(ciphers); +void DataChannel::GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const { + GetSupportedDataCryptoSuites(crypto_suites); } bool DataChannel::ShouldSetupDtlsSrtp() const { - return (data_channel_type_ == DCT_RTP); + return (data_channel_type_ == DCT_RTP) && BaseChannel::ShouldSetupDtlsSrtp(); } void DataChannel::OnStreamClosedRemotely(uint32_t sid) {
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h index 603115c..d8fde67 100644 --- a/talk/session/media/channel.h +++ b/talk/session/media/channel.h
@@ -38,19 +38,24 @@ #include "talk/media/base/mediaengine.h" #include "talk/media/base/streamparams.h" #include "talk/media/base/videocapturer.h" -#include "webrtc/p2p/base/transportcontroller.h" -#include "webrtc/p2p/client/socketmonitor.h" #include "talk/session/media/audiomonitor.h" #include "talk/session/media/bundlefilter.h" #include "talk/session/media/mediamonitor.h" #include "talk/session/media/mediasession.h" #include "talk/session/media/rtcpmuxfilter.h" #include "talk/session/media/srtpfilter.h" +#include "webrtc/audio/audio_sink.h" #include "webrtc/base/asyncudpsocket.h" #include "webrtc/base/criticalsection.h" #include "webrtc/base/network.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/window.h" +#include "webrtc/p2p/base/transportcontroller.h" +#include "webrtc/p2p/client/socketmonitor.h" + +namespace webrtc { +class AudioSinkInterface; +} // namespace webrtc namespace cricket { @@ -174,8 +179,11 @@ // Sets the |transport_channel_| (and |rtcp_transport_channel_|, if |rtcp_| is // true). Gets the transport channels from |transport_controller_|. bool SetTransport_w(const std::string& transport_name); + void set_transport_channel(TransportChannel* transport); - void set_rtcp_transport_channel(TransportChannel* transport); + void set_rtcp_transport_channel(TransportChannel* transport, + bool update_writablity); + bool was_ever_writable() const { return was_ever_writable_; } void set_local_content_direction(MediaContentDirection direction) { local_content_direction_ = direction; @@ -213,6 +221,8 @@ int flags); void OnReadyToSend(TransportChannel* channel); + void OnDtlsState(TransportChannel* channel, DtlsTransportState state); + bool PacketIsRtcp(const TransportChannel* channel, const char* data, size_t len); bool SendPacket(bool rtcp, @@ -235,8 +245,9 @@ // Do the DTLS key expansion and impose it on the SRTP/SRTCP filters. // |rtcp_channel| indicates whether to set up the RTP or RTCP filter. bool SetupDtlsSrtp(bool rtcp_channel); + void MaybeSetupDtlsSrtp_w(); // Set the DTLS-SRTP cipher policy on this channel as appropriate. - bool SetDtlsSrtpCiphers(TransportChannel *tc, bool rtcp); + bool SetDtlsSrtpCryptoSuites(TransportChannel* tc, bool rtcp); virtual void ChangeState() = 0; @@ -282,9 +293,8 @@ void OnMessage(rtc::Message* pmsg) override; // Handled in derived classes - // Get the SRTP ciphers to use for RTP media - virtual void GetSrtpCryptoSuiteNames( - std::vector<std::string>* ciphers) const = 0; + // Get the SRTP crypto suites to use for RTP media + virtual void GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const = 0; virtual void OnConnectionMonitorUpdate(ConnectionMonitor* monitor, const std::vector<ConnectionInfo>& infos) = 0; @@ -356,8 +366,6 @@ // own ringing sound sigslot::signal1<VoiceChannel*> SignalEarlyMediaTimeout; - // TODO(ronghuawu): Replace PressDTMF with InsertDtmf. - bool PressDTMF(int digit, bool playout); // Returns if the telephone-event has been negotiated. bool CanInsertDtmf(); // Send and/or play a DTMF |event| according to the |flags|. @@ -365,8 +373,11 @@ // The |ssrc| should be either 0 or a valid send stream ssrc. // The valid value for the |event| are 0 which corresponding to DTMF // event 0-9, *, #, A-D. - bool InsertDtmf(uint32_t ssrc, int event_code, int duration, int flags); + bool InsertDtmf(uint32_t ssrc, int event_code, int duration); bool SetOutputVolume(uint32_t ssrc, double volume); + void SetRawAudioSink(uint32_t ssrc, + rtc::scoped_ptr<webrtc::AudioSinkInterface> sink); + // Get statistics about the current media session. bool GetStats(VoiceMediaInfo* stats); @@ -402,12 +413,12 @@ ContentAction action, std::string* error_desc); void HandleEarlyMediaTimeout(); - bool InsertDtmf_w(uint32_t ssrc, int event, int duration, int flags); + bool InsertDtmf_w(uint32_t ssrc, int event, int duration); bool SetOutputVolume_w(uint32_t ssrc, double volume); bool GetStats_w(VoiceMediaInfo* stats); virtual void OnMessage(rtc::Message* pmsg); - virtual void GetSrtpCryptoSuiteNames(std::vector<std::string>* ciphers) const; + virtual void GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const; virtual void OnConnectionMonitorUpdate( ConnectionMonitor* monitor, const std::vector<ConnectionInfo>& infos); virtual void OnMediaMonitorUpdate( @@ -456,8 +467,6 @@ // True if we've added a screencast. Doesn't matter if the capturer // has been started or not. bool IsScreencasting(); - int GetScreencastFps(uint32_t ssrc); - int GetScreencastMaxPixels(uint32_t ssrc); // Get statistics about the current media session. bool GetStats(VideoMediaInfo* stats); @@ -476,7 +485,6 @@ private: typedef std::map<uint32_t, VideoCapturer*> ScreencastMap; - struct ScreencastDetailsData; // overrides from BaseChannel virtual void ChangeState(); @@ -493,11 +501,10 @@ bool RemoveScreencast_w(uint32_t ssrc); void OnScreencastWindowEvent_s(uint32_t ssrc, rtc::WindowEvent we); bool IsScreencasting_w() const; - void GetScreencastDetails_w(ScreencastDetailsData* d) const; bool GetStats_w(VideoMediaInfo* stats); virtual void OnMessage(rtc::Message* pmsg); - virtual void GetSrtpCryptoSuiteNames(std::vector<std::string>* ciphers) const; + virtual void GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const; virtual void OnConnectionMonitorUpdate( ConnectionMonitor* monitor, const std::vector<ConnectionInfo>& infos); virtual void OnMediaMonitorUpdate( @@ -614,7 +621,7 @@ virtual bool WantsPacket(bool rtcp, rtc::Buffer* packet); virtual void OnMessage(rtc::Message* pmsg); - virtual void GetSrtpCryptoSuiteNames(std::vector<std::string>* ciphers) const; + virtual void GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const; virtual void OnConnectionMonitorUpdate( ConnectionMonitor* monitor, const std::vector<ConnectionInfo>& infos); virtual void OnMediaMonitorUpdate(
diff --git a/talk/session/media/channel_unittest.cc b/talk/session/media/channel_unittest.cc index 1823320..6b1d66f 100644 --- a/talk/session/media/channel_unittest.cc +++ b/talk/session/media/channel_unittest.cc
@@ -33,8 +33,8 @@ #include "talk/media/base/rtpdump.h" #include "talk/media/base/screencastid.h" #include "talk/media/base/testutils.h" -#include "webrtc/p2p/base/faketransportcontroller.h" #include "talk/session/media/channel.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/fileutils.h" #include "webrtc/base/gunit.h" #include "webrtc/base/helpers.h" @@ -44,6 +44,7 @@ #include "webrtc/base/ssladapter.h" #include "webrtc/base/sslidentity.h" #include "webrtc/base/window.h" +#include "webrtc/p2p/base/faketransportcontroller.h" #define MAYBE_SKIP_TEST(feature) \ if (!(rtc::SSLStreamAdapter::feature())) { \ @@ -174,17 +175,15 @@ if (flags1 & DTLS) { // Confirmed to work with KT_RSA and KT_ECDSA. - transport_controller1_.SetLocalCertificate(rtc::RTCCertificate::Create( - rtc::scoped_ptr<rtc::SSLIdentity>( - rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)) - .Pass())); + transport_controller1_.SetLocalCertificate( + rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>( + rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)))); } if (flags2 & DTLS) { // Confirmed to work with KT_RSA and KT_ECDSA. - transport_controller2_.SetLocalCertificate(rtc::RTCCertificate::Create( - rtc::scoped_ptr<rtc::SSLIdentity>( - rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)) - .Pass())); + transport_controller2_.SetLocalCertificate( + rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>( + rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)))); } // Add stream information (SSRC) to the local content but not to the remote @@ -1473,12 +1472,6 @@ EXPECT_TRUE(channel2_->bundle_filter()->FindPayloadType(pl_type1)); EXPECT_FALSE(channel1_->bundle_filter()->FindPayloadType(pl_type2)); EXPECT_FALSE(channel2_->bundle_filter()->FindPayloadType(pl_type2)); - // channel1 - should only have media_content2 as remote. i.e. kSsrc2 - EXPECT_TRUE(channel1_->bundle_filter()->FindStream(kSsrc2)); - EXPECT_FALSE(channel1_->bundle_filter()->FindStream(kSsrc1)); - // channel2 - should only have media_content1 as remote. i.e. kSsrc1 - EXPECT_TRUE(channel2_->bundle_filter()->FindStream(kSsrc1)); - EXPECT_FALSE(channel2_->bundle_filter()->FindStream(kSsrc2)); // Both channels can receive pl_type1 only. EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type1)); @@ -1503,8 +1496,9 @@ EXPECT_TRUE(SendCustomRtcp1(kSsrc2)); EXPECT_TRUE(SendCustomRtcp2(kSsrc1)); - EXPECT_FALSE(CheckCustomRtcp1(kSsrc1)); - EXPECT_FALSE(CheckCustomRtcp2(kSsrc2)); + // Bundle filter shouldn't filter out any RTCP. + EXPECT_TRUE(CheckCustomRtcp1(kSsrc1)); + EXPECT_TRUE(CheckCustomRtcp2(kSsrc2)); } // Test that the media monitor can be run and gives timely callbacks. @@ -2116,23 +2110,6 @@ Base::TestMediaMonitor(); } -// Test that PressDTMF properly forwards to the media channel. -TEST_F(VoiceChannelTest, TestDtmf) { - CreateChannels(0, 0); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(SendAccept()); - EXPECT_EQ(0U, media_channel1_->dtmf_info_queue().size()); - - EXPECT_TRUE(channel1_->PressDTMF(1, true)); - EXPECT_TRUE(channel1_->PressDTMF(8, false)); - - ASSERT_EQ(2U, media_channel1_->dtmf_info_queue().size()); - EXPECT_TRUE(CompareDtmfInfo(media_channel1_->dtmf_info_queue()[0], - 0, 1, 160, cricket::DF_PLAY | cricket::DF_SEND)); - EXPECT_TRUE(CompareDtmfInfo(media_channel1_->dtmf_info_queue()[1], - 0, 8, 160, cricket::DF_SEND)); -} - // Test that InsertDtmf properly forwards to the media channel. TEST_F(VoiceChannelTest, TestInsertDtmf) { CreateChannels(0, 0); @@ -2140,18 +2117,17 @@ EXPECT_TRUE(SendAccept()); EXPECT_EQ(0U, media_channel1_->dtmf_info_queue().size()); - EXPECT_TRUE(channel1_->InsertDtmf(1, 3, 100, cricket::DF_SEND)); - EXPECT_TRUE(channel1_->InsertDtmf(2, 5, 110, cricket::DF_PLAY)); - EXPECT_TRUE(channel1_->InsertDtmf(3, 7, 120, - cricket::DF_PLAY | cricket::DF_SEND)); + EXPECT_TRUE(channel1_->InsertDtmf(1, 3, 100)); + EXPECT_TRUE(channel1_->InsertDtmf(2, 5, 110)); + EXPECT_TRUE(channel1_->InsertDtmf(3, 7, 120)); ASSERT_EQ(3U, media_channel1_->dtmf_info_queue().size()); EXPECT_TRUE(CompareDtmfInfo(media_channel1_->dtmf_info_queue()[0], - 1, 3, 100, cricket::DF_SEND)); + 1, 3, 100)); EXPECT_TRUE(CompareDtmfInfo(media_channel1_->dtmf_info_queue()[1], - 2, 5, 110, cricket::DF_PLAY)); + 2, 5, 110)); EXPECT_TRUE(CompareDtmfInfo(media_channel1_->dtmf_info_queue()[2], - 3, 7, 120, cricket::DF_PLAY | cricket::DF_SEND)); + 3, 7, 120)); } TEST_F(VoiceChannelTest, TestSetContentFailure) { @@ -2253,21 +2229,19 @@ } TEST_F(VoiceChannelTest, SendBundleToBundle) { - Base::SendBundleToBundle(kAudioPts, ARRAY_SIZE(kAudioPts), false, false); + Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), false, false); } TEST_F(VoiceChannelTest, SendBundleToBundleSecure) { - Base::SendBundleToBundle(kAudioPts, ARRAY_SIZE(kAudioPts), false, true); + Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), false, true); } TEST_F(VoiceChannelTest, SendBundleToBundleWithRtcpMux) { - Base::SendBundleToBundle( - kAudioPts, ARRAY_SIZE(kAudioPts), true, false); + Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), true, false); } TEST_F(VoiceChannelTest, SendBundleToBundleWithRtcpMuxSecure) { - Base::SendBundleToBundle( - kAudioPts, ARRAY_SIZE(kAudioPts), true, true); + Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), true, true); } // VideoChannelTest @@ -2501,21 +2475,19 @@ } TEST_F(VideoChannelTest, SendBundleToBundle) { - Base::SendBundleToBundle(kVideoPts, ARRAY_SIZE(kVideoPts), false, false); + Base::SendBundleToBundle(kVideoPts, arraysize(kVideoPts), false, false); } TEST_F(VideoChannelTest, SendBundleToBundleSecure) { - Base::SendBundleToBundle(kVideoPts, ARRAY_SIZE(kVideoPts), false, true); + Base::SendBundleToBundle(kVideoPts, arraysize(kVideoPts), false, true); } TEST_F(VideoChannelTest, SendBundleToBundleWithRtcpMux) { - Base::SendBundleToBundle( - kVideoPts, ARRAY_SIZE(kVideoPts), true, false); + Base::SendBundleToBundle(kVideoPts, arraysize(kVideoPts), true, false); } TEST_F(VideoChannelTest, SendBundleToBundleWithRtcpMuxSecure) { - Base::SendBundleToBundle( - kVideoPts, ARRAY_SIZE(kVideoPts), true, true); + Base::SendBundleToBundle(kVideoPts, arraysize(kVideoPts), true, true); } TEST_F(VideoChannelTest, TestSrtpError) {
diff --git a/talk/session/media/channelmanager.cc b/talk/session/media/channelmanager.cc index e7e1cd4..e7a4b8b 100644 --- a/talk/session/media/channelmanager.cc +++ b/talk/session/media/channelmanager.cc
@@ -49,6 +49,7 @@ #include "webrtc/base/sigslotrepeater.h" #include "webrtc/base/stringencode.h" #include "webrtc/base/stringutils.h" +#include "webrtc/base/trace_event.h" namespace cricket { @@ -101,8 +102,6 @@ initialized_ = false; main_thread_ = rtc::Thread::Current(); worker_thread_ = worker_thread; - // Get the default audio options from the media engine. - audio_options_ = media_engine_->GetAudioOptions(); audio_output_volume_ = kNotSetOutputVolume; local_renderer_ = NULL; capturing_ = false; @@ -156,7 +155,7 @@ void ChannelManager::GetSupportedAudioRtpHeaderExtensions( RtpHeaderExtensions* ext) const { - *ext = media_engine_->audio_rtp_header_extensions(); + *ext = media_engine_->GetAudioCapabilities().header_extensions; } void ChannelManager::GetSupportedVideoCodecs( @@ -175,7 +174,7 @@ void ChannelManager::GetSupportedVideoRtpHeaderExtensions( RtpHeaderExtensions* ext) const { - *ext = media_engine_->video_rtp_header_extensions(); + *ext = media_engine_->GetVideoCapabilities().header_extensions; } void ChannelManager::GetSupportedDataCodecs( @@ -205,11 +204,6 @@ return false; } - if (!SetAudioOptions(audio_options_)) { - LOG(LS_WARNING) << "Failed to SetAudioOptions with options: " - << audio_options_.ToString(); - } - // If audio_output_volume_ has been set via SetOutputVolume(), set the // audio output volume of the engine. if (kNotSetOutputVolume != audio_output_volume_ && @@ -218,11 +212,6 @@ << audio_output_volume_; } - // Now apply the default video codec that has been set earlier. - if (default_video_encoder_config_.max_codec.id != 0) { - SetDefaultVideoEncoderConfig(default_video_encoder_config_); - } - return initialized_; } @@ -295,6 +284,7 @@ } void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) { + TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel"); if (voice_channel) { worker_thread_->Invoke<void>( Bind(&ChannelManager::DestroyVoiceChannel_w, this, voice_channel)); @@ -302,6 +292,7 @@ } void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) { + TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel_w"); // Destroy voice channel. ASSERT(initialized_); ASSERT(worker_thread_ == rtc::Thread::Current()); @@ -351,6 +342,7 @@ } void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) { + TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel"); if (video_channel) { worker_thread_->Invoke<void>( Bind(&ChannelManager::DestroyVideoChannel_w, this, video_channel)); @@ -358,6 +350,7 @@ } void ChannelManager::DestroyVideoChannel_w(VideoChannel* video_channel) { + TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel_w"); // Destroy video channel. ASSERT(initialized_); ASSERT(worker_thread_ == rtc::Thread::Current()); @@ -408,6 +401,7 @@ } void ChannelManager::DestroyDataChannel(DataChannel* data_channel) { + TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel"); if (data_channel) { worker_thread_->Invoke<void>( Bind(&ChannelManager::DestroyDataChannel_w, this, data_channel)); @@ -415,6 +409,7 @@ } void ChannelManager::DestroyDataChannel_w(DataChannel* data_channel) { + TRACE_EVENT0("webrtc", "ChannelManager::DestroyDataChannel_w"); // Destroy data channel. ASSERT(initialized_); DataChannels::iterator it = std::find(data_channels_.begin(), @@ -427,43 +422,6 @@ delete data_channel; } -bool ChannelManager::SetAudioOptions(const AudioOptions& options) { - // "Get device ids from DeviceManager" - these are the defaults returned. - Device in_dev("", -1); - Device out_dev("", -1); - - // If we're initialized, pass the settings to the media engine. - bool ret = true; - if (initialized_) { - ret = worker_thread_->Invoke<bool>( - Bind(&ChannelManager::SetAudioOptions_w, this, - options, &in_dev, &out_dev)); - } - - // If all worked well, save the values for use in GetAudioOptions. - if (ret) { - audio_options_ = options; - } - return ret; -} - -bool ChannelManager::SetAudioOptions_w( - const AudioOptions& options, - const Device* in_dev, const Device* out_dev) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - ASSERT(initialized_); - - // Set audio options - bool ret = media_engine_->SetAudioOptions(options); - - // Set the audio devices - if (ret) { - ret = media_engine_->SetSoundDevices(in_dev, out_dev); - } - - return ret; -} - bool ChannelManager::GetOutputVolume(int* level) { if (!initialized_) { return false; @@ -487,39 +445,6 @@ return ret; } -bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) { - bool ret = true; - if (initialized_) { - ret = worker_thread_->Invoke<bool>( - Bind(&MediaEngineInterface::SetDefaultVideoEncoderConfig, - media_engine_.get(), c)); - } - if (ret) { - default_video_encoder_config_ = c; - } - return ret; -} - -void ChannelManager::SetVoiceLogging(int level, const char* filter) { - if (initialized_) { - worker_thread_->Invoke<void>( - Bind(&MediaEngineInterface::SetVoiceLogging, - media_engine_.get(), level, filter)); - } else { - media_engine_->SetVoiceLogging(level, filter); - } -} - -void ChannelManager::SetVideoLogging(int level, const char* filter) { - if (initialized_) { - worker_thread_->Invoke<void>( - Bind(&MediaEngineInterface::SetVideoLogging, - media_engine_.get(), level, filter)); - } else { - media_engine_->SetVideoLogging(level, filter); - } -} - std::vector<cricket::VideoFormat> ChannelManager::GetSupportedFormats( VideoCapturer* capturer) const { ASSERT(capturer != NULL);
diff --git a/talk/session/media/channelmanager.h b/talk/session/media/channelmanager.h index 6312e61..2bc516b 100644 --- a/talk/session/media/channelmanager.h +++ b/talk/session/media/channelmanager.h
@@ -129,7 +129,6 @@ bool GetOutputVolume(int* level); bool SetOutputVolume(int level); - bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config); // RTX will be enabled/disabled in engines that support it. The supporting // engines will start offering an RTX codec. Must be called before Init(). bool SetVideoRtxEnabled(bool enable); @@ -137,10 +136,6 @@ // Starts/stops the local microphone and enables polling of the input level. bool capturing() const { return capturing_; } - // Configures the logging output of the mediaengine(s). - void SetVoiceLogging(int level, const char* filter); - void SetVideoLogging(int level, const char* filter); - // Gets capturer's supported formats in a thread safe manner std::vector<cricket::VideoFormat> GetSupportedFormats( VideoCapturer* capturer) const; @@ -181,11 +176,6 @@ sigslot::signal2<VideoCapturer*, CaptureState> SignalVideoCaptureStateChange; - protected: - // Adds non-transient parameters which can only be changed through the - // options store. - bool SetAudioOptions(const AudioOptions& options); - private: typedef std::vector<VoiceChannel*> VoiceChannels; typedef std::vector<VideoChannel*> VideoChannels; @@ -217,8 +207,6 @@ bool rtcp, DataChannelType data_channel_type); void DestroyDataChannel_w(DataChannel* data_channel); - bool SetAudioOptions_w(const AudioOptions& options, - const Device* in_dev, const Device* out_dev); void OnVideoCaptureStateChange(VideoCapturer* capturer, CaptureState result); void GetSupportedFormats_w( @@ -238,9 +226,7 @@ VideoChannels video_channels_; DataChannels data_channels_; - AudioOptions audio_options_; int audio_output_volume_; - VideoEncoderConfig default_video_encoder_config_; VideoRenderer* local_renderer_; bool enable_rtx_;
diff --git a/talk/session/media/channelmanager_unittest.cc b/talk/session/media/channelmanager_unittest.cc index fa6aa2c..4740f0f 100644 --- a/talk/session/media/channelmanager_unittest.cc +++ b/talk/session/media/channelmanager_unittest.cc
@@ -183,38 +183,6 @@ cm_->Terminate(); } -// Test that SetDefaultVideoCodec passes through the right values. -TEST_F(ChannelManagerTest, SetDefaultVideoEncoderConfig) { - cricket::VideoCodec codec(96, "G264", 1280, 720, 60, 0); - cricket::VideoEncoderConfig config(codec, 1, 2); - EXPECT_TRUE(cm_->Init()); - EXPECT_TRUE(cm_->SetDefaultVideoEncoderConfig(config)); - EXPECT_EQ(config, fme_->default_video_encoder_config()); -} - -struct GetCapturerFrameSize : public sigslot::has_slots<> { - void OnVideoFrame(VideoCapturer* capturer, const VideoFrame* frame) { - width = frame->GetWidth(); - height = frame->GetHeight(); - } - GetCapturerFrameSize(VideoCapturer* capturer) : width(0), height(0) { - capturer->SignalVideoFrame.connect(this, - &GetCapturerFrameSize::OnVideoFrame); - static_cast<FakeVideoCapturer*>(capturer)->CaptureFrame(); - } - size_t width; - size_t height; -}; - -// Test that SetDefaultVideoCodec passes through the right values. -TEST_F(ChannelManagerTest, SetDefaultVideoCodecBeforeInit) { - cricket::VideoCodec codec(96, "G264", 1280, 720, 60, 0); - cricket::VideoEncoderConfig config(codec, 1, 2); - EXPECT_TRUE(cm_->SetDefaultVideoEncoderConfig(config)); - EXPECT_TRUE(cm_->Init()); - EXPECT_EQ(config, fme_->default_video_encoder_config()); -} - TEST_F(ChannelManagerTest, GetSetOutputVolumeBeforeInit) { int level; // Before init, SetOutputVolume() remembers the volume but does not change the @@ -250,33 +218,6 @@ EXPECT_EQ(60, level); } -// Test that logging options set before Init are applied properly, -// and retained even after Init. -TEST_F(ChannelManagerTest, SetLoggingBeforeInit) { - cm_->SetVoiceLogging(rtc::LS_INFO, "test-voice"); - cm_->SetVideoLogging(rtc::LS_VERBOSE, "test-video"); - EXPECT_EQ(rtc::LS_INFO, fme_->voice_loglevel()); - EXPECT_STREQ("test-voice", fme_->voice_logfilter().c_str()); - EXPECT_EQ(rtc::LS_VERBOSE, fme_->video_loglevel()); - EXPECT_STREQ("test-video", fme_->video_logfilter().c_str()); - EXPECT_TRUE(cm_->Init()); - EXPECT_EQ(rtc::LS_INFO, fme_->voice_loglevel()); - EXPECT_STREQ("test-voice", fme_->voice_logfilter().c_str()); - EXPECT_EQ(rtc::LS_VERBOSE, fme_->video_loglevel()); - EXPECT_STREQ("test-video", fme_->video_logfilter().c_str()); -} - -// Test that logging options set after Init are applied properly. -TEST_F(ChannelManagerTest, SetLogging) { - EXPECT_TRUE(cm_->Init()); - cm_->SetVoiceLogging(rtc::LS_INFO, "test-voice"); - cm_->SetVideoLogging(rtc::LS_VERBOSE, "test-video"); - EXPECT_EQ(rtc::LS_INFO, fme_->voice_loglevel()); - EXPECT_STREQ("test-voice", fme_->voice_logfilter().c_str()); - EXPECT_EQ(rtc::LS_VERBOSE, fme_->video_loglevel()); - EXPECT_STREQ("test-video", fme_->video_logfilter().c_str()); -} - TEST_F(ChannelManagerTest, SetVideoRtxEnabled) { std::vector<VideoCodec> codecs; const VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
diff --git a/talk/session/media/mediasession.cc b/talk/session/media/mediasession.cc index 7413026..24f01b4 100644 --- a/talk/session/media/mediasession.cc +++ b/talk/session/media/mediasession.cc
@@ -50,6 +50,17 @@ namespace { const char kInline[] = "inline:"; + +void GetSupportedCryptoSuiteNames(void (*func)(std::vector<int>*), + std::vector<std::string>* names) { +#ifdef HAVE_SRTP + std::vector<int> crypto_suites; + func(&crypto_suites); + for (const auto crypto : crypto_suites) { + names->push_back(rtc::SrtpCryptoSuiteToName(crypto)); + } +#endif +} } namespace cricket { @@ -152,30 +163,50 @@ } // For audio, HMAC 32 is prefered because of the low overhead. -void GetSupportedAudioCryptoSuites( - std::vector<std::string>* crypto_suites) { +void GetSupportedAudioCryptoSuites(std::vector<int>* crypto_suites) { #ifdef HAVE_SRTP - crypto_suites->push_back(rtc::CS_AES_CM_128_HMAC_SHA1_32); - crypto_suites->push_back(rtc::CS_AES_CM_128_HMAC_SHA1_80); + crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32); + crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80); #endif } -void GetSupportedVideoCryptoSuites( - std::vector<std::string>* crypto_suites) { - GetDefaultSrtpCryptoSuiteNames(crypto_suites); +void GetSupportedAudioCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names) { + GetSupportedCryptoSuiteNames(GetSupportedAudioCryptoSuites, + crypto_suite_names); } -void GetSupportedDataCryptoSuites( - std::vector<std::string>* crypto_suites) { - GetDefaultSrtpCryptoSuiteNames(crypto_suites); +void GetSupportedVideoCryptoSuites(std::vector<int>* crypto_suites) { + GetDefaultSrtpCryptoSuites(crypto_suites); } -void GetDefaultSrtpCryptoSuiteNames(std::vector<std::string>* crypto_suites) { +void GetSupportedVideoCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names) { + GetSupportedCryptoSuiteNames(GetSupportedVideoCryptoSuites, + crypto_suite_names); +} + +void GetSupportedDataCryptoSuites(std::vector<int>* crypto_suites) { + GetDefaultSrtpCryptoSuites(crypto_suites); +} + +void GetSupportedDataCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names) { + GetSupportedCryptoSuiteNames(GetSupportedDataCryptoSuites, + crypto_suite_names); +} + +void GetDefaultSrtpCryptoSuites(std::vector<int>* crypto_suites) { #ifdef HAVE_SRTP - crypto_suites->push_back(rtc::CS_AES_CM_128_HMAC_SHA1_80); + crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80); #endif } +void GetDefaultSrtpCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names) { + GetSupportedCryptoSuiteNames(GetDefaultSrtpCryptoSuites, crypto_suite_names); +} + // For video support only 80-bit SHA1 HMAC. For audio 32-bit HMAC is // tolerated unless bundle is enabled because it is low overhead. Pick the // crypto in the list that is supported. @@ -518,8 +549,8 @@ // Updates the transport infos of the |sdesc| according to the given // |bundle_group|. The transport infos of the content names within the -// |bundle_group| should be updated to use the ufrag and pwd of the first -// content within the |bundle_group|. +// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the +// first content within the |bundle_group|. static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group, SessionDescription* sdesc) { // The bundle should not be empty. @@ -540,6 +571,8 @@ selected_transport_info->description.ice_ufrag; const std::string& selected_pwd = selected_transport_info->description.ice_pwd; + ConnectionRole selected_connection_role = + selected_transport_info->description.connection_role; for (TransportInfos::iterator it = sdesc->transport_infos().begin(); it != sdesc->transport_infos().end(); ++it) { @@ -547,6 +580,7 @@ it->content_name != selected_content_name) { it->description.ice_ufrag = selected_ufrag; it->description.ice_pwd = selected_pwd; + it->description.connection_role = selected_connection_role; } } return true; @@ -602,6 +636,11 @@ target_cryptos->end()); } +static bool IsRtpProtocol(const std::string& protocol) { + return protocol.empty() || + (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos); +} + static bool IsRtpContent(SessionDescription* sdesc, const std::string& content_name) { bool is_rtp = false; @@ -612,9 +651,7 @@ if (!media_desc) { return false; } - is_rtp = media_desc->protocol().empty() || - (media_desc->protocol().find(cricket::kMediaProtocolRtpPrefix) != - std::string::npos); + is_rtp = IsRtpProtocol(media_desc->protocol()); } return is_rtp; } @@ -726,6 +763,11 @@ offer->set_crypto_required(CT_SDES); } offer->set_rtcp_mux(options.rtcp_mux_enabled); + // TODO(deadbeef): Once we're sure this works correctly, enable it in + // CreateOffer. + // if (offer->type() == cricket::MEDIA_TYPE_VIDEO) { + // offer->set_rtcp_reduced_size(true); + // } offer->set_multistream(options.is_muc); offer->set_rtp_header_extensions(rtp_extensions); @@ -1004,6 +1046,11 @@ answer->set_rtp_header_extensions(negotiated_rtp_extensions); answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux()); + // TODO(deadbeef): Once we're sure this works correctly, enable it in + // CreateAnswer. + // if (answer->type() == cricket::MEDIA_TYPE_VIDEO) { + // answer->set_rtcp_reduced_size(offer->rtcp_reduced_size()); + // } if (sdes_policy != SEC_DISABLED) { CryptoParams crypto; @@ -1036,12 +1083,16 @@ answer->set_direction(MD_RECVONLY); break; case MD_RECVONLY: - answer->set_direction(answer->streams().empty() ? MD_INACTIVE - : MD_SENDONLY); + answer->set_direction(IsRtpProtocol(answer->protocol()) && + answer->streams().empty() + ? MD_INACTIVE + : MD_SENDONLY); break; case MD_SENDRECV: - answer->set_direction(answer->streams().empty() ? MD_RECVONLY - : MD_SENDRECV); + answer->set_direction(IsRtpProtocol(answer->protocol()) && + answer->streams().empty() + ? MD_RECVONLY + : MD_SENDRECV); break; default: RTC_DCHECK(false && "MediaContentDescription has unexpected direction."); @@ -1508,13 +1559,18 @@ const AudioCodecs& audio_codecs, StreamParamsVec* current_streams, SessionDescription* desc) const { + const ContentInfo* current_audio_content = + GetFirstAudioContent(current_description); + std::string content_name = + current_audio_content ? current_audio_content->name : CN_AUDIO; + cricket::SecurePolicy sdes_policy = - IsDtlsActive(CN_AUDIO, current_description) ? - cricket::SEC_DISABLED : secure(); + IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED + : secure(); scoped_ptr<AudioContentDescription> audio(new AudioContentDescription()); std::vector<std::string> crypto_suites; - GetSupportedAudioCryptoSuites(&crypto_suites); + GetSupportedAudioCryptoSuiteNames(&crypto_suites); if (!CreateMediaContentOffer( options, audio_codecs, @@ -1546,8 +1602,8 @@ } } - desc->AddContent(CN_AUDIO, NS_JINGLE_RTP, audio.release()); - if (!AddTransportOffer(CN_AUDIO, options.transport_options, + desc->AddContent(content_name, NS_JINGLE_RTP, audio.release()); + if (!AddTransportOffer(content_name, options.audio_transport_options, current_description, desc)) { return false; } @@ -1562,13 +1618,18 @@ const VideoCodecs& video_codecs, StreamParamsVec* current_streams, SessionDescription* desc) const { + const ContentInfo* current_video_content = + GetFirstVideoContent(current_description); + std::string content_name = + current_video_content ? current_video_content->name : CN_VIDEO; + cricket::SecurePolicy sdes_policy = - IsDtlsActive(CN_VIDEO, current_description) ? - cricket::SEC_DISABLED : secure(); + IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED + : secure(); scoped_ptr<VideoContentDescription> video(new VideoContentDescription()); std::vector<std::string> crypto_suites; - GetSupportedVideoCryptoSuites(&crypto_suites); + GetSupportedVideoCryptoSuiteNames(&crypto_suites); if (!CreateMediaContentOffer( options, video_codecs, @@ -1601,8 +1662,8 @@ } } - desc->AddContent(CN_VIDEO, NS_JINGLE_RTP, video.release()); - if (!AddTransportOffer(CN_VIDEO, options.transport_options, + desc->AddContent(content_name, NS_JINGLE_RTP, video.release()); + if (!AddTransportOffer(content_name, options.video_transport_options, current_description, desc)) { return false; } @@ -1623,9 +1684,14 @@ FilterDataCodecs(data_codecs, is_sctp); + const ContentInfo* current_data_content = + GetFirstDataContent(current_description); + std::string content_name = + current_data_content ? current_data_content->name : CN_DATA; + cricket::SecurePolicy sdes_policy = - IsDtlsActive(CN_DATA, current_description) ? - cricket::SEC_DISABLED : secure(); + IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED + : secure(); std::vector<std::string> crypto_suites; if (is_sctp) { // SDES doesn't make sense for SCTP, so we disable it, and we only @@ -1638,7 +1704,7 @@ data->set_protocol( secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp); } else { - GetSupportedDataCryptoSuites(&crypto_suites); + GetSupportedDataCryptoSuiteNames(&crypto_suites); } if (!CreateMediaContentOffer( @@ -1655,13 +1721,13 @@ } if (is_sctp) { - desc->AddContent(CN_DATA, NS_JINGLE_DRAFT_SCTP, data.release()); + desc->AddContent(content_name, NS_JINGLE_DRAFT_SCTP, data.release()); } else { data->set_bandwidth(options.data_bandwidth); SetMediaProtocol(secure_transport, data.get()); - desc->AddContent(CN_DATA, NS_JINGLE_RTP, data.release()); + desc->AddContent(content_name, NS_JINGLE_RTP, data.release()); } - if (!AddTransportOffer(CN_DATA, options.transport_options, + if (!AddTransportOffer(content_name, options.data_transport_options, current_description, desc)) { return false; } @@ -1676,10 +1742,9 @@ SessionDescription* answer) const { const ContentInfo* audio_content = GetFirstAudioContent(offer); - scoped_ptr<TransportDescription> audio_transport( - CreateTransportAnswer(audio_content->name, offer, - options.transport_options, - current_description)); + scoped_ptr<TransportDescription> audio_transport(CreateTransportAnswer( + audio_content->name, offer, options.audio_transport_options, + current_description)); if (!audio_transport) { return false; } @@ -1735,10 +1800,9 @@ StreamParamsVec* current_streams, SessionDescription* answer) const { const ContentInfo* video_content = GetFirstVideoContent(offer); - scoped_ptr<TransportDescription> video_transport( - CreateTransportAnswer(video_content->name, offer, - options.transport_options, - current_description)); + scoped_ptr<TransportDescription> video_transport(CreateTransportAnswer( + video_content->name, offer, options.video_transport_options, + current_description)); if (!video_transport) { return false; } @@ -1791,10 +1855,9 @@ StreamParamsVec* current_streams, SessionDescription* answer) const { const ContentInfo* data_content = GetFirstDataContent(offer); - scoped_ptr<TransportDescription> data_transport( - CreateTransportAnswer(data_content->name, offer, - options.transport_options, - current_description)); + scoped_ptr<TransportDescription> data_transport(CreateTransportAnswer( + data_content->name, offer, options.data_transport_options, + current_description)); if (!data_transport) { return false; }
diff --git a/talk/session/media/mediasession.h b/talk/session/media/mediasession.h index e92628e..1540274 100644 --- a/talk/session/media/mediasession.h +++ b/talk/session/media/mediasession.h
@@ -134,6 +134,10 @@ bool HasSendMediaStream(MediaType type) const; + // TODO(deadbeef): Put all the audio/video/data-specific options into a map + // structure (content name -> options). + // MediaSessionDescriptionFactory assumes there will never be more than one + // audio/video/data content, but this will change with unified plan. bool recv_audio; bool recv_video; DataChannelType data_channel_type; @@ -144,7 +148,9 @@ // bps. -1 == auto. int video_bandwidth; int data_bandwidth; - TransportOptions transport_options; + TransportOptions audio_transport_options; + TransportOptions video_transport_options; + TransportOptions data_transport_options; struct Stream { Stream(MediaType type, @@ -167,17 +173,7 @@ // "content" (as used in XEP-0166) descriptions for voice and video. class MediaContentDescription : public ContentDescription { public: - MediaContentDescription() - : rtcp_mux_(false), - bandwidth_(kAutoBandwidth), - crypto_required_(CT_NONE), - rtp_header_extensions_set_(false), - multistream_(false), - conference_mode_(false), - partial_(false), - buffered_mode_latency_(kBufferedModeDisabled), - direction_(MD_SENDRECV) { - } + MediaContentDescription() {} virtual MediaType type() const = 0; virtual bool has_codecs() const = 0; @@ -195,6 +191,11 @@ bool rtcp_mux() const { return rtcp_mux_; } void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; } + bool rtcp_reduced_size() const { return rtcp_reduced_size_; } + void set_rtcp_reduced_size(bool reduced_size) { + rtcp_reduced_size_ = reduced_size; + } + int bandwidth() const { return bandwidth_; } void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; } @@ -291,19 +292,20 @@ int buffered_mode_latency() const { return buffered_mode_latency_; } protected: - bool rtcp_mux_; - int bandwidth_; + bool rtcp_mux_ = false; + bool rtcp_reduced_size_ = false; + int bandwidth_ = kAutoBandwidth; std::string protocol_; std::vector<CryptoParams> cryptos_; - CryptoType crypto_required_; + CryptoType crypto_required_ = CT_NONE; std::vector<RtpHeaderExtension> rtp_header_extensions_; - bool rtp_header_extensions_set_; - bool multistream_; + bool rtp_header_extensions_set_ = false; + bool multistream_ = false; StreamParamsVec streams_; - bool conference_mode_; - bool partial_; - int buffered_mode_latency_; - MediaContentDirection direction_; + bool conference_mode_ = false; + bool partial_ = false; + int buffered_mode_latency_ = kBufferedModeDisabled; + MediaContentDirection direction_ = MD_SENDRECV; }; template <class C> @@ -547,10 +549,19 @@ const DataContentDescription* GetFirstDataContentDescription( const SessionDescription* sdesc); -void GetSupportedAudioCryptoSuites(std::vector<std::string>* crypto_suites); -void GetSupportedVideoCryptoSuites(std::vector<std::string>* crypto_suites); -void GetSupportedDataCryptoSuites(std::vector<std::string>* crypto_suites); -void GetDefaultSrtpCryptoSuiteNames(std::vector<std::string>* crypto_suites); +void GetSupportedAudioCryptoSuites(std::vector<int>* crypto_suites); +void GetSupportedVideoCryptoSuites(std::vector<int>* crypto_suites); +void GetSupportedDataCryptoSuites(std::vector<int>* crypto_suites); +void GetDefaultSrtpCryptoSuites(std::vector<int>* crypto_suites); +void GetSupportedAudioCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names); +void GetSupportedVideoCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names); +void GetSupportedDataCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names); +void GetDefaultSrtpCryptoSuiteNames( + std::vector<std::string>* crypto_suite_names); + } // namespace cricket #endif // TALK_SESSION_MEDIA_MEDIASESSION_H_
diff --git a/talk/session/media/mediasession_unittest.cc b/talk/session/media/mediasession_unittest.cc index 72aefc8..20b72e9 100644 --- a/talk/session/media/mediasession_unittest.cc +++ b/talk/session/media/mediasession_unittest.cc
@@ -69,6 +69,9 @@ using cricket::AudioContentDescription; using cricket::VideoContentDescription; using cricket::DataContentDescription; +using cricket::GetFirstAudioContent; +using cricket::GetFirstVideoContent; +using cricket::GetFirstDataContent; using cricket::GetFirstAudioContentDescription; using cricket::GetFirstVideoContentDescription; using cricket::GetFirstDataContentDescription; @@ -235,11 +238,9 @@ f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2)); f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2)); tdf1_.set_certificate(rtc::RTCCertificate::Create( - rtc::scoped_ptr<rtc::SSLIdentity>( - new rtc::FakeSSLIdentity("id1")).Pass())); + rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1")))); tdf2_.set_certificate(rtc::RTCCertificate::Create( - rtc::scoped_ptr<rtc::SSLIdentity>( - new rtc::FakeSSLIdentity("id2")).Pass())); + rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2")))); } // Create a video StreamParamsVec object with: @@ -607,6 +608,7 @@ ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80); EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol()); } + // Create a RTP data offer, and ensure it matches what we expect. TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) { MediaSessionOptions opts; @@ -2313,3 +2315,30 @@ audio_content = answer->GetContentByName("audio"); EXPECT_TRUE(VerifyNoCNCodecs(audio_content)); } + +// Test that the content name ("mid" in SDP) is unchanged when creating a +// new offer. +TEST_F(MediaSessionDescriptionFactoryTest, + TestContentNameNotChangedInSubsequentOffers) { + MediaSessionOptions opts; + opts.recv_audio = true; + opts.recv_video = true; + opts.data_channel_type = cricket::DCT_SCTP; + // Create offer and modify the default content names. + rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr)); + for (ContentInfo& content : offer->contents()) { + content.name.append("_modified"); + } + + rtc::scoped_ptr<SessionDescription> updated_offer( + f1_.CreateOffer(opts, offer.get())); + const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get()); + const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get()); + const ContentInfo* data_content = GetFirstDataContent(updated_offer.get()); + ASSERT_TRUE(audio_content != nullptr); + ASSERT_TRUE(video_content != nullptr); + ASSERT_TRUE(data_content != nullptr); + EXPECT_EQ("audio_modified", audio_content->name); + EXPECT_EQ("video_modified", video_content->name); + EXPECT_EQ("data_modified", data_content->name); +}
diff --git a/talk/session/media/srtpfilter.cc b/talk/session/media/srtpfilter.cc index 079ddfb..a200a3c 100644 --- a/talk/session/media/srtpfilter.cc +++ b/talk/session/media/srtpfilter.cc
@@ -146,10 +146,10 @@ return DoSetAnswer(answer_params, source, false); } -bool SrtpFilter::SetRtpParams(const std::string& send_cs, +bool SrtpFilter::SetRtpParams(int send_cs, const uint8_t* send_key, int send_key_len, - const std::string& recv_cs, + int recv_cs, const uint8_t* recv_key, int recv_key_len) { if (IsActive()) { @@ -179,10 +179,10 @@ // SrtpSession. // - In the muxed case, they are keyed with the same keys, so // this function is not needed -bool SrtpFilter::SetRtcpParams(const std::string& send_cs, +bool SrtpFilter::SetRtcpParams(int send_cs, const uint8_t* send_key, int send_key_len, - const std::string& recv_cs, + int recv_cs, const uint8_t* recv_key, int recv_key_len) { // This can only be called once, but can be safely called after @@ -428,10 +428,12 @@ ParseKeyParams(recv_params.key_params, recv_key, sizeof(recv_key))); if (ret) { CreateSrtpSessions(); - ret = (send_session_->SetSend(send_params.cipher_suite, - send_key, sizeof(send_key)) && - recv_session_->SetRecv(recv_params.cipher_suite, - recv_key, sizeof(recv_key))); + ret = (send_session_->SetSend( + rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite), send_key, + sizeof(send_key)) && + recv_session_->SetRecv( + rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite), recv_key, + sizeof(recv_key))); } if (ret) { LOG(LS_INFO) << "SRTP activated with negotiated parameters:" @@ -448,6 +450,10 @@ bool SrtpFilter::ResetParams() { offer_params_.clear(); state_ = ST_INIT; + send_session_ = nullptr; + recv_session_ = nullptr; + send_rtcp_session_ = nullptr; + recv_rtcp_session_ = nullptr; LOG(LS_INFO) << "SRTP reset to init state"; return true; } @@ -507,11 +513,11 @@ } } -bool SrtpSession::SetSend(const std::string& cs, const uint8_t* key, int len) { +bool SrtpSession::SetSend(int cs, const uint8_t* key, int len) { return SetKey(ssrc_any_outbound, cs, key, len); } -bool SrtpSession::SetRecv(const std::string& cs, const uint8_t* key, int len) { +bool SrtpSession::SetRecv(int cs, const uint8_t* key, int len) { return SetKey(ssrc_any_inbound, cs, key, len); } @@ -658,10 +664,7 @@ srtp_stat_->set_signal_silent_time(signal_silent_time_in_ms); } -bool SrtpSession::SetKey(int type, - const std::string& cs, - const uint8_t* key, - int len) { +bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, int len) { if (session_) { LOG(LS_ERROR) << "Failed to create SRTP session: " << "SRTP session already created"; @@ -675,15 +678,15 @@ srtp_policy_t policy; memset(&policy, 0, sizeof(policy)); - if (cs == rtc::CS_AES_CM_128_HMAC_SHA1_80) { + if (cs == rtc::SRTP_AES128_CM_SHA1_80) { crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); - } else if (cs == rtc::CS_AES_CM_128_HMAC_SHA1_32) { + } else if (cs == rtc::SRTP_AES128_CM_SHA1_32) { crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); // rtp is 32, crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // rtcp still 80 } else { LOG(LS_WARNING) << "Failed to create SRTP session: unsupported" - << " cipher_suite " << cs.c_str(); + << " cipher_suite " << cs; return false; }
diff --git a/talk/session/media/srtpfilter.h b/talk/session/media/srtpfilter.h index 3c3a8e8..6b941f3 100644 --- a/talk/session/media/srtpfilter.h +++ b/talk/session/media/srtpfilter.h
@@ -104,16 +104,16 @@ // Just set up both sets of keys directly. // Used with DTLS-SRTP. - bool SetRtpParams(const std::string& send_cs, + bool SetRtpParams(int send_cs, const uint8_t* send_key, int send_key_len, - const std::string& recv_cs, + int recv_cs, const uint8_t* recv_key, int recv_key_len); - bool SetRtcpParams(const std::string& send_cs, + bool SetRtcpParams(int send_cs, const uint8_t* send_key, int send_key_len, - const std::string& recv_cs, + int recv_cs, const uint8_t* recv_key, int recv_key_len); @@ -138,6 +138,8 @@ // Update the silent threshold (in ms) for signaling errors. void set_signal_silent_time(uint32_t signal_silent_time_in_ms); + bool ResetParams(); + sigslot::repeater3<uint32_t, Mode, Error> SignalSrtpError; protected: @@ -153,7 +155,6 @@ CryptoParams* selected_params); bool ApplyParams(const CryptoParams& send_params, const CryptoParams& recv_params); - bool ResetParams(); static bool ParseKeyParams(const std::string& params, uint8_t* key, int len); private: @@ -199,10 +200,10 @@ // Configures the session for sending data using the specified // cipher-suite and key. Receiving must be done by a separate session. - bool SetSend(const std::string& cs, const uint8_t* key, int len); + bool SetSend(int cs, const uint8_t* key, int len); // Configures the session for receiving data using the specified // cipher-suite and key. Sending must be done by a separate session. - bool SetRecv(const std::string& cs, const uint8_t* key, int len); + bool SetRecv(int cs, const uint8_t* key, int len); // Encrypts/signs an individual RTP/RTCP packet, in-place. // If an HMAC is used, this will increase the packet size. @@ -232,7 +233,7 @@ SignalSrtpError; private: - bool SetKey(int type, const std::string& cs, const uint8_t* key, int len); + bool SetKey(int type, int cs, const uint8_t* key, int len); // Returns send stream current packet index from srtp db. bool GetSendStreamPacketIndex(void* data, int in_len, int64_t* index);
diff --git a/talk/session/media/srtpfilter_unittest.cc b/talk/session/media/srtpfilter_unittest.cc index 8122455..1187438 100644 --- a/talk/session/media/srtpfilter_unittest.cc +++ b/talk/session/media/srtpfilter_unittest.cc
@@ -508,21 +508,17 @@ // Test directly setting the params with AES_CM_128_HMAC_SHA1_80 TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_80) { - EXPECT_TRUE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_80, - kTestKey1, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_80, + EXPECT_TRUE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen)); - EXPECT_TRUE(f2_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_80, - kTestKey2, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_80, + EXPECT_TRUE(f2_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_80, - kTestKey1, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_80, + EXPECT_TRUE(f1_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen)); - EXPECT_TRUE(f2_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_80, - kTestKey2, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_80, + EXPECT_TRUE(f2_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); EXPECT_TRUE(f1_.IsActive()); EXPECT_TRUE(f2_.IsActive()); @@ -531,21 +527,17 @@ // Test directly setting the params with AES_CM_128_HMAC_SHA1_32 TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_32) { - EXPECT_TRUE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_32, - kTestKey1, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_32, + EXPECT_TRUE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32, kTestKey2, kTestKeyLen)); - EXPECT_TRUE(f2_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_32, - kTestKey2, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_32, + EXPECT_TRUE(f2_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey2, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_32, - kTestKey1, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_32, + EXPECT_TRUE(f1_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32, kTestKey2, kTestKeyLen)); - EXPECT_TRUE(f2_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_32, - kTestKey2, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_32, + EXPECT_TRUE(f2_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey2, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen)); EXPECT_TRUE(f1_.IsActive()); EXPECT_TRUE(f2_.IsActive()); @@ -554,25 +546,21 @@ // Test directly setting the params with bogus keys TEST_F(SrtpFilterTest, TestSetParamsKeyTooShort) { - EXPECT_FALSE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_80, - kTestKey1, kTestKeyLen - 1, - CS_AES_CM_128_HMAC_SHA1_80, + EXPECT_FALSE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, + kTestKeyLen - 1, rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen - 1)); - EXPECT_FALSE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_80, - kTestKey1, kTestKeyLen - 1, - CS_AES_CM_128_HMAC_SHA1_80, + EXPECT_FALSE(f1_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, + kTestKeyLen - 1, rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen - 1)); } #if defined(ENABLE_EXTERNAL_AUTH) TEST_F(SrtpFilterTest, TestGetSendAuthParams) { - EXPECT_TRUE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_32, - kTestKey1, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_32, + EXPECT_TRUE(f1_.SetRtpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32, kTestKey2, kTestKeyLen)); - EXPECT_TRUE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_32, - kTestKey1, kTestKeyLen, - CS_AES_CM_128_HMAC_SHA1_32, + EXPECT_TRUE(f1_.SetRtcpParams(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, + kTestKeyLen, rtc::SRTP_AES128_CM_SHA1_32, kTestKey2, kTestKeyLen)); uint8_t* auth_key = NULL; int auth_key_len = 0, auth_tag_len = 0; @@ -629,28 +617,30 @@ // Test that we can set up the session and keys properly. TEST_F(SrtpSessionTest, TestGoodSetup) { - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); } // Test that we can't change the keys once set. TEST_F(SrtpSessionTest, TestBadSetup) { - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_FALSE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey2, kTestKeyLen)); - EXPECT_FALSE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey2, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_FALSE( + s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen)); + EXPECT_FALSE( + s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey2, kTestKeyLen)); } // Test that we fail keys of the wrong length. TEST_F(SrtpSessionTest, TestKeysTooShort) { - EXPECT_FALSE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, 1)); - EXPECT_FALSE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, 1)); + EXPECT_FALSE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, 1)); + EXPECT_FALSE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, 1)); } // Test that we can encrypt and decrypt RTP/RTCP using AES_CM_128_HMAC_SHA1_80. TEST_F(SrtpSessionTest, TestProtect_AES_CM_128_HMAC_SHA1_80) { - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_80); TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_80); TestUnprotectRtp(CS_AES_CM_128_HMAC_SHA1_80); @@ -659,8 +649,8 @@ // Test that we can encrypt and decrypt RTP/RTCP using AES_CM_128_HMAC_SHA1_32. TEST_F(SrtpSessionTest, TestProtect_AES_CM_128_HMAC_SHA1_32) { - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_32, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_32, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen)); TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_32); TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_32); TestUnprotectRtp(CS_AES_CM_128_HMAC_SHA1_32); @@ -668,7 +658,7 @@ } TEST_F(SrtpSessionTest, TestGetSendStreamPacketIndex) { - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_32, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_32, kTestKey1, kTestKeyLen)); int64_t index; int out_len = 0; EXPECT_TRUE(s1_.ProtectRtp(rtp_packet_, rtp_len_, @@ -681,8 +671,8 @@ // Test that we fail to unprotect if someone tampers with the RTP/RTCP paylaods. TEST_F(SrtpSessionTest, TestTamperReject) { int out_len; - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); TestProtectRtp(CS_AES_CM_128_HMAC_SHA1_80); TestProtectRtcp(CS_AES_CM_128_HMAC_SHA1_80); rtp_packet_[0] = 0x12; @@ -694,8 +684,8 @@ // Test that we fail to unprotect if the payloads are not authenticated. TEST_F(SrtpSessionTest, TestUnencryptReject) { int out_len; - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); EXPECT_FALSE(s2_.UnprotectRtp(rtp_packet_, rtp_len_, &out_len)); EXPECT_FALSE(s2_.UnprotectRtcp(rtcp_packet_, rtcp_len_, &out_len)); } @@ -703,7 +693,7 @@ // Test that we fail when using buffers that are too small. TEST_F(SrtpSessionTest, TestBuffersTooSmall) { int out_len; - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); EXPECT_FALSE(s1_.ProtectRtp(rtp_packet_, rtp_len_, sizeof(rtp_packet_) - 10, &out_len)); EXPECT_FALSE(s1_.ProtectRtcp(rtcp_packet_, rtcp_len_, @@ -717,8 +707,8 @@ static const uint16_t replay_window = 1024; int out_len; - EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); - EXPECT_TRUE(s2_.SetRecv(CS_AES_CM_128_HMAC_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s1_.SetSend(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); + EXPECT_TRUE(s2_.SetRecv(rtc::SRTP_AES128_CM_SHA1_80, kTestKey1, kTestKeyLen)); // Initial sequence number. rtc::SetBE16(reinterpret_cast<uint8_t*>(rtp_packet_) + 2, seqnum_big);
diff --git a/third_party/gflags/BUILD.gn b/third_party/gflags/BUILD.gn index a2f1c3d..e8a5a13 100644 --- a/third_party/gflags/BUILD.gn +++ b/third_party/gflags/BUILD.gn
@@ -13,7 +13,7 @@ } config("gflags_config") { - include_dirs = [ + include_dirs = [ "$gflags_gen_arch_root/include", # For configured files. "src", # For everything else. ] @@ -25,6 +25,13 @@ "GFLAGS_DLL_DECLARE_FLAG=", "GFLAGS_DLL_DEFINE_FLAG=", ] + + # GN orders flags on a target before flags from configs. The default config + # adds -Wall, and this flag have to be after -Wall -- so they need to + # come from a config and can't be on the target directly. + if (is_clang) { + cflags = [ "-Wno-unused-local-typedef" ] + } } source_set("gflags") { @@ -42,9 +49,7 @@ ] } - include_dirs = [ - "$gflags_gen_arch_root/include/private", # For config.h - ] + include_dirs = [ "$gflags_gen_arch_root/include/private" ] # For config.h public_configs = [ ":gflags_config" ]
diff --git a/third_party/gflags/gflags.gyp b/third_party/gflags/gflags.gyp index 76d2448..d3f2788 100644 --- a/third_party/gflags/gflags.gyp +++ b/third_party/gflags/gflags.gyp
@@ -79,8 +79,10 @@ }, }], ['clang==1', { + 'cflags': ['-Wno-unused-local-typedef',], 'cflags!': ['-Wheader-hygiene',], 'xcode_settings': { + 'WARNING_CFLAGS': ['-Wno-unused-local-typedef',], 'WARNING_CFLAGS!': ['-Wheader-hygiene',], }, }],
diff --git a/third_party/gtest-parallel/README.webrtc b/third_party/gtest-parallel/README.webrtc index acea04f..7e7fdda 100644 --- a/third_party/gtest-parallel/README.webrtc +++ b/third_party/gtest-parallel/README.webrtc
@@ -1,5 +1,5 @@ URL: https://github.com/google/gtest-parallel -Version: c0f8ded77566c657ccc7f745fd9cb070750cccf8 +Version: 92eb6adf9df6eee34bb768b40af984e68e86d7cf License: Apache 2.0 License File: LICENSE
diff --git a/third_party/gtest-parallel/gtest-parallel b/third_party/gtest-parallel/gtest-parallel index 0be59e4..3e2fdb4 100755 --- a/third_party/gtest-parallel/gtest-parallel +++ b/third_party/gtest-parallel/gtest-parallel
@@ -13,16 +13,67 @@ # See the License for the specific language governing permissions and # limitations under the License. import cPickle +import errno import gzip import multiprocessing import optparse import os +import signal import subprocess import sys +import tempfile +import thread import threading import time import zlib +# An object that catches SIGINT sent to the Python process and notices +# if processes passed to wait() die by SIGINT (we need to look for +# both of those cases, because pressing Ctrl+C can result in either +# the main process or one of the subprocesses getting the signal). +# +# Before a SIGINT is seen, wait(p) will simply call p.wait() and +# return the result. Once a SIGINT has been seen (in the main process +# or a subprocess, including the one the current call is waiting for), +# wait(p) will call p.terminate() and raise ProcessWasInterrupted. +class SigintHandler(object): + class ProcessWasInterrupted(Exception): pass + sigint_returncodes = {-signal.SIGINT, # Unix + -1073741510, # Windows + } + def __init__(self): + self.__lock = threading.Lock() + self.__processes = set() + self.__got_sigint = False + signal.signal(signal.SIGINT, self.__sigint_handler) + def __on_sigint(self): + self.__got_sigint = True + while self.__processes: + try: + self.__processes.pop().terminate() + except OSError: + pass + def __sigint_handler(self, signal_num, frame): + with self.__lock: + self.__on_sigint() + def got_sigint(self): + with self.__lock: + return self.__got_sigint + def wait(self, p): + with self.__lock: + if self.__got_sigint: + p.terminate() + self.__processes.add(p) + code = p.wait() + with self.__lock: + self.__processes.discard(p) + if code in self.sigint_returncodes: + self.__on_sigint() + if self.__got_sigint: + raise self.ProcessWasInterrupted + return code +sigint_handler = SigintHandler() + # Return the width of the terminal, or None if it couldn't be # determined (e.g. because we're not being run interactively). def term_width(out): @@ -53,15 +104,21 @@ else: self.__out_file.write("\r" + msg[:self.__width].ljust(self.__width)) self.__previous_line_was_transient = True - def permanent_line(self, msg): + def flush_transient_output(self): if self.__previous_line_was_transient: self.__out_file.write("\n") self.__previous_line_was_transient = False + def permanent_line(self, msg): + self.flush_transient_output() self.__out_file.write(msg + "\n") stdout_lock = threading.Lock() class FilterFormat: + if sys.stdout.isatty(): + # stdout needs to be unbuffered since the output is interactive. + sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) + out = Outputter(sys.stdout) total_tests = 0 finished_tests = 0 @@ -80,7 +137,6 @@ if command == "TEST": (binary, test) = arg.split(' ', 1) self.tests[job_id] = (binary, test.strip()) - self.outputs[job_id] = [] elif command == "EXIT": (exit_code, time_ms) = [int(x) for x in arg.split(' ', 1)] self.finished_tests += 1 @@ -88,8 +144,9 @@ self.print_test_status(test, time_ms) if exit_code != 0: self.failures.append(self.tests[job_id]) - for line in self.outputs[job_id]: - self.out.permanent_line(line) + with open(self.outputs[job_id]) as f: + for line in f.readlines(): + self.out.permanent_line(line.rstrip()) self.out.permanent_line( "[%d/%d] %s returned/aborted with exit code %d (%d ms)" % (self.finished_tests, self.total_tests, test, exit_code, time_ms)) @@ -97,17 +154,15 @@ self.total_tests = int(arg.split(' ', 1)[1]) self.out.transient_line("[0/%d] Running tests..." % self.total_tests) - def add_stdout(self, job_id, output): - self.outputs[job_id].append(output) + def logfile(self, job_id, name): + self.outputs[job_id] = name def log(self, line): stdout_lock.acquire() (prefix, output) = line.split(' ', 1) - if prefix[-1] == ':': - self.handle_meta(int(prefix[:-1]), output) - else: - self.add_stdout(int(prefix[:-1]), output) + assert prefix[-1] == ':' + self.handle_meta(int(prefix[:-1]), output) stdout_lock.release() def end(self): @@ -116,6 +171,7 @@ % (len(self.failures), self.total_tests)) for (binary, test) in self.failures: self.out.permanent_line(" " + binary + ": " + test) + self.out.flush_transient_output() class RawFormat: def log(self, line): @@ -123,6 +179,10 @@ sys.stdout.write(line + "\n") sys.stdout.flush() stdout_lock.release() + def logfile(self, job_id, name): + with open(self.outputs[job_id]) as f: + for line in f.readlines(): + self.log(str(job_id) + '> ' + line.rstrip()) def end(self): pass @@ -149,17 +209,19 @@ return for ((test_binary, test_name), runtime) in times.items(): if (type(test_binary) is not str or type(test_name) is not str - or type(runtime) not in {int, long}): + or type(runtime) not in {int, long, type(None)}): return self.__times = times def get_test_time(self, binary, testname): - "Return the last duration for the given test, or 0 if there's no record." - return self.__times.get((binary, testname), 0) + """Return the last duration for the given test as an integer number of + milliseconds, or None if the test failed or if there's no record for it.""" + return self.__times.get((binary, testname), None) def record_test_time(self, binary, testname, runtime_ms): - "Record that the given test ran in the specified number of milliseconds." + """Record that the given test ran in the specified number of + milliseconds. If the test failed, runtime_ms should be None.""" with self.__lock: self.__times[(binary, testname)] = runtime_ms @@ -184,6 +246,9 @@ parser = optparse.OptionParser( usage = 'usage: %prog [options] binary [binary ...] -- [additional args]') +parser.add_option('-d', '--output_dir', type='string', + default=os.path.join(tempfile.gettempdir(), "gtest-parallel"), + help='output directory for test logs') parser.add_option('-r', '--repeat', type='int', default=1, help='repeat tests') parser.add_option('-w', '--workers', type='int', @@ -197,6 +262,8 @@ default=False, help='run disabled tests too') parser.add_option('--format', type='string', default='filter', help='output format (raw,filter)') +parser.add_option('--print_test_times', action='store_true', default=False, + help='When done, list the run time of each test') (options, binaries) = parser.parse_args() @@ -240,17 +307,21 @@ if line[0] != " ": test_group = line.strip() continue - line = line.strip() - if not options.gtest_also_run_disabled_tests and 'DISABLED' in line: - continue + # Remove comments for parameterized tests and strip whitespace. line = line.split('#')[0].strip() if not line: continue test = test_group + line + if not options.gtest_also_run_disabled_tests and 'DISABLED_' in test: + continue tests.append((times.get_test_time(test_binary, test), test_binary, test, command)) -tests.sort(reverse=True) + +# Sort tests by falling runtime (with None, which is what we get for +# new and failing tests, being considered larger than any real +# runtime). +tests.sort(reverse=True, key=lambda x: ((1 if x[0] is None else 0), x)) # Repeat tests (-r flag). tests *= options.repeat @@ -260,31 +331,41 @@ exit_code = 0 +# Create directory for test log output. +try: + os.makedirs(options.output_dir) +except OSError as e: + # Ignore errors if this directory already exists. + if e.errno != errno.EEXIST or not os.path.isdir(options.output_dir): + raise e +# Remove files from old test runs. +for logfile in os.listdir(options.output_dir): + os.remove(os.path.join(options.output_dir, logfile)) + # Run the specified job. Return the elapsed time in milliseconds if -# the job succeeds, or a very large number (larger than any reasonable -# elapsed time) if the job fails. (This ensures that failing tests -# will run first the next time.) +# the job succeeds, or None if the job fails. (This ensures that +# failing tests will run first the next time.) def run_job((command, job_id, test)): begin = time.time() - sub = subprocess.Popen(command + ['--gtest_filter=' + test] + - ['--gtest_color=' + options.gtest_color], - stdout = subprocess.PIPE, - stderr = subprocess.STDOUT) - while True: - line = sub.stdout.readline() - if line == '': - break - logger.log(str(job_id) + '> ' + line.rstrip()) + with tempfile.NamedTemporaryFile(dir=options.output_dir, delete=False) as log: + sub = subprocess.Popen(command + ['--gtest_filter=' + test] + + ['--gtest_color=' + options.gtest_color], + stdout=log.file, + stderr=log.file) + try: + code = sigint_handler.wait(sub) + except sigint_handler.ProcessWasInterrupted: + thread.exit() + runtime_ms = int(1000 * (time.time() - begin)) + logger.logfile(job_id, log.name) - code = sub.wait() - runtime_ms = int(1000 * (time.time() - begin)) logger.log("%s: EXIT %s %d" % (job_id, code, runtime_ms)) if code == 0: return runtime_ms global exit_code exit_code = code - return sys.maxint + return None def worker(): global job_id @@ -312,4 +393,10 @@ [t.join() for t in workers] logger.end() times.write_to_file(save_file) -sys.exit(exit_code) +if options.print_test_times: + ts = sorted((times.get_test_time(test_binary, test), test_binary, test) + for (_, test_binary, test, _) in tests + if times.get_test_time(test_binary, test) is not None) + for (time_ms, test_binary, test) in ts: + print "%8s %s" % ("%dms" % time_ms, test) +sys.exit(-signal.SIGINT if sigint_handler.got_sigint() else exit_code)
diff --git a/third_party/winsdk_samples/winsdk_samples.gyp b/third_party/winsdk_samples/winsdk_samples.gyp index a9b8598..12bc265 100644 --- a/third_party/winsdk_samples/winsdk_samples.gyp +++ b/third_party/winsdk_samples/winsdk_samples.gyp
@@ -85,6 +85,32 @@ '<(baseclasses_dir)/wxutil.cpp', '<(baseclasses_dir)/wxutil.h', ], + 'conditions': [ + ['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-comment', + '-Wno-delete-non-virtual-dtor', + '-Wno-ignored-attributes', + '-Wno-logical-op-parentheses', + '-Wno-non-pod-varargs', + '-Wno-microsoft-extra-qualification', + '-Wno-missing-braces', + '-Wno-overloaded-virtual', + '-Wno-parentheses', + '-Wno-reorder', + '-Wno-string-conversion', + '-Wno-tautological-constant-out-of-range-compare', + '-Wno-unused-private-field', + '-Wno-writable-strings', + ], + }, + }, + },], + ], # conditions. }, ], }
diff --git a/tools/OWNERS b/tools/OWNERS index 965de1e..3a3f60c 100644 --- a/tools/OWNERS +++ b/tools/OWNERS
@@ -1,4 +1,3 @@ kjellander@webrtc.org phoglund@webrtc.org niklas.enbom@webrtc.org -andrew@webrtc.org
diff --git a/tools/autoroller/roll_chromium_revision.py b/tools/autoroller/roll_chromium_revision.py index 917ecd6..1f974e0 100755 --- a/tools/autoroller/roll_chromium_revision.py +++ b/tools/autoroller/roll_chromium_revision.py
@@ -25,9 +25,6 @@ CHROMIUM_LOG_TEMPLATE = CHROMIUM_SRC_URL + '/+log/%s' CHROMIUM_FILE_TEMPLATE = CHROMIUM_SRC_URL + '/+/%s/%s' -# Run these CQ trybots in addition to the default ones in infra/config/cq.cfg. -EXTRA_TRYBOTS = 'tryserver.webrtc:win_baremetal,mac_baremetal,linux_baremetal' - COMMIT_POSITION_RE = re.compile('^Cr-Commit-Position: .*#([0-9]+).*$') CLANG_REVISION_RE = re.compile(r'^CLANG_REVISION=(\d+)$') ROLL_BRANCH_NAME = 'roll_chromium_revision' @@ -38,14 +35,14 @@ sys.path.append(CHECKOUT_ROOT_DIR) import setup_links -sys.path.append(os.path.join(CHECKOUT_ROOT_DIR, 'tools')) +sys.path.append(os.path.join(CHECKOUT_ROOT_DIR, 'build')) import find_depot_tools find_depot_tools.add_depot_tools_to_path() from gclient import GClientKeywords -CLANG_UPDATE_SCRIPT_URL_PATH = 'tools/clang/scripts/update.sh' +CLANG_UPDATE_SCRIPT_URL_PATH = 'tools/clang/scripts/update.py' CLANG_UPDATE_SCRIPT_LOCAL_PATH = os.path.join('tools', 'clang', 'scripts', - 'update.sh') + 'update.py') DepsEntry = collections.namedtuple('DepsEntry', 'path url revision') ChangedDep = collections.namedtuple('ChangedDep', @@ -292,7 +289,6 @@ commit_msg.append('No update to Clang.\n') commit_msg.append('TBR=%s' % tbr_authors) - commit_msg.append('CQ_EXTRA_TRYBOTS=%s' % EXTRA_TRYBOTS) return '\n'.join(commit_msg)
diff --git a/tools/refactoring/addfileheader.py b/tools/refactoring/addfileheader.py deleted file mode 100644 index 01c8a8b..0000000 --- a/tools/refactoring/addfileheader.py +++ /dev/null
@@ -1,163 +0,0 @@ -#!/usr/bin/env python - -import stringmanipulation -import filemanagement -import sys - -extensions = ['.h','.cc','.c','.cpp'] - -ignore_these = ['my_ignore_header.h'] - -if((len(sys.argv) != 2) and (len(sys.argv) != 3)): - print 'parameters are: directory [--commit]' - quit() - -directory = sys.argv[1]; -if(not filemanagement.pathexist(directory)): - print 'path ' + directory + ' does not exist' - quit() - -if((len(sys.argv) == 3) and (sys.argv[2] != '--commit')): - print 'parameters are: parent directory extension new extension [--commit]' - quit() - -commit = False -if(len(sys.argv) == 3): - commit = True - -files_to_fix = [] -for extension in extensions: - files_to_fix.extend(filemanagement.listallfilesinfolder(directory,\ - extension)) - -# Just steal the header from the template -def fileheaderasstring(): - template_file_name = 'license_template.txt' - if (not filemanagement.fileexist(template_file_name)): - print 'File ' + template_file_name + ' not found!' - quit() - template_file = open(template_file_name,'r') - return_string = '' - for line in template_file: - return_string += line - return return_string - -# Just steal the header from the template -def fileheaderasarray(): - template_file_name = 'license_template.txt' - if (not filemanagement.fileexist(template_file_name)): - print 'File ' + template_file_name + ' not found!' - quit() - template_file = open(template_file_name,'r') - return_value = [] - for line in template_file: - return_value.append(line) - return return_value - - -def findheader(path, file_name): - full_file_name = path + file_name - if (not filemanagement.fileexist(full_file_name)): - print 'File ' + file_name + ' not found!' - print 'Unexpected error!' - quit() - file_handle = open(full_file_name) - template_file_content = fileheaderasarray() - compare_content = [] - # load the same number of lines from file as the fileheader - for index in range(len(template_file_content)): - line = file_handle.readline() - if (line == ''): - return False - compare_content.append(line) - - while (True): - found = True - for index in range(len(template_file_content)): - line1 = template_file_content[index] - line2 = compare_content[index] - if(line1 != line2): - found = False - break - if (found): - return True - compare_content = compare_content[1:len(compare_content)] - line = file_handle.readline() - if (line == ''): - return False - compare_content.append(line) - return False - -# Used to store temporary result before flushing to real file when finished -def temporaryfilename(old_file_name): - return old_file_name + '.deleteme' - -def updatefile(path, old_file_name): - full_old_file_name = path + old_file_name - if (not filemanagement.fileexist(full_old_file_name)): - print 'File ' + full_old_file_name + ' is not found.' - print 'Should not happen! Ever!' - quit() - - full_temporary_file_name = path + temporaryfilename(old_file_name) - - # Make sure that the files are closed by putting them out of scope - old_file = open(full_old_file_name,'r') - temporary_file = open(full_temporary_file_name,'w') - - temporary_file.writelines(fileheaderasstring()) - remove_whitespaces = True - for line in old_file: - if (remove_whitespaces and (len(line.split()) == 0)): - continue - else: - remove_whitespaces = False - temporary_file.writelines(line) - old_file.close() - temporary_file.close() - - filemanagement.copyfile(full_old_file_name,full_temporary_file_name) - filemanagement.deletefile(full_temporary_file_name) - - -failed_files = [] -skipped_files = [] -for index in range(len(files_to_fix)): - if(commit): - print (100*index)/len(files_to_fix) - path_dir = files_to_fix[index][0] - filename = files_to_fix[index][1] - is_ignore = False - for ignore_names in ignore_these: - if(filename == ignore_names): - is_ignore = True - break - if(is_ignore): - continue - -# Let the word copyright be our sanity, i.e. make sure there is only one -# copy right occurance or report that there will be no change - if(filemanagement.findstringinfile(path_dir,filename,'Copyright') or - filemanagement.findstringinfile(path_dir,filename,'copyright') or - filemanagement.findstringinfile(path_dir,filename,'COPYRIGHT')): - if(findheader(path_dir,filename)): - skipped_files.append(path_dir + filename) - else: - failed_files.append(path_dir + filename) - continue - - if (not commit): - print 'File ' + path_dir + filename + ' will be updated' - continue - updatefile(path_dir,filename) - -tense = 'will be' -if (commit): - tense = 'has been' -if (len(skipped_files) > 0): - print str(len(skipped_files)) + ' file(s) ' + tense + ' skipped since they already have the correct header' - -if (len(failed_files) > 0): - print 'Following files seem to have an invalid file header:' -for line in failed_files: - print line
diff --git a/tools/refactoring/filemanagement.py b/tools/refactoring/filemanagement.py deleted file mode 100644 index 4ff64ce..0000000 --- a/tools/refactoring/filemanagement.py +++ /dev/null
@@ -1,72 +0,0 @@ -import fnmatch -import os -import stringmanipulation - -def fileexist( file_name ): - return os.path.isfile(file_name) - -def pathexist( path ): - return os.path.exists(path) - -def fixpath( path ): - return_value = path - if( return_value[len(return_value) - 1] != '/'): - return_value = return_value + '/' - return return_value - -def listallfilesinfolder( path, extension ): - matches = [] - signature = '*' + extension - for root, dirnames, filenames in os.walk(path): - for filename in fnmatch.filter(filenames, signature): - matches.append([fixpath(root), filename]) - return matches - -def copyfile(to_file, from_file): - if(not fileexist(from_file)): - return - command = 'cp -f ' + from_file + ' ' + to_file - os.system(command) - #print command - -def deletefile(file_to_delete): - if(not fileexist(file_to_delete)): - return - os.system('rm ' + file_to_delete) - -# very ugly but works, so keep for now -def findstringinfile(path,file_name,search_string): - command = 'grep \'' + search_string + '\' ' + path + file_name + ' > deleteme.txt' - return_value = os.system(command) -# print command - return (return_value == 0) - -def replacestringinfolder( path, old_string, new_string, extension ): - if(not stringmanipulation.isextension(extension)): - print 'failed to search and replace' - return - if(len(old_string) == 0): - print 'failed to search and replace' - return - find_command = 'ls '+ path + '/*' + extension - sed_command = 'sed -i \'s/' + old_string + '/' + new_string +\ - '/g\' *' + extension - command_string = find_command + ' | xargs ' + sed_command + ' 2> deleteme.txt' - os.system(command_string) - #print command_string - -#find ./ -name "*.h" -type f | xargs -P 0 sed -i 's/process_thread_wrapper.h/process_thread.h/g' *.h deleteme.txt -def replacestringinallsubfolders( old_string, new_string, extension): - if(not stringmanipulation.isextension(extension)): - print 'failed to search and replace' - return - if(len(old_string) == 0): - print 'failed to search and replace' - return - - find_command = 'find ./ -name \"*' + extension + '\" -type f' - sed_command = 'sed -i \'s/' + old_string + '/' + new_string +\ - '/g\' *' + extension - command_string = find_command + ' | xargs -P 0 ' + sed_command + ' 2> deleteme.txt' - os.system(command_string) - #print command_string
diff --git a/tools/refactoring/fixincludeguards.py b/tools/refactoring/fixincludeguards.py deleted file mode 100644 index 0b56355..0000000 --- a/tools/refactoring/fixincludeguards.py +++ /dev/null
@@ -1,145 +0,0 @@ -#!/usr/bin/env python - -import stringmanipulation -import filemanagement -import sys - -extensions = ['.h'] - -ignore_these = ['my_ignore_header.h'] - -if((len(sys.argv) != 2) and (len(sys.argv) != 3)): - print 'parameters are: directory [--commit]' - quit() - -directory = sys.argv[1]; -if(not filemanagement.pathexist(directory)): - print 'path ' + directory + ' does not exist' - quit() - -if((len(sys.argv) == 3) and (sys.argv[2] != '--commit')): - print 'parameters are: parent directory extension new extension [--commit]' - quit() - -commit = False -if(len(sys.argv) == 3): - commit = True - -for extension in extensions: - files_to_fix = filemanagement.listallfilesinfolder(directory,\ - extension) - -def buildincludeguardname(path,filename): - full_file_name = 'WEBRTC_' + path + filename - full_file_name = full_file_name.upper() - full_file_name = stringmanipulation.replaceoccurances(full_file_name, '/', '_') - full_file_name = stringmanipulation.replaceoccurances(full_file_name, '\\', '_') - full_file_name = stringmanipulation.replaceoccurances(full_file_name, '.', '_') - full_file_name += '_' - return full_file_name - -def buildnewincludeguardset(path,filename): - include_guard_name = buildincludeguardname(path,filename) - if(include_guard_name == ''): - return [] - return_value = [] - return_value.append('#ifndef ' + include_guard_name) - return_value.append('#define ' + include_guard_name) - return_value.append(include_guard_name) - return return_value - -def printincludeguardset(include_guard_set): - print 'First line: ' + include_guard_set[0] - print 'Second line: ' + include_guard_set[1] - print 'Last line: ' + include_guard_set[2] - return - -include_guard_begin_identifier = ['#ifndef', '#if !defined'] -include_guard_second_identifier = ['#define'] -def findincludeguardidentifier(line): - for begin_identifier in include_guard_begin_identifier: - line = stringmanipulation.removealloccurances(line,begin_identifier) - for second_identifier in include_guard_begin_identifier: - line = stringmanipulation.removealloccurances(line,second_identifier) - removed_prefix = [True,''] - line = stringmanipulation.whitespacestoonespace(line) - while(removed_prefix[0]): - removed_prefix = stringmanipulation.removeprefix(line,' ') - line = removed_prefix[1] - line = stringmanipulation.removealloccurances(line,'(') - if(line == ''): - return '' - word_pos = stringmanipulation.getword(line,0) - return_value = line[0:word_pos[1]] - return_value = return_value.rstrip('\r\n') - return return_value - -def findoldincludeguardset(path,filename): - return_value = [] - full_file_name = path + filename - file_pointer = open(full_file_name,'r') - include_guard_name = '' - for line in file_pointer: - if (include_guard_name == ''): - for compare_string in include_guard_begin_identifier: - if (stringmanipulation.issubstring(compare_string, line) != -1): - include_guard_name = findincludeguardidentifier(line) - if (include_guard_name == ''): - break - line = line.rstrip('\r\n') - return_value.append(line) - break - else: - for compare_string in include_guard_second_identifier: - if (stringmanipulation.issubstring(compare_string, line) != -1): - if (stringmanipulation.issubstring(include_guard_name, line) != -1): - line = line.rstrip('\r\n') - return_value.append(line) - return_value.append(include_guard_name) - return return_value - include_guard_name = '' - return_value = [] - return [] - -failed_files = [] -for index in range(len(files_to_fix)): - if(commit): - print (100*index)/len(files_to_fix) - path_dir = files_to_fix[index][0] - filename = files_to_fix[index][1] - is_ignore = False - for ignore_names in ignore_these: - if(filename == ignore_names): - is_ignore = True - break - if(is_ignore): - continue - old_include_guard_set = findoldincludeguardset(path_dir,filename) - if (len(old_include_guard_set) != 3) : - failed_files.append('unable to figure out the include guards for ' + filename) - continue - - new_include_guard_set = buildnewincludeguardset(path_dir,filename) - if (len(new_include_guard_set) != 3) : - failed_files.append('unable to figure out new the include guards for ' + filename) - continue - - if(not commit): - print 'old guard: ' + old_include_guard_set[2] - print 'new guard: ' + new_include_guard_set[2] - continue - - for index in range(2): - # enough to only replace for file. However, no function for that - for extension in extensions: - filemanagement.replacestringinfolder(path_dir,old_include_guard_set[index],new_include_guard_set[index],extension) - # special case for last to avoid complications - for extension in extensions: - filemanagement.replacestringinfolder(path_dir,' ' + old_include_guard_set[2],' ' + new_include_guard_set[2],extension) - filemanagement.replacestringinfolder(path_dir,'\\/\\/' + old_include_guard_set[2],'\\/\\/ ' + new_include_guard_set[2],extension) - - -if(len(failed_files) > 0): - print 'Following failures should be investigated manually:' -for line in failed_files: - print line
diff --git a/tools/refactoring/fixnames.py b/tools/refactoring/fixnames.py deleted file mode 100644 index 15381e3..0000000 --- a/tools/refactoring/fixnames.py +++ /dev/null
@@ -1,387 +0,0 @@ -#!/usr/bin/env python - -import stringmanipulation -import filemanagement -import p4commands -import sys - -name_space_to_ignore = 'GIPS::' -#only allow one prefix to be removed since allowing multiple will complicate -# things -prefix_to_filter = 'gips' -#words_to_filter = ['Module'] -# it might be dangerous to remove GIPS but keep it default -words_to_filter = ['Module','GIPS'] - -# This script finds all the words that should be replaced in an h-file. Once -# all words that should be replaced are found it does a global search and -# replace. - -extensions_to_edit = ['.cpp','.cc','.h'] - -#line = ' ~hiGIPSCriticalSectionScoped()' -#print line -#position = stringmanipulation.getword(line,11) -#old_word = line[position[0]:position[0]+position[1]] -#result = stringmanipulation.removealloccurances(old_word,'gips') -#new_word = result -#print old_word -#print position[0] -#print position[0]+position[1] -#print new_word -#quit() - -# Ignore whole line if any item in this table is a substring of the line -do_not_replace_line_table = [] -do_not_replace_line_table.append('namespace GIPS') - -# [old_string,new_string] -# List of things to remove that are static: -manual_replace_table = [] -#manual_replace_table.append(['using namespace GIPS;','']) -#manual_replace_table.append(['CreateGipsEvent','CreateEvent']) -#manual_replace_table.append(['CreateGIPSTrace','CreateTrace']) -#manual_replace_table.append(['ReturnGIPSTrace','ReturnTrace']) -#manual_replace_table.append(['CreateGIPSFile','CreateFile']) -replace_table = manual_replace_table -#replace_table.append(['GIPS::','webrtc::']) -# List of things to not remove that are static, i.e. exceptions: -# don't replace any of the GIPS_Words since that will affect all files -# do that in a separate script! -do_not_replace_table = [] -do_not_replace_table.append('GIPS_CipherTypes') -do_not_replace_table.append('GIPS_AuthenticationTypes') -do_not_replace_table.append('GIPS_SecurityLevels') -do_not_replace_table.append('GIPS_encryption') -do_not_replace_table.append('~GIPS_encryption') -do_not_replace_table.append('GIPS_transport') -do_not_replace_table.append('~GIPS_transport') -do_not_replace_table.append('GIPSTraceCallback') -do_not_replace_table.append('~GIPSTraceCallback') -do_not_replace_table.append('GIPS_RTP_CSRC_SIZE') -do_not_replace_table.append('GIPS_RTPDirections') -do_not_replace_table.append('GIPS_RTP_INCOMING') -do_not_replace_table.append('GIPS_RTP_OUTGOING') -do_not_replace_table.append('GIPSFrameType') -do_not_replace_table.append('GIPS_FRAME_EMPTY') -do_not_replace_table.append('GIPS_AUDIO_FRAME_SPEECH') -do_not_replace_table.append('GIPS_AUDIO_FRAME_CN') -do_not_replace_table.append('GIPS_VIDEO_FRAME_KEY') -do_not_replace_table.append('GIPS_VIDEO_FRAME_DELTA') -do_not_replace_table.append('GIPS_VIDEO_FRAME_GOLDEN') -do_not_replace_table.append('GIPS_VIDEO_FRAME_DELTA_KEY') -do_not_replace_table.append('GIPS_PacketType') -do_not_replace_table.append('GIPS_PACKET_TYPE_RTP') -do_not_replace_table.append('GIPS_PACKET_TYPE_KEEP_ALIVE') -do_not_replace_table.append('GIPS_AudioLayers') -do_not_replace_table.append('GIPS_AUDIO_PLATFORM_DEFAULT') -do_not_replace_table.append('GIPS_AUDIO_WINDOWS_WAVE') -do_not_replace_table.append('GIPS_AUDIO_WINDOWS_CORE') -do_not_replace_table.append('GIPS_AUDIO_LINUX_ALSA') -do_not_replace_table.append('GIPS_AUDIO_LINUX_PULSE') -do_not_replace_table.append('GIPS_AUDIO_FORMAT') -do_not_replace_table.append('GIPS_PCM_16_16KHZ') -do_not_replace_table.append('GIPS_PCM_16_8KHZ') -do_not_replace_table.append('GIPS_G729') -do_not_replace_table.append('GIPSAMRmode') -do_not_replace_table.append('GIPS_RFC3267_BWEFFICIENT') -do_not_replace_table.append('GIPS_RFC3267_OCTETALIGNED') -do_not_replace_table.append('GIPS_RFC3267_FILESTORAGE') -do_not_replace_table.append('GIPS_NCModes') -do_not_replace_table.append('GIPS_NC_OFF') -do_not_replace_table.append('GIPS_NC_MILD') -do_not_replace_table.append('GIPS_NC_MODERATE') -do_not_replace_table.append('GIPS_NC_AGGRESSIVE') -do_not_replace_table.append('GIPS_NC_VERY_AGGRESSIVE') -do_not_replace_table.append('GIPS_AGCModes') -do_not_replace_table.append('GIPS_AGC_OFF') -do_not_replace_table.append('GIPS_AGC_ANALOG') -do_not_replace_table.append('GIPS_AGC_DIGITAL') -do_not_replace_table.append('GIPS_AGC_STANDALONE_DIG') -do_not_replace_table.append('GIPS_ECModes') -do_not_replace_table.append('GIPS_EC_UNCHANGED') -do_not_replace_table.append('GIPS_EC_DEFAULT') -do_not_replace_table.append('GIPS_EC_CONFERENCE') -do_not_replace_table.append('GIPS_EC_AEC') -do_not_replace_table.append('GIPS_EC_AES') -do_not_replace_table.append('GIPS_EC_AECM') -do_not_replace_table.append('GIPS_EC_NEC_IAD') -do_not_replace_table.append('GIPS_AESModes') -do_not_replace_table.append('GIPS_AES_DEFAULT') -do_not_replace_table.append('GIPS_AES_NORMAL') -do_not_replace_table.append('GIPS_AES_HIGH') -do_not_replace_table.append('GIPS_AES_ATTENUATE') -do_not_replace_table.append('GIPS_AES_NORMAL_SOFT_TRANS') -do_not_replace_table.append('GIPS_AES_HIGH_SOFT_TRANS') -do_not_replace_table.append('GIPS_AES_ATTENUATE_SOFT_TRANS') -do_not_replace_table.append('GIPS_AECMModes') -do_not_replace_table.append('GIPS_AECM_QUIET_EARPIECE_OR_HEADSET') -do_not_replace_table.append('GIPS_AECM_EARPIECE') -do_not_replace_table.append('GIPS_AECM_LOUD_EARPIECE') -do_not_replace_table.append('GIPS_AECM_SPEAKERPHONE') -do_not_replace_table.append('GIPS_AECM_LOUD_SPEAKERPHONE') -do_not_replace_table.append('AECM_LOUD_SPEAKERPHONE') -do_not_replace_table.append('GIPS_VAD_CONVENTIONAL') -do_not_replace_table.append('GIPS_VAD_AGGRESSIVE_LOW') -do_not_replace_table.append('GIPS_VAD_AGGRESSIVE_MID') -do_not_replace_table.append('GIPS_VAD_AGGRESSIVE_HIGH') -do_not_replace_table.append('GIPS_NetEQModes') -do_not_replace_table.append('GIPS_NETEQ_DEFAULT') -do_not_replace_table.append('GIPS_NETEQ_STREAMING') -do_not_replace_table.append('GIPS_NETEQ_FAX') -do_not_replace_table.append('GIPS_NetEQBGNModes') -do_not_replace_table.append('GIPS_BGN_ON') -do_not_replace_table.append('GIPS_BGN_FADE') -do_not_replace_table.append('GIPS_BGN_OFF') -do_not_replace_table.append('GIPS_OnHoldModes') -do_not_replace_table.append('GIPS_HOLD_SEND_AND_PLAY') -do_not_replace_table.append('GIPS_HOLD_SEND_ONLY') -do_not_replace_table.append('GIPS_HOLD_PLAY_ONLY') -do_not_replace_table.append('GIPS_PayloadFrequencies') -do_not_replace_table.append('GIPS_FREQ_8000_HZ') -do_not_replace_table.append('GIPS_FREQ_16000_HZ') -do_not_replace_table.append('GIPS_FREQ_32000_HZ') -do_not_replace_table.append('GIPS_TelephoneEventDetectionMethods') -do_not_replace_table.append('GIPS_IN_BAND') -do_not_replace_table.append('GIPS_OUT_OF_BAND') -do_not_replace_table.append('GIPS_IN_AND_OUT_OF_BAND') -do_not_replace_table.append('GIPS_ProcessingTypes') -do_not_replace_table.append('GIPS_PLAYBACK_PER_CHANNEL') -do_not_replace_table.append('GIPS_PLAYBACK_ALL_CHANNELS_MIXED') -do_not_replace_table.append('GIPS_RECORDING_PER_CHANNEL') -do_not_replace_table.append('GIPS_RECORDING_ALL_CHANNELS_MIXED') -do_not_replace_table.append('GIPS_StereoChannel') -do_not_replace_table.append('GIPS_StereoLeft') -do_not_replace_table.append('GIPS_StereoRight') -do_not_replace_table.append('GIPS_StereoBoth') -do_not_replace_table.append('GIPS_stat_val') -do_not_replace_table.append('GIPS_P56_statistics') -do_not_replace_table.append('GIPS_echo_statistics') -do_not_replace_table.append('GIPS_NetworkStatistics') -do_not_replace_table.append('GIPS_JitterStatistics') -do_not_replace_table.append('GIPSVideoRawType') -do_not_replace_table.append('GIPS_VIDEO_I420') -do_not_replace_table.append('GIPS_VIDEO_YV12') -do_not_replace_table.append('GIPS_VIDEO_YUY2') -do_not_replace_table.append('GIPS_VIDEO_UYVY') -do_not_replace_table.append('GIPS_VIDEO_IYUV') -do_not_replace_table.append('GIPS_VIDEO_ARGB') -do_not_replace_table.append('GIPS_VIDEO_RGB24') -do_not_replace_table.append('GIPS_VIDEO_RGB565') -do_not_replace_table.append('GIPS_VIDEO_ARGB4444') -do_not_replace_table.append('GIPS_VIDEO_ARGB1555') -do_not_replace_table.append('GIPS_VIDEO_MJPG') -do_not_replace_table.append('GIPS_VIDEO_NV12') -do_not_replace_table.append('GIPS_VIDEO_NV21') -do_not_replace_table.append('GIPS_VIDEO_Unknown') -do_not_replace_table.append('GIPSVideoLayouts') -do_not_replace_table.append('GIPS_LAYOUT_NONE') -do_not_replace_table.append('GIPS_LAYOUT_DEFAULT') -do_not_replace_table.append('GIPS_LAYOUT_ADVANCED1') -do_not_replace_table.append('GIPS_LAYOUT_ADVANCED2') -do_not_replace_table.append('GIPS_LAYOUT_ADVANCED3') -do_not_replace_table.append('GIPS_LAYOUT_ADVANCED4') -do_not_replace_table.append('GIPS_LAYOUT_FULL') -do_not_replace_table.append('KGIPSConfigParameterSize') -do_not_replace_table.append('KGIPSPayloadNameSize') -do_not_replace_table.append('GIPSVideoCodecH263') -do_not_replace_table.append('GIPSVideoH264Packetization') -do_not_replace_table.append('GIPS_H264_SingleMode') -do_not_replace_table.append('GIPS_H264_NonInterleavedMode') -do_not_replace_table.append('GIPSVideoCodecComplexity') -do_not_replace_table.append('GIPSVideoCodec_Complexity_Normal') -do_not_replace_table.append('GIPSVideoCodec_Comlexity_High') -do_not_replace_table.append('GIPSVideoCodec_Comlexity_Higher') -do_not_replace_table.append('GIPSVideoCodec_Comlexity_Max') -do_not_replace_table.append('GIPSVideoCodecH264') -do_not_replace_table.append('GIPSVideoH264Packetization') -do_not_replace_table.append('GIPSVideoCodecComplexity') -do_not_replace_table.append('GIPSVideoCodecProfile') -do_not_replace_table.append('KGIPSConfigParameterSize') -do_not_replace_table.append('KGIPSMaxSVCLayers') -do_not_replace_table.append('GIPSVideoH264LayerTypes') -do_not_replace_table.append('GIPS_H264SVC_Base') -do_not_replace_table.append('GIPS_H264SVC_Extend_2X2') -do_not_replace_table.append('GIPS_H264SVC_Extend_1X1') -do_not_replace_table.append('GIPS_H264SVC_Extend_MGS') -do_not_replace_table.append('GIPS_H264SVC_Extend_1_5') -do_not_replace_table.append('GIPS_H264SVC_Extend_Custom') -do_not_replace_table.append('GIPSVideoH264LayersProperties') -do_not_replace_table.append('GIPSVideoH264LayerTypes') -do_not_replace_table.append('GIPSVideoH264Layers') -do_not_replace_table.append('GIPSVideoH264LayersProperties') -do_not_replace_table.append('GIPSVideoCodecH264SVC') -do_not_replace_table.append('GIPSVideoCodecComplexity') -do_not_replace_table.append('GIPSVideoCodecProfile') -do_not_replace_table.append('GIPSVideoH264Layers') -do_not_replace_table.append('GIPSVideoCodecVP8') -do_not_replace_table.append('GIPSVideoCodecComplexity') -do_not_replace_table.append('GIPSVideoCodecMPEG') -do_not_replace_table.append('GIPSVideoCodecGeneric') -do_not_replace_table.append('GIPSVideoCodecType') -do_not_replace_table.append('GIPSVideoCodec_H263') -do_not_replace_table.append('GIPSVideoCodec_H264') -do_not_replace_table.append('GIPSVideoCodec_H264SVC') -do_not_replace_table.append('GIPSVideoCodec_VP8') -do_not_replace_table.append('GIPSVideoCodec_MPEG4') -do_not_replace_table.append('GIPSVideoCodec_I420') -do_not_replace_table.append('GIPSVideoCodec_RED') -do_not_replace_table.append('GIPSVideoCodec_ULPFEC') -do_not_replace_table.append('GIPSVideoCodec_Unknown') -do_not_replace_table.append('GIPSVideoCodecUnion') -do_not_replace_table.append('GIPSVideoCodecH263') -do_not_replace_table.append('GIPSVideoCodecH264') -do_not_replace_table.append('GIPSVideoCodecH264SVC') -do_not_replace_table.append('GIPSVideoCodecVP8') -do_not_replace_table.append('GIPSVideoCodecMPEG4') -do_not_replace_table.append('GIPSVideoCodecGeneric') -do_not_replace_table.append('GIPSVideoCodec') -do_not_replace_table.append('GIPSVideoCodecType') -do_not_replace_table.append('GIPSVideoCodecUnion') -do_not_replace_table.append('GIPSAudioFrame') -do_not_replace_table.append('GIPS_CodecInst') -do_not_replace_table.append('GIPS_FileFormats') -do_not_replace_table.append('GIPSTickTime') -do_not_replace_table.append('GIPS_Word64') -do_not_replace_table.append('GIPS_UWord64') -do_not_replace_table.append('GIPS_Word32') -do_not_replace_table.append('GIPS_UWord32') -do_not_replace_table.append('GIPS_Word16') -do_not_replace_table.append('GIPS_UWord16') -do_not_replace_table.append('GIPS_Word8') -do_not_replace_table.append('GIPS_UWord8') - -if((len(sys.argv) != 2) and (len(sys.argv) != 3)): - print 'parameters are: parent directory [--commit]' - quit() - -if((len(sys.argv) == 3) and (sys.argv[2] != '--commit')): - print 'parameters are: parent directory [--commit]' - quit() - -commit = (len(sys.argv) == 3) - -directory = sys.argv[1]; -if(not filemanagement.pathexist(directory)): - print 'path ' + directory + ' does not exist' - quit() - -# APIs are all in h-files -extension = '.h' - -# All h-files -files_to_modify = filemanagement.listallfilesinfolder(directory,\ - extension) - -def isinmanualremovetable( compare_word ): - for old_word, new_word in manual_replace_table: - if(old_word == compare_word): - return True - return False - -# Begin -# This function looks at each line and decides which words should be replaced -# that is this is the only part of the script that you will ever want to change! -def findstringstoreplace(line): - original_line = line -# Dont replace compiler directives - if(line[0] == '#'): - return [] -# Dont allow global removal of namespace gips since it is very intrusive - for sub_string_compare in do_not_replace_line_table: - index = stringmanipulation.issubstring(line,sub_string_compare) - if(index != -1): - return [] - - return_value = [] - - line = stringmanipulation.removeccomment(line) - line = stringmanipulation.whitespacestoonespace(line) - if(len(line) == 0): - return [] - if(line[0] == '*'): - return [] - index = stringmanipulation.issubstring(line,prefix_to_filter) - while index >= 0: - dont_store_hit = False - word_position = stringmanipulation.getword(line, index) - start_of_word = word_position[0] - size_of_word = word_position[1] - end_of_word = start_of_word + size_of_word - old_word = line[start_of_word:end_of_word] - if(isinmanualremovetable(old_word)): - dont_store_hit = True - if((end_of_word + 2 < len(line)) and\ - name_space_to_ignore == line[start_of_word:end_of_word+2]): - dont_store_hit = True - - result = stringmanipulation.removeprefix(old_word,prefix_to_filter) - new_word = result[1] - for word_to_filter in words_to_filter: - new_word = stringmanipulation.removealloccurances(new_word,word_to_filter) - result = stringmanipulation.removeprefix(new_word,'_') - new_word = result[1] - new_word = stringmanipulation.fixabbreviations(new_word) - new_word = stringmanipulation.removealloccurances(new_word,'_') - if(not dont_store_hit): - return_value.append([old_word,new_word]) -# remove the word we found from the string so we dont find it again - line = line[0:start_of_word] + line[end_of_word:len(line)] - index = stringmanipulation.issubstring(line,'GIPS') - - return return_value -# End - -# loop through all files -for path, file_name in files_to_modify: -# if(file_name != 'GIPSTickUtil.h'): -# continue - full_file_name = path + file_name - file_pointer = open(full_file_name,'r') -# print file_name -#loop through all lines - for line in file_pointer: -# print line - local_replace_string = findstringstoreplace(line) - #print local_replace_string - if(len(local_replace_string) != 0): - replace_table.extend(local_replace_string) - - -# we have built our replace table now -replace_table = stringmanipulation.removeduplicates( replace_table ) -replace_table = stringmanipulation.ordertablesizefirst( replace_table ) -replace_table = stringmanipulation.complement(replace_table,\ - do_not_replace_table) - -def replaceoriginal( path,my_table ): - size_of_table = len(my_table) - for index in range(len(my_table)): - old_name = my_table[index][0] - new_name = my_table[index][1] - filemanagement.replacestringinfolder(path, old_name, new_name,\ - ".h") - print (100*index) / (size_of_table*2) - -def replaceall( my_table, extension_list ): - size_of_table = len(my_table) - for index in range(len(my_table)): - old_name = my_table[index][0] - new_name = my_table[index][1] - new_name = new_name - for extension in extensions_to_edit: - filemanagement.replacestringinallsubfolders(old_name, new_name, - extension) - print 100*(size_of_table + index) / (size_of_table*2) - - -if(commit): - print 'commiting' - replace_table = stringmanipulation.removenochange(replace_table) - p4commands.checkoutallfiles() - replaceoriginal(directory,replace_table) - replaceall(replace_table,extensions_to_edit) - p4commands.revertunchangedfiles() -else: - for old_name, new_name in replace_table: - print 'Going to replace [' + old_name + '] with [' + new_name + ']'
diff --git a/tools/refactoring/integratefiles.py b/tools/refactoring/integratefiles.py deleted file mode 100644 index c5cc892..0000000 --- a/tools/refactoring/integratefiles.py +++ /dev/null
@@ -1,100 +0,0 @@ -#!/usr/bin/env python - -import stringmanipulation -import filemanagement -import p4commands -import sys - -extensions = ['.h', '.cpp', '.cc', '.gyp'] - -ignore_these = ['list_no_stl.h','map_no_stl.h','constructor_magic.h'] - -exceptions = [ -['GIPSRWLock.h','rw_lock.h'], -['GIPSCriticalsection.h','critical_section.h'], -] - -if((len(sys.argv) != 4) and (len(sys.argv) != 5)): - print 'parameters are: parent directory extension new extension [--commit]' - quit() - -directory = sys.argv[1]; -if(not filemanagement.pathexist(directory)): - print 'path ' + directory + ' does not exist' - quit() - -old_extension = sys.argv[2] -if(not stringmanipulation.isextension(old_extension)): - print old_extension + ' is not a valid extension' - quit() - -new_extension = sys.argv[3] -if(not stringmanipulation.isextension(new_extension)): - print new_extension + ' is not a valid extension' - quit() - -if((len(sys.argv) == 5) and (sys.argv[4] != '--commit')): - print 'parameters are: parent directory extension new extension [--commit]' - quit() - -commit = False -if(len(sys.argv) == 5): - commit = True - -files_to_integrate = filemanagement.listallfilesinfolder(directory,\ - old_extension) - -if(commit): - p4commands.checkoutallfiles() -for index in range(len(files_to_integrate)): - if(commit): - print (100*index)/len(files_to_integrate) - path_dir = files_to_integrate[index][0] - filename = files_to_integrate[index][1] - is_ignore = False - for ignore_names in ignore_these: - if(filename == ignore_names): - is_ignore = True - break - if(is_ignore): - continue - - new_file_name = '' - is_exception = False - for exception_name,exception_name_new in exceptions: - if(filename == exception_name): - is_exception = True - new_file_name = exception_name_new - break - - if(not is_exception): - new_file_name = filename - - new_file_name = stringmanipulation.removeallprefix(new_file_name,\ - 'gips') - new_file_name = stringmanipulation.removealloccurances(new_file_name,\ - 'module') - new_file_name = stringmanipulation.changeextension(new_file_name,\ - old_extension,\ - new_extension) - new_file_name = stringmanipulation.fixabbreviations( new_file_name ) - new_file_name = stringmanipulation.lowercasewithunderscore(new_file_name) - if(not commit): - print 'File ' + filename + ' will be replaced with ' + new_file_name - continue - full_new_file_name = path_dir + new_file_name - full_old_file_name = path_dir + filename - if(full_new_file_name != full_old_file_name): - p4commands.integratefile(full_old_file_name,full_new_file_name) - else: - print 'skipping ' + new_file_name + ' due to no change' - for extension in extensions: - print 'replacing ' + filename - if (extension == ".gyp"): - filemanagement.replacestringinallsubfolders( - filename,new_file_name,extension) - else: - filemanagement.replacestringinallsubfolders( - '\"' + filename + '\"', '\"' + new_file_name + '\"', extension) -if(commit): - p4commands.revertunchangedfiles()
diff --git a/tools/refactoring/p4commands.py b/tools/refactoring/p4commands.py deleted file mode 100644 index 71ac31b..0000000 --- a/tools/refactoring/p4commands.py +++ /dev/null
@@ -1,31 +0,0 @@ -import os -import filemanagement - -# checks out entire p4 repository -def checkoutallfiles(): - os.system('p4 edit //depotGoogle/...') - return - -# reverts all unchanged files, this is completely innoculus -def revertunchangedfiles(): - os.system('p4 revert -a //depotGoogle/...') - return - -def integratefile( old_name, new_name): - if(old_name == new_name): - return - if(not filemanagement.fileexist(old_name)): - return - integrate_command = 'p4 integrate -o -f ' +\ - old_name +\ - ' ' +\ - new_name +\ - ' > p4summary.txt 2> error.txt' - os.system(integrate_command) - #print integrate_command - delete_command = 'p4 delete -c default ' +\ - old_name +\ - ' > p4summary.txt 2> error.txt' - os.system(delete_command) - #print delete_command - return
diff --git a/tools/refactoring/removetrace.py b/tools/refactoring/removetrace.py deleted file mode 100644 index 43c622d..0000000 --- a/tools/refactoring/removetrace.py +++ /dev/null
@@ -1,161 +0,0 @@ -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -# NOTE: This is a hack which disobeys a number of conventions and best -# practices. It's here just to be easily shared. If it's to remain in the -# repository it should be refactored. - -#!/usr/bin/env python - -import stringmanipulation -import filemanagement -import sys - -trace_remove_key_word = 'kTraceModuleCall' - -if((len(sys.argv) != 2) and (len(sys.argv) != 3)): - print 'parameters are: parent directory [--commit]' - quit() - -if((len(sys.argv) == 3) and (sys.argv[2] != '--commit')): - print 'parameters are: parent directory [--commit]' - quit() - -commit = (len(sys.argv) == 3) - -directory = sys.argv[1]; -occurances = [] - -trace_identifier = 'WEBRTC_TRACE(' -extensions = ['.h','.cc','.c','.cpp'] -files_to_fix = [] -for extension in extensions: - files_to_fix.extend(filemanagement.listallfilesinfolder(directory,\ - extension)) - -# This function identifies the begining of a trace statement -def istracebegining(line): - return stringmanipulation.issubstring(line, trace_identifier) != -1 - -def endofstatement(line): - return stringmanipulation.issubstring(line, ';') != -1 - -def removekeywordfound(line): - return stringmanipulation.issubstring(line, trace_remove_key_word) != -1 - -# Used to store temporary result before flushing to real file when finished -def temporaryfilename(): - return 'deleteme.txt' - - -def find_occurances(path, file_name): - full_filename = path + file_name - file_handle = open(full_filename,'r') - line_is_trace = False - last_trace_line = -1 - for line_nr, line in enumerate(file_handle): - if(istracebegining(line)): - line_is_trace = True; - last_trace_line = line_nr - - if(line_is_trace): - if(removekeywordfound(line)): - occurances.append(last_trace_line) - - if(endofstatement(line)): - line_is_trace = False; - -def remove_occurances(path, file_name): - full_file_name = path + file_name - if (not filemanagement.fileexist(full_file_name)): - print 'File ' + full_file_name + ' is not found.' - print 'Should not happen! Ever!' - quit() - - full_temporary_file_name = path + temporaryfilename() - temporary_file = open(full_temporary_file_name,'w') - original_file = open(full_file_name,'r') - next_occurance_id = 0; - removing_statement = False - if(len(occurances) == next_occurance_id): - return - next_occurance = occurances[next_occurance_id] - next_occurance_id += 1 - for line_nr, line in enumerate(original_file): - if(line_nr == next_occurance): - removing_statement = True - if(len(occurances) == next_occurance_id): - next_occurance_id = -1 - else: - next_occurance = occurances[next_occurance_id] - next_occurance_id += 1 - - if (not removing_statement): - temporary_file.writelines(line) - - if(endofstatement(line)): - removing_statement = False; - - temporary_file.close() - original_file.close() - filemanagement.copyfile(full_file_name,full_temporary_file_name) - filemanagement.deletefile(full_temporary_file_name) - -def nextoccurance(): - if (len(occurances) == 0): - return -1 - return_value = occurances[0] - occurances = occurances[1:len(occurances)] - return return_value - -def would_be_removed_occurances(path, file_name): - full_file_name = path + file_name - if (not filemanagement.fileexist(full_file_name)): - print 'File ' + full_file_name + ' is not found.' - print 'Should not happen! Ever!' - quit() - - original_file = open(full_file_name,'r') - removing_statement = False - next_occurance_id = 0; - if(len(occurances) == next_occurance_id): - return - next_occurance = occurances[next_occurance_id] - next_occurance_id += 1 - for line_nr, line in enumerate(original_file): - if(line_nr == next_occurance): - removing_statement = True - if(len(occurances) == next_occurance_id): - return - next_occurance = occurances[next_occurance_id] - next_occurance_id += 1 - - if (removing_statement): - print line_nr - - if(endofstatement(line)): - removing_statement = False; - if(next_occurance == -1): - break - original_file.close() - -for index in range(len(files_to_fix)): - if(commit): - print (100*index)/len(files_to_fix) - - path_dir = files_to_fix[index][0] - filename = files_to_fix[index][1] - - #print path_dir + filename - occurances = [] - find_occurances(path_dir, filename) - - if(not commit): - would_be_removed_occurances(path_dir, filename) - continue - remove_occurances(path_dir, filename)
diff --git a/tools/refactoring/stringmanipulation.py b/tools/refactoring/stringmanipulation.py deleted file mode 100644 index 0d9e0ff..0000000 --- a/tools/refactoring/stringmanipulation.py +++ /dev/null
@@ -1,303 +0,0 @@ -import string - -# returns tuple, [success,updated_string] where the updated string has -# has one less (the first) occurance of match string -def removefirstoccurance( remove_string, match_string ): - lowercase_string = remove_string.lower() - lowercase_match_string = match_string.lower() - lowest_index = lowercase_string.find(lowercase_match_string) - if(lowest_index == -1): - return [False,remove_string] - past_match_index = lowest_index + len(lowercase_match_string) - highest_index = len(remove_string) - remove_string = remove_string[0:lowest_index] + remove_string[past_match_index: highest_index] - return [True,remove_string] - -# returns a string with all occurances of match_string removed -def removealloccurances( remove_string, match_string ): - return_value = [True, remove_string] - while(return_value[0]): - return_value = removefirstoccurance(return_value[1],match_string) - return return_value[1] - -# removes an occurance of match_string only if it's first in the string -# returns tuple [succes, new_string] -def removeprefix( remove_string, match_string ): - lowercase_string = remove_string.lower() - lowercase_match_string = match_string.lower() - lowest_index = lowercase_string.find(lowercase_match_string) - if(lowest_index == -1): - return [False,remove_string] - if(lowest_index != 0): - return [False,remove_string] - past_match_index = lowest_index + len(lowercase_match_string) - highest_index = len(remove_string) - remove_string = remove_string[0:lowest_index] + remove_string[past_match_index: highest_index] -# print lowest_index -# print past_match_index - return [True,remove_string] - -# removes multiple occurances of match string as long as they are first in -# the string -def removeallprefix( remove_string, match_string ): - return_value = [True, remove_string] - while(return_value[0]): - return_value = removeprefix(return_value[1],match_string) - return return_value[1] - -# returns true if extensionstring is a correct extension -def isextension( extensionstring ): - if(len(extensionstring) < 2): - return False - if(extensionstring[0] != '.'): - return False - if(extensionstring[1:len(extensionstring)-1].find('.') != -1): - return False - return True - -# returns the index of start of the last occurance of match_string -def findlastoccurance( original_string, match_string ): - search_index = original_string.find(match_string) - found_index = search_index - last_index = len(original_string) - 1 - while((search_index != -1) and (search_index < last_index)): - search_index = original_string[search_index+1:last_index].find(match_string) - if(search_index != -1): - found_index = search_index - return found_index - -# changes extension from original_extension to new_extension -def changeextension( original_string, original_extension, new_extension): - if(not isextension(original_extension)): - return original_string - if(not isextension(new_extension)): - return original_string - index = findlastoccurance(original_string, original_extension) - if(index == -1): - return original_string - return_value = original_string[0:index] + new_extension - return return_value - -# wanted to do this with str.find however didnt seem to work so do it manually -# returns the index of the first capital letter -def findfirstcapitalletter( original_string ): - for index in range(len(original_string)): - if(original_string[index].lower() != original_string[index]): - return index - return -1 - - -# replaces capital letters with underscore and lower case letter (except very -# first -def lowercasewithunderscore( original_string ): -# ignore the first letter since there should be no underscore in front of it - if(len(original_string) < 2): - return original_string - return_value = original_string[1:len(original_string)] - index = findfirstcapitalletter(return_value) - while(index != -1): - return_value = return_value[0:index] + \ - '_' + \ - return_value[index].lower() + \ - return_value[index+1:len(return_value)] - index = findfirstcapitalletter(return_value) - return_value = original_string[0].lower() + return_value - return return_value - -# my table is a duplicate of strings -def removeduplicates( my_table ): - new_table = [] - for old_string1, new_string1 in my_table: - found = 0 - for old_string2, new_string2 in new_table: - if(old_string1 == old_string2): - found += 1 - if(new_string1 == new_string2): - if(new_string1 == ''): - found += found - else: - found += 1 - if(found == 1): - print 'missmatching set, terminating program' - print old_string1 - print new_string1 - print old_string2 - print new_string2 - quit() - if(found == 2): - break - if(found == 0): - new_table.append([old_string1,new_string1]) - return new_table - -def removenochange( my_table ): - new_table = [] - for old_string, new_string in my_table: - if(old_string != new_string): - new_table.append([old_string,new_string]) - return new_table - -# order table after size of the string (can be used to replace bigger strings -# first which is useful since smaller strings can be inside the bigger string) -# E.g. GIPS is a sub string of GIPSVE if we remove GIPS first GIPSVE will never -# be removed. N is small so no need for fancy sort algorithm. Use selection sort -def ordertablesizefirst( my_table ): - for current_index in range(len(my_table)): - biggest_string = 0 - biggest_string_index = -1 - for search_index in range(len(my_table)): - if(search_index < current_index): - continue - length_of_string = len(my_table[search_index][0]) - if(length_of_string > biggest_string): - biggest_string = length_of_string - biggest_string_index = search_index - if(biggest_string_index == -1): - print 'sorting algorithm failed, program exit' - quit() - old_value = my_table[current_index] - my_table[current_index] = my_table[biggest_string_index] - my_table[biggest_string_index] = old_value - return my_table - -# returns true if string 1 or 2 is a substring of the other, assuming neither -# has whitespaces -def issubstring( string1, string2 ): - if(len(string1) == 0): - return -1 - if(len(string2) == 0): - return -1 - large_string = string1 - small_string = string2 - if(len(string1) < len(string2)): - large_string = string2 - small_string = string1 - - for index in range(len(large_string)): - large_sub_string = large_string[index:index+len(small_string)].lower() - if(large_sub_string ==\ - small_string.lower()): - return index - return -1 - -#not_part_of_word_table = [' ','(',')','{','}',':','\t','*','&','/','[',']','.',',','\n'] -#def ispartofword( char ): -# for item in not_part_of_word_table: -# if(char == item): -# return False -# return True - -# must be numerical,_ or charachter -def ispartofword( char ): - if(char.isalpha()): - return True - if(char.isalnum()): - return True - if(char == '_'): - return True - return False - -# returns the index of the first letter in the word that the current_index -# is pointing to and the size of the word -def getword( line, current_index): - if(current_index < 0): - return [] - line = line.rstrip() - if(len(line) <= current_index): - return [] - if(line[current_index] == ' '): - return [] - start_pos = current_index - while start_pos >= 0: - if(not ispartofword(line[start_pos])): - start_pos += 1 - break - start_pos -= 1 - if(start_pos == -1): - start_pos = 0 - end_pos = current_index - while end_pos < len(line): - if(not ispartofword(line[end_pos])): - break - end_pos += 1 - return [start_pos,end_pos - start_pos] - -# my table is a tuple [string1,string2] complement_to_table is just a list -# of strings to compare to string1 -def complement( my_table, complement_to_table ): - new_table = [] - for index in range(len(my_table)): - found = False; - for compare_string in complement_to_table: - if(my_table[index][0].lower() == compare_string.lower()): - found = True - if(not found): - new_table.append(my_table[index]) - return new_table - -def removestringfromhead( line, remove_string): - for index in range(len(line)): - if(line[index:index+len(remove_string)] != remove_string): - return line[index:index+len(line)] - return '' - -def removeccomment( line ): - comment_string = '//' - for index in range(len(line)): - if(line[index:index+len(comment_string)] == comment_string): - return line[0:index] - return line - -def whitespacestoonespace( line ): - return ' '.join(line.split()) - -def fixabbreviations( original_string ): - previouswascapital = (original_string[0].upper() == original_string[0]) - new_string = '' - for index in range(len(original_string)): - if(index == 0): - new_string += original_string[index] - continue - if(original_string[index] == '_'): - new_string += original_string[index] - previouswascapital = False - continue - if(original_string[index].isdigit()): - new_string += original_string[index] - previouswascapital = False - continue - currentiscapital = (original_string[index].upper() == original_string[index]) - letter_to_add = original_string[index] - if(previouswascapital and currentiscapital): - letter_to_add = letter_to_add.lower() - if(previouswascapital and (not currentiscapital)): - old_letter = new_string[len(new_string)-1] - new_string = new_string[0:len(new_string)-1] - new_string += old_letter.upper() - previouswascapital = currentiscapital - new_string += letter_to_add - return new_string - -def replaceoccurances(old_string, replace_string, replace_with_string): - if (len(replace_string) == 0): - return old_string - if (len(old_string) < len(replace_string)): - return old_string - # Simple implementation, could proably be done smarter - new_string = '' - for index in range(len(old_string)): - #print new_string - if(len(replace_string) > (len(old_string) - index)): - new_string += old_string[index:index + len(old_string)] - break - match = (len(replace_string) > 0) - for replace_index in range(len(replace_string)): - if (replace_string[replace_index] != old_string[index + replace_index]): - match = False - break - if (match): - new_string += replace_with_string - index =+ len(replace_string) - else: - new_string += old_string[index] - return new_string
diff --git a/tools/refactoring/trim.py b/tools/refactoring/trim.py deleted file mode 100644 index 5539f5f..0000000 --- a/tools/refactoring/trim.py +++ /dev/null
@@ -1,29 +0,0 @@ -#!/usr/bin/env python - -import sys -import fileinput - -# Defaults -TABSIZE = 4 - -usage = """ -Replaces all TAB characters with %(TABSIZE)d space characters. -In addition, all trailing space characters are removed. -usage: trim file ... -file ... : files are changed in place without taking any backup. -""" % vars() - -def main(): - - if len(sys.argv) == 1: - sys.stderr.write(usage) - sys.exit(2) - - # Iterate over the lines of all files listed in sys.argv[1:] - for line in fileinput.input(sys.argv[1:], inplace=True): - line = line.replace('\t',' '*TABSIZE); # replace TABs - line = line.rstrip(None) # remove trailing whitespaces - print line # modify the file - -if __name__ == '__main__': - main()
diff --git a/tools/refactoring/trimall.py b/tools/refactoring/trimall.py deleted file mode 100644 index 7a1c458..0000000 --- a/tools/refactoring/trimall.py +++ /dev/null
@@ -1,59 +0,0 @@ -#!/usr/bin/env python - -import sys -import fileinput -import filemanagement -import p4commands - -# Defaults -TABSIZE = 4 - -extensions = ['.h','.cc','.c','.cpp'] - -ignore_these = ['my_ignore_header.h'] - -usage = """ -Replaces all TAB characters with %(TABSIZE)d space characters. -In addition, all trailing space characters are removed. -usage: trim directory -""" % vars() - -if((len(sys.argv) != 2) and (len(sys.argv) != 3)): - sys.stderr.write(usage) - sys.exit(2) - -directory = sys.argv[1]; -if(not filemanagement.pathexist(directory)): - sys.stderr.write(usage) - sys.exit(2) - -if((len(sys.argv) == 3) and (sys.argv[2] != '--commit')): - sys.stderr.write(usage) - sys.exit(2) - -commit = False -if(len(sys.argv) == 3): - commit = True - -files_to_fix = [] -for extension in extensions: - files_to_fix.extend(filemanagement.listallfilesinfolder(directory,\ - extension)) - -def main(): - if (commit): - p4commands.checkoutallfiles() - for path,file_name in files_to_fix: - full_file_name = path + file_name - if (not commit): - print full_file_name + ' will be edited' - continue - for line in fileinput.input(full_file_name, inplace=True): - line = line.replace('\t',' '*TABSIZE); # replace TABs - line = line.rstrip(None) # remove trailing whitespaces - print line # modify the file - if (commit): - p4commands.revertunchangedfiles() - -if __name__ == '__main__': - main()
diff --git a/tools/refactoring/webrtc_reformat.py b/tools/refactoring/webrtc_reformat.py deleted file mode 100755 index 269d1c3..0000000 --- a/tools/refactoring/webrtc_reformat.py +++ /dev/null
@@ -1,212 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""WebRTC reformat script. - -This script is used to reformat WebRTC code from the old code style to Google -C++ code style. This script does not indent code; use clang-reformat-chrome.py -as described in go/webrtc/engineering/reformatting-gips---google. -""" - -__author__ = 'mflodman@webrtc.org (Magnus Flodman)' - -import fnmatch -import os -import re -import subprocess -import sys - - -def LowerWord(obj): - """Helper for DeCamelCase.""" - optional_last_letters = obj.group(3) or '' - return obj.group(1) + '_' + obj.group(2).lower() + optional_last_letters - - -def DeCamelCase(text): - """De-camelize variable names. - - This function will look at any stringLikeThis and format it in steps. The - sequence will be stringLikeThis -> string_likeThis -> string_like_this. - """ - possible_tokens_before_vars = '[ _*\(\&\!\[]' - pattern = re.compile(r'(?<=' + possible_tokens_before_vars + ')' + - # Match some lower-case characters - '([a-z]+)' + - # Don't match kFoo, !kFoo, [kFoo], etc - '(?<!' + possible_tokens_before_vars + 'k)' + - # Match some upper-case characters - '([A-Z]+)([a-z])?') - while re.search(pattern, text): - text = re.sub(pattern, LowerWord, text) - return text - - -def MoveUnderScore(text): - """Moves the underscore from beginning of variable name to the end.""" - # TODO(mflodman) Replace \1 with ?-expression. - # We don't want to change macros and #defines though, so don't do anything - # if the first character is uppercase (normal variables shouldn't have that). - pattern = r'([ \*\!\&\(\[\]])_(?!_)(?![A-Z])(\w+)' - return re.sub(pattern, r'\1\2_', text) - - -def PostfixToPrefixInForLoops(text): - """Converts x++ to ++x in the increment part of a for loop.""" - pattern = r'(for \(.*;.*;) (\w+)\+\+\)' - return re.sub(pattern, r'\1++\2)', text) - - -def SortIncludeHeaders(text, filename): - """Sorts all include headers in alphabetic order. - - The file's own header goes first, followed by system headers and then - project headers. This function will exit if we detect any fancy #ifdef logic - among the includes - that's a lot harder to sort. - - Args: - text: The file text. - filename: The file we are reformatting. - - Returns: - The text with includes sorted. - """ - # Get all includes in file. - include_pattern = re.compile('#include.+\n') - includes = re.findall(include_pattern, text) - - # Sort system headers and project headers separately. - sys_includes = [] - project_includes = [] - self_include = '' - sys_pattern = re.compile('#include <') - h_filename, _ = os.path.splitext(os.path.basename(filename)) - - for item in includes: - if re.search(h_filename + '\.', item): - self_include = item - elif re.search(sys_pattern, item): - sys_includes.append(item) - else: - project_includes.append(item) - - sys_includes = sorted(sys_includes) - project_includes = sorted(project_includes) - headers = (self_include + '\n' + ''.join(sys_includes) + '\n' + - ''.join(project_includes)) - - # Replace existing headers with the sorted string. - text_no_hdrs = re.sub(include_pattern, r'???', text) - - # Insert sorted headers unless we detect #ifdefs right next to the headers. - if re.search(r'(#ifdef|#ifndef|#if).*\s*\?{3,}\s*#endif', text_no_hdrs): - print 'WARNING: Include headers not sorted in ' + filename - return text - - return_text = re.sub(r'\?{3,}', headers, text_no_hdrs, 1) - if re.search(r'\?{3,}', text_no_hdrs): - # Remove possible remaining ???. - return_text = re.sub(r'\?{3,}', r'', return_text) - - return return_text - - -def AddPath(match): - """Helper for adding file path for WebRTC header files, ignoring other.""" - file_to_examine = match.group(1) + '.h' - # TODO(mflodman) Use current directory and find webrtc/. - for path, _, files in os.walk('./webrtc'): - for filename in files: - if fnmatch.fnmatch(filename, file_to_examine): - path_name = os.path.join(path, filename).replace('./', '') - return '#include "%s"\n' % path_name - - # No path found, return original string. - return '#include "'+ file_to_examine + '"\n' - - -def AddHeaderPath(text): - """Add path to all included header files that have no path yet.""" - headers = re.compile('#include "(.+).h"\n') - return re.sub(headers, AddPath, text) - - -def AddWebrtcToOldSrcRelativePath(match): - file_to_examine = match.group(1) + '.h' - path, filename = os.path.split(file_to_examine) - dirs_in_webrtc = [name for name in os.listdir('./webrtc') - if os.path.isdir(os.path.join('./webrtc', name))] - for dir_in_webrtc in dirs_in_webrtc: - if path.startswith(dir_in_webrtc): - return '#include "%s"\n' % os.path.join('webrtc', path, filename) - return '#include "%s"\n' % file_to_examine - -def AddWebrtcPrefixToOldSrcRelativePaths(text): - """For all paths starting with for instance video_engine, add webrtc/.""" - headers = re.compile('#include "(.+).h"\n') - return re.sub(headers, AddWebrtcToOldSrcRelativePath, text) - - -def FixIncludeGuards(text, file_name): - """Change include guard according to the stantard.""" - # Remove a possible webrtc/ from the path. - file_name = re.sub(r'(webrtc\/)(.+)', r'\2', file_name) - new_guard = 'WEBRTC_' + file_name - new_guard = new_guard.upper() - new_guard = re.sub(r'([/\.])', r'_', new_guard) - new_guard += '_' - - text = re.sub(r'#ifndef WEBRTC_.+\n', r'#ifndef ' + new_guard + '\n', text, 1) - text = re.sub(r'#define WEBRTC_.+\n', r'#define ' + new_guard + '\n', text, 1) - text = re.sub(r'#endif *\/\/ *WEBRTC_.+\n', r'#endif // ' + new_guard + '\n', - text, 1) - - return text - - -def SaveFile(filename, text): - os.remove(filename) - f = open(filename, 'w') - f.write(text) - f.close() - - -def main(): - args = sys.argv[1:] - if not args: - print 'Usage: %s <filename>' % sys.argv[0] - sys.exit(1) - - for filename in args: - f = open(filename) - text = f.read() - f.close() - - text = DeCamelCase(text) - text = MoveUnderScore(text) - text = PostfixToPrefixInForLoops(text) - text = AddHeaderPath(text) - text = AddWebrtcPrefixToOldSrcRelativePaths(text) - text = SortIncludeHeaders(text, filename) - - # Remove the original file and re-create it with the reformatted content. - SaveFile(filename, text) - - if filename.endswith('.h'): - f = open(filename) - text = f.read() - f.close() - text = FixIncludeGuards(text, filename) - SaveFile(filename, text) - - print filename + ' done.' - - -if __name__ == '__main__': - main()
diff --git a/tools/sslroots/generate_sslroots.py b/tools/sslroots/generate_sslroots.py new file mode 100644 index 0000000..65751f1 --- /dev/null +++ b/tools/sslroots/generate_sslroots.py
@@ -0,0 +1,190 @@ +# -*- coding:utf-8 -*- +# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + + +"""This is a tool to transform a crt file into a C/C++ header. + +Usage: +generate_sslroots.py cert_file.crt [--verbose | -v] [--full_cert | -f] + +Arguments: + -v Print output while running. + -f Add public key and certificate name. Default is to skip and reduce + generated file size. +""" + +import commands +from optparse import OptionParser +import os +import re +import string + +_GENERATED_FILE = 'sslroots.h' +_PREFIX = '__generated__' +_EXTENSION = '.crt' +_SUBJECT_NAME_ARRAY = 'subject_name' +_SUBJECT_NAME_VARIABLE = 'SubjectName' +_PUBLIC_KEY_ARRAY = 'public_key' +_PUBLIC_KEY_VARIABLE = 'PublicKey' +_CERTIFICATE_ARRAY = 'certificate' +_CERTIFICATE_VARIABLE = 'Certificate' +_CERTIFICATE_SIZE_VARIABLE = 'CertificateSize' +_INT_TYPE = 'size_t' +_CHAR_TYPE = 'const unsigned char*' +_VERBOSE = 'verbose' + + +def main(): + """The main entrypoint.""" + parser = OptionParser('usage %prog FILE') + parser.add_option('-v', '--verbose', dest='verbose', action='store_true') + parser.add_option('-f', '--full_cert', dest='full_cert', action='store_true') + options, args = parser.parse_args() + if len(args) < 1: + parser.error('No crt file specified.') + return + root_dir = _SplitCrt(args[0], options) + _GenCFiles(root_dir, options) + _Cleanup(root_dir) + + +def _SplitCrt(source_file, options): + sub_file_blocks = [] + label_name = '' + root_dir = os.path.dirname(os.path.abspath(source_file)) + '/' + _PrintOutput(root_dir, options) + f = open(source_file) + for line in f: + if line.startswith('# Label: '): + sub_file_blocks.append(line) + label = re.search(r'\".*\"', line) + temp_label = label.group(0) + end = len(temp_label)-1 + label_name = _SafeName(temp_label[1:end]) + elif line.startswith('-----END CERTIFICATE-----'): + sub_file_blocks.append(line) + new_file_name = root_dir + _PREFIX + label_name + _EXTENSION + _PrintOutput('Generating: ' + new_file_name, options) + new_file = open(new_file_name, 'w') + for out_line in sub_file_blocks: + new_file.write(out_line) + new_file.close() + sub_file_blocks = [] + else: + sub_file_blocks.append(line) + f.close() + return root_dir + + +def _GenCFiles(root_dir, options): + output_header_file = open(root_dir + _GENERATED_FILE, 'w') + output_header_file.write(_CreateOutputHeader()) + if options.full_cert: + subject_name_list = _CreateArraySectionHeader(_SUBJECT_NAME_VARIABLE, + _CHAR_TYPE, options) + public_key_list = _CreateArraySectionHeader(_PUBLIC_KEY_VARIABLE, + _CHAR_TYPE, options) + certificate_list = _CreateArraySectionHeader(_CERTIFICATE_VARIABLE, + _CHAR_TYPE, options) + certificate_size_list = _CreateArraySectionHeader(_CERTIFICATE_SIZE_VARIABLE, + _INT_TYPE, options) + + for _, _, files in os.walk(root_dir): + for current_file in files: + if current_file.startswith(_PREFIX): + prefix_length = len(_PREFIX) + length = len(current_file) - len(_EXTENSION) + label = current_file[prefix_length:length] + filtered_output, cert_size = _CreateCertSection(root_dir, current_file, + label, options) + output_header_file.write(filtered_output + '\n\n\n') + if options.full_cert: + subject_name_list += _AddLabelToArray(label, _SUBJECT_NAME_ARRAY) + public_key_list += _AddLabelToArray(label, _PUBLIC_KEY_ARRAY) + certificate_list += _AddLabelToArray(label, _CERTIFICATE_ARRAY) + certificate_size_list += (' %s,\n') %(cert_size) + + if options.full_cert: + subject_name_list += _CreateArraySectionFooter() + output_header_file.write(subject_name_list) + public_key_list += _CreateArraySectionFooter() + output_header_file.write(public_key_list) + certificate_list += _CreateArraySectionFooter() + output_header_file.write(certificate_list) + certificate_size_list += _CreateArraySectionFooter() + output_header_file.write(certificate_size_list) + output_header_file.close() + + +def _Cleanup(root_dir): + for f in os.listdir(root_dir): + if f.startswith(_PREFIX): + os.remove(root_dir + f) + + +def _CreateCertSection(root_dir, source_file, label, options): + command = 'openssl x509 -in %s%s -noout -C' %(root_dir, source_file) + _PrintOutput(command, options) + output = commands.getstatusoutput(command)[1] + renamed_output = output.replace('unsigned char XXX_', + 'const unsigned char ' + label + '_') + filtered_output = '' + cert_block = '^const unsigned char.*?};$' + prog = re.compile(cert_block, re.IGNORECASE | re.MULTILINE | re.DOTALL) + if not options.full_cert: + filtered_output = prog.sub('', renamed_output, count=2) + else: + filtered_output = renamed_output + + cert_size_block = r'\d\d\d+' + prog2 = re.compile(cert_size_block, re.MULTILINE | re.VERBOSE) + result = prog2.findall(renamed_output) + cert_size = result[len(result) - 1] + + return filtered_output, cert_size + + +def _CreateOutputHeader(): + output = ('// This file is the root certificates in C form that are needed to' + ' connect to\n// Google.\n\n' + '// It was generated with the following command line:\n' + '// > python tools/certs/generate_sslroots.py' + '\n// https://pki.google.com/roots.pem\n\n') + return output + + +def _CreateArraySectionHeader(type_name, type_type, options): + output = ('const %s kSSLCert%sList[] = {\n') %(type_type, type_name) + _PrintOutput(output, options) + return output + + +def _AddLabelToArray(label, type_name): + return ' %s_%s,\n' %(label, type_name) + + +def _CreateArraySectionFooter(): + return '};\n\n' + + +def _SafeName(original_file_name): + bad_chars = ' -./\\()áéíÅ‘ú' + replacement_chars = '' + for _ in bad_chars: + replacement_chars += '_' + translation_table = string.maketrans(bad_chars, replacement_chars) + return original_file_name.translate(translation_table) + + +def _PrintOutput(output, options): + if options.verbose: + print output + +if __name__ == '__main__': + main()
diff --git a/tools/valgrind-webrtc/drmemory/suppressions.txt b/tools/valgrind-webrtc/drmemory/suppressions.txt index 2addea5..1b0626c 100644 --- a/tools/valgrind-webrtc/drmemory/suppressions.txt +++ b/tools/valgrind-webrtc/drmemory/suppressions.txt
@@ -2,22 +2,6 @@ # It acts as a place holder for future additions for WebRTC. # It must exist for the Python wrapper script to work properly. -INVALID HEAP ARGUMENT -name=https://code.google.com/p/webrtc/issues/detail?id=2321 (1) -drmemorylib.dll!replace_operator_delete_array -*!webrtc::scoped_array<short>::~scoped_array<short> -*!webrtc::PushResampler::~PushResampler -... -*!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void> - -INVALID HEAP ARGUMENT -name=https://code.google.com/p/webrtc/issues/detail?id=2321 (2) -drmemorylib.dll!replace_operator_delete_array -*!webrtc::scoped_array<float>::~scoped_array<float> -*!webrtc::PushSincResampler::~PushSincResampler -... -*!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void> - GDI USAGE ERROR name=https://code.google.com/p/webrtc/issues/detail?id=2323 (1) system call NtGdiDeleteObjectApp @@ -90,25 +74,6 @@ *!webrtc::test::UdpSocketManager_AddAndRemoveSocketDoesNotLeakMemory_Test::TestBody *!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void> -INVALID HEAP ARGUMENT -name=https://code.google.com/p/webrtc/issues/detail?id=2515 (1) -drmemorylib.dll!replace_operator_delete_nothrow -*!webrtc::scoped_array<short>::~scoped_array<short> -*!webrtc::NetEqImpl::~NetEqImpl -*!webrtc::NetEqImpl::`scalar deleting destructor' -... -*!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void> - -INVALID HEAP ARGUMENT -name=https://code.google.com/p/webrtc/issues/detail?id=2515 (2) -drmemorylib.dll!replace_operator_delete_nothrow -*!webrtc::scoped_array<short>::reset -*!webrtc::NetEqImpl::SetSampleRateAndChannels -*!webrtc::NetEqImpl::InsertPacketInternal -*!webrtc::NetEqImpl::InsertPacket -... -*!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void> - UNINITIALIZED READ name=https://code.google.com/p/webrtc/issues/detail?id=2516 system call NtUserGetThreadDesktop parameter value #1
diff --git a/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-drmemory_win32.txt b/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-drmemory_win32.txt index d41c231..d041dbd 100644 --- a/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-drmemory_win32.txt +++ b/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-drmemory_win32.txt
@@ -1,7 +1,7 @@ # Flakily fails or crashes on Dr Memory Full. # https://code.google.com/p/webrtc/issues/detail?id=3158 DtmfSenderTest.* -JsepPeerConnectionP2PTestClient.* +P2PTestConductor.* PeerConnectionEndToEndTest.* PeerConnectionInterfaceTest.* # Issue 3453
diff --git a/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-memcheck.txt b/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-memcheck.txt index 40974a2..9cf29b8 100644 --- a/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-memcheck.txt +++ b/tools/valgrind-webrtc/gtest_exclude/libjingle_peerconnection_unittest.gtest-memcheck.txt
@@ -1,6 +1,6 @@ # Tests that are failing when run under memcheck. # https://code.google.com/p/webrtc/issues/detail?id=4387 DtmfSenderTest.* -JsepPeerConnectionP2PTestClient.* +P2PTestConductor.* PeerConnectionEndToEndTest.* PeerConnectionInterfaceTest.*
diff --git a/tools/valgrind-webrtc/gtest_exclude/modules_tests.gtest-drmemory.txt b/tools/valgrind-webrtc/gtest_exclude/modules_tests.gtest-drmemory.txt index e4f3ae2..1642e3c 100644 --- a/tools/valgrind-webrtc/gtest_exclude/modules_tests.gtest-drmemory.txt +++ b/tools/valgrind-webrtc/gtest_exclude/modules_tests.gtest-drmemory.txt
@@ -8,6 +8,5 @@ AudioCodingModuleTest.TestVADDTX* AudioCodingModuleTest.TestOpus* FecTest.FecTest -TestVp8Impl.BaseUnitTest VideoProcessorIntegrationTest.ProcessNoLossChangeBitRateVP8 VideoProcessorIntegrationTest.*VP9
diff --git a/tools/valgrind-webrtc/gtest_exclude/rtc_unittests.gtest-drmemory.txt b/tools/valgrind-webrtc/gtest_exclude/rtc_unittests.gtest-drmemory.txt index 092b785..8880627 100644 --- a/tools/valgrind-webrtc/gtest_exclude/rtc_unittests.gtest-drmemory.txt +++ b/tools/valgrind-webrtc/gtest_exclude/rtc_unittests.gtest-drmemory.txt
@@ -5,3 +5,6 @@ PortTest.* PseudoTcpTest.TestSendBothUseLargeWindowScale SharedExclusiveLockTest.TestSharedShared +# Fails on Dr Memory Light. +# https://bugs.chromium.org/p/webrtc/issues/detail?id=5199 +ThreadTest.ThreeThreadsInvoke
diff --git a/tools/valgrind-webrtc/gtest_exclude/system_wrappers_unittests.gtest-drmemory_win32.txt b/tools/valgrind-webrtc/gtest_exclude/system_wrappers_unittests.gtest-drmemory_win32.txt old mode 100755 new mode 100644 index 0bceb97..a3344c7 --- a/tools/valgrind-webrtc/gtest_exclude/system_wrappers_unittests.gtest-drmemory_win32.txt +++ b/tools/valgrind-webrtc/gtest_exclude/system_wrappers_unittests.gtest-drmemory_win32.txt
@@ -1,3 +1,4 @@ -# https://code.google.com/p/webrtc/issues/detail?id=2330 -ClockTest.NtpTime - +# https://code.google.com/p/webrtc/issues/detail?id=2330 +ClockTest.NtpTime +CritSectTest.ThreadWakesOnce +CritSectTest.ThreadWakesTwice
diff --git a/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-drmemory_win32.txt b/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-drmemory_win32.txt index 309fd40..c4d953a 100644 --- a/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-drmemory_win32.txt +++ b/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-drmemory_win32.txt
@@ -3,14 +3,23 @@ EndToEndTest.CanSwitchToUseAllSsrcs EndToEndTest.SendsAndReceivesMultipleStreams EndToEndTest.ReceivesAndRetransmitsNack -# https://code.google.com/p/webrtc/issues/detail?id=3471 -VideoSendStreamTest.RetransmitsNackOverRtxWithPacing +EndToEndTest.ReceivesTransportFeedback # Flaky: https://code.google.com/p/webrtc/issues/detail?id=3552 EndToEndTest.RestartingSendStreamPreservesRtpState EndToEndTest.RestartingSendStreamPreservesRtpStatesWithRtx EndToEndTest.SendsAndReceivesH264 EndToEndTest.SendsAndReceivesVP9 +EndToEndTest.TransportFeedbackNotConfigured +EndToEndTest.TransportSeqNumOnAudioAndVideo VideoSendStreamTest.CanReconfigureToUseStartBitrateAbovePreviousMax VideoSendStreamTest.ReconfigureBitratesSetsEncoderBitratesCorrectly +# https://code.google.com/p/webrtc/issues/detail?id=5417 +VideoSendStreamTest.Vp9NonFlexMode_2Tl2SLayers +VideoSendStreamTest.Vp9NonFlexMode_3Tl2SLayers +VideoSendStreamTest.Vp9FlexModeRefCount # https://code.google.com/p/webrtc/issues/detail?id=4979 EndToEndTest.AssignsTransportSequenceNumbers +# Flaky: https://bugs.chromium.org/p/webrtc/issues/detail?id=5225 +BitrateEstimatorTest.SwitchesToASTThenBackToTOFForVideo +# https://bugs.chromium.org/p/webrtc/issues/detail?id=5312 +RtcEventLogTest.DropOldEvents
diff --git a/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-memcheck.txt b/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-memcheck.txt index 57387dc..6faf218 100644 --- a/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-memcheck.txt +++ b/tools/valgrind-webrtc/gtest_exclude/video_engine_tests.gtest-memcheck.txt
@@ -6,3 +6,5 @@ # Flaky under memcheck (WebRTC issue 5134) EndToEndTest.AssignsTransportSequenceNumbers +# https://bugs.chromium.org/p/webrtc/issues/detail?id=5312 +RtcEventLogTest.DropOldEvents
diff --git a/tools/valgrind-webrtc/memcheck/suppressions.txt b/tools/valgrind-webrtc/memcheck/suppressions.txt index 6291df2..9919522 100644 --- a/tools/valgrind-webrtc/memcheck/suppressions.txt +++ b/tools/valgrind-webrtc/memcheck/suppressions.txt
@@ -232,159 +232,6 @@ } { - bug_332_1 - Memcheck:Uninitialized - ... - fun:_ZN6webrtc11VoEBaseImpl16NeedMorePlayDataEjhhjPvRj - fun:_ZN6webrtc17AudioDeviceBuffer18RequestPlayoutDataEj - fun:_ZN6webrtc21AudioDeviceLinuxPulse17PlayThreadProcessEv - fun:_ZN6webrtc21AudioDeviceLinuxPulse14PlayThreadFuncEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug_332_2 - Memcheck:Unaddressable - fun:memcpy@@GLIBC_2.14 - fun:_ZN6webrtc21AudioDeviceLinuxPulse16ReadRecordedDataEPKvm - fun:_ZN6webrtc21AudioDeviceLinuxPulse16RecThreadProcessEv - fun:_ZN6webrtc21AudioDeviceLinuxPulse13RecThreadFuncEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug_332_3 - Memcheck:Uninitialized - fun:_ZN6webrtc11RTCPUtility21RTCPParseCommonHeaderEPKhS2_RNS0_16RTCPCommonHeaderE - ... - fun:_ZN6webrtc12RTCPReceiver10HandleSDESERNS_11RTCPUtility12RTCPParserV2E - fun:_ZN6webrtc12RTCPReceiver18IncomingRTCPPacketERNS_8RTCPHelp21RTCPPacketInformationEPNS_11RTCPUtility12RTCPParserV2E - fun:_ZN6webrtc17ModuleRtpRtcpImpl14IncomingPacketEPKht - fun:_ZN6webrtc3voe7Channel18IncomingRTCPPacketEPKaiPKct - fun:_ZN6webrtc16UdpTransportImpl20IncomingRTCPFunctionEPKaiPKNS_13SocketAddressE - fun:_ZN6webrtc16UdpTransportImpl20IncomingRTCPCallbackEPvPKaiPKNS_13SocketAddressE - fun:_ZN6webrtc14UdpSocketPosix11HasIncomingEv - fun:_ZN6webrtc25UdpSocketManagerPosixImpl7ProcessEv - fun:_ZN6webrtc25UdpSocketManagerPosixImpl3RunEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug_332_4 - Memcheck:Uninitialized - ... - fun:_ZN6webrtc3voe10AudioLevel12ComputeLevelERKNS_10AudioFrameE - fun:_ZN6webrtc3voe11OutputMixer28DoOperationsOnCombinedSignalEv - fun:_ZN6webrtc11VoEBaseImpl16NeedMorePlayDataEjhhjPvRj - fun:_ZN6webrtc17AudioDeviceBuffer18RequestPlayoutDataEj - fun:_ZN6webrtc21AudioDeviceLinuxPulse17PlayThreadProcessEv - fun:_ZN6webrtc21AudioDeviceLinuxPulse14PlayThreadFuncEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug_332_5 - Memcheck:Uninitialized - fun:WebRtcSpl_UpBy2ShortToInt - fun:WebRtcSpl_Resample8khzTo22khz - fun:_ZN6webrtc9Resampler4PushEPKsiPsiRi - fun:_ZN6webrtc3voe16RemixAndResampleERKNS_10AudioFrameEPNS_9ResamplerEPS1_ - fun:_ZN6webrtc3voe11OutputMixer13GetMixedAudioEiiPNS_10AudioFrameE - fun:_ZN6webrtc11VoEBaseImpl16NeedMorePlayDataEjhhjPvRj - fun:_ZN6webrtc17AudioDeviceBuffer18RequestPlayoutDataEj - fun:_ZN6webrtc21AudioDeviceLinuxPulse17PlayThreadProcessEv - fun:_ZN6webrtc21AudioDeviceLinuxPulse14PlayThreadFuncEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug 332_6 - Memcheck:Param - socketcall.sendto(msg) - obj:*libpthread-*.so - fun:_ZN6webrtc14UdpSocketPosix6SendToEPKaiRKNS_13SocketAddressE - fun:_ZN6webrtc16UdpTransportImpl14SendRTCPPacketEiPKvi - fun:_ZN6webrtc3voe7Channel14SendRTCPPacketEiPKvi - ... - fun:_ZN6webrtc17ModuleRtpRtcpImpl14IncomingPacketEPKht - fun:_ZN6webrtc3voe7Channel17IncomingRTPPacketEPKaiPKct - fun:_ZN6webrtc16UdpTransportImpl19IncomingRTPFunctionEPKaiPKNS_13SocketAddressE - fun:_ZN6webrtc16UdpTransportImpl19IncomingRTPCallbackEPvPKaiPKNS_13SocketAddressE - fun:_ZN6webrtc14UdpSocketPosix11HasIncomingEv - fun:_ZN6webrtc25UdpSocketManagerPosixImpl7ProcessEv - fun:_ZN6webrtc25UdpSocketManagerPosixImpl3RunEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - - -{ - bug_332_7 - Memcheck:Param - socketcall.sendto(msg) - obj:*libpthread-*.so - fun:_ZN6webrtc14UdpSocketPosix6SendToEPKaiRKNS_13SocketAddressE - fun:_ZN6webrtc16UdpTransportImpl10SendPacketEiPKvi - ... - fun:_ZN6webrtc21AudioDeviceLinuxPulse16ReadRecordedDataEPKvm - fun:_ZN6webrtc21AudioDeviceLinuxPulse16RecThreadProcessEv - fun:_ZN6webrtc21AudioDeviceLinuxPulse13RecThreadFuncEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug_332_8 - Memcheck:Param - socketcall.sendto(msg) - obj:*libpthread-*.so - fun:_ZN6webrtc14UdpSocketPosix6SendToEPKaiRKNS_13SocketAddressE - fun:_ZN6webrtc16UdpTransportImpl14SendRTCPPacketEiPKvi - fun:_ZN6webrtc3voe7Channel14SendRTCPPacketEiPKvi - fun:_ZN6webrtc10RTCPSender13SendToNetworkEPKht - fun:_ZN6webrtc10RTCPSender8SendRTCPEjiPKtbm - fun:_ZN6webrtc17ModuleRtpRtcpImpl7ProcessEv - fun:_ZN6webrtc17ProcessThreadImpl7ProcessEv - fun:_ZN6webrtc17ProcessThreadImpl3RunEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug_332_9 - Memcheck:Uninitialized - ... - fun:_ZN6webrtc17AudioDeviceBuffer19DeliverRecordedDataEv - fun:_ZN6webrtc21AudioDeviceLinuxPulse19ProcessRecordedDataEPajj - fun:_ZN6webrtc21AudioDeviceLinuxPulse16ReadRecordedDataEPKvm - fun:_ZN6webrtc21AudioDeviceLinuxPulse16RecThreadProcessEv - fun:_ZN6webrtc21AudioDeviceLinuxPulse13RecThreadFuncEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ - bug_332_10 - Memcheck:Uninitialized - ... - fun:_ZN6webrtc12RTCPReceiver18IncomingRTCPPacketERNS_8RTCPHelp21RTCPPacketInformationEPNS_11RTCPUtility12RTCPParserV2E - fun:_ZN6webrtc17ModuleRtpRtcpImpl14IncomingPacketEPKht - fun:_ZN6webrtc3voe7Channel18IncomingRTCPPacketEPKaiPKct - fun:_ZN6webrtc16UdpTransportImpl20IncomingRTCPFunctionEPKaiPKNS_13SocketAddressE - fun:_ZN6webrtc16UdpTransportImpl20IncomingRTCPCallbackEPvPKaiPKNS_13SocketAddressE - fun:_ZN6webrtc14UdpSocketPosix11HasIncomingEv - fun:_ZN6webrtc25UdpSocketManagerPosixImpl7ProcessEv - fun:_ZN6webrtc25UdpSocketManagerPosixImpl3RunEPv - fun:_ZN6webrtc11ThreadPosix3RunEv - fun:StartThread -} - -{ bug_891 Memcheck:Unaddressable fun:XShmPutImage
diff --git a/webrtc/.gitignore b/webrtc/.gitignore index dade989..89cb6db 100644 --- a/webrtc/.gitignore +++ b/webrtc/.gitignore
@@ -1 +1,27 @@ -# This file is for projects that checkout webrtc/ directly (e.g. Chromium). +# 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 +*.ncb +*.ninja +*.props +*.pyc +*.rules +*.scons +*.sdf +*.sln +*.suo +*.targets +*.user +*.vcproj +*.vcxproj +*.vcxproj.filters +*.vpj +*.vpw +*.vpwhistu +*.vtg +*.xcodeproj +*_proto.xml +*_proto_cpp.xml +*~ +.*.sw?
diff --git a/webrtc/BUILD.gn b/webrtc/BUILD.gn index ac14d7d..be824b7 100644 --- a/webrtc/BUILD.gn +++ b/webrtc/BUILD.gn
@@ -8,8 +8,8 @@ # 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") @@ -178,8 +178,8 @@ public_configs = [ ":common_inherited_config" ] deps = [ - "audio", ":webrtc_common", + "audio", "base:rtc_base", "call", "common_audio", @@ -219,8 +219,8 @@ 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", ] } @@ -238,6 +238,12 @@ 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") { @@ -279,3 +285,14 @@ 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", + ] + } +}
diff --git a/webrtc/api/BUILD.gn b/webrtc/api/BUILD.gn new file mode 100644 index 0000000..7cfa083 --- /dev/null +++ b/webrtc/api/BUILD.gn
@@ -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", + ] + } + } +}
diff --git a/webrtc/api/OWNERS b/webrtc/api/OWNERS new file mode 100644 index 0000000..cd06158 --- /dev/null +++ b/webrtc/api/OWNERS
@@ -0,0 +1 @@ +tkchin@webrtc.org
diff --git a/webrtc/api/api.gyp b/webrtc/api/api.gyp new file mode 100644 index 0000000..ba3fe8d --- /dev/null +++ b/webrtc/api/api.gyp
@@ -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" + ], +}
diff --git a/webrtc/api/api_tests.gyp b/webrtc/api/api_tests.gyp new file mode 100644 index 0000000..c2c18bc --- /dev/null +++ b/webrtc/api/api_tests.gyp
@@ -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" + ], +}
diff --git a/webrtc/api/objc/OWNERS b/webrtc/api/objc/OWNERS new file mode 100644 index 0000000..cd06158 --- /dev/null +++ b/webrtc/api/objc/OWNERS
@@ -0,0 +1 @@ +tkchin@webrtc.org
diff --git a/webrtc/api/objc/README b/webrtc/api/objc/README new file mode 100644 index 0000000..bd33e61 --- /dev/null +++ b/webrtc/api/objc/README
@@ -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.
diff --git a/webrtc/api/objc/RTCEAGLVideoView.h b/webrtc/api/objc/RTCEAGLVideoView.h new file mode 100644 index 0000000..1a57df7 --- /dev/null +++ b/webrtc/api/objc/RTCEAGLVideoView.h
@@ -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
diff --git a/webrtc/api/objc/RTCEAGLVideoView.m b/webrtc/api/objc/RTCEAGLVideoView.m new file mode 100644 index 0000000..e664ede --- /dev/null +++ b/webrtc/api/objc/RTCEAGLVideoView.m
@@ -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
diff --git a/webrtc/api/objc/RTCIceCandidate+Private.h b/webrtc/api/objc/RTCIceCandidate+Private.h new file mode 100644 index 0000000..ca95a43 --- /dev/null +++ b/webrtc/api/objc/RTCIceCandidate+Private.h
@@ -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
diff --git a/webrtc/api/objc/RTCIceCandidate.h b/webrtc/api/objc/RTCIceCandidate.h new file mode 100644 index 0000000..41ea69e --- /dev/null +++ b/webrtc/api/objc/RTCIceCandidate.h
@@ -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
diff --git a/webrtc/api/objc/RTCIceCandidate.mm b/webrtc/api/objc/RTCIceCandidate.mm new file mode 100644 index 0000000..9e094f6 --- /dev/null +++ b/webrtc/api/objc/RTCIceCandidate.mm
@@ -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
diff --git a/webrtc/api/objc/RTCIceServer+Private.h b/webrtc/api/objc/RTCIceServer+Private.h new file mode 100644 index 0000000..59f5a92 --- /dev/null +++ b/webrtc/api/objc/RTCIceServer+Private.h
@@ -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
diff --git a/webrtc/api/objc/RTCIceServer.h b/webrtc/api/objc/RTCIceServer.h new file mode 100644 index 0000000..be4e0d7 --- /dev/null +++ b/webrtc/api/objc/RTCIceServer.h
@@ -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
diff --git a/webrtc/api/objc/RTCIceServer.mm b/webrtc/api/objc/RTCIceServer.mm new file mode 100644 index 0000000..7a898e0 --- /dev/null +++ b/webrtc/api/objc/RTCIceServer.mm
@@ -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
diff --git a/webrtc/api/objc/RTCMediaConstraints+Private.h b/webrtc/api/objc/RTCMediaConstraints+Private.h new file mode 100644 index 0000000..2c4b722 --- /dev/null +++ b/webrtc/api/objc/RTCMediaConstraints+Private.h
@@ -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
diff --git a/webrtc/api/objc/RTCMediaConstraints.h b/webrtc/api/objc/RTCMediaConstraints.h new file mode 100644 index 0000000..a8ad391 --- /dev/null +++ b/webrtc/api/objc/RTCMediaConstraints.h
@@ -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
diff --git a/webrtc/api/objc/RTCMediaConstraints.mm b/webrtc/api/objc/RTCMediaConstraints.mm new file mode 100644 index 0000000..a53a517 --- /dev/null +++ b/webrtc/api/objc/RTCMediaConstraints.mm
@@ -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
diff --git a/webrtc/api/objc/RTCMediaSource+Private.h b/webrtc/api/objc/RTCMediaSource+Private.h new file mode 100644 index 0000000..fcbaad8 --- /dev/null +++ b/webrtc/api/objc/RTCMediaSource+Private.h
@@ -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
diff --git a/webrtc/api/objc/RTCMediaSource.h b/webrtc/api/objc/RTCMediaSource.h new file mode 100644 index 0000000..0b36b8d --- /dev/null +++ b/webrtc/api/objc/RTCMediaSource.h
@@ -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
diff --git a/webrtc/api/objc/RTCMediaSource.mm b/webrtc/api/objc/RTCMediaSource.mm new file mode 100644 index 0000000..5f46ab8 --- /dev/null +++ b/webrtc/api/objc/RTCMediaSource.mm
@@ -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
diff --git a/webrtc/api/objc/RTCMediaStreamTrack+Private.h b/webrtc/api/objc/RTCMediaStreamTrack+Private.h new file mode 100644 index 0000000..3e17e63 --- /dev/null +++ b/webrtc/api/objc/RTCMediaStreamTrack+Private.h
@@ -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
diff --git a/webrtc/api/objc/RTCMediaStreamTrack.h b/webrtc/api/objc/RTCMediaStreamTrack.h new file mode 100644 index 0000000..beb48d3 --- /dev/null +++ b/webrtc/api/objc/RTCMediaStreamTrack.h
@@ -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
diff --git a/webrtc/api/objc/RTCMediaStreamTrack.mm b/webrtc/api/objc/RTCMediaStreamTrack.mm new file mode 100644 index 0000000..e5751b0 --- /dev/null +++ b/webrtc/api/objc/RTCMediaStreamTrack.mm
@@ -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
diff --git a/webrtc/api/objc/RTCNSGLVideoView.h b/webrtc/api/objc/RTCNSGLVideoView.h new file mode 100644 index 0000000..27eb31e --- /dev/null +++ b/webrtc/api/objc/RTCNSGLVideoView.h
@@ -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
diff --git a/webrtc/api/objc/RTCNSGLVideoView.m b/webrtc/api/objc/RTCNSGLVideoView.m new file mode 100644 index 0000000..063e6f1 --- /dev/null +++ b/webrtc/api/objc/RTCNSGLVideoView.m
@@ -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
diff --git a/webrtc/api/objc/RTCOpenGLVideoRenderer.h b/webrtc/api/objc/RTCOpenGLVideoRenderer.h new file mode 100644 index 0000000..729839c --- /dev/null +++ b/webrtc/api/objc/RTCOpenGLVideoRenderer.h
@@ -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
diff --git a/webrtc/api/objc/RTCOpenGLVideoRenderer.mm b/webrtc/api/objc/RTCOpenGLVideoRenderer.mm new file mode 100644 index 0000000..56a6431 --- /dev/null +++ b/webrtc/api/objc/RTCOpenGLVideoRenderer.mm
@@ -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
diff --git a/webrtc/api/objc/RTCSessionDescription+Private.h b/webrtc/api/objc/RTCSessionDescription+Private.h new file mode 100644 index 0000000..aa0314d --- /dev/null +++ b/webrtc/api/objc/RTCSessionDescription+Private.h
@@ -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
diff --git a/webrtc/api/objc/RTCSessionDescription.h b/webrtc/api/objc/RTCSessionDescription.h new file mode 100644 index 0000000..5f00b1c --- /dev/null +++ b/webrtc/api/objc/RTCSessionDescription.h
@@ -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
diff --git a/webrtc/api/objc/RTCSessionDescription.mm b/webrtc/api/objc/RTCSessionDescription.mm new file mode 100644 index 0000000..7ed0760 --- /dev/null +++ b/webrtc/api/objc/RTCSessionDescription.mm
@@ -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
diff --git a/webrtc/api/objc/RTCStatsReport+Private.h b/webrtc/api/objc/RTCStatsReport+Private.h new file mode 100644 index 0000000..5b7dc32 --- /dev/null +++ b/webrtc/api/objc/RTCStatsReport+Private.h
@@ -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
diff --git a/webrtc/api/objc/RTCStatsReport.h b/webrtc/api/objc/RTCStatsReport.h new file mode 100644 index 0000000..fc66faf --- /dev/null +++ b/webrtc/api/objc/RTCStatsReport.h
@@ -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
diff --git a/webrtc/api/objc/RTCStatsReport.mm b/webrtc/api/objc/RTCStatsReport.mm new file mode 100644 index 0000000..35a5229 --- /dev/null +++ b/webrtc/api/objc/RTCStatsReport.mm
@@ -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
diff --git a/webrtc/api/objc/RTCVideoFrame+Private.h b/webrtc/api/objc/RTCVideoFrame+Private.h new file mode 100644 index 0000000..954344a --- /dev/null +++ b/webrtc/api/objc/RTCVideoFrame+Private.h
@@ -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 "RTCVideoFrame.h" + +#include "talk/media/base/videoframe.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface RTCVideoFrame () + +- (instancetype)initWithNativeFrame:(const cricket::VideoFrame *)nativeFrame + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END
diff --git a/webrtc/api/objc/RTCVideoFrame.h b/webrtc/api/objc/RTCVideoFrame.h new file mode 100644 index 0000000..8ed23ba --- /dev/null +++ b/webrtc/api/objc/RTCVideoFrame.h
@@ -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
diff --git a/webrtc/api/objc/RTCVideoFrame.mm b/webrtc/api/objc/RTCVideoFrame.mm new file mode 100644 index 0000000..db2d07b --- /dev/null +++ b/webrtc/api/objc/RTCVideoFrame.mm
@@ -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
diff --git a/webrtc/api/objc/RTCVideoRenderer.h b/webrtc/api/objc/RTCVideoRenderer.h new file mode 100644 index 0000000..a974562 --- /dev/null +++ b/webrtc/api/objc/RTCVideoRenderer.h
@@ -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
diff --git a/webrtc/api/objc/WebRTC-Prefix.pch b/webrtc/api/objc/WebRTC-Prefix.pch new file mode 100644 index 0000000..990b160 --- /dev/null +++ b/webrtc/api/objc/WebRTC-Prefix.pch
@@ -0,0 +1,13 @@ +/* + * Copyright 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif
diff --git a/webrtc/api/objctests/RTCIceCandidateTest.mm b/webrtc/api/objctests/RTCIceCandidateTest.mm new file mode 100644 index 0000000..391db44 --- /dev/null +++ b/webrtc/api/objctests/RTCIceCandidateTest.mm
@@ -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]; + } +}
diff --git a/webrtc/api/objctests/RTCIceServerTest.mm b/webrtc/api/objctests/RTCIceServerTest.mm new file mode 100644 index 0000000..5fa43f8 --- /dev/null +++ b/webrtc/api/objctests/RTCIceServerTest.mm
@@ -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]; + } +}
diff --git a/webrtc/api/objctests/RTCMediaConstraintsTest.mm b/webrtc/api/objctests/RTCMediaConstraintsTest.mm new file mode 100644 index 0000000..44ffe3d --- /dev/null +++ b/webrtc/api/objctests/RTCMediaConstraintsTest.mm
@@ -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]; + } +}
diff --git a/webrtc/api/objctests/RTCSessionDescriptionTest.mm b/webrtc/api/objctests/RTCSessionDescriptionTest.mm new file mode 100644 index 0000000..2404ded --- /dev/null +++ b/webrtc/api/objctests/RTCSessionDescriptionTest.mm
@@ -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]; + } +}
diff --git a/webrtc/audio/BUILD.gn b/webrtc/audio/BUILD.gn index d5061db..5a9902e 100644 --- a/webrtc/audio/BUILD.gn +++ b/webrtc/audio/BUILD.gn
@@ -14,6 +14,9 @@ "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", ] @@ -29,7 +32,7 @@ deps = [ "..:webrtc_common", - "../voice_engine", "../system_wrappers", + "../voice_engine", ] }
diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc index 34197c3..64d0083 100644 --- a/webrtc/audio/audio_receive_stream.cc +++ b/webrtc/audio/audio_receive_stream.cc
@@ -11,20 +11,41 @@ #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; @@ -60,120 +81,62 @@ namespace internal { AudioReceiveStream::AudioReceiveStream( - RemoteBitrateEstimator* remote_bitrate_estimator, - const webrtc::AudioReceiveStream::Config& config, - VoiceEngine* voice_engine) - : remote_bitrate_estimator_(remote_bitrate_estimator), - config_(config), - voice_engine_(voice_engine), - voe_base_(voice_engine), + 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(config.voe_channel_id != -1); - RTC_DCHECK(remote_bitrate_estimator_ != nullptr); - RTC_DCHECK(voice_engine_ != nullptr); - RTC_DCHECK(rtp_header_parser_ != nullptr); - for (const auto& ext : config.rtp.extensions) { - // One-byte-extension local identifiers are in the range 1-14 inclusive. - RTC_DCHECK_GE(ext.id, 1); - RTC_DCHECK_LE(ext.id, 14); - if (ext.name == RtpExtension::kAudioLevel) { - RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension( - kRtpExtensionAudioLevel, ext.id)); - } else if (ext.name == RtpExtension::kAbsSendTime) { - RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension( - kRtpExtensionAbsoluteSendTime, ext.id)); - } else if (ext.name == RtpExtension::kTransportSequenceNumber) { - RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension( - kRtpExtensionTransportSequenceNumber, ext.id)); + 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(); -} - -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_); - ScopedVoEInterface<VoENetEqStats> neteq(voice_engine_); - ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine_); - ScopedVoEInterface<VoEVideoSync> sync(voice_engine_); - ScopedVoEInterface<VoEVolumeControl> volume(voice_engine_); - unsigned int ssrc = 0; - webrtc::CallStatistics call_stats = {0}; - webrtc::CodecInst codec_inst = {0}; - // Only collect stats if we have seen some traffic with the SSRC. - if (rtp->GetRemoteSSRC(config_.voe_channel_id, ssrc) == -1 || - rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1 || - codec->GetRecCodec(config_.voe_channel_id, codec_inst) == -1) { - return stats; + channel_proxy_->SetCongestionControlObjects(nullptr, nullptr, nullptr); + if (remote_bitrate_estimator_) { + remote_bitrate_estimator_->RemoveStream(config_.rtp.remote_ssrc); } - - 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); - 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); - } - { - int jitter_buffer_delay_ms = 0; - int playout_buffer_delay_ms = 0; - sync->GetDelayEstimate(config_.voe_channel_id, &jitter_buffer_delay_ms, - &playout_buffer_delay_ms); - stats.delay_estimate_ms = - jitter_buffer_delay_ms + playout_buffer_delay_ms; - } - { - unsigned int level = 0; - if (volume->GetSpeechOutputLevelFullRange(config_.voe_channel_id, level) - != -1) { - stats.audio_level = static_cast<int32_t>(level); - } - } - - webrtc::NetworkStatistics ns = {0}; - if (neteq->GetNetworkStatistics(config_.voe_channel_id, ns) != -1) { - // Get jitter buffer and total delay (alg + jitter + playout) stats. - 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); - } - - webrtc::AudioDecodingCallStats ds; - if (neteq->GetDecodingCallStatistics(config_.voe_channel_id, &ds) != -1) { - 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; - } - - stats.capture_start_ntp_time_ms = call_stats.capture_start_ntp_time_ms_; - - return stats; -} - -const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - return config_; } void AudioReceiveStream::Start() { @@ -204,15 +167,16 @@ // 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 absolute sender time. RTP timestamps - // may have different rates for audio and video and shouldn't be mixed. - if (config_.combined_audio_video_bwe && - header.extension.hasAbsoluteSendTime) { + // 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; @@ -222,5 +186,71 @@ } 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
diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h index 5d02b0e..4940c6a 100644 --- a/webrtc/audio/audio_receive_stream.h +++ b/webrtc/audio/audio_receive_stream.h
@@ -12,23 +12,25 @@ #define WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_ #include "webrtc/audio_receive_stream.h" -#include "webrtc/audio/scoped_voe_interface.h" +#include "webrtc/audio_state.h" #include "webrtc/base/thread_checker.h" -#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" -#include "webrtc/voice_engine/include/voe_base.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" namespace webrtc { - +class CongestionController; class RemoteBitrateEstimator; -class VoiceEngine; + +namespace voe { +class ChannelProxy; +} // namespace voe namespace internal { class AudioReceiveStream final : public webrtc::AudioReceiveStream { public: - AudioReceiveStream(RemoteBitrateEstimator* remote_bitrate_estimator, + AudioReceiveStream(CongestionController* congestion_controller, const webrtc::AudioReceiveStream::Config& config, - VoiceEngine* voice_engine); + const rtc::scoped_refptr<webrtc::AudioState>& audio_state); ~AudioReceiveStream() override; // webrtc::ReceiveStream implementation. @@ -43,16 +45,19 @@ // 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* const remote_bitrate_estimator_; + RemoteBitrateEstimator* remote_bitrate_estimator_ = nullptr; const webrtc::AudioReceiveStream::Config config_; - VoiceEngine* voice_engine_; - // We hold one interface pointer to the VoE to make sure it is kept alive. - ScopedVoEInterface<VoEBase> voe_base_; + 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); };
diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc index 4e267f1..eb008b3 100644 --- a/webrtc/audio/audio_receive_stream_unittest.cc +++ b/webrtc/audio/audio_receive_stream_unittest.cc
@@ -8,154 +8,320 @@ * 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/test/fake_voice_engine.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 webrtc::ByteWriter; +using testing::_; +using testing::Return; -const size_t kAbsoluteSendTimeLength = 4; - -void BuildAbsoluteSendTimeExtension(uint8_t* buffer, - int id, - uint32_t abs_send_time) { - const size_t kRtpOneByteHeaderLength = 4; - const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE; - ByteWriter<uint16_t>::WriteBigEndian(buffer, kRtpOneByteHeaderExtensionId); - - const uint32_t kPosLength = 2; - ByteWriter<uint16_t>::WriteBigEndian(buffer + kPosLength, - kAbsoluteSendTimeLength / 4); - - const uint8_t kLengthOfData = 3; - buffer[kRtpOneByteHeaderLength] = (id << 4) + (kLengthOfData - 1); - ByteWriter<uint32_t, kLengthOfData>::WriteBigEndian( - buffer + kRtpOneByteHeaderLength + 1, abs_send_time); +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; } -size_t CreateRtpHeaderWithAbsSendTime(uint8_t* header, - int extension_id, - uint32_t abs_send_time) { +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. - int32_t rtp_header_length = webrtc::kRtpHeaderSize; + 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. - BuildAbsoluteSendTimeExtension(header + rtp_header_length, extension_id, - abs_send_time); - rtp_header_length += kAbsoluteSendTimeLength; - return rtp_header_length; + BuildOneByteExtension(header.begin() + webrtc::kRtpHeaderSize, extension_id, + extension_value, value_length); + return header; } } // namespace -namespace webrtc { -namespace test { - TEST(AudioReceiveStreamTest, ConfigToString) { - const int kAbsSendTimeId = 3; AudioReceiveStream::Config config; - config.rtp.remote_ssrc = 1234; - config.rtp.local_ssrc = 5678; + config.rtp.remote_ssrc = kRemoteSsrc; + config.rtp.local_ssrc = kLocalSsrc; config.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); - config.voe_channel_id = 1; + 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: 3}]}, " + 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: 1, combined_audio_video_bwe: true}", config.ToString()); + "voe_channel_id: 2, combined_audio_video_bwe: true}", + config.ToString()); } TEST(AudioReceiveStreamTest, ConstructDestruct) { - MockRemoteBitrateEstimator remote_bitrate_estimator; - FakeVoiceEngine voice_engine; - AudioReceiveStream::Config config; - config.voe_channel_id = 1; - internal::AudioReceiveStream recv_stream(&remote_bitrate_estimator, config, - &voice_engine); + 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) { - MockRemoteBitrateEstimator remote_bitrate_estimator; - FakeVoiceEngine voice_engine; - AudioReceiveStream::Config config; - config.combined_audio_video_bwe = true; - config.voe_channel_id = FakeVoiceEngine::kRecvChannelId; - const int kAbsSendTimeId = 3; - config.rtp.extensions.push_back( - RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); - internal::AudioReceiveStream recv_stream(&remote_bitrate_estimator, config, - &voice_engine); - uint8_t rtp_packet[30]; + 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; - CreateRtpHeaderWithAbsSendTime(rtp_packet, kAbsSendTimeId, kAbsSendTimeValue); + std::vector<uint8_t> rtp_packet = + CreateRtpHeaderWithOneByteExtension(kAbsSendTimeId, kAbsSendTimeValue, 3); PacketTime packet_time(5678000, 0); const size_t kExpectedHeaderLength = 20; - EXPECT_CALL(remote_bitrate_estimator, - IncomingPacket(packet_time.timestamp / 1000, - sizeof(rtp_packet) - kExpectedHeaderLength, testing::_, false)) + 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, sizeof(rtp_packet), packet_time)); + 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) { - MockRemoteBitrateEstimator remote_bitrate_estimator; - FakeVoiceEngine voice_engine; - AudioReceiveStream::Config config; - config.rtp.remote_ssrc = FakeVoiceEngine::kRecvSsrc; - config.voe_channel_id = FakeVoiceEngine::kRecvChannelId; - internal::AudioReceiveStream recv_stream(&remote_bitrate_estimator, config, - &voice_engine); - + ConfigHelper helper; + internal::AudioReceiveStream recv_stream( + helper.congestion_controller(), helper.config(), helper.audio_state()); + helper.SetupMockForGetStats(); AudioReceiveStream::Stats stats = recv_stream.GetStats(); - const CallStatistics& call_stats = FakeVoiceEngine::kRecvCallStats; - const CodecInst& codec_inst = FakeVoiceEngine::kRecvCodecInst; - const NetworkStatistics& net_stats = FakeVoiceEngine::kRecvNetworkStats; - const AudioDecodingCallStats& decode_stats = - FakeVoiceEngine::kRecvAudioDecodingCallStats; - EXPECT_EQ(FakeVoiceEngine::kRecvSsrc, stats.remote_ssrc); - EXPECT_EQ(static_cast<int64_t>(call_stats.bytesReceived), stats.bytes_rcvd); - EXPECT_EQ(static_cast<uint32_t>(call_stats.packetsReceived), + 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(call_stats.cumulativeLost, stats.packets_lost); - EXPECT_EQ(Q8ToFloat(call_stats.fractionLost), stats.fraction_lost); - EXPECT_EQ(std::string(codec_inst.plname), stats.codec_name); - EXPECT_EQ(call_stats.extendedMax, stats.ext_seqnum); - EXPECT_EQ(call_stats.jitterSamples / (codec_inst.plfreq / 1000), + 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(net_stats.currentBufferSize, stats.jitter_buffer_ms); - EXPECT_EQ(net_stats.preferredBufferSize, stats.jitter_buffer_preferred_ms); - EXPECT_EQ(static_cast<uint32_t>(FakeVoiceEngine::kRecvJitterBufferDelay + - FakeVoiceEngine::kRecvPlayoutBufferDelay), stats.delay_estimate_ms); - EXPECT_EQ(static_cast<int32_t>(FakeVoiceEngine::kRecvSpeechOutputLevel), - stats.audio_level); - EXPECT_EQ(Q14ToFloat(net_stats.currentExpandRate), stats.expand_rate); - EXPECT_EQ(Q14ToFloat(net_stats.currentSpeechExpandRate), + 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(net_stats.currentSecondaryDecodedRate), + EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSecondaryDecodedRate), stats.secondary_decoded_rate); - EXPECT_EQ(Q14ToFloat(net_stats.currentAccelerateRate), stats.accelerate_rate); - EXPECT_EQ(Q14ToFloat(net_stats.currentPreemptiveRate), + EXPECT_EQ(Q14ToFloat(kNetworkStats.currentAccelerateRate), + stats.accelerate_rate); + EXPECT_EQ(Q14ToFloat(kNetworkStats.currentPreemptiveRate), stats.preemptive_expand_rate); - EXPECT_EQ(decode_stats.calls_to_silence_generator, + EXPECT_EQ(kAudioDecodeStats.calls_to_silence_generator, stats.decoding_calls_to_silence_generator); - EXPECT_EQ(decode_stats.calls_to_neteq, stats.decoding_calls_to_neteq); - EXPECT_EQ(decode_stats.decoded_normal, stats.decoding_normal); - EXPECT_EQ(decode_stats.decoded_plc, stats.decoding_plc); - EXPECT_EQ(decode_stats.decoded_cng, stats.decoding_cng); - EXPECT_EQ(decode_stats.decoded_plc_cng, stats.decoding_plc_cng); - EXPECT_EQ(call_stats.capture_start_ntp_time_ms_, + 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
diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc index ccfdca5..35a6552 100644 --- a/webrtc/audio/audio_send_stream.cc +++ b/webrtc/audio/audio_send_stream.cc
@@ -12,13 +12,20 @@ #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 { @@ -32,6 +39,7 @@ } } ss << ']'; + ss << ", c_name: " << c_name; ss << '}'; return ss.str(); } @@ -48,115 +56,43 @@ } namespace internal { -AudioSendStream::AudioSendStream(const webrtc::AudioSendStream::Config& config, - VoiceEngine* voice_engine) - : config_(config), - voice_engine_(voice_engine), - voe_base_(voice_engine) { +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(voice_engine_); + 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(); -} - -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<VoERTP_RTCP> rtp(voice_engine_); - ScopedVoEInterface<VoEVolumeControl> volume(voice_engine_); - unsigned int ssrc = 0; - webrtc::CallStatistics call_stats = {0}; - if (rtp->GetLocalSSRC(config_.voe_channel_id, ssrc) == -1 || - rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1) { - return stats; - } - - stats.bytes_sent = call_stats.bytesSent; - stats.packets_sent = call_stats.packetsSent; - - 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. - std::vector<webrtc::ReportBlock> blocks; - if (rtp->GetRemoteRTCPReportBlocks(config_.voe_channel_id, &blocks) != -1) { - for (const webrtc::ReportBlock& block : blocks) { - // 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; - } - } - } - } - - // 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; - } - - // Local speech level. - { - unsigned int level = 0; - if (volume->GetSpeechInputLevelFullRange(level) != -1) { - stats.audio_level = static_cast<int32_t>(level); - } - } - - // TODO(ajm): Re-enable this metric once we have a reliable implementation. - stats.aec_quality_min = -1; - - bool echo_metrics_on = false; - if (processing->GetEcMetricsStatus(echo_metrics_on) != -1 && - 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; - if (processing->GetEcDelayMetrics(median, std, dummy) != -1) { - 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; - if (processing->GetEchoMetrics(erl, erle, dummy1, dummy2) != -1) { - stats.echo_return_loss = erl; - stats.echo_return_loss_enhancement = erle; - } - } - - // TODO(solenberg): Collect typing noise warnings here too! - // bool typing_noise_detected = typing_noise_detected_; - - return stats; -} - -const webrtc::AudioSendStream::Config& AudioSendStream::config() const { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - return config_; + channel_proxy_->SetCongestionControlObjects(nullptr, nullptr, nullptr); } void AudioSendStream::Start() { @@ -178,5 +114,108 @@ // 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
diff --git a/webrtc/audio/audio_send_stream.h b/webrtc/audio/audio_send_stream.h index ae81dfc..8b96350 100644 --- a/webrtc/audio/audio_send_stream.h +++ b/webrtc/audio/audio_send_stream.h
@@ -12,20 +12,24 @@ #define WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_ #include "webrtc/audio_send_stream.h" -#include "webrtc/audio/scoped_voe_interface.h" +#include "webrtc/audio_state.h" #include "webrtc/base/thread_checker.h" -#include "webrtc/voice_engine/include/voe_base.h" +#include "webrtc/base/scoped_ptr.h" namespace webrtc { - +class CongestionController; class VoiceEngine; -namespace internal { +namespace voe { +class ChannelProxy; +} // namespace voe +namespace internal { class AudioSendStream final : public webrtc::AudioSendStream { public: AudioSendStream(const webrtc::AudioSendStream::Config& config, - VoiceEngine* voice_engine); + const rtc::scoped_refptr<webrtc::AudioState>& audio_state, + CongestionController* congestion_controller); ~AudioSendStream() override; // webrtc::SendStream implementation. @@ -35,16 +39,19 @@ 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_; - VoiceEngine* voice_engine_; - // We hold one interface pointer to the VoE to make sure it is kept alive. - ScopedVoEInterface<VoEBase> voe_base_; + rtc::scoped_refptr<webrtc::AudioState> audio_state_; + rtc::scoped_ptr<voe::ChannelProxy> channel_proxy_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream); };
diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc index 227ec83..466c157 100644 --- a/webrtc/audio/audio_send_stream_unittest.cc +++ b/webrtc/audio/audio_send_stream_unittest.cc
@@ -8,69 +8,238 @@ * 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/test/fake_voice_engine.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) { - const int kAbsSendTimeId = 3; AudioSendStream::Config config(nullptr); - config.rtp.ssrc = 1234; + config.rtp.ssrc = kSsrc; config.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); - config.voe_channel_id = 1; + 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}]}, " - "voe_channel_id: 1, cng_payload_type: 42, 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) { - FakeVoiceEngine voice_engine; - AudioSendStream::Config config(nullptr); - config.voe_channel_id = 1; - internal::AudioSendStream send_stream(config, &voice_engine); + 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) { - FakeVoiceEngine voice_engine; - AudioSendStream::Config config(nullptr); - config.rtp.ssrc = FakeVoiceEngine::kSendSsrc; - config.voe_channel_id = FakeVoiceEngine::kSendChannelId; - internal::AudioSendStream send_stream(config, &voice_engine); - + ConfigHelper helper; + internal::AudioSendStream send_stream(helper.config(), helper.audio_state(), + helper.congestion_controller()); + helper.SetupMockForGetStats(); AudioSendStream::Stats stats = send_stream.GetStats(); - const CallStatistics& call_stats = FakeVoiceEngine::kSendCallStats; - const CodecInst& codec_inst = FakeVoiceEngine::kSendCodecInst; - const ReportBlock& report_block = FakeVoiceEngine::kSendReportBlock; - EXPECT_EQ(FakeVoiceEngine::kSendSsrc, stats.local_ssrc); - EXPECT_EQ(static_cast<int64_t>(call_stats.bytesSent), stats.bytes_sent); - EXPECT_EQ(call_stats.packetsSent, stats.packets_sent); - EXPECT_EQ(static_cast<int32_t>(report_block.cumulative_num_packets_lost), + 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(report_block.fraction_lost), stats.fraction_lost); - EXPECT_EQ(std::string(codec_inst.plname), stats.codec_name); - EXPECT_EQ(static_cast<int32_t>(report_block.extended_highest_sequence_number), + 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>(report_block.interarrival_jitter / - (codec_inst.plfreq / 1000)), stats.jitter_ms); - EXPECT_EQ(call_stats.rttMs, stats.rtt_ms); - EXPECT_EQ(static_cast<int32_t>(FakeVoiceEngine::kSendSpeechInputLevel), - stats.audio_level); + 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(FakeVoiceEngine::kSendEchoDelayMedian, stats.echo_delay_median_ms); - EXPECT_EQ(FakeVoiceEngine::kSendEchoDelayStdDev, stats.echo_delay_std_ms); - EXPECT_EQ(FakeVoiceEngine::kSendEchoReturnLoss, stats.echo_return_loss); - EXPECT_EQ(FakeVoiceEngine::kSendEchoReturnLossEnhancement, - stats.echo_return_loss_enhancement); + 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
diff --git a/webrtc/audio/audio_sink.h b/webrtc/audio/audio_sink.h new file mode 100644 index 0000000..999644f --- /dev/null +++ b/webrtc/audio/audio_sink.h
@@ -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_
diff --git a/webrtc/audio/audio_state.cc b/webrtc/audio/audio_state.cc new file mode 100644 index 0000000..e63f97a --- /dev/null +++ b/webrtc/audio/audio_state.cc
@@ -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
diff --git a/webrtc/audio/audio_state.h b/webrtc/audio/audio_state.h new file mode 100644 index 0000000..2cb83e4 --- /dev/null +++ b/webrtc/audio/audio_state.h
@@ -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_
diff --git a/webrtc/audio/audio_state_unittest.cc b/webrtc/audio/audio_state_unittest.cc new file mode 100644 index 0000000..11fbdb4 --- /dev/null +++ b/webrtc/audio/audio_state_unittest.cc
@@ -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
diff --git a/webrtc/audio/webrtc_audio.gypi b/webrtc/audio/webrtc_audio.gypi index b9d45db..53b7d16 100644 --- a/webrtc/audio/webrtc_audio.gypi +++ b/webrtc/audio/webrtc_audio.gypi
@@ -18,6 +18,9 @@ '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', ],
diff --git a/webrtc/audio_receive_stream.h b/webrtc/audio_receive_stream.h index 3e5a518..8cab094 100644 --- a/webrtc/audio_receive_stream.h +++ b/webrtc/audio_receive_stream.h
@@ -15,6 +15,7 @@ #include <string> #include <vector> +#include "webrtc/base/scoped_ptr.h" #include "webrtc/config.h" #include "webrtc/stream.h" #include "webrtc/transport.h" @@ -23,6 +24,12 @@ 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: @@ -66,6 +73,12 @@ // 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; @@ -95,6 +108,16 @@ }; 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
diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h index 89b73e6..d1af9e0 100644 --- a/webrtc/audio_send_stream.h +++ b/webrtc/audio_send_stream.h
@@ -23,6 +23,11 @@ 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 { @@ -59,8 +64,11 @@ // Sender SSRC. uint32_t ssrc = 0; - // RTP header extensions used for the received stream. + // 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 @@ -81,6 +89,9 @@ 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
diff --git a/webrtc/audio_state.h b/webrtc/audio_state.h new file mode 100644 index 0000000..fa5784c --- /dev/null +++ b/webrtc/audio_state.h
@@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef 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_
diff --git a/webrtc/base/Android.mk b/webrtc/base/Android.mk index 6a786df..f2aafad 100644 --- a/webrtc/base/Android.mk +++ b/webrtc/base/Android.mk
@@ -21,6 +21,7 @@ checks.cc \ criticalsection.cc \ event.cc \ + event_tracer.cc \ logging.cc \ platform_file.cc \ platform_thread.cc \
diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn index 11a2664..0f7a3f2 100644 --- a/webrtc/base/BUILD.gn +++ b/webrtc/base/BUILD.gn
@@ -10,6 +10,13 @@ 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", @@ -41,6 +48,7 @@ config("ios_config") { libs = [ + "AVFoundation.framework", "CFNetwork.framework", #"Foundation.framework", # Already included in //build/config:default_libs. @@ -90,6 +98,7 @@ # 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" ] @@ -107,23 +116,28 @@ "byteorder.h", "checks.cc", "checks.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", - "maybe.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", "safe_conversions.h", "safe_conversions_impl.h", "scoped_ptr.h", @@ -143,10 +157,16 @@ "trace_event.h", ] - if (!build_with_chromium) { + if (build_with_chromium) { + # Dependency on chromium's logging (in //base). + deps += [ "//base:base" ] sources += [ - "basictypes.h", - "constructormagic.h", + "../../webrtc_overrides/webrtc/base/logging.cc", + "../../webrtc_overrides/webrtc/base/logging.h", + ] + include_dirs = [ "../../webrtc_overrides" ] + } else { + sources += [ "logging.cc", "logging.h", ] @@ -157,7 +177,8 @@ cflags = [] cflags_cc = [] libs = [] - deps = [ + deps = [] + public_deps = [ ":rtc_base_approved", ] @@ -194,7 +215,6 @@ "autodetectproxy.h", "base64.cc", "base64.h", - "basicdefs.h", "common.cc", "common.h", "crc32.cc", @@ -312,19 +332,20 @@ if (is_posix) { sources += [ + "ifaddrs-android.h", + "ifaddrs_converter.cc", "unixfilesystem.cc", "unixfilesystem.h", ] } if (build_with_chromium) { - sources += [ - "../../webrtc_overrides/webrtc/base/logging.cc", - "../../webrtc_overrides/webrtc/base/logging.h", - ] - deps += [ "..:webrtc_common" ] + if (is_mac) { + sources += [ "macifaddrs_converter.cc" ] + } + if (is_win) { sources += [ "../../webrtc_overrides/webrtc/base/win32socketinit.cc" ] } @@ -592,5 +613,28 @@ 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", + ] } }
diff --git a/webrtc/base/OWNERS b/webrtc/base/OWNERS index 9a527df..2f40090 100644 --- a/webrtc/base/OWNERS +++ b/webrtc/base/OWNERS
@@ -9,4 +9,10 @@ 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 +
diff --git a/webrtc/base/array_view.h b/webrtc/base/array_view.h index 019bd8b..a7ca66c 100644 --- a/webrtc/base/array_view.h +++ b/webrtc/base/array_view.h
@@ -11,18 +11,63 @@ #ifndef WEBRTC_BASE_ARRAY_VIEW_H_ #define WEBRTC_BASE_ARRAY_VIEW_H_ -#include <vector> - #include "webrtc/base/checks.h" namespace rtc { -// Keeps track of an array (a pointer and a size) that it doesn't own. -// ArrayView objects are immutable except for assignment, and small enough to -// be cheaply passed by value. +// 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: // -// Note that ArrayView<T> and ArrayView<const T> are distinct types; this is -// how you would represent mutable and unmutable views of an array. +// 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: @@ -50,17 +95,12 @@ // std::vector). template <typename U> ArrayView(U& u) : ArrayView(u.data(), u.size()) {} - // TODO(kwiberg): Remove the special case for std::vector (and the include of - // <vector>); it is handled by the general case in C++11, since std::vector - // has a data() method there. - template <typename U> - ArrayView(std::vector<U>& u) - : ArrayView(u.empty() ? nullptr : &u[0], 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_); @@ -72,6 +112,15 @@ 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); }
diff --git a/webrtc/base/array_view_unittest.cc b/webrtc/base/array_view_unittest.cc index 0d1bff0..8bb1bcc 100644 --- a/webrtc/base/array_view_unittest.cc +++ b/webrtc/base/array_view_unittest.cc
@@ -214,4 +214,20 @@ } } +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
diff --git a/webrtc/base/atomicops.h b/webrtc/base/atomicops.h index a863566..a286bf0 100644 --- a/webrtc/base/atomicops.h +++ b/webrtc/base/atomicops.h
@@ -42,6 +42,16 @@ 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); @@ -58,6 +68,15 @@ 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 };
diff --git a/webrtc/base/autodetectproxy_unittest.cc b/webrtc/base/autodetectproxy_unittest.cc index bc57304..2ae7a6a 100644 --- a/webrtc/base/autodetectproxy_unittest.cc +++ b/webrtc/base/autodetectproxy_unittest.cc
@@ -12,7 +12,6 @@ #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 {
diff --git a/webrtc/base/base.gyp b/webrtc/base/base.gyp index 4b6ad85..c918263 100644 --- a/webrtc/base/base.gyp +++ b/webrtc/base/base.gyp
@@ -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': [ { @@ -31,7 +71,6 @@ 'sources': [ 'array_view.h', 'atomicops.h', - 'basictypes.h', 'bitbuffer.cc', 'bitbuffer.h', 'buffer.cc', @@ -46,6 +85,7 @@ 'constructormagic.h', 'criticalsection.cc', 'criticalsection.h', + 'deprecation.h', 'event.cc', 'event.h', 'event_tracer.cc', @@ -54,15 +94,18 @@ 'exp_filter.h', 'logging.cc', 'logging.h', - 'maybe.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', @@ -85,9 +128,16 @@ ], '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', @@ -102,6 +152,9 @@ '<(webrtc_root)/common.gyp:webrtc_common', 'rtc_base_approved', ], + 'export_dependent_settings': [ + 'rtc_base_approved', + ], 'defines': [ 'FEATURE_ENABLE_SSL', 'SSL_USE_OPENSSL', @@ -131,7 +184,6 @@ 'bandwidthsmoother.h', 'base64.cc', 'base64.h', - 'basicdefs.h', 'bind.h', 'callback.h', 'common.cc', @@ -172,6 +224,9 @@ 'httpserver.h', 'ifaddrs-android.cc', 'ifaddrs-android.h', + 'ifaddrs_converter.cc', + 'ifaddrs_converter.h', + 'macifaddrs_converter.cc', 'iosfilesystem.mm', 'ipaddress.cc', 'ipaddress.h', @@ -380,8 +435,6 @@ '../../boringssl/src/include', ], 'sources': [ - '../../webrtc_overrides/webrtc/base/logging.cc', - '../../webrtc_overrides/webrtc/base/logging.h', '../../webrtc_overrides/webrtc/base/win32socketinit.cc', ], 'sources!': [ @@ -390,7 +443,6 @@ 'bandwidthsmoother.h', 'bind.h', 'callback.h', - 'constructormagic.h', 'dbus.cc', 'dbus.h', 'diskcache_win32.cc', @@ -494,6 +546,17 @@ 'WEBRTC_EXTERNAL_JSON', ], }], + ['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', + ], + }, + }, + }], ], }], ['OS == "android"', { @@ -602,6 +665,9 @@ ], }], ['OS=="win"', { + 'sources!': [ + 'ifaddrs_converter.cc', + ], 'link_settings': { 'libraries': [ '-lcrypt32.lib', @@ -653,6 +719,7 @@ }], ['OS!="ios" and OS!="mac"', { 'sources!': [ + 'macifaddrs_converter.cc', 'scoped_autorelease_pool.mm', ], }],
diff --git a/webrtc/base/base_tests.gyp b/webrtc/base/base_tests.gyp index ee371f4..5d73d50 100644 --- a/webrtc/base/base_tests.gyp +++ b/webrtc/base/base_tests.gyp
@@ -71,22 +71,25 @@ 'httpserver_unittest.cc', 'ipaddress_unittest.cc', 'logging_unittest.cc', - 'maybe_unittest.cc', 'md5digest_unittest.cc', 'messagedigest_unittest.cc', 'messagequeue_unittest.cc', 'multipart_unittest.cc', 'nat_unittest.cc', 'network_unittest.cc', + 'optional_unittest.cc', 'optionsfile_unittest.cc', 'pathutils_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', @@ -131,6 +134,18 @@ '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': [ 'macutils_unittest.cc',
diff --git a/webrtc/base/basicdefs.h b/webrtc/base/basicdefs.h deleted file mode 100644 index 1dee2ae..0000000 --- a/webrtc/base/basicdefs.h +++ /dev/null
@@ -1,20 +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. - */ - -#ifndef WEBRTC_BASE_BASICDEFS_H_ -#define WEBRTC_BASE_BASICDEFS_H_ - -#if HAVE_CONFIG_H -#include "config.h" // NOLINT -#endif - -#define ARRAY_SIZE(x) (static_cast<int>(sizeof(x) / sizeof(x[0]))) - -#endif // WEBRTC_BASE_BASICDEFS_H_
diff --git a/webrtc/base/bitbuffer_unittest.cc b/webrtc/base/bitbuffer_unittest.cc index 99701f7..ce42257 100644 --- a/webrtc/base/bitbuffer_unittest.cc +++ b/webrtc/base/bitbuffer_unittest.cc
@@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "webrtc/base/arraysize.h" #include "webrtc/base/bitbuffer.h" #include "webrtc/base/bytebuffer.h" #include "webrtc/base/common.h" @@ -301,11 +302,11 @@ char test_string[] = "my precious"; uint8_t bytes[64] = {0}; BitBufferWriter buffer(bytes, 64); - for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) { + for (size_t i = 0; i < arraysize(test_string); ++i) { EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i])); } buffer.Seek(0, 0); - for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) { + for (size_t i = 0; i < arraysize(test_string); ++i) { uint32_t val; EXPECT_TRUE(buffer.ReadExponentialGolomb(&val)); EXPECT_LE(val, std::numeric_limits<uint8_t>::max());
diff --git a/webrtc/base/buffer.cc b/webrtc/base/buffer.cc index 90e687b..62855f1 100644 --- a/webrtc/base/buffer.cc +++ b/webrtc/base/buffer.cc
@@ -11,6 +11,7 @@ #include "webrtc/base/buffer.h" #include <cassert> +#include <utility> namespace rtc { @@ -22,7 +23,9 @@ } Buffer::Buffer(Buffer&& buf) - : size_(buf.size()), capacity_(buf.capacity()), data_(buf.data_.Pass()) { + : size_(buf.size()), + capacity_(buf.capacity()), + data_(std::move(buf.data_)) { assert(IsConsistent()); buf.OnMovedFrom(); }
diff --git a/webrtc/base/buffer.h b/webrtc/base/buffer.h index 7b9402b..ff9bb73 100644 --- a/webrtc/base/buffer.h +++ b/webrtc/base/buffer.h
@@ -15,6 +15,8 @@ #include <cassert> #include <cstring> #include <utility> // std::swap (C++11 and later) + +#include "webrtc/base/deprecation.h" #include "webrtc/base/scoped_ptr.h" namespace rtc { @@ -104,7 +106,7 @@ assert(buf.IsConsistent()); size_ = buf.size_; capacity_ = buf.capacity_; - data_ = buf.data_.Pass(); + data_ = std::move(buf.data_); buf.OnMovedFrom(); return *this; } @@ -164,15 +166,17 @@ return; scoped_ptr<uint8_t[]> new_data(new uint8_t[capacity]); std::memcpy(new_data.get(), data_.get(), size_); - data_ = new_data.Pass(); + data_ = std::move(new_data); capacity_ = capacity; assert(IsConsistent()); } - // We can't call std::move(b), so call b.Pass() instead to do the same job. - Buffer&& Pass() { + // b.Pass() does the same thing as std::move(b). + // Deprecated; remove in March 2016 (bug 5373). + RTC_DEPRECATED Buffer&& Pass() { return DEPRECATED_Pass(); } + Buffer&& DEPRECATED_Pass() { assert(IsConsistent()); - return static_cast<Buffer&&>(*this); + return std::move(*this); } // Resets the buffer to zero size and capacity. Works even if the buffer has
diff --git a/webrtc/base/buffer_unittest.cc b/webrtc/base/buffer_unittest.cc index f1ae6b8..0b93b9b 100644 --- a/webrtc/base/buffer_unittest.cc +++ b/webrtc/base/buffer_unittest.cc
@@ -138,7 +138,7 @@ TEST(BufferTest, TestMoveConstruct) { Buffer buf1(kTestData, 3, 40); const uint8_t* data = buf1.data(); - Buffer buf2(buf1.Pass()); + Buffer buf2(buf1.DEPRECATED_Pass()); EXPECT_EQ(buf2.size(), 3u); EXPECT_EQ(buf2.capacity(), 40u); EXPECT_EQ(buf2.data(), data); @@ -152,7 +152,7 @@ Buffer buf1(kTestData, 3, 40); const uint8_t* data = buf1.data(); Buffer buf2(kTestData); - buf2 = buf1.Pass(); + buf2 = buf1.DEPRECATED_Pass(); EXPECT_EQ(buf2.size(), 3u); EXPECT_EQ(buf2.capacity(), 40u); EXPECT_EQ(buf2.data(), data);
diff --git a/webrtc/base/bufferqueue.cc b/webrtc/base/bufferqueue.cc index 955af51..1ac57ab 100644 --- a/webrtc/base/bufferqueue.cc +++ b/webrtc/base/bufferqueue.cc
@@ -38,19 +38,19 @@ return false; } + bool was_writable = queue_.size() < capacity_; Buffer* packet = queue_.front(); queue_.pop_front(); - size_t next_packet_size = packet->size(); - if (bytes > next_packet_size) { - bytes = next_packet_size; - } - + bytes = std::min(bytes, packet->size()); memcpy(buffer, packet->data(), bytes); if (bytes_read) { *bytes_read = bytes; } free_list_.push_back(packet); + if (!was_writable) { + NotifyWritableForTest(); + } return true; } @@ -61,6 +61,7 @@ return false; } + bool was_readable = !queue_.empty(); Buffer* packet; if (!free_list_.empty()) { packet = free_list_.back(); @@ -74,6 +75,9 @@ *bytes_written = bytes; } queue_.push_back(packet); + if (!was_readable) { + NotifyReadableForTest(); + } return true; }
diff --git a/webrtc/base/bufferqueue.h b/webrtc/base/bufferqueue.h index 4941fcc..458f018 100644 --- a/webrtc/base/bufferqueue.h +++ b/webrtc/base/bufferqueue.h
@@ -21,26 +21,33 @@ class BufferQueue { public: - // Creates a buffer queue queue with a given capacity and default buffer size. + // Creates a buffer queue with a given capacity and default buffer size. BufferQueue(size_t capacity, size_t default_size); - ~BufferQueue(); + virtual ~BufferQueue(); // Return number of queued buffers. size_t size() const; // ReadFront will only read one buffer at a time and will truncate buffers // that don't fit in the passed memory. + // Returns true unless no data could be returned. bool ReadFront(void* data, size_t bytes, size_t* bytes_read); // WriteBack always writes either the complete memory or nothing. + // Returns true unless no data could be written. bool WriteBack(const void* data, size_t bytes, size_t* bytes_written); + protected: + // These methods are called when the state of the queue changes. + virtual void NotifyReadableForTest() {} + virtual void NotifyWritableForTest() {} + private: size_t capacity_; size_t default_size_; - std::deque<Buffer*> queue_; - std::vector<Buffer*> free_list_; - mutable CriticalSection crit_; // object lock + mutable CriticalSection crit_; + std::deque<Buffer*> queue_ GUARDED_BY(crit_); + std::vector<Buffer*> free_list_ GUARDED_BY(crit_); RTC_DISALLOW_COPY_AND_ASSIGN(BufferQueue); };
diff --git a/webrtc/base/bytebuffer_unittest.cc b/webrtc/base/bytebuffer_unittest.cc index 56b0e05..0287d85 100644 --- a/webrtc/base/bytebuffer_unittest.cc +++ b/webrtc/base/bytebuffer_unittest.cc
@@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "webrtc/base/arraysize.h" #include "webrtc/base/bytebuffer.h" #include "webrtc/base/byteorder.h" #include "webrtc/base/common.h" @@ -114,7 +115,7 @@ TEST(ByteBufferTest, TestReadWriteBuffer) { ByteBuffer::ByteOrder orders[2] = { ByteBuffer::ORDER_HOST, ByteBuffer::ORDER_NETWORK }; - for (size_t i = 0; i < ARRAY_SIZE(orders); i++) { + for (size_t i = 0; i < arraysize(orders); i++) { ByteBuffer buffer(orders[i]); EXPECT_EQ(orders[i], buffer.Order()); uint8_t ru8;
diff --git a/webrtc/base/callback_unittest.cc b/webrtc/base/callback_unittest.cc index 66c9391..db294cd 100644 --- a/webrtc/base/callback_unittest.cc +++ b/webrtc/base/callback_unittest.cc
@@ -11,6 +11,8 @@ #include "webrtc/base/bind.h" #include "webrtc/base/callback.h" #include "webrtc/base/gunit.h" +#include "webrtc/base/keep_ref_until_done.h" +#include "webrtc/base/refcount.h" namespace rtc { @@ -26,6 +28,21 @@ int b(int x) const { return x * x; } }; +class RefCountedBindTester : public RefCountInterface { + public: + RefCountedBindTester() : count_(0) {} + int AddRef() const override { + return ++count_; + } + int Release() const { + return --count_; + } + int RefCount() const { return count_; } + + private: + mutable int count_; +}; + } // namespace TEST(CallbackTest, VoidReturn) { @@ -78,4 +95,46 @@ EXPECT_EQ(25, cb1()); } +TEST(KeepRefUntilDoneTest, simple) { + RefCountedBindTester t; + EXPECT_EQ(0, t.RefCount()); + { + Callback0<void> cb = KeepRefUntilDone(&t); + EXPECT_EQ(1, t.RefCount()); + cb(); + EXPECT_EQ(1, t.RefCount()); + cb(); + EXPECT_EQ(1, t.RefCount()); + } + EXPECT_EQ(0, t.RefCount()); +} + +TEST(KeepRefUntilDoneTest, copy) { + RefCountedBindTester t; + EXPECT_EQ(0, t.RefCount()); + Callback0<void> cb2; + { + Callback0<void> cb = KeepRefUntilDone(&t); + EXPECT_EQ(1, t.RefCount()); + cb2 = cb; + } + EXPECT_EQ(1, t.RefCount()); + cb2 = Callback0<void>(); + EXPECT_EQ(0, t.RefCount()); +} + +TEST(KeepRefUntilDoneTest, scopedref) { + RefCountedBindTester t; + EXPECT_EQ(0, t.RefCount()); + { + scoped_refptr<RefCountedBindTester> t_scoped_ref(&t); + Callback0<void> cb = KeepRefUntilDone(t_scoped_ref); + t_scoped_ref = nullptr; + EXPECT_EQ(1, t.RefCount()); + cb(); + EXPECT_EQ(1, t.RefCount()); + } + EXPECT_EQ(0, t.RefCount()); +} + } // namespace rtc
diff --git a/webrtc/base/common.h b/webrtc/base/common.h index e615c76..1b1dac6 100644 --- a/webrtc/base/common.h +++ b/webrtc/base/common.h
@@ -54,14 +54,16 @@ #endif // !defined(WEBRTC_WIN) -#define ARRAY_SIZE(x) (static_cast<int>(sizeof(x) / sizeof(x[0]))) - ///////////////////////////////////////////////////////////////////////////// // Assertions ///////////////////////////////////////////////////////////////////////////// #ifndef ENABLE_DEBUG -#define ENABLE_DEBUG _DEBUG +#if !defined(NDEBUG) +#define ENABLE_DEBUG 1 +#else +#define ENABLE_DEBUG 0 +#endif #endif // !defined(ENABLE_DEBUG) // Even for release builds, allow for the override of LogAssert. Though no @@ -176,7 +178,7 @@ // Forces compiler to inline, even against its better judgement. Use wisely. #if defined(__GNUC__) -#define FORCE_INLINE __attribute__((always_inline)) +#define FORCE_INLINE __attribute__ ((__always_inline__)) #elif defined(WEBRTC_WIN) #define FORCE_INLINE __forceinline #else @@ -191,7 +193,7 @@ // libjingle are merged. #if !defined(WARN_UNUSED_RESULT) #if defined(__GNUC__) || defined(__clang__) -#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#define WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) #else #define WARN_UNUSED_RESULT #endif
diff --git a/webrtc/base/cpumonitor_unittest.cc b/webrtc/base/cpumonitor_unittest.cc deleted file mode 100644 index 379f62f..0000000 --- a/webrtc/base/cpumonitor_unittest.cc +++ /dev/null
@@ -1,389 +0,0 @@ -/* - * Copyright 2010 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can 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 <iomanip> -#include <iostream> -#include <vector> - -#if defined(WEBRTC_WIN) -#include "webrtc/base/win32.h" -#endif - -#include "webrtc/base/cpumonitor.h" -#include "webrtc/base/flags.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/timeutils.h" -#include "webrtc/base/timing.h" -#include "webrtc/test/testsupport/gtest_disable.h" - -namespace rtc { - -static const int kMaxCpus = 1024; -static const int kSettleTime = 100; // Amount of time to between tests. -static const int kIdleTime = 500; // Amount of time to be idle in ms. -static const int kBusyTime = 1000; // Amount of time to be busy in ms. -static const int kLongInterval = 2000; // Interval longer than busy times - -class BusyThread : public rtc::Thread { - public: - BusyThread(double load, double duration, double interval) : - load_(load), duration_(duration), interval_(interval) { - } - virtual ~BusyThread() { - Stop(); - } - void Run() { - Timing time; - double busy_time = interval_ * load_ / 100.0; - for (;;) { - time.BusyWait(busy_time); - time.IdleWait(interval_ - busy_time); - if (duration_) { - duration_ -= interval_; - if (duration_ <= 0) { - break; - } - } - } - } - private: - double load_; - double duration_; - double interval_; -}; - -class CpuLoadListener : public sigslot::has_slots<> { - public: - CpuLoadListener() - : current_cpus_(0), - cpus_(0), - process_load_(.0f), - system_load_(.0f), - count_(0) { - } - - void OnCpuLoad(int current_cpus, int cpus, float proc_load, float sys_load) { - current_cpus_ = current_cpus; - cpus_ = cpus; - process_load_ = proc_load; - system_load_ = sys_load; - ++count_; - } - - int current_cpus() const { return current_cpus_; } - int cpus() const { return cpus_; } - float process_load() const { return process_load_; } - float system_load() const { return system_load_; } - int count() const { return count_; } - - private: - int current_cpus_; - int cpus_; - float process_load_; - float system_load_; - int count_; -}; - -// Set affinity (which cpu to run on), but respecting FLAG_affinity: -// -1 means no affinity - run on whatever cpu is available. -// 0 .. N means run on specific cpu. The tool will create N threads and call -// SetThreadAffinity on 0 to N - 1 as cpu. FLAG_affinity sets the first cpu -// so the range becomes affinity to affinity + N - 1 -// Note that this function affects Windows scheduling, effectively giving -// the thread with affinity for a specified CPU more priority on that CPU. -bool SetThreadAffinity(BusyThread* t, int cpu, int affinity) { -#if defined(WEBRTC_WIN) - if (affinity >= 0) { - return ::SetThreadAffinityMask(t->GetHandle(), - 1 << (cpu + affinity)) != FALSE; - } -#endif - return true; -} - -bool SetThreadPriority(BusyThread* t, int prio) { - if (!prio) { - return true; - } - bool ok = t->SetPriority(static_cast<rtc::ThreadPriority>(prio)); - if (!ok) { - std::cout << "Error setting thread priority." << std::endl; - } - return ok; -} - -int CpuLoad(double cpuload, double duration, int numthreads, - int priority, double interval, int affinity) { - int ret = 0; - std::vector<BusyThread*> threads; - for (int i = 0; i < numthreads; ++i) { - threads.push_back(new BusyThread(cpuload, duration, interval)); - // NOTE(fbarchard): Priority must be done before Start. - if (!SetThreadPriority(threads[i], priority) || - !threads[i]->Start() || - !SetThreadAffinity(threads[i], i, affinity)) { - ret = 1; - break; - } - } - // Wait on each thread - if (ret == 0) { - for (int i = 0; i < numthreads; ++i) { - threads[i]->Stop(); - } - } - - for (int i = 0; i < numthreads; ++i) { - delete threads[i]; - } - return ret; -} - -// Make 2 CPUs busy -static void CpuTwoBusyLoop(int busytime) { - CpuLoad(100.0, busytime / 1000.0, 2, 1, 0.050, -1); -} - -// Make 1 CPUs busy -static void CpuBusyLoop(int busytime) { - CpuLoad(100.0, busytime / 1000.0, 1, 1, 0.050, -1); -} - -// Make 1 use half CPU time. -static void CpuHalfBusyLoop(int busytime) { - CpuLoad(50.0, busytime / 1000.0, 1, 1, 0.050, -1); -} - -void TestCpuSampler(bool test_proc, bool test_sys, bool force_fallback) { - CpuSampler sampler; - sampler.set_force_fallback(force_fallback); - EXPECT_TRUE(sampler.Init()); - sampler.set_load_interval(100); - int cpus = sampler.GetMaxCpus(); - - // Test1: CpuSampler under idle situation. - Thread::SleepMs(kSettleTime); - sampler.GetProcessLoad(); - sampler.GetSystemLoad(); - - Thread::SleepMs(kIdleTime); - - float proc_idle = 0.f, sys_idle = 0.f; - if (test_proc) { - proc_idle = sampler.GetProcessLoad(); - } - if (test_sys) { - sys_idle = sampler.GetSystemLoad(); - } - if (test_proc) { - LOG(LS_INFO) << "ProcessLoad Idle: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << proc_idle; - EXPECT_GE(proc_idle, 0.f); - EXPECT_LE(proc_idle, static_cast<float>(cpus)); - } - if (test_sys) { - LOG(LS_INFO) << "SystemLoad Idle: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << sys_idle; - EXPECT_GE(sys_idle, 0.f); - EXPECT_LE(sys_idle, static_cast<float>(cpus)); - } - - // Test2: CpuSampler with main process at 50% busy. - Thread::SleepMs(kSettleTime); - sampler.GetProcessLoad(); - sampler.GetSystemLoad(); - - CpuHalfBusyLoop(kBusyTime); - - float proc_halfbusy = 0.f, sys_halfbusy = 0.f; - if (test_proc) { - proc_halfbusy = sampler.GetProcessLoad(); - } - if (test_sys) { - sys_halfbusy = sampler.GetSystemLoad(); - } - if (test_proc) { - LOG(LS_INFO) << "ProcessLoad Halfbusy: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << proc_halfbusy; - EXPECT_GE(proc_halfbusy, 0.f); - EXPECT_LE(proc_halfbusy, static_cast<float>(cpus)); - } - if (test_sys) { - LOG(LS_INFO) << "SystemLoad Halfbusy: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << sys_halfbusy; - EXPECT_GE(sys_halfbusy, 0.f); - EXPECT_LE(sys_halfbusy, static_cast<float>(cpus)); - } - - // Test3: CpuSampler with main process busy. - Thread::SleepMs(kSettleTime); - sampler.GetProcessLoad(); - sampler.GetSystemLoad(); - - CpuBusyLoop(kBusyTime); - - float proc_busy = 0.f, sys_busy = 0.f; - if (test_proc) { - proc_busy = sampler.GetProcessLoad(); - } - if (test_sys) { - sys_busy = sampler.GetSystemLoad(); - } - if (test_proc) { - LOG(LS_INFO) << "ProcessLoad Busy: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << proc_busy; - EXPECT_GE(proc_busy, 0.f); - EXPECT_LE(proc_busy, static_cast<float>(cpus)); - } - if (test_sys) { - LOG(LS_INFO) << "SystemLoad Busy: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << sys_busy; - EXPECT_GE(sys_busy, 0.f); - EXPECT_LE(sys_busy, static_cast<float>(cpus)); - } - - // Test4: CpuSampler with 2 cpus process busy. - if (cpus >= 2) { - Thread::SleepMs(kSettleTime); - sampler.GetProcessLoad(); - sampler.GetSystemLoad(); - - CpuTwoBusyLoop(kBusyTime); - - float proc_twobusy = 0.f, sys_twobusy = 0.f; - if (test_proc) { - proc_twobusy = sampler.GetProcessLoad(); - } - if (test_sys) { - sys_twobusy = sampler.GetSystemLoad(); - } - if (test_proc) { - LOG(LS_INFO) << "ProcessLoad 2 CPU Busy:" - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << proc_twobusy; - EXPECT_GE(proc_twobusy, 0.f); - EXPECT_LE(proc_twobusy, static_cast<float>(cpus)); - } - if (test_sys) { - LOG(LS_INFO) << "SystemLoad 2 CPU Busy: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << sys_twobusy; - EXPECT_GE(sys_twobusy, 0.f); - EXPECT_LE(sys_twobusy, static_cast<float>(cpus)); - } - } - - // Test5: CpuSampler with idle process after being busy. - Thread::SleepMs(kSettleTime); - sampler.GetProcessLoad(); - sampler.GetSystemLoad(); - - Thread::SleepMs(kIdleTime); - - if (test_proc) { - proc_idle = sampler.GetProcessLoad(); - } - if (test_sys) { - sys_idle = sampler.GetSystemLoad(); - } - if (test_proc) { - LOG(LS_INFO) << "ProcessLoad Idle: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << proc_idle; - EXPECT_GE(proc_idle, 0.f); - EXPECT_LE(proc_idle, proc_busy); - } - if (test_sys) { - LOG(LS_INFO) << "SystemLoad Idle: " - << std::setiosflags(std::ios_base::fixed) - << std::setprecision(2) << std::setw(6) << sys_idle; - EXPECT_GE(sys_idle, 0.f); - EXPECT_LE(sys_idle, static_cast<float>(cpus)); - } -} - -TEST(CpuMonitorTest, TestCpus) { - CpuSampler sampler; - EXPECT_TRUE(sampler.Init()); - int current_cpus = sampler.GetCurrentCpus(); - int cpus = sampler.GetMaxCpus(); - LOG(LS_INFO) << "Current Cpus: " << std::setw(9) << current_cpus; - LOG(LS_INFO) << "Maximum Cpus: " << std::setw(9) << cpus; - EXPECT_GT(cpus, 0); - EXPECT_LE(cpus, kMaxCpus); - EXPECT_GT(current_cpus, 0); - EXPECT_LE(current_cpus, cpus); -} - -#if defined(WEBRTC_WIN) -// Tests overall system CpuSampler using legacy OS fallback code if applicable. -TEST(CpuMonitorTest, TestGetSystemLoadForceFallback) { - TestCpuSampler(false, true, true); -} -#endif - -// Tests both process and system functions in use at same time. -TEST(CpuMonitorTest, TestGetBothLoad) { - TestCpuSampler(true, true, false); -} - -// Tests a query less than the interval produces the same value. -TEST(CpuMonitorTest, TestInterval) { - CpuSampler sampler; - EXPECT_TRUE(sampler.Init()); - - // Test1: Set interval to large value so sampler will not update. - sampler.set_load_interval(kLongInterval); - - sampler.GetProcessLoad(); - sampler.GetSystemLoad(); - - float proc_orig = sampler.GetProcessLoad(); - float sys_orig = sampler.GetSystemLoad(); - - Thread::SleepMs(kIdleTime); - - float proc_halftime = sampler.GetProcessLoad(); - float sys_halftime = sampler.GetSystemLoad(); - - EXPECT_EQ(proc_orig, proc_halftime); - EXPECT_EQ(sys_orig, sys_halftime); -} - -TEST(CpuMonitorTest, TestCpuMonitor) { - CpuMonitor monitor(Thread::Current()); - CpuLoadListener listener; - monitor.SignalUpdate.connect(&listener, &CpuLoadListener::OnCpuLoad); - EXPECT_TRUE(monitor.Start(10)); - // We have checked cpu load more than twice. - EXPECT_TRUE_WAIT(listener.count() > 2, 1000); - EXPECT_GT(listener.current_cpus(), 0); - EXPECT_GT(listener.cpus(), 0); - EXPECT_GE(listener.process_load(), .0f); - EXPECT_GE(listener.system_load(), .0f); - - monitor.Stop(); - // Wait 20 ms to ake sure all signals are delivered. - Thread::Current()->ProcessMessages(20); - int old_count = listener.count(); - Thread::Current()->ProcessMessages(20); - // Verfy no more siganls. - EXPECT_EQ(old_count, listener.count()); -} - -} // namespace rtc
diff --git a/webrtc/base/crc32.cc b/webrtc/base/crc32.cc index eae338a..97b8214 100644 --- a/webrtc/base/crc32.cc +++ b/webrtc/base/crc32.cc
@@ -10,7 +10,7 @@ #include "webrtc/base/crc32.h" -#include "webrtc/base/basicdefs.h" +#include "webrtc/base/arraysize.h" namespace rtc { @@ -22,9 +22,9 @@ static uint32_t kCrc32Table[256] = {0}; static void EnsureCrc32TableInited() { - if (kCrc32Table[ARRAY_SIZE(kCrc32Table) - 1]) + if (kCrc32Table[arraysize(kCrc32Table) - 1]) return; // already inited - for (uint32_t i = 0; i < ARRAY_SIZE(kCrc32Table); ++i) { + for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) { uint32_t c = i; for (size_t j = 0; j < 8; ++j) { if (c & 1) {
diff --git a/webrtc/base/criticalsection.h b/webrtc/base/criticalsection.h index ddbf857..5b3eaf5 100644 --- a/webrtc/base/criticalsection.h +++ b/webrtc/base/criticalsection.h
@@ -89,7 +89,7 @@ #if defined(WEBRTC_WIN) _Check_return_ bool locked() const; #else - bool locked() const __attribute__((warn_unused_result)); + bool locked() const __attribute__ ((__warn_unused_result__)); #endif private: CriticalSection* const cs_;
diff --git a/webrtc/base/criticalsection_unittest.cc b/webrtc/base/criticalsection_unittest.cc index ff4fdef..d6990c0 100644 --- a/webrtc/base/criticalsection_unittest.cc +++ b/webrtc/base/criticalsection_unittest.cc
@@ -14,9 +14,9 @@ #include "webrtc/base/criticalsection.h" #include "webrtc/base/event.h" #include "webrtc/base/gunit.h" +#include "webrtc/base/scoped_ptr.h" #include "webrtc/base/scopedptrcollection.h" #include "webrtc/base/thread.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace rtc { @@ -220,6 +220,28 @@ EXPECT_EQ(0, value); } +TEST(AtomicOpsTest, SimplePtr) { + class Foo {}; + Foo* volatile foo = nullptr; + scoped_ptr<Foo> a(new Foo()); + scoped_ptr<Foo> b(new Foo()); + // Reading the initial value should work as expected. + EXPECT_TRUE(rtc::AtomicOps::AcquireLoadPtr(&foo) == nullptr); + // Setting using compare and swap should work. + EXPECT_TRUE(rtc::AtomicOps::CompareAndSwapPtr( + &foo, static_cast<Foo*>(nullptr), a.get()) == nullptr); + EXPECT_TRUE(rtc::AtomicOps::AcquireLoadPtr(&foo) == a.get()); + // Setting another value but with the wrong previous pointer should fail + // (remain a). + EXPECT_TRUE(rtc::AtomicOps::CompareAndSwapPtr( + &foo, static_cast<Foo*>(nullptr), b.get()) == a.get()); + EXPECT_TRUE(rtc::AtomicOps::AcquireLoadPtr(&foo) == a.get()); + // Replacing a with b should work. + EXPECT_TRUE(rtc::AtomicOps::CompareAndSwapPtr(&foo, a.get(), b.get()) == + a.get()); + EXPECT_TRUE(rtc::AtomicOps::AcquireLoadPtr(&foo) == b.get()); +} + TEST(AtomicOpsTest, Increment) { // Create and start lots of threads. AtomicOpRunner<IncrementOp, UniqueValueVerifier> runner(0);
diff --git a/webrtc/base/deprecation.h b/webrtc/base/deprecation.h new file mode 100644 index 0000000..ce950f9 --- /dev/null +++ b/webrtc/base/deprecation.h
@@ -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_BASE_DEPRECATION_H_ +#define WEBRTC_BASE_DEPRECATION_H_ + +// Annotate the declarations of deprecated functions with this to cause a +// compiler warning when they're used. Like so: +// +// RTC_DEPRECATED std::pony PonyPlz(const std::pony_spec& ps); +// +// NOTE 1: The annotation goes on the declaration in the .h file, not the +// definition in the .cc file! +// +// NOTE 2: In order to keep unit testing the deprecated function without +// getting warnings, do something like this: +// +// std::pony DEPRECATED_PonyPlz(const std::pony_spec& ps); +// RTC_DEPRECATED inline std::pony PonyPlz(const std::pony_spec& ps) { +// return DEPRECATED_PonyPlz(ps); +// } +// +// In other words, rename the existing function, and provide an inline wrapper +// using the original name that calls it. That way, callers who are willing to +// call it using the DEPRECATED_-prefixed name don't get the warning. +// +// TODO(kwiberg): Remove this when we can use [[deprecated]] from C++14. +#if defined(_MSC_VER) +// Note: Deprecation warnings seem to fail to trigger on Windows +// (https://bugs.chromium.org/p/webrtc/issues/detail?id=5368). +#define RTC_DEPRECATED __declspec(deprecated) +#elif defined(__GNUC__) +#define RTC_DEPRECATED __attribute__ ((__deprecated__)) +#else +#define RTC_DEPRECATED +#endif + +#endif // WEBRTC_BASE_DEPRECATION_H_
diff --git a/webrtc/base/diskcache.cc b/webrtc/base/diskcache.cc index 6bbc53e..a1fba6a 100644 --- a/webrtc/base/diskcache.cc +++ b/webrtc/base/diskcache.cc
@@ -15,6 +15,7 @@ #endif #include <algorithm> +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/diskcache.h" #include "webrtc/base/fileutils.h" @@ -23,11 +24,11 @@ #include "webrtc/base/stringencode.h" #include "webrtc/base/stringutils.h" -#ifdef _DEBUG +#if !defined(NDEBUG) #define TRANSPARENT_CACHE_NAMES 1 -#else // !_DEBUG +#else #define TRANSPARENT_CACHE_NAMES 0 -#endif // !_DEBUG +#endif namespace rtc { @@ -211,14 +212,14 @@ } bool DiskCache::CheckLimit() { -#ifdef _DEBUG +#if !defined(NDEBUG) // Temporary check to make sure everything is working correctly. size_t cache_size = 0; for (EntryMap::iterator it = map_.begin(); it != map_.end(); ++it) { cache_size += it->second.size; } ASSERT(cache_size == total_size_); -#endif // _DEBUG +#endif // TODO: Replace this with a non-brain-dead algorithm for clearing out the // oldest resources... something that isn't O(n^2) @@ -263,7 +264,7 @@ #endif // !TRANSPARENT_CACHE_NAMES char extension[32]; - sprintfn(extension, ARRAY_SIZE(extension), ".%u", index); + sprintfn(extension, arraysize(extension), ".%u", index); Pathname pathname; pathname.SetFolder(folder_);
diff --git a/webrtc/base/event_tracer.cc b/webrtc/base/event_tracer.cc index 5c6d39f..4174589 100644 --- a/webrtc/base/event_tracer.cc +++ b/webrtc/base/event_tracer.cc
@@ -7,15 +7,26 @@ * 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/event_tracer.h" +#include <inttypes.h> + +#include <vector> + +#include "webrtc/base/checks.h" +#include "webrtc/base/criticalsection.h" +#include "webrtc/base/event.h" +#include "webrtc/base/logging.h" +#include "webrtc/base/platform_thread.h" +#include "webrtc/base/timeutils.h" +#include "webrtc/base/trace_event.h" + namespace webrtc { namespace { -GetCategoryEnabledPtr g_get_category_enabled_ptr = 0; -AddTraceEventPtr g_add_trace_event_ptr = 0; +GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr; +AddTraceEventPtr g_add_trace_event_ptr = nullptr; } // namespace @@ -25,7 +36,6 @@ g_add_trace_event_ptr = add_trace_event_ptr; } -// static const unsigned char* EventTracer::GetCategoryEnabled(const char* name) { if (g_get_category_enabled_ptr) return g_get_category_enabled_ptr(name); @@ -34,7 +44,8 @@ return reinterpret_cast<const unsigned char*>("\0"); } -// static +// Arguments to this function (phase, etc.) are as defined in +// webrtc/base/trace_event.h. void EventTracer::AddTraceEvent(char phase, const unsigned char* category_enabled, const char* name, @@ -58,3 +69,202 @@ } } // namespace webrtc + +namespace rtc { +namespace tracing { +namespace { + +static bool EventTracingThreadFunc(void* params); + +// Atomic-int fast path for avoiding logging when disabled. +static volatile int g_event_logging_active = 0; + +// TODO(pbos): Log metadata for all threads, etc. +class EventLogger final { + public: + EventLogger() + : logging_thread_(EventTracingThreadFunc, this, "EventTracingThread"), + shutdown_event_(false, false) {} + ~EventLogger() { RTC_DCHECK(thread_checker_.CalledOnValidThread()); } + + void AddTraceEvent(const char* name, + const unsigned char* category_enabled, + char phase, + uint64_t timestamp, + int pid, + rtc::PlatformThreadId thread_id) { + rtc::CritScope lock(&crit_); + trace_events_.push_back( + {name, category_enabled, phase, timestamp, 1, thread_id}); + } + +// The TraceEvent format is documented here: +// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview + void Log() { + RTC_DCHECK(output_file_); + static const int kLoggingIntervalMs = 100; + fprintf(output_file_, "{ \"traceEvents\": [\n"); + bool has_logged_event = false; + while (true) { + bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs); + std::vector<TraceEvent> events; + { + rtc::CritScope lock(&crit_); + trace_events_.swap(events); + } + for (const TraceEvent& e : events) { + fprintf(output_file_, + "%s{ \"name\": \"%s\"" + ", \"cat\": \"%s\"" + ", \"ph\": \"%c\"" + ", \"ts\": %" PRIu64 + ", \"pid\": %d" +#if defined(WEBRTC_WIN) + ", \"tid\": %lu" +#else + ", \"tid\": %d" +#endif // defined(WEBRTC_WIN) + "}\n", + has_logged_event ? "," : " ", e.name, e.category_enabled, + e.phase, e.timestamp, e.pid, e.tid); + has_logged_event = true; + } + if (shutting_down) + break; + } + fprintf(output_file_, "]}\n"); + if (output_file_owned_) + fclose(output_file_); + output_file_ = nullptr; + } + + void Start(FILE* file, bool owned) { + RTC_DCHECK(file); + RTC_DCHECK(!output_file_); + output_file_ = file; + output_file_owned_ = owned; + { + rtc::CritScope lock(&crit_); + // Since the atomic fast-path for adding events to the queue can be + // bypassed while the logging thread is shutting down there may be some + // stale events in the queue, hence the vector needs to be cleared to not + // log events from a previous logging session (which may be days old). + trace_events_.clear(); + } + // Enable event logging (fast-path). This should be disabled since starting + // shouldn't be done twice. + RTC_CHECK_EQ(0, + rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 0, 1)); + + // Finally start, everything should be set up now. + logging_thread_.Start(); + } + + void Stop() { + // Try to stop. Abort if we're not currently logging. + if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0) + return; + + // Wake up logging thread to finish writing. + shutdown_event_.Set(); + // Join the logging thread. + logging_thread_.Stop(); + } + + private: + struct TraceEvent { + const char* name; + const unsigned char* category_enabled; + char phase; + uint64_t timestamp; + int pid; + rtc::PlatformThreadId tid; + }; + + rtc::CriticalSection crit_; + std::vector<TraceEvent> trace_events_ GUARDED_BY(crit_); + rtc::PlatformThread logging_thread_; + rtc::Event shutdown_event_; + rtc::ThreadChecker thread_checker_; + FILE* output_file_ = nullptr; + bool output_file_owned_ = false; +}; + +static bool EventTracingThreadFunc(void* params) { + static_cast<EventLogger*>(params)->Log(); + return true; +} + +static EventLogger* volatile g_event_logger = nullptr; +static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT(""); +const unsigned char* InternalGetCategoryEnabled(const char* name) { + const char* prefix_ptr = &kDisabledTracePrefix[0]; + const char* name_ptr = name; + // Check whether name contains the default-disabled prefix. + while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') { + ++prefix_ptr; + ++name_ptr; + } + return reinterpret_cast<const unsigned char*>(*prefix_ptr == '\0' ? "" + : name); +} + +void InternalAddTraceEvent(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags) { + // Fast path for when event tracing is inactive. + if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0) + return; + + g_event_logger->AddTraceEvent(name, category_enabled, phase, + rtc::TimeMicros(), 1, rtc::CurrentThreadId()); +} + +} // namespace + +void SetupInternalTracer() { + RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( + &g_event_logger, static_cast<EventLogger*>(nullptr), + new EventLogger()) == nullptr); + g_event_logger = new EventLogger(); + webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent); +} + +void StartInternalCaptureToFile(FILE* file) { + g_event_logger->Start(file, false); +} + +bool StartInternalCapture(const char* filename) { + FILE* file = fopen(filename, "w"); + if (!file) { + LOG(LS_ERROR) << "Failed to open trace file '" << filename + << "' for writing."; + return false; + } + g_event_logger->Start(file, true); + return true; +} + +void StopInternalCapture() { + g_event_logger->Stop(); +} + +void ShutdownInternalTracer() { + StopInternalCapture(); + EventLogger* old_logger = rtc::AtomicOps::AcquireLoadPtr(&g_event_logger); + RTC_DCHECK(old_logger); + RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr( + &g_event_logger, old_logger, + static_cast<EventLogger*>(nullptr)) == old_logger); + delete old_logger; + webrtc::SetupEventTracer(nullptr, nullptr); +} + +} // namespace tracing +} // namespace rtc
diff --git a/webrtc/base/event_tracer.h b/webrtc/base/event_tracer.h index cfc6e9e..51c8cfd 100644 --- a/webrtc/base/event_tracer.h +++ b/webrtc/base/event_tracer.h
@@ -26,6 +26,8 @@ #ifndef WEBRTC_BASE_EVENT_TRACER_H_ #define WEBRTC_BASE_EVENT_TRACER_H_ +#include <stdio.h> + namespace webrtc { typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name); @@ -68,4 +70,16 @@ } // namespace webrtc +namespace rtc { +namespace tracing { +// Set up internal event tracer. +void SetupInternalTracer(); +bool StartInternalCapture(const char* filename); +void StartInternalCaptureToFile(FILE* file); +void StopInternalCapture(); +// Make sure we run this, this will tear down the internal tracing. +void ShutdownInternalTracer(); +} // namespace tracing +} // namespace rtc + #endif // WEBRTC_BASE_EVENT_TRACER_H_
diff --git a/webrtc/base/fakenetwork.h b/webrtc/base/fakenetwork.h index fb99d59..e3996e6 100644 --- a/webrtc/base/fakenetwork.h +++ b/webrtc/base/fakenetwork.h
@@ -12,6 +12,7 @@ #define WEBRTC_BASE_FAKENETWORK_H_ #include <string> +#include <utility> #include <vector> #include "webrtc/base/network.h" @@ -31,7 +32,7 @@ public: FakeNetworkManager() : thread_(Thread::Current()) {} - typedef std::vector<SocketAddress> IfaceList; + typedef std::vector<std::pair<SocketAddress, AdapterType>> IfaceList; void AddInterface(const SocketAddress& iface) { // Ensure a unique name for the interface if its name is not given. @@ -39,16 +40,22 @@ } void AddInterface(const SocketAddress& iface, const std::string& if_name) { + AddInterface(iface, if_name, ADAPTER_TYPE_UNKNOWN); + } + + void AddInterface(const SocketAddress& iface, + const std::string& if_name, + AdapterType type) { SocketAddress address(if_name, 0); address.SetResolvedIP(iface.ipaddr()); - ifaces_.push_back(address); + ifaces_.push_back(std::make_pair(address, type)); DoUpdateNetworks(); } void RemoveInterface(const SocketAddress& iface) { for (IfaceList::iterator it = ifaces_.begin(); it != ifaces_.end(); ++it) { - if (it->EqualIPs(iface)) { + if (it->first.EqualIPs(iface)) { ifaces_.erase(it); break; } @@ -76,6 +83,7 @@ } using NetworkManagerBase::set_enumeration_permission; + using NetworkManagerBase::set_default_local_addresses; private: void DoUpdateNetworks() { @@ -85,17 +93,17 @@ for (IfaceList::iterator it = ifaces_.begin(); it != ifaces_.end(); ++it) { int prefix_length = 0; - if (it->ipaddr().family() == AF_INET) { + if (it->first.ipaddr().family() == AF_INET) { prefix_length = kFakeIPv4NetworkPrefixLength; - } else if (it->ipaddr().family() == AF_INET6) { + } else if (it->first.ipaddr().family() == AF_INET6) { prefix_length = kFakeIPv6NetworkPrefixLength; } - IPAddress prefix = TruncateIP(it->ipaddr(), prefix_length); - scoped_ptr<Network> net(new Network(it->hostname(), - it->hostname(), - prefix, - prefix_length)); - net->AddIP(it->ipaddr()); + IPAddress prefix = TruncateIP(it->first.ipaddr(), prefix_length); + scoped_ptr<Network> net(new Network(it->first.hostname(), + it->first.hostname(), prefix, + prefix_length, it->second)); + net->set_default_local_address_provider(this); + net->AddIP(it->first.ipaddr()); networks.push_back(net.release()); } bool changed; @@ -111,6 +119,9 @@ int next_index_ = 0; int start_count_ = 0; bool sent_first_update_ = false; + + IPAddress default_local_ipv4_address_; + IPAddress default_local_ipv6_address_; }; } // namespace rtc
diff --git a/webrtc/base/fakesslidentity.h b/webrtc/base/fakesslidentity.h index 7926580..ec603a5 100644 --- a/webrtc/base/fakesslidentity.h +++ b/webrtc/base/fakesslidentity.h
@@ -25,9 +25,11 @@ // SHA-1 is the default digest algorithm because it is available in all build // configurations used for unit testing. explicit FakeSSLCertificate(const std::string& data) - : data_(data), digest_algorithm_(DIGEST_SHA_1) {} + : data_(data), digest_algorithm_(DIGEST_SHA_1), expiration_time_(-1) {} explicit FakeSSLCertificate(const std::vector<std::string>& certs) - : data_(certs.front()), digest_algorithm_(DIGEST_SHA_1) { + : data_(certs.front()), + digest_algorithm_(DIGEST_SHA_1), + expiration_time_(-1) { std::vector<std::string>::const_iterator it; // Skip certs[0]. for (it = certs.begin() + 1; it != certs.end(); ++it) { @@ -45,6 +47,12 @@ VERIFY(SSLIdentity::PemToDer(kPemTypeCertificate, data_, &der_string)); der_buffer->SetData(der_string.c_str(), der_string.size()); } + int64_t CertificateExpirationTime() const override { + return expiration_time_; + } + void SetCertificateExpirationTime(int64_t expiration_time) { + expiration_time_ = expiration_time; + } void set_digest_algorithm(const std::string& algorithm) { digest_algorithm_ = algorithm; } @@ -78,6 +86,8 @@ std::string data_; std::vector<FakeSSLCertificate> certs_; std::string digest_algorithm_; + // Expiration time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC). + int64_t expiration_time_; }; class FakeSSLIdentity : public rtc::SSLIdentity {
diff --git a/webrtc/base/filerotatingstream.cc b/webrtc/base/filerotatingstream.cc index 65dfd63..0809994 100644 --- a/webrtc/base/filerotatingstream.cc +++ b/webrtc/base/filerotatingstream.cc
@@ -281,7 +281,7 @@ // Rotates the files by deleting the file at |rotation_index_|, which is the // oldest file and then renaming the newer files to have an incremented index. // See header file comments for example. - RTC_DCHECK_LE(rotation_index_, file_names_.size()); + RTC_DCHECK_LT(rotation_index_, file_names_.size()); std::string file_to_delete = file_names_[rotation_index_]; if (Filesystem::IsFile(file_to_delete)) { if (!Filesystem::DeleteFile(file_to_delete)) {
diff --git a/webrtc/base/fileutils.cc b/webrtc/base/fileutils.cc index 6f385d7..cb23153 100644 --- a/webrtc/base/fileutils.cc +++ b/webrtc/base/fileutils.cc
@@ -10,6 +10,7 @@ #include <assert.h> +#include "webrtc/base/arraysize.h" #include "webrtc/base/pathutils.h" #include "webrtc/base/fileutils.h" #include "webrtc/base/stringutils.h" @@ -273,8 +274,8 @@ } version += 1; char version_base[MAX_PATH]; - sprintfn(version_base, ARRAY_SIZE(version_base), "%s-%u", - basename.c_str(), version); + sprintfn(version_base, arraysize(version_base), "%s-%u", basename.c_str(), + version); path.SetBasename(version_base); } return true;
diff --git a/webrtc/base/format_macros.h b/webrtc/base/format_macros.h index 5d7dcc3..90f86a6 100644 --- a/webrtc/base/format_macros.h +++ b/webrtc/base/format_macros.h
@@ -73,6 +73,8 @@ #else // WEBRTC_WIN +#include <inttypes.h> + #if !defined(PRId64) #define PRId64 "I64d" #endif
diff --git a/webrtc/base/gunit.h b/webrtc/base/gunit.h index c2bc844..1a6c363 100644 --- a/webrtc/base/gunit.h +++ b/webrtc/base/gunit.h
@@ -13,7 +13,7 @@ #include "webrtc/base/logging.h" #include "webrtc/base/thread.h" -#if defined(WEBRTC_ANDROID) || defined(GTEST_RELATIVE_PATH) +#if defined(GTEST_RELATIVE_PATH) #include "testing/gtest/include/gtest/gtest.h" #else #include "testing/base/public/gunit.h" @@ -35,7 +35,7 @@ rtc::Thread::Current()->ProcessMessages(1); \ res = (ex); \ } \ - } while (0); + } while (0) // The typical EXPECT_XXXX and ASSERT_XXXXs, but done until true or a timeout. #define EXPECT_TRUE_WAIT(ex, timeout) \ @@ -43,28 +43,28 @@ bool res; \ WAIT_(ex, timeout, res); \ if (!res) EXPECT_TRUE(ex); \ - } while (0); + } while (0) #define EXPECT_EQ_WAIT(v1, v2, timeout) \ do { \ bool res; \ WAIT_(v1 == v2, timeout, res); \ if (!res) EXPECT_EQ(v1, v2); \ - } while (0); + } while (0) #define ASSERT_TRUE_WAIT(ex, timeout) \ do { \ bool res; \ WAIT_(ex, timeout, res); \ if (!res) ASSERT_TRUE(ex); \ - } while (0); + } while (0) #define ASSERT_EQ_WAIT(v1, v2, timeout) \ do { \ bool res; \ WAIT_(v1 == v2, timeout, res); \ if (!res) ASSERT_EQ(v1, v2); \ - } while (0); + } while (0) // Version with a "soft" timeout and a margin. This logs if the timeout is // exceeded, but it only fails if the expression still isn't true after the @@ -82,6 +82,6 @@ if (!res) { \ EXPECT_TRUE(ex); \ } \ - } while (0); + } while (0) #endif // WEBRTC_BASE_GUNIT_H_
diff --git a/webrtc/base/helpers.cc b/webrtc/base/helpers.cc index 8e59b64..1ad5d0e 100644 --- a/webrtc/base/helpers.cc +++ b/webrtc/base/helpers.cc
@@ -164,17 +164,21 @@ int seed_; }; -// TODO: Use Base64::Base64Table instead. -static const char BASE64[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' -}; - namespace { +// TODO: Use Base64::Base64Table instead. +static const char kBase64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + +static const char kHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + +static const char kUuidDigit17[4] = {'8', '9', 'a', 'b'}; + // This round about way of creating a global RNG is to safe-guard against // indeterminant static initialization order. scoped_ptr<RandomGenerator>& GetGlobalRng() { @@ -232,7 +236,7 @@ } bool CreateRandomString(size_t len, std::string* str) { - return CreateRandomString(len, BASE64, 64, str); + return CreateRandomString(len, kBase64, 64, str); } bool CreateRandomString(size_t len, const std::string& table, @@ -241,6 +245,41 @@ static_cast<int>(table.size()), str); } +// Version 4 UUID is of the form: +// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx +// Where 'x' is a hex digit, and 'y' is 8, 9, a or b. +std::string CreateRandomUuid() { + std::string str; + scoped_ptr<uint8_t[]> bytes(new uint8_t[31]); + if (!Rng().Generate(bytes.get(), 31)) { + LOG(LS_ERROR) << "Failed to generate random string!"; + return str; + } + str.reserve(36); + for (size_t i = 0; i < 8; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + for (size_t i = 8; i < 12; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + str.push_back('4'); + for (size_t i = 12; i < 15; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + str.push_back(kUuidDigit17[bytes[15] % 4]); + for (size_t i = 16; i < 19; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + for (size_t i = 19; i < 31; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + return str; +} + uint32_t CreateRandomId() { uint32_t id; if (!Rng().Generate(&id, sizeof(id))) {
diff --git a/webrtc/base/helpers.h b/webrtc/base/helpers.h index 102c08b..0e79373 100644 --- a/webrtc/base/helpers.h +++ b/webrtc/base/helpers.h
@@ -39,6 +39,9 @@ bool CreateRandomString(size_t length, const std::string& table, std::string* str); +// Generates a (cryptographically) random UUID version 4 string. +std::string CreateRandomUuid(); + // Generates a random id. uint32_t CreateRandomId();
diff --git a/webrtc/base/helpers_unittest.cc b/webrtc/base/helpers_unittest.cc index 6ea0167..83cc685 100644 --- a/webrtc/base/helpers_unittest.cc +++ b/webrtc/base/helpers_unittest.cc
@@ -43,16 +43,23 @@ EXPECT_EQ(256U, random2.size()); } +TEST_F(RandomTest, TestCreateRandomUuid) { + std::string random = CreateRandomUuid(); + EXPECT_EQ(36U, random.size()); +} + TEST_F(RandomTest, TestCreateRandomForTest) { // Make sure we get the output we expect. SetRandomTestMode(true); EXPECT_EQ(2154761789U, CreateRandomId()); EXPECT_EQ("h0ISP4S5SJKH/9EY", CreateRandomString(16)); + EXPECT_EQ("41706e92-cdd3-46d9-a22d-8ff1737ffb11", CreateRandomUuid()); // Reset and make sure we get the same output. SetRandomTestMode(true); EXPECT_EQ(2154761789U, CreateRandomId()); EXPECT_EQ("h0ISP4S5SJKH/9EY", CreateRandomString(16)); + EXPECT_EQ("41706e92-cdd3-46d9-a22d-8ff1737ffb11", CreateRandomUuid()); // Test different character sets. SetRandomTestMode(true);
diff --git a/webrtc/base/httpcommon-inl.h b/webrtc/base/httpcommon-inl.h index d1c0bf0..188d9e6 100644 --- a/webrtc/base/httpcommon-inl.h +++ b/webrtc/base/httpcommon-inl.h
@@ -11,6 +11,7 @@ #ifndef WEBRTC_BASE_HTTPCOMMON_INL_H__ #define WEBRTC_BASE_HTTPCOMMON_INL_H__ +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/httpcommon.h" @@ -80,7 +81,7 @@ template<class CTYPE> void Url<CTYPE>::do_get_url(string* val) const { CTYPE protocol[9]; - asccpyn(protocol, ARRAY_SIZE(protocol), secure_ ? "https://" : "http://"); + asccpyn(protocol, arraysize(protocol), secure_ ? "https://" : "http://"); val->append(protocol); do_get_address(val); do_get_full_path(val); @@ -91,8 +92,8 @@ val->append(host_); if (port_ != HttpDefaultPort(secure_)) { CTYPE format[5], port[32]; - asccpyn(format, ARRAY_SIZE(format), ":%hu"); - sprintfn(port, ARRAY_SIZE(port), format, port_); + asccpyn(format, arraysize(format), ":%hu"); + sprintfn(port, arraysize(port), format, port_); val->append(port); } }
diff --git a/webrtc/base/httpcommon.cc b/webrtc/base/httpcommon.cc index 0c3547e..c90bea5 100644 --- a/webrtc/base/httpcommon.cc +++ b/webrtc/base/httpcommon.cc
@@ -21,6 +21,7 @@ #include <algorithm> +#include "webrtc/base/arraysize.h" #include "webrtc/base/base64.h" #include "webrtc/base/common.h" #include "webrtc/base/cryptstring.h" @@ -377,7 +378,7 @@ gmt = non_gmt + ((zone[0] == '+') ? offset : -offset); } else { size_t zindex; - if (!find_string(zindex, zone, kTimeZones, ARRAY_SIZE(kTimeZones))) { + if (!find_string(zindex, zone, kTimeZones, arraysize(kTimeZones))) { return false; } gmt = non_gmt + kTimeZoneOffsets[zindex] * 60 * 60;
diff --git a/webrtc/base/ifaddrs_converter.cc b/webrtc/base/ifaddrs_converter.cc new file mode 100644 index 0000000..7dd3555 --- /dev/null +++ b/webrtc/base/ifaddrs_converter.cc
@@ -0,0 +1,60 @@ +/* + * 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 "webrtc/base/ifaddrs_converter.h" + +namespace rtc { + +IfAddrsConverter::IfAddrsConverter() {} + +IfAddrsConverter::~IfAddrsConverter() {} + +bool IfAddrsConverter::ConvertIfAddrsToIPAddress( + const struct ifaddrs* interface, + InterfaceAddress* ip, + IPAddress* mask) { + switch (interface->ifa_addr->sa_family) { + case AF_INET: { + *ip = IPAddress( + reinterpret_cast<sockaddr_in*>(interface->ifa_addr)->sin_addr); + *mask = IPAddress( + reinterpret_cast<sockaddr_in*>(interface->ifa_netmask)->sin_addr); + return true; + } + case AF_INET6: { + int ip_attributes = IPV6_ADDRESS_FLAG_NONE; + if (!ConvertNativeAttributesToIPAttributes(interface, &ip_attributes)) { + return false; + } + *ip = InterfaceAddress( + reinterpret_cast<sockaddr_in6*>(interface->ifa_addr)->sin6_addr, + ip_attributes); + *mask = IPAddress( + reinterpret_cast<sockaddr_in6*>(interface->ifa_netmask)->sin6_addr); + return true; + } + default: { return false; } + } +} + +bool IfAddrsConverter::ConvertNativeAttributesToIPAttributes( + const struct ifaddrs* interface, + int* ip_attributes) { + *ip_attributes = IPV6_ADDRESS_FLAG_NONE; + return true; +} + +#if !defined(WEBRTC_MAC) +// For MAC and IOS, it's defined in macifaddrs_converter.cc +IfAddrsConverter* CreateIfAddrsConverter() { + return new IfAddrsConverter(); +} +#endif +} // namespace rtc
diff --git a/webrtc/base/ifaddrs_converter.h b/webrtc/base/ifaddrs_converter.h new file mode 100644 index 0000000..0a1cdb9 --- /dev/null +++ b/webrtc/base/ifaddrs_converter.h
@@ -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. + */ + +#ifndef WEBRTC_BASE_IFADDRS_CONVERTER_H_ +#define WEBRTC_BASE_IFADDRS_CONVERTER_H_ + +#if defined(WEBRTC_ANDROID) +#include "webrtc/base/ifaddrs-android.h" +#else +#include <ifaddrs.h> +#endif // WEBRTC_ANDROID + +#include "webrtc/base/ipaddress.h" + +namespace rtc { + +// This class converts native interface addresses to our internal IPAddress +// class. Subclasses should override ConvertNativeToIPAttributes to implement +// the different ways of retrieving IPv6 attributes for various POSIX platforms. +class IfAddrsConverter { + public: + IfAddrsConverter(); + virtual ~IfAddrsConverter(); + virtual bool ConvertIfAddrsToIPAddress(const struct ifaddrs* interface, + InterfaceAddress* ipaddress, + IPAddress* mask); + + protected: + virtual bool ConvertNativeAttributesToIPAttributes( + const struct ifaddrs* interface, + int* ip_attributes); +}; + +IfAddrsConverter* CreateIfAddrsConverter(); + +} // namespace rtc + +#endif // WEBRTC_BASE_IFADDRS_CONVERTER_H_
diff --git a/webrtc/base/ipaddress.cc b/webrtc/base/ipaddress.cc index 316207f..c92f33c 100644 --- a/webrtc/base/ipaddress.cc +++ b/webrtc/base/ipaddress.cc
@@ -27,8 +27,10 @@ #include "webrtc/base/ipaddress.h" #include "webrtc/base/byteorder.h" -#include "webrtc/base/nethelpers.h" +#include "webrtc/base/checks.h" #include "webrtc/base/logging.h" +#include "webrtc/base/nethelpers.h" +#include "webrtc/base/stringutils.h" #include "webrtc/base/win32.h" namespace rtc { @@ -41,8 +43,6 @@ static const in6_addr kV4CompatibilityPrefix = {{{0}}}; static const in6_addr k6BonePrefix = {{{0x3f, 0xfe, 0}}}; -bool IPAddress::strip_sensitive_ = false; - static bool IsPrivateV4(uint32_t ip); static in_addr ExtractMappedAddress(const in6_addr& addr); @@ -144,9 +144,10 @@ } std::string IPAddress::ToSensitiveString() const { - if (!strip_sensitive_) - return ToString(); - +#if !defined(NDEBUG) + // Return non-stripped in debug. + return ToString(); +#else switch (family_) { case AF_INET: { std::string address = ToString(); @@ -158,12 +159,20 @@ return address; } case AF_INET6: { - // TODO(grunell): Return a string of format 1:2:3:x:x:x:x:x or such - // instead of zeroing out. - return TruncateIP(*this, 128 - 80).ToString(); + std::string result; + result.resize(INET6_ADDRSTRLEN); + in6_addr addr = ipv6_address(); + size_t len = + rtc::sprintfn(&(result[0]), result.size(), "%x:%x:%x:x:x:x:x:x", + (addr.s6_addr[0] << 8) + addr.s6_addr[1], + (addr.s6_addr[2] << 8) + addr.s6_addr[3], + (addr.s6_addr[4] << 8) + addr.s6_addr[5]); + result.resize(len); + return result; } } return std::string(); +#endif } IPAddress IPAddress::Normalized() const { @@ -186,10 +195,6 @@ return IPAddress(v6addr); } -void IPAddress::set_strip_sensitive(bool enable) { - strip_sensitive_ = enable; -} - bool InterfaceAddress::operator==(const InterfaceAddress &other) const { return ipv6_flags_ == other.ipv6_flags() && static_cast<const IPAddress&>(*this) == other; @@ -506,4 +511,15 @@ } return rtc::IPAddress(); } + +IPAddress GetAnyIP(int family) { + if (family == AF_INET) { + return rtc::IPAddress(INADDR_ANY); + } + if (family == AF_INET6) { + return rtc::IPAddress(in6addr_any); + } + return rtc::IPAddress(); +} + } // Namespace rtc
diff --git a/webrtc/base/ipaddress.h b/webrtc/base/ipaddress.h index fe2d6e2..ef1e3d8 100644 --- a/webrtc/base/ipaddress.h +++ b/webrtc/base/ipaddress.h
@@ -112,16 +112,12 @@ // Whether this is an unspecified IP address. bool IsNil() const; - static void set_strip_sensitive(bool enable); - private: int family_; union { in_addr ip4; in6_addr ip6; } u_; - - static bool strip_sensitive_; }; // IP class which could represent IPv6 address flags which is only @@ -180,6 +176,7 @@ IPAddress TruncateIP(const IPAddress& ip, int length); IPAddress GetLoopbackIP(int family); +IPAddress GetAnyIP(int family); // Returns the number of contiguously set bits, counting from the MSB in network // byte order, in this IPAddress. Bits after the first 0 encountered are not
diff --git a/webrtc/base/ipaddress_unittest.cc b/webrtc/base/ipaddress_unittest.cc index d5cb6f7..62773c1 100644 --- a/webrtc/base/ipaddress_unittest.cc +++ b/webrtc/base/ipaddress_unittest.cc
@@ -25,6 +25,10 @@ 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff, 0xfe, 0xe5, 0x00, 0xc3}}}; +static const in6_addr kIPv6PublicAddr2 = {{{0x24, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, + 0xbe, 0x30, 0x5b, 0xff, + 0xfe, 0xe5, 0x00, 0xc3}}}; static const in6_addr kIPv4MappedAnyAddr = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, @@ -52,7 +56,12 @@ "2620:0:1008:1201:2089:6dda:385e:80c0"; static const std::string kIPv6PublicAddrString = "2401:fa00:4:1000:be30:5bff:fee5:c3"; -static const std::string kIPv6PublicAddrAnonymizedString = "2401:fa00:4::"; +static const std::string kIPv6PublicAddr2String = + "2401::1000:be30:5bff:fee5:c3"; +static const std::string kIPv6PublicAddrAnonymizedString = + "2401:fa00:4:x:x:x:x:x"; +static const std::string kIPv6PublicAddr2AnonymizedString = + "2401:0:0:x:x:x:x:x"; static const std::string kIPv4MappedAnyAddrString = "::ffff:0:0"; static const std::string kIPv4MappedRFC1918AddrString = "::ffff:c0a8:701"; static const std::string kIPv4MappedLoopbackAddrString = "::ffff:7f00:1"; @@ -888,20 +897,20 @@ TEST(IPAddressTest, TestToSensitiveString) { IPAddress addr_v4 = IPAddress(kIPv4PublicAddr); - EXPECT_EQ(kIPv4PublicAddrString, addr_v4.ToString()); - EXPECT_EQ(kIPv4PublicAddrString, addr_v4.ToSensitiveString()); - IPAddress::set_strip_sensitive(true); - EXPECT_EQ(kIPv4PublicAddrString, addr_v4.ToString()); - EXPECT_EQ(kIPv4PublicAddrAnonymizedString, addr_v4.ToSensitiveString()); - IPAddress::set_strip_sensitive(false); - IPAddress addr_v6 = IPAddress(kIPv6PublicAddr); + IPAddress addr_v6_2 = IPAddress(kIPv6PublicAddr2); + EXPECT_EQ(kIPv4PublicAddrString, addr_v4.ToString()); EXPECT_EQ(kIPv6PublicAddrString, addr_v6.ToString()); - EXPECT_EQ(kIPv6PublicAddrString, addr_v6.ToSensitiveString()); - IPAddress::set_strip_sensitive(true); - EXPECT_EQ(kIPv6PublicAddrString, addr_v6.ToString()); + EXPECT_EQ(kIPv6PublicAddr2String, addr_v6_2.ToString()); +#if defined(NDEBUG) + EXPECT_EQ(kIPv4PublicAddrAnonymizedString, addr_v4.ToSensitiveString()); EXPECT_EQ(kIPv6PublicAddrAnonymizedString, addr_v6.ToSensitiveString()); - IPAddress::set_strip_sensitive(false); + EXPECT_EQ(kIPv6PublicAddr2AnonymizedString, addr_v6_2.ToSensitiveString()); +#else + EXPECT_EQ(kIPv4PublicAddrString, addr_v4.ToSensitiveString()); + EXPECT_EQ(kIPv6PublicAddrString, addr_v6.ToSensitiveString()); + EXPECT_EQ(kIPv6PublicAddr2String, addr_v6_2.ToSensitiveString()); +#endif // defined(NDEBUG) } TEST(IPAddressTest, TestInterfaceAddress) {
diff --git a/webrtc/base/keep_ref_until_done.h b/webrtc/base/keep_ref_until_done.h new file mode 100644 index 0000000..269e1c8 --- /dev/null +++ b/webrtc/base/keep_ref_until_done.h
@@ -0,0 +1,43 @@ +/* + * 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_KEEP_REF_UNTIL_DONE_H_ +#define WEBRTC_BASE_KEEP_REF_UNTIL_DONE_H_ + +#include "webrtc/base/bind.h" +#include "webrtc/base/callback.h" +#include "webrtc/base/refcount.h" +#include "webrtc/base/scoped_ref_ptr.h" + +namespace rtc { + +namespace impl { +template <class T> +static inline void DoNothing(const scoped_refptr<T>& object) {} +} // namespace impl + +// KeepRefUntilDone keeps a reference to |object| until the returned +// callback goes out of scope. If the returned callback is copied, the +// reference will be released when the last callback goes out of scope. +template <class ObjectT> +static inline Callback0<void> KeepRefUntilDone(ObjectT* object) { + return rtc::Bind(&impl::DoNothing<ObjectT>, scoped_refptr<ObjectT>(object)); +} + +template <class ObjectT> +static inline Callback0<void> KeepRefUntilDone( + const scoped_refptr<ObjectT>& object) { + return rtc::Bind(&impl::DoNothing<ObjectT>, object); +} + +} // namespace rtc + + +#endif // WEBRTC_BASE_KEEP_REF_UNTIL_DONE_H_
diff --git a/webrtc/base/latebindingsymboltable_unittest.cc b/webrtc/base/latebindingsymboltable_unittest.cc index 30ebd17..0079f20 100644 --- a/webrtc/base/latebindingsymboltable_unittest.cc +++ b/webrtc/base/latebindingsymboltable_unittest.cc
@@ -21,9 +21,10 @@ #define LIBM_SYMBOLS_CLASS_NAME LibmTestSymbolTable #define LIBM_SYMBOLS_LIST \ - X(acos) \ - X(sin) \ - X(tan) + X(acosf) \ + X(sinf) \ + X(tanf) + #define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME LIBM_SYMBOLS_CLASS_NAME #define LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST LIBM_SYMBOLS_LIST @@ -39,9 +40,9 @@ EXPECT_FALSE(table.IsLoaded()); ASSERT_TRUE(table.Load()); EXPECT_TRUE(table.IsLoaded()); - EXPECT_EQ(table.acos()(0.5), acos(0.5)); - EXPECT_EQ(table.sin()(0.5), sin(0.5)); - EXPECT_EQ(table.tan()(0.5), tan(0.5)); + EXPECT_EQ(table.acosf()(0.5f), acosf(0.5f)); + EXPECT_EQ(table.sinf()(0.5f), sinf(0.5f)); + EXPECT_EQ(table.tanf()(0.5f), tanf(0.5f)); // It would be nice to check that the addresses are the same, but the nature // of dynamic linking and relocation makes them actually be different. table.Unload();
diff --git a/webrtc/base/linux.cc b/webrtc/base/linux.cc index 1586b27..0894d39 100644 --- a/webrtc/base/linux.cc +++ b/webrtc/base/linux.cc
@@ -233,33 +233,6 @@ return true; } -#if !defined(WEBRTC_CHROMIUM_BUILD) -static bool ExpectLineFromStream(FileStream* stream, - std::string* out) { - StreamResult res = stream->ReadLine(out); - if (res != SR_SUCCESS) { - if (res != SR_EOS) { - LOG(LS_ERROR) << "Error when reading from stream"; - } else { - LOG(LS_ERROR) << "Incorrect number of lines in stream"; - } - return false; - } - return true; -} - -static void ExpectEofFromStream(FileStream* stream) { - std::string unused; - StreamResult res = stream->ReadLine(&unused); - if (res == SR_SUCCESS) { - LOG(LS_WARNING) << "Ignoring unexpected extra lines from stream"; - } else if (res != SR_EOS) { - LOG(LS_WARNING) << "Error when checking for extra lines from stream"; - } -} - -#endif - std::string ReadLinuxUname() { struct utsname buf; if (uname(&buf) < 0) {
diff --git a/webrtc/base/logging.cc b/webrtc/base/logging.cc index b02be27..686b9b2 100644 --- a/webrtc/base/logging.cc +++ b/webrtc/base/logging.cc
@@ -92,13 +92,13 @@ ///////////////////////////////////////////////////////////////////////////// // By default, release builds don't log, debug builds at info level -#if _DEBUG +#if !defined(NDEBUG) LoggingSeverity LogMessage::min_sev_ = LS_INFO; LoggingSeverity LogMessage::dbg_sev_ = LS_INFO; -#else // !_DEBUG +#else LoggingSeverity LogMessage::min_sev_ = LS_NONE; LoggingSeverity LogMessage::dbg_sev_ = LS_NONE; -#endif // !_DEBUG +#endif bool LogMessage::log_to_stderr_ = true; namespace { @@ -340,7 +340,7 @@ LoggingSeverity severity, const std::string& tag) { bool log_to_stderr = log_to_stderr_; -#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && (!defined(_DEBUG) || defined(NDEBUG)) +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG) // On the Mac, all stderr output goes to the Console log and causes clutter. // So in opt builds, don't log to stderr unless the user specifically sets // a preference to do so.
diff --git a/webrtc/base/logging.h b/webrtc/base/logging.h index 1208275..e40ca44 100644 --- a/webrtc/base/logging.h +++ b/webrtc/base/logging.h
@@ -285,7 +285,7 @@ rtc::LogMessage(__FILE__, __LINE__, sev).stream() // The _F version prefixes the message with the current function name. -#if (defined(__GNUC__) && defined(_DEBUG)) || defined(WANT_PRETTY_LOG_F) +#if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F) #define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": " #define LOG_T_F(sev) LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": " #else
diff --git a/webrtc/base/logging_unittest.cc b/webrtc/base/logging_unittest.cc index 3719cde..6047361 100644 --- a/webrtc/base/logging_unittest.cc +++ b/webrtc/base/logging_unittest.cc
@@ -14,7 +14,6 @@ #include "webrtc/base/pathutils.h" #include "webrtc/base/stream.h" #include "webrtc/base/thread.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace rtc {
diff --git a/webrtc/base/macasyncsocket.cc b/webrtc/base/macasyncsocket.cc index 1f12500..8f811ea 100644 --- a/webrtc/base/macasyncsocket.cc +++ b/webrtc/base/macasyncsocket.cc
@@ -112,7 +112,7 @@ SetError(EALREADY); return SOCKET_ERROR; } - if (addr.IsUnresolved()) { + if (addr.IsUnresolvedIP()) { LOG(LS_VERBOSE) << "Resolving addr in MacAsyncSocket::Connect"; resolver_ = new AsyncResolver(); resolver_->SignalWorkDone.connect(this,
diff --git a/webrtc/base/macifaddrs_converter.cc b/webrtc/base/macifaddrs_converter.cc new file mode 100644 index 0000000..0916cb5 --- /dev/null +++ b/webrtc/base/macifaddrs_converter.cc
@@ -0,0 +1,281 @@ +/* + * 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 <net/if.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include "webrtc/base/checks.h" +#include "webrtc/base/ifaddrs_converter.h" +#include "webrtc/base/logging.h" +#include "webrtc/base/scoped_ptr.h" + +#if !defined(WEBRTC_IOS) +#include <net/if_media.h> +#include <netinet/in_var.h> +#else // WEBRTC_IOS +#define SCOPE6_ID_MAX 16 + +struct in6_addrlifetime { + time_t ia6t_expire; /* valid lifetime expiration time */ + time_t ia6t_preferred; /* preferred lifetime expiration time */ + u_int32_t ia6t_vltime; /* valid lifetime */ + u_int32_t ia6t_pltime; /* prefix lifetime */ +}; + +struct in6_ifstat { + u_quad_t ifs6_in_receive; /* # of total input datagram */ + u_quad_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */ + u_quad_t ifs6_in_toobig; /* # of datagrams exceeded MTU */ + u_quad_t ifs6_in_noroute; /* # of datagrams with no route */ + u_quad_t ifs6_in_addrerr; /* # of datagrams with invalid dst */ + u_quad_t ifs6_in_protounknown; /* # of datagrams with unknown proto */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_truncated; /* # of truncated datagrams */ + u_quad_t ifs6_in_discard; /* # of discarded datagrams */ + /* NOTE: fragment timeout is not here */ + u_quad_t ifs6_in_deliver; /* # of datagrams delivered to ULP */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_out_forward; /* # of datagrams forwarded */ + /* NOTE: increment on outgoing if */ + u_quad_t ifs6_out_request; /* # of outgoing datagrams from ULP */ + /* NOTE: does not include forwrads */ + u_quad_t ifs6_out_discard; /* # of discarded datagrams */ + u_quad_t ifs6_out_fragok; /* # of datagrams fragmented */ + u_quad_t ifs6_out_fragfail; /* # of datagrams failed on fragment */ + u_quad_t ifs6_out_fragcreat; /* # of fragment datagrams */ + /* NOTE: this is # after fragment */ + u_quad_t ifs6_reass_reqd; /* # of incoming fragmented packets */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_reass_ok; /* # of reassembled packets */ + /* NOTE: this is # after reass */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_reass_fail; /* # of reass failures */ + /* NOTE: may not be packet count */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_mcast; /* # of inbound multicast datagrams */ + u_quad_t ifs6_out_mcast; /* # of outbound multicast datagrams */ +}; +struct icmp6_ifstat { + /* + * Input statistics + */ + /* ipv6IfIcmpInMsgs, total # of input messages */ + u_quad_t ifs6_in_msg; + /* ipv6IfIcmpInErrors, # of input error messages */ + u_quad_t ifs6_in_error; + /* ipv6IfIcmpInDestUnreachs, # of input dest unreach errors */ + u_quad_t ifs6_in_dstunreach; + /* ipv6IfIcmpInAdminProhibs, # of input admin. prohibited errs */ + u_quad_t ifs6_in_adminprohib; + /* ipv6IfIcmpInTimeExcds, # of input time exceeded errors */ + u_quad_t ifs6_in_timeexceed; + /* ipv6IfIcmpInParmProblems, # of input parameter problem errors */ + u_quad_t ifs6_in_paramprob; + /* ipv6IfIcmpInPktTooBigs, # of input packet too big errors */ + u_quad_t ifs6_in_pkttoobig; + /* ipv6IfIcmpInEchos, # of input echo requests */ + u_quad_t ifs6_in_echo; + /* ipv6IfIcmpInEchoReplies, # of input echo replies */ + u_quad_t ifs6_in_echoreply; + /* ipv6IfIcmpInRouterSolicits, # of input router solicitations */ + u_quad_t ifs6_in_routersolicit; + /* ipv6IfIcmpInRouterAdvertisements, # of input router advertisements */ + u_quad_t ifs6_in_routeradvert; + /* ipv6IfIcmpInNeighborSolicits, # of input neighbor solicitations */ + u_quad_t ifs6_in_neighborsolicit; + /* ipv6IfIcmpInNeighborAdvertisements, # of input neighbor advs. */ + u_quad_t ifs6_in_neighboradvert; + /* ipv6IfIcmpInRedirects, # of input redirects */ + u_quad_t ifs6_in_redirect; + /* ipv6IfIcmpInGroupMembQueries, # of input MLD queries */ + u_quad_t ifs6_in_mldquery; + /* ipv6IfIcmpInGroupMembResponses, # of input MLD reports */ + u_quad_t ifs6_in_mldreport; + /* ipv6IfIcmpInGroupMembReductions, # of input MLD done */ + u_quad_t ifs6_in_mlddone; + + /* + * Output statistics. We should solve unresolved routing problem... + */ + /* ipv6IfIcmpOutMsgs, total # of output messages */ + u_quad_t ifs6_out_msg; + /* ipv6IfIcmpOutErrors, # of output error messages */ + u_quad_t ifs6_out_error; + /* ipv6IfIcmpOutDestUnreachs, # of output dest unreach errors */ + u_quad_t ifs6_out_dstunreach; + /* ipv6IfIcmpOutAdminProhibs, # of output admin. prohibited errs */ + u_quad_t ifs6_out_adminprohib; + /* ipv6IfIcmpOutTimeExcds, # of output time exceeded errors */ + u_quad_t ifs6_out_timeexceed; + /* ipv6IfIcmpOutParmProblems, # of output parameter problem errors */ + u_quad_t ifs6_out_paramprob; + /* ipv6IfIcmpOutPktTooBigs, # of output packet too big errors */ + u_quad_t ifs6_out_pkttoobig; + /* ipv6IfIcmpOutEchos, # of output echo requests */ + u_quad_t ifs6_out_echo; + /* ipv6IfIcmpOutEchoReplies, # of output echo replies */ + u_quad_t ifs6_out_echoreply; + /* ipv6IfIcmpOutRouterSolicits, # of output router solicitations */ + u_quad_t ifs6_out_routersolicit; + /* ipv6IfIcmpOutRouterAdvertisements, # of output router advs. */ + u_quad_t ifs6_out_routeradvert; + /* ipv6IfIcmpOutNeighborSolicits, # of output neighbor solicitations */ + u_quad_t ifs6_out_neighborsolicit; + /* ipv6IfIcmpOutNeighborAdvertisements, # of output neighbor advs. */ + u_quad_t ifs6_out_neighboradvert; + /* ipv6IfIcmpOutRedirects, # of output redirects */ + u_quad_t ifs6_out_redirect; + /* ipv6IfIcmpOutGroupMembQueries, # of output MLD queries */ + u_quad_t ifs6_out_mldquery; + /* ipv6IfIcmpOutGroupMembResponses, # of output MLD reports */ + u_quad_t ifs6_out_mldreport; + /* ipv6IfIcmpOutGroupMembReductions, # of output MLD done */ + u_quad_t ifs6_out_mlddone; +}; + +struct in6_ifreq { + char ifr_name[IFNAMSIZ]; + union { + struct sockaddr_in6 ifru_addr; + struct sockaddr_in6 ifru_dstaddr; + int ifru_flags; + int ifru_flags6; + int ifru_metric; + int ifru_intval; + caddr_t ifru_data; + struct in6_addrlifetime ifru_lifetime; + struct in6_ifstat ifru_stat; + struct icmp6_ifstat ifru_icmp6stat; + u_int32_t ifru_scope_id[SCOPE6_ID_MAX]; + } ifr_ifru; +}; + +#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq) + +#define IN6_IFF_ANYCAST 0x0001 /* anycast address */ +#define IN6_IFF_TENTATIVE 0x0002 /* tentative address */ +#define IN6_IFF_DUPLICATED 0x0004 /* DAD detected duplicate */ +#define IN6_IFF_DETACHED 0x0008 /* may be detached from the link */ +#define IN6_IFF_DEPRECATED 0x0010 /* deprecated address */ +#define IN6_IFF_TEMPORARY 0x0080 /* temporary (anonymous) address. */ + +#endif // WEBRTC_IOS + +namespace rtc { + +namespace { + +class IPv6AttributesGetter { + public: + IPv6AttributesGetter(); + virtual ~IPv6AttributesGetter(); + bool IsInitialized() const; + bool GetIPAttributes(const char* ifname, + const sockaddr* sock_addr, + int* native_attributes); + + private: + // on MAC or IOS, we have to use ioctl with a socket to query an IPv6 + // interface's attribute. + int ioctl_socket_; +}; + +IPv6AttributesGetter::IPv6AttributesGetter() + : ioctl_socket_( + socket(AF_INET6, SOCK_DGRAM, 0 /* unspecified protocol */)) { + RTC_DCHECK_GE(ioctl_socket_, 0); +} + +bool IPv6AttributesGetter::IsInitialized() const { + return ioctl_socket_ >= 0; +} + +IPv6AttributesGetter::~IPv6AttributesGetter() { + if (!IsInitialized()) { + return; + } + close(ioctl_socket_); +} + +bool IPv6AttributesGetter::GetIPAttributes(const char* ifname, + const sockaddr* sock_addr, + int* native_attributes) { + if (!IsInitialized()) { + return false; + } + + struct in6_ifreq ifr = {}; + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); + memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len); + int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr); + if (rv >= 0) { + *native_attributes = ifr.ifr_ifru.ifru_flags; + } else { + LOG(LS_ERROR) << "ioctl returns " << errno; + } + return (rv >= 0); +} + +// Converts native IPv6 address attributes to net IPv6 address attributes. If +// it returns false, the IP address isn't suitable for one-to-one communications +// applications and should be ignored. +bool ConvertNativeToIPAttributes(int native_attributes, int* net_attributes) { + // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE, + // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are + // still progressing through duplicated address detection (DAD) or are not + // suitable for one-to-one communication applications. + if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED | + IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) { + return false; + } + + if (native_attributes & IN6_IFF_TEMPORARY) { + *net_attributes |= IPV6_ADDRESS_FLAG_TEMPORARY; + } + + if (native_attributes & IN6_IFF_DEPRECATED) { + *net_attributes |= IPV6_ADDRESS_FLAG_DEPRECATED; + } + + return true; +} + +class MacIfAddrsConverter : public IfAddrsConverter { + public: + MacIfAddrsConverter() : ip_attribute_getter_(new IPv6AttributesGetter()) {} + ~MacIfAddrsConverter() override {} + + bool ConvertNativeAttributesToIPAttributes(const struct ifaddrs* interface, + int* ip_attributes) override { + int native_attributes; + if (!ip_attribute_getter_->GetIPAttributes( + interface->ifa_name, interface->ifa_addr, &native_attributes)) { + return false; + } + + if (!ConvertNativeToIPAttributes(native_attributes, ip_attributes)) { + return false; + } + + return true; + } + + private: + rtc::scoped_ptr<IPv6AttributesGetter> ip_attribute_getter_; +}; + +} // namespace + +IfAddrsConverter* CreateIfAddrsConverter() { + return new MacIfAddrsConverter(); +} + +} // namespace rtc
diff --git a/webrtc/base/macutils.cc b/webrtc/base/macutils.cc index 6e436d4..7b1ff47 100644 --- a/webrtc/base/macutils.cc +++ b/webrtc/base/macutils.cc
@@ -191,10 +191,10 @@ AECreateDesc(typeNull, NULL, 0, &result_data); OSAScriptError(component, kOSAErrorMessage, typeChar, &result_data); int len = AEGetDescDataSize(&result_data); - char* data = (char*) malloc(len); + char* data = (char*)malloc(len); if (data != NULL) { err = AEGetDescData(&result_data, data, len); - LOG(LS_ERROR) << "Script error: " << data; + LOG(LS_ERROR) << "Script error: " << std::string(data, len); } AEDisposeDesc(&script_desc); AEDisposeDesc(&result_data);
diff --git a/webrtc/base/maybe.h b/webrtc/base/maybe.h deleted file mode 100644 index df20436..0000000 --- a/webrtc/base/maybe.h +++ /dev/null
@@ -1,121 +0,0 @@ -/* - * 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_MAYBE_H_ -#define WEBRTC_BASE_MAYBE_H_ - -#include <algorithm> -#include <utility> - -#include "webrtc/base/checks.h" - -namespace rtc { - -// Simple std::experimental::optional-wannabe. It either contains a T or not. -// In order to keep the implementation simple and portable, this implementation -// actually contains a (default-constructed) T even when it supposedly doesn't -// contain a value; use e.g. rtc::scoped_ptr<T> instead if that's too -// expensive. -// -// A moved-from Maybe<T> may only be destroyed, and assigned to if T allows -// being assigned to after having been moved from. Specifically, you may not -// assume that it just doesn't contain a value anymore. -// -// TODO(kwiberg): Get rid of this class when the standard library has -// std::optional (and we're allowed to use it). -template <typename T> -class Maybe final { - public: - // Construct an empty Maybe. - Maybe() : has_value_(false) {} - - // Construct a Maybe that contains a value. Note: These are non-explicit, so - // that a T will implicitly convert to Maybe<T>. - Maybe(const T& val) : value_(val), has_value_(true) {} - Maybe(T&& val) : value_(static_cast<T&&>(val)), has_value_(true) {} - - // Copy and move constructors. - // TODO(kwiberg): =default the move constructor when MSVC supports it. - Maybe(const Maybe&) = default; - Maybe(Maybe&& m) - : value_(static_cast<T&&>(m.value_)), has_value_(m.has_value_) {} - - // Assignment. Note that we allow assignment from either Maybe<T> or plain T. - // TODO(kwiberg): =default the move assignment op when MSVC supports it. - Maybe& operator=(const Maybe&) = default; - Maybe& operator=(Maybe&& m) { - value_ = static_cast<T&&>(m.value_); - has_value_ = m.has_value_; - return *this; - } - Maybe& operator=(const T& val) { - value_ = val; - has_value_ = true; - return *this; - } - Maybe& operator=(T&& val) { - value_ = static_cast<T&&>(val); - has_value_ = true; - return *this; - } - - friend void swap(Maybe& m1, Maybe& m2) { - using std::swap; - swap(m1.value_, m2.value_); - swap(m1.has_value_, m2.has_value_); - } - - // Conversion to bool to test if we have a value. - explicit operator bool() const { return has_value_; } - - // Dereferencing. Only allowed if we have a value. - const T* operator->() const { - RTC_DCHECK(has_value_); - return &value_; - } - T* operator->() { - RTC_DCHECK(has_value_); - return &value_; - } - const T& operator*() const { - RTC_DCHECK(has_value_); - return value_; - } - T& operator*() { - RTC_DCHECK(has_value_); - return value_; - } - - // Dereference with a default value in case we don't have a value. - const T& value_or(const T& default_val) const { - return has_value_ ? value_ : default_val; - } - - // Equality tests. Two Maybes are equal if they contain equivalent values, or - // if they're both empty. - friend bool operator==(const Maybe& m1, const Maybe& m2) { - return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ - : m1.has_value_ == m2.has_value_; - } - friend bool operator!=(const Maybe& m1, const Maybe& m2) { - return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ - : m1.has_value_ != m2.has_value_; - } - - private: - // Invariant: Unless *this has been moved from, value_ is default-initialized - // (or copied or moved from a default-initialized T) if !has_value_. - T value_; - bool has_value_; -}; - -} // namespace rtc - -#endif // WEBRTC_BASE_MAYBE_H_
diff --git a/webrtc/base/maybe_unittest.cc b/webrtc/base/maybe_unittest.cc deleted file mode 100644 index 73fdc90..0000000 --- a/webrtc/base/maybe_unittest.cc +++ /dev/null
@@ -1,485 +0,0 @@ -/* - * 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 <sstream> -#include <string> -#include <utility> -#include <vector> - -#include "webrtc/base/gunit.h" -#include "webrtc/base/maybe.h" - -namespace rtc { - -namespace { - -// Class whose instances logs various method calls (constructor, destructor, -// etc.). Each instance has a unique ID (a simple global sequence number) and -// an origin ID. When a copy is made, the new object gets a fresh ID but copies -// the origin ID from the original. When a new Logger is created from scratch, -// it gets a fresh ID, and the origin ID is the same as the ID (default -// constructor) or given as an argument (explicit constructor). -class Logger { - public: - Logger() : id_(next_id_++), origin_(id_) { Log("default constructor"); } - explicit Logger(int origin) : id_(next_id_++), origin_(origin) { - Log("explicit constructor"); - } - Logger(const Logger& other) : id_(next_id_++), origin_(other.origin_) { - LogFrom("copy constructor", other); - } - Logger(Logger&& other) : id_(next_id_++), origin_(other.origin_) { - LogFrom("move constructor", other); - } - ~Logger() { Log("destructor"); } - Logger& operator=(const Logger& other) { - origin_ = other.origin_; - LogFrom("operator= copy", other); - return *this; - } - Logger& operator=(Logger&& other) { - origin_ = other.origin_; - LogFrom("operator= move", other); - return *this; - } - friend void swap(Logger& a, Logger& b) { - using std::swap; - swap(a.origin_, b.origin_); - Log2("swap", a, b); - } - friend bool operator==(const Logger& a, const Logger& b) { - Log2("operator==", a, b); - return a.origin_ == b.origin_; - } - friend bool operator!=(const Logger& a, const Logger& b) { - Log2("operator!=", a, b); - return a.origin_ != b.origin_; - } - void Foo() { Log("Foo()"); } - void Foo() const { Log("Foo() const"); } - static rtc::scoped_ptr<std::vector<std::string>> Setup() { - auto s = rtc_make_scoped_ptr(new std::vector<std::string>); - Logger::log_ = s.get(); - Logger::next_id_ = 0; - return s; - } - - private: - int id_; - int origin_; - static std::vector<std::string>* log_; - static int next_id_; - void Log(const char* msg) const { - std::ostringstream oss; - oss << id_ << ':' << origin_ << ". " << msg; - log_->push_back(oss.str()); - } - void LogFrom(const char* msg, const Logger& other) const { - std::ostringstream oss; - oss << id_ << ':' << origin_ << ". " << msg << " (from " << other.id_ << ':' - << other.origin_ << ")"; - log_->push_back(oss.str()); - } - static void Log2(const char* msg, const Logger& a, const Logger& b) { - std::ostringstream oss; - oss << msg << ' ' << a.id_ << ':' << a.origin_ << ", " << b.id_ << ':' - << b.origin_; - log_->push_back(oss.str()); - } -}; - -std::vector<std::string>* Logger::log_ = nullptr; -int Logger::next_id_ = 0; - -// Append all the other args to the vector pointed to by the first arg. -template <typename T> -void VectorAppend(std::vector<T>* v) {} -template <typename T, typename... Ts> -void VectorAppend(std::vector<T>* v, const T& e, Ts... es) { - v->push_back(e); - VectorAppend(v, es...); -} - -// Create a vector of strings. Because we're not allowed to use -// std::initializer_list. -template <typename... Ts> -std::vector<std::string> V(Ts... es) { - std::vector<std::string> strings; - VectorAppend(&strings, static_cast<std::string>(es)...); - return strings; -} - -} // namespace - -TEST(MaybeTest, TestConstructDefault) { - auto log = Logger::Setup(); - { - Maybe<Logger> x; - EXPECT_FALSE(x); - } - EXPECT_EQ(V("0:0. default constructor", "0:0. destructor"), *log); -} - -TEST(MaybeTest, TestConstructCopyEmpty) { - auto log = Logger::Setup(); - { - Maybe<Logger> x; - EXPECT_FALSE(x); - auto y = x; - EXPECT_FALSE(y); - } - EXPECT_EQ(V("0:0. default constructor", "1:0. copy constructor (from 0:0)", - "1:0. destructor", "0:0. destructor"), - *log); -} - -TEST(MaybeTest, TestConstructCopyFull) { - auto log = Logger::Setup(); - { - Logger a; - Maybe<Logger> x = a; - EXPECT_TRUE(x); - log->push_back("---"); - auto y = x; - EXPECT_TRUE(y); - log->push_back("---"); - } - EXPECT_EQ(V("0:0. default constructor", "1:0. copy constructor (from 0:0)", - "---", "2:0. copy constructor (from 1:0)", "---", - "2:0. destructor", "1:0. destructor", "0:0. destructor"), - *log); -} - -TEST(MaybeTest, TestConstructMoveEmpty) { - auto log = Logger::Setup(); - { - Maybe<Logger> x; - EXPECT_FALSE(x); - auto y = static_cast<Maybe<Logger>&&>(x); - EXPECT_FALSE(y); - } - EXPECT_EQ(V("0:0. default constructor", "1:0. move constructor (from 0:0)", - "1:0. destructor", "0:0. destructor"), - *log); -} - -TEST(MaybeTest, TestConstructMoveFull) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(17); - EXPECT_TRUE(x); - log->push_back("---"); - auto y = static_cast<Maybe<Logger>&&>(x); - EXPECT_TRUE(x); - EXPECT_TRUE(y); - log->push_back("---"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", - "0:17. destructor", "---", "2:17. move constructor (from 1:17)", "---", - "2:17. destructor", "1:17. destructor"), - *log); -} - -TEST(MaybeTest, TestCopyAssignToEmptyFromEmpty) { - auto log = Logger::Setup(); - { - Maybe<Logger> x, y; - x = y; - } - EXPECT_EQ( - V("0:0. default constructor", "1:1. default constructor", - "0:1. operator= copy (from 1:1)", "1:1. destructor", "0:1. destructor"), - *log); -} - -TEST(MaybeTest, TestCopyAssignToFullFromEmpty) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(17); - Maybe<Logger> y; - log->push_back("---"); - x = y; - log->push_back("---"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", - "0:17. destructor", "2:2. default constructor", "---", - "1:2. operator= copy (from 2:2)", "---", "2:2. destructor", - "1:2. destructor"), - *log); -} - -TEST(MaybeTest, TestCopyAssignToEmptyFromFull) { - auto log = Logger::Setup(); - { - Maybe<Logger> x; - Maybe<Logger> y = Logger(17); - log->push_back("---"); - x = y; - log->push_back("---"); - } - EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", - "2:17. move constructor (from 1:17)", "1:17. destructor", "---", - "0:17. operator= copy (from 2:17)", "---", "2:17. destructor", - "0:17. destructor"), - *log); -} - -TEST(MaybeTest, TestCopyAssignToFullFromFull) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(17); - Maybe<Logger> y = Logger(42); - log->push_back("---"); - x = y; - log->push_back("---"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", - "0:17. destructor", "2:42. explicit constructor", - "3:42. move constructor (from 2:42)", "2:42. destructor", "---", - "1:42. operator= copy (from 3:42)", "---", "3:42. destructor", - "1:42. destructor"), - *log); -} - -TEST(MaybeTest, TestCopyAssignToEmptyFromT) { - auto log = Logger::Setup(); - { - Maybe<Logger> x; - Logger y(17); - log->push_back("---"); - x = y; - log->push_back("---"); - } - EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", "---", - "0:17. operator= copy (from 1:17)", "---", "1:17. destructor", - "0:17. destructor"), - *log); -} - -TEST(MaybeTest, TestCopyAssignToFullFromT) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(17); - Logger y(42); - log->push_back("---"); - x = y; - log->push_back("---"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", - "0:17. destructor", "2:42. explicit constructor", "---", - "1:42. operator= copy (from 2:42)", "---", "2:42. destructor", - "1:42. destructor"), - *log); -} - -TEST(MaybeTest, TestMoveAssignToEmptyFromEmpty) { - auto log = Logger::Setup(); - { - Maybe<Logger> x, y; - x = static_cast<Maybe<Logger>&&>(y); - } - EXPECT_EQ( - V("0:0. default constructor", "1:1. default constructor", - "0:1. operator= move (from 1:1)", "1:1. destructor", "0:1. destructor"), - *log); -} - -TEST(MaybeTest, TestMoveAssignToFullFromEmpty) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(17); - Maybe<Logger> y; - log->push_back("---"); - x = static_cast<Maybe<Logger>&&>(y); - log->push_back("---"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", - "0:17. destructor", "2:2. default constructor", "---", - "1:2. operator= move (from 2:2)", "---", "2:2. destructor", - "1:2. destructor"), - *log); -} - -TEST(MaybeTest, TestMoveAssignToEmptyFromFull) { - auto log = Logger::Setup(); - { - Maybe<Logger> x; - Maybe<Logger> y = Logger(17); - log->push_back("---"); - x = static_cast<Maybe<Logger>&&>(y); - log->push_back("---"); - } - EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", - "2:17. move constructor (from 1:17)", "1:17. destructor", "---", - "0:17. operator= move (from 2:17)", "---", "2:17. destructor", - "0:17. destructor"), - *log); -} - -TEST(MaybeTest, TestMoveAssignToFullFromFull) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(17); - Maybe<Logger> y = Logger(42); - log->push_back("---"); - x = static_cast<Maybe<Logger>&&>(y); - log->push_back("---"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", - "0:17. destructor", "2:42. explicit constructor", - "3:42. move constructor (from 2:42)", "2:42. destructor", "---", - "1:42. operator= move (from 3:42)", "---", "3:42. destructor", - "1:42. destructor"), - *log); -} - -TEST(MaybeTest, TestMoveAssignToEmptyFromT) { - auto log = Logger::Setup(); - { - Maybe<Logger> x; - Logger y(17); - log->push_back("---"); - x = static_cast<Logger&&>(y); - log->push_back("---"); - } - EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", "---", - "0:17. operator= move (from 1:17)", "---", "1:17. destructor", - "0:17. destructor"), - *log); -} - -TEST(MaybeTest, TestMoveAssignToFullFromT) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(17); - Logger y(42); - log->push_back("---"); - x = static_cast<Logger&&>(y); - log->push_back("---"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", - "0:17. destructor", "2:42. explicit constructor", "---", - "1:42. operator= move (from 2:42)", "---", "2:42. destructor", - "1:42. destructor"), - *log); -} - -TEST(MaybeTest, TestDereference) { - auto log = Logger::Setup(); - { - Maybe<Logger> x = Logger(42); - const auto& y = x; - log->push_back("---"); - x->Foo(); - y->Foo(); - static_cast<Maybe<Logger>&&>(x)->Foo(); - static_cast<const Maybe<Logger>&&>(y)->Foo(); - log->push_back("---"); - (*x).Foo(); - (*y).Foo(); - (*static_cast<Maybe<Logger>&&>(x)).Foo(); - (*static_cast<const Maybe<Logger>&&>(y)).Foo(); - log->push_back("---"); - } - EXPECT_EQ(V("0:42. explicit constructor", - "1:42. move constructor (from 0:42)", "0:42. destructor", "---", - "1:42. Foo()", "1:42. Foo() const", "1:42. Foo()", - "1:42. Foo() const", "---", "1:42. Foo()", "1:42. Foo() const", - "1:42. Foo()", "1:42. Foo() const", "---", "1:42. destructor"), - *log); -} - -TEST(MaybeTest, TestDereferenceWithDefault) { - auto log = Logger::Setup(); - { - const Logger a(17), b(42); - Maybe<Logger> x(a); - Maybe<Logger> y; - log->push_back("-1-"); - EXPECT_EQ(a, x.value_or(Logger(42))); - log->push_back("-2-"); - EXPECT_EQ(b, y.value_or(Logger(42))); - log->push_back("-3-"); - EXPECT_EQ(a, Maybe<Logger>(Logger(17)).value_or(b)); - log->push_back("-4-"); - EXPECT_EQ(b, Maybe<Logger>().value_or(b)); - log->push_back("-5-"); - } - EXPECT_EQ( - V("0:17. explicit constructor", "1:42. explicit constructor", - "2:17. copy constructor (from 0:17)", "3:3. default constructor", "-1-", - "4:42. explicit constructor", "operator== 0:17, 2:17", - "4:42. destructor", "-2-", "5:42. explicit constructor", - "operator== 1:42, 5:42", "5:42. destructor", "-3-", - "6:17. explicit constructor", "7:17. move constructor (from 6:17)", - "operator== 0:17, 7:17", "7:17. destructor", "6:17. destructor", "-4-", - "8:8. default constructor", "operator== 1:42, 1:42", "8:8. destructor", - "-5-", "3:3. destructor", "2:17. destructor", "1:42. destructor", - "0:17. destructor"), - *log); -} - -TEST(MaybeTest, TestEquality) { - auto log = Logger::Setup(); - { - Logger a(17), b(42); - Maybe<Logger> ma1(a), ma2(a), mb(b), me1, me2; - log->push_back("---"); - EXPECT_EQ(ma1, ma1); - EXPECT_EQ(ma1, ma2); - EXPECT_NE(ma1, mb); - EXPECT_NE(ma1, me1); - EXPECT_EQ(me1, me1); - EXPECT_EQ(me1, me2); - log->push_back("---"); - } - EXPECT_EQ(V("0:17. explicit constructor", "1:42. explicit constructor", - "2:17. copy constructor (from 0:17)", - "3:17. copy constructor (from 0:17)", - "4:42. copy constructor (from 1:42)", "5:5. default constructor", - "6:6. default constructor", "---", "operator== 2:17, 2:17", - "operator== 2:17, 3:17", "operator!= 2:17, 4:42", "---", - "6:6. destructor", "5:5. destructor", "4:42. destructor", - "3:17. destructor", "2:17. destructor", "1:42. destructor", - "0:17. destructor"), - *log); -} - -TEST(MaybeTest, TestSwap) { - auto log = Logger::Setup(); - { - Logger a(17), b(42); - Maybe<Logger> x1(a), x2(b), y1(a), y2, z1, z2; - log->push_back("---"); - swap(x1, x2); // Swap full <-> full. - swap(y1, y2); // Swap full <-> empty. - swap(z1, z2); // Swap empty <-> empty. - log->push_back("---"); - } - EXPECT_EQ(V("0:17. explicit constructor", "1:42. explicit constructor", - "2:17. copy constructor (from 0:17)", - "3:42. copy constructor (from 1:42)", - "4:17. copy constructor (from 0:17)", "5:5. default constructor", - "6:6. default constructor", "7:7. default constructor", "---", - "swap 2:42, 3:17", "swap 4:5, 5:17", "swap 6:7, 7:6", "---", - "7:6. destructor", "6:7. destructor", "5:17. destructor", - "4:5. destructor", "3:17. destructor", "2:42. destructor", - "1:42. destructor", "0:17. destructor"), - *log); -} - -} // namespace rtc
diff --git a/webrtc/base/messagehandler.h b/webrtc/base/messagehandler.h index df82b4e..b55b229 100644 --- a/webrtc/base/messagehandler.h +++ b/webrtc/base/messagehandler.h
@@ -11,6 +11,8 @@ #ifndef WEBRTC_BASE_MESSAGEHANDLER_H_ #define WEBRTC_BASE_MESSAGEHANDLER_H_ +#include <utility> + #include "webrtc/base/constructormagic.h" #include "webrtc/base/scoped_ptr.h" @@ -54,8 +56,8 @@ : public MessageHandler { public: explicit FunctorMessageHandler(const FunctorT& functor) : functor_(functor) {} - virtual void OnMessage(Message* msg) { result_ = functor_().Pass(); } - rtc::scoped_ptr<ReturnT> result() { return result_.Pass(); } + virtual void OnMessage(Message* msg) { result_ = std::move(functor_()); } + rtc::scoped_ptr<ReturnT> result() { return std::move(result_); } private: FunctorT functor_;
diff --git a/webrtc/base/messagequeue_unittest.cc b/webrtc/base/messagequeue_unittest.cc index 871542d..78024e0 100644 --- a/webrtc/base/messagequeue_unittest.cc +++ b/webrtc/base/messagequeue_unittest.cc
@@ -16,7 +16,6 @@ #include "webrtc/base/thread.h" #include "webrtc/base/timeutils.h" #include "webrtc/base/nullsocketserver.h" -#include "webrtc/test/testsupport/gtest_disable.h" using namespace rtc;
diff --git a/webrtc/base/nat_unittest.cc b/webrtc/base/nat_unittest.cc index e967b29..8be1be9 100644 --- a/webrtc/base/nat_unittest.cc +++ b/webrtc/base/nat_unittest.cc
@@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include <algorithm> #include <string> #include "webrtc/base/gunit.h" @@ -20,7 +21,6 @@ #include "webrtc/base/testclient.h" #include "webrtc/base/asynctcpsocket.h" #include "webrtc/base/virtualsocketserver.h" -#include "webrtc/test/testsupport/gtest_disable.h" using namespace rtc; @@ -207,6 +207,12 @@ std::vector<Network*> networks; network_manager.GetNetworks(&networks); + networks.erase(std::remove_if(networks.begin(), networks.end(), + [](rtc::Network* network) { + return rtc::kDefaultNetworkIgnoreMask & + network->type(); + }), + networks.end()); if (networks.empty()) { LOG(LS_WARNING) << "Not enough network adapters for test."; return;
diff --git a/webrtc/base/natsocketfactory.cc b/webrtc/base/natsocketfactory.cc index 548a80c..0abd2a1 100644 --- a/webrtc/base/natsocketfactory.cc +++ b/webrtc/base/natsocketfactory.cc
@@ -10,6 +10,7 @@ #include "webrtc/base/natsocketfactory.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/logging.h" #include "webrtc/base/natserver.h" #include "webrtc/base/virtualsocketserver.h" @@ -270,7 +271,7 @@ // Sends the destination address to the server to tell it to connect. void SendConnectRequest() { char buf[kNATEncodedIPv6AddressSize]; - size_t length = PackAddressForNAT(buf, ARRAY_SIZE(buf), remote_addr_); + size_t length = PackAddressForNAT(buf, arraysize(buf), remote_addr_); socket_->Send(buf, length); }
diff --git a/webrtc/base/network.cc b/webrtc/base/network.cc index 879c1e4..488c475 100644 --- a/webrtc/base/network.cc +++ b/webrtc/base/network.cc
@@ -24,23 +24,13 @@ #elif !defined(__native_client__) #include <net/if.h> #endif -#include <sys/socket.h> -#include <sys/utsname.h> -#include <sys/ioctl.h> -#include <unistd.h> -#include <errno.h> - -#if defined(WEBRTC_ANDROID) -#include "webrtc/base/ifaddrs-android.h" -#elif !defined(__native_client__) -#include <ifaddrs.h> -#endif - #endif // WEBRTC_POSIX #if defined(WEBRTC_WIN) #include "webrtc/base/win32.h" #include <Iphlpapi.h> +#elif !defined(__native_client__) +#include "webrtc/base/ifaddrs_converter.h" #endif #include <stdio.h> @@ -129,7 +119,8 @@ } } -bool IsIgnoredIPv6(const IPAddress& ip) { +#if !defined(__native_client__) +bool IsIgnoredIPv6(const InterfaceAddress& ip) { if (ip.family() != AF_INET6) { return false; } @@ -146,11 +137,23 @@ return true; } + // Ignore deprecated IPv6. + if (ip.ipv6_flags() & IPV6_ADDRESS_FLAG_DEPRECATED) { + return true; + } + return false; } +#endif // !defined(__native_client__) } // namespace +// These addresses are used as the targets to find out the default local address +// on a multi-homed endpoint. They are actually DNS servers. +const char kPublicIPv4Host[] = "8.8.8.8"; +const char kPublicIPv6Host[] = "2001:4860:4860::8888"; +const int kPublicPort = 53; // DNS port. + std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix, int prefix_length) { std::ostringstream ost; @@ -169,6 +172,10 @@ return ENUMERATION_ALLOWED; } +bool NetworkManager::GetDefaultLocalAddress(int family, IPAddress* addr) const { + return false; +} + NetworkManagerBase::NetworkManagerBase() : enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED), max_ipv6_networks_(kMaxIPv6Networks), @@ -191,6 +198,7 @@ const rtc::IPAddress ipv4_any_address(INADDR_ANY); ipv4_any_address_network_.reset( new rtc::Network("any", "any", ipv4_any_address, 0)); + ipv4_any_address_network_->set_default_local_address_provider(this); ipv4_any_address_network_->AddIP(ipv4_any_address); } networks->push_back(ipv4_any_address_network_.get()); @@ -200,6 +208,7 @@ const rtc::IPAddress ipv6_any_address(in6addr_any); ipv6_any_address_network_.reset( new rtc::Network("any", "any", ipv6_any_address, 0)); + ipv6_any_address_network_->set_default_local_address_provider(this); ipv6_any_address_network_->AddIP(ipv6_any_address); } networks->push_back(ipv6_any_address_network_.get()); @@ -230,20 +239,12 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks, bool* changed, NetworkManager::Stats* stats) { + *changed = false; // AddressList in this map will track IP addresses for all Networks // with the same key. std::map<std::string, AddressList> consolidated_address_list; NetworkList list(new_networks); - - // Result of Network merge. Element in this list should have unique key. - NetworkList merged_list; std::sort(list.begin(), list.end(), CompareNetworks); - - *changed = false; - - if (networks_.size() != list.size()) - *changed = true; - // First, build a set of network-keys to the ipaddresses. for (Network* network : list) { bool might_add_to_merged_list = false; @@ -275,6 +276,8 @@ } // Next, look for existing network objects to re-use. + // Result of Network merge. Element in this list should have unique key. + NetworkList merged_list; for (const auto& kv : consolidated_address_list) { const std::string& key = kv.first; Network* net = kv.second.net; @@ -289,17 +292,36 @@ *changed = true; } else { // This network exists in the map already. Reset its IP addresses. - *changed = existing->second->SetIPs(kv.second.ips, *changed); - merged_list.push_back(existing->second); - if (existing->second != net) { + Network* existing_net = existing->second; + *changed = existing_net->SetIPs(kv.second.ips, *changed); + merged_list.push_back(existing_net); + // If the existing network was not active, networks have changed. + if (!existing_net->active()) { + *changed = true; + } + ASSERT(net->active()); + if (existing_net != net) { delete net; } } } - networks_ = merged_list; + // It may still happen that the merged list is a subset of |networks_|. + // To detect this change, we compare their sizes. + if (merged_list.size() != networks_.size()) { + *changed = true; + } - // If the network lists changes, we resort it. + // If the network list changes, we re-assign |networks_| to the merged list + // and re-sort it. if (*changed) { + networks_ = merged_list; + // Reset the active states of all networks. + for (const auto& kv : networks_map_) { + kv.second->set_active(false); + } + for (Network* network : networks_) { + network->set_active(true); + } std::sort(networks_.begin(), networks_.end(), SortNetworks); // Now network interfaces are sorted, we should set the preference value // for each of the interfaces we are planning to use. @@ -321,9 +343,30 @@ } } +void NetworkManagerBase::set_default_local_addresses(const IPAddress& ipv4, + const IPAddress& ipv6) { + if (ipv4.family() == AF_INET) { + default_local_ipv4_address_ = ipv4; + } + if (ipv6.family() == AF_INET6) { + default_local_ipv6_address_ = ipv6; + } +} + +bool NetworkManagerBase::GetDefaultLocalAddress(int family, + IPAddress* ipaddr) const { + if (family == AF_INET && !default_local_ipv4_address_.IsNil()) { + *ipaddr = default_local_ipv4_address_; + return true; + } else if (family == AF_INET6 && !default_local_ipv6_address_.IsNil()) { + *ipaddr = default_local_ipv6_address_; + return true; + } + return false; +} + BasicNetworkManager::BasicNetworkManager() : thread_(NULL), sent_first_update_(false), start_count_(0), - network_ignore_mask_(kDefaultNetworkIgnoreMask), ignore_non_default_routes_(false) { } @@ -346,49 +389,47 @@ #elif defined(WEBRTC_POSIX) void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces, + IfAddrsConverter* ifaddrs_converter, bool include_ignored, NetworkList* networks) const { NetworkMap current_networks; + for (struct ifaddrs* cursor = interfaces; cursor != NULL; cursor = cursor->ifa_next) { IPAddress prefix; IPAddress mask; - IPAddress ip; + InterfaceAddress ip; int scope_id = 0; // Some interfaces may not have address assigned. - if (!cursor->ifa_addr || !cursor->ifa_netmask) + if (!cursor->ifa_addr || !cursor->ifa_netmask) { continue; + } + // Skip ones which are down. + if (!(cursor->ifa_flags & IFF_RUNNING)) { + continue; + } + // Skip unknown family. + if (cursor->ifa_addr->sa_family != AF_INET && + cursor->ifa_addr->sa_family != AF_INET6) { + continue; + } + // Skip IPv6 if not enabled. + if (cursor->ifa_addr->sa_family == AF_INET6 && !ipv6_enabled()) { + continue; + } + // Convert to InterfaceAddress. + if (!ifaddrs_converter->ConvertIfAddrsToIPAddress(cursor, &ip, &mask)) { + continue; + } - switch (cursor->ifa_addr->sa_family) { - case AF_INET: { - ip = IPAddress( - reinterpret_cast<sockaddr_in*>(cursor->ifa_addr)->sin_addr); - mask = IPAddress( - reinterpret_cast<sockaddr_in*>(cursor->ifa_netmask)->sin_addr); - break; - } - case AF_INET6: { - if (ipv6_enabled()) { - ip = IPAddress( - reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_addr); - - if (IsIgnoredIPv6(ip)) { - continue; - } - - mask = IPAddress( - reinterpret_cast<sockaddr_in6*>(cursor->ifa_netmask)->sin6_addr); - scope_id = - reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_scope_id; - break; - } else { - continue; - } - } - default: { + // Special case for IPv6 address. + if (cursor->ifa_addr->sa_family == AF_INET6) { + if (IsIgnoredIPv6(ip)) { continue; } + scope_id = + reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_scope_id; } int prefix_length = CountIPMaskBits(mask); @@ -409,14 +450,14 @@ #endif // TODO(phoglund): Need to recognize other types as well. scoped_ptr<Network> network(new Network(cursor->ifa_name, - cursor->ifa_name, - prefix, - prefix_length, - adapter_type)); + cursor->ifa_name, prefix, + prefix_length, adapter_type)); + network->set_default_local_address_provider(this); network->set_scope_id(scope_id); network->AddIP(ip); network->set_ignored(IsIgnoredNetwork(*network)); if (include_ignored || !network->ignored()) { + current_networks[key] = network.get(); networks->push_back(network.release()); } } else { @@ -434,7 +475,9 @@ return false; } - ConvertIfAddrs(interfaces, include_ignored, networks); + rtc::scoped_ptr<IfAddrsConverter> ifaddrs_converter(CreateIfAddrsConverter()); + ConvertIfAddrs(interfaces, ifaddrs_converter.get(), include_ignored, + networks); freeifaddrs(interfaces); return true; @@ -511,14 +554,14 @@ PIP_ADAPTER_PREFIX prefixlist = adapter_addrs->FirstPrefix; std::string name; std::string description; -#ifdef _DEBUG +#if !defined(NDEBUG) name = ToUtf8(adapter_addrs->FriendlyName, wcslen(adapter_addrs->FriendlyName)); #endif description = ToUtf8(adapter_addrs->Description, wcslen(adapter_addrs->Description)); for (; address; address = address->Next) { -#ifndef _DEBUG +#if defined(NDEBUG) name = rtc::ToString(count); #endif @@ -563,16 +606,15 @@ // TODO(phoglund): Need to recognize other types as well. adapter_type = ADAPTER_TYPE_LOOPBACK; } - scoped_ptr<Network> network(new Network(name, - description, - prefix, - prefix_length, - adapter_type)); + scoped_ptr<Network> network(new Network(name, description, prefix, + prefix_length, adapter_type)); + network->set_default_local_address_provider(this); network->set_scope_id(scope_id); network->AddIP(ip); bool ignored = IsIgnoredNetwork(*network); network->set_ignored(ignored); if (include_ignored || !network->ignored()) { + current_networks[key] = network.get(); networks->push_back(network.release()); } } else { @@ -624,9 +666,6 @@ } } - if (network_ignore_mask_ & network.type()) { - return true; - } #if defined(WEBRTC_POSIX) // Filter out VMware/VirtualBox interfaces, typically named vmnet1, // vmnet8, or vboxnet0. @@ -724,6 +763,25 @@ } } +IPAddress BasicNetworkManager::QueryDefaultLocalAddress(int family) const { + ASSERT(thread_ == Thread::Current()); + ASSERT(thread_->socketserver() != nullptr); + ASSERT(family == AF_INET || family == AF_INET6); + + scoped_ptr<AsyncSocket> socket( + thread_->socketserver()->CreateAsyncSocket(family, SOCK_DGRAM)); + if (!socket) { + return IPAddress(); + } + + if (!socket->Connect( + SocketAddress(family == AF_INET ? kPublicIPv4Host : kPublicIPv6Host, + kPublicPort))) { + return IPAddress(); + } + return socket->GetLocalAddress().ipaddr(); +} + void BasicNetworkManager::UpdateNetworksOnce() { if (!start_count_) return; @@ -735,7 +793,10 @@ SignalError(); } else { bool changed; - MergeNetworkList(list, &changed); + NetworkManager::Stats stats; + MergeNetworkList(list, &changed, &stats); + set_default_local_addresses(QueryDefaultLocalAddress(AF_INET), + QueryDefaultLocalAddress(AF_INET6)); if (changed || !sent_first_update_) { SignalNetworksChanged(); sent_first_update_ = true; @@ -748,39 +809,45 @@ thread_->PostDelayed(kNetworksUpdateIntervalMs, this, kUpdateNetworksMessage); } -void BasicNetworkManager::DumpNetworks(bool include_ignored) { +void BasicNetworkManager::DumpNetworks() { NetworkList list; - CreateNetworks(include_ignored, &list); + GetNetworks(&list); LOG(LS_INFO) << "NetworkManager detected " << list.size() << " networks:"; for (const Network* network : list) { - if (!network->ignored() || include_ignored) { - LOG(LS_INFO) << network->ToString() << ": " - << network->description() - << ((network->ignored()) ? ", Ignored" : ""); - } - } - // Release the network list created previously. - // Do this in a seperated for loop for better readability. - for (Network* network : list) { - delete network; + LOG(LS_INFO) << network->ToString() << ": " << network->description() + << ", active ? " << network->active() + << ((network->ignored()) ? ", Ignored" : ""); } } -Network::Network(const std::string& name, const std::string& desc, - const IPAddress& prefix, int prefix_length) - : name_(name), description_(desc), prefix_(prefix), +Network::Network(const std::string& name, + const std::string& desc, + const IPAddress& prefix, + int prefix_length) + : name_(name), + description_(desc), + prefix_(prefix), prefix_length_(prefix_length), - key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0), - ignored_(false), type_(ADAPTER_TYPE_UNKNOWN), preference_(0) { -} + key_(MakeNetworkKey(name, prefix, prefix_length)), + scope_id_(0), + ignored_(false), + type_(ADAPTER_TYPE_UNKNOWN), + preference_(0) {} -Network::Network(const std::string& name, const std::string& desc, - const IPAddress& prefix, int prefix_length, AdapterType type) - : name_(name), description_(desc), prefix_(prefix), +Network::Network(const std::string& name, + const std::string& desc, + const IPAddress& prefix, + int prefix_length, + AdapterType type) + : name_(name), + description_(desc), + prefix_(prefix), prefix_length_(prefix_length), - key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0), - ignored_(false), type_(type), preference_(0) { -} + key_(MakeNetworkKey(name, prefix, prefix_length)), + scope_id_(0), + ignored_(false), + type_(type), + preference_(0) {} Network::~Network() = default;
diff --git a/webrtc/base/network.h b/webrtc/base/network.h index ab3a88d..2f2e1b3 100644 --- a/webrtc/base/network.h +++ b/webrtc/base/network.h
@@ -28,6 +28,10 @@ namespace rtc { +extern const char kPublicIPv4Host[]; +extern const char kPublicIPv6Host[]; + +class IfAddrsConverter; class Network; class NetworkMonitorInterface; class Thread; @@ -51,9 +55,18 @@ std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix, int prefix_length); +class DefaultLocalAddressProvider { + public: + virtual ~DefaultLocalAddressProvider() = default; + // The default local address is the local address used in multi-homed endpoint + // when the any address (0.0.0.0 or ::) is used as the local address. It's + // important to check the return value as a IP family may not be enabled. + virtual bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const = 0; +}; + // Generic network manager interface. It provides list of local // networks. -class NetworkManager { +class NetworkManager : public DefaultLocalAddressProvider { public: typedef std::vector<Network*> NetworkList; @@ -67,7 +80,7 @@ }; NetworkManager(); - virtual ~NetworkManager(); + ~NetworkManager() override; // Called when network list is updated. sigslot::signal0<> SignalNetworksChanged; @@ -99,8 +112,9 @@ // TODO(guoweis): remove this body when chromium implements this. virtual void GetAnyAddressNetworks(NetworkList* networks) {} - // Dumps a list of networks available to LS_INFO. - virtual void DumpNetworks(bool include_ignored) {} + // Dumps the current list of networks in the network manager. + virtual void DumpNetworks() {} + bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const override; struct Stats { int ipv4_network_count; @@ -128,6 +142,8 @@ EnumerationPermission enumeration_permission() const override; + bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const override; + protected: typedef std::map<std::string, Network*> NetworkMap; // Updates |networks_| with the networks listed in |list|. If @@ -146,6 +162,9 @@ enumeration_permission_ = state; } + void set_default_local_addresses(const IPAddress& ipv4, + const IPAddress& ipv6); + private: friend class NetworkTest; @@ -159,6 +178,9 @@ rtc::scoped_ptr<rtc::Network> ipv4_any_address_network_; rtc::scoped_ptr<rtc::Network> ipv6_any_address_network_; + + IPAddress default_local_ipv4_address_; + IPAddress default_local_ipv6_address_; }; // Basic implementation of the NetworkManager interface that gets list @@ -173,8 +195,7 @@ void StartUpdating() override; void StopUpdating() override; - // Logs the available networks. - void DumpNetworks(bool include_ignored) override; + void DumpNetworks() override; // MessageHandler interface. void OnMessage(Message* msg) override; @@ -186,18 +207,6 @@ network_ignore_list_ = list; } - // Sets the network types to ignore. For instance, calling this with - // ADAPTER_TYPE_ETHERNET | ADAPTER_TYPE_LOOPBACK will ignore Ethernet and - // loopback interfaces. Set to kDefaultNetworkIgnoreMask by default. - void set_network_ignore_mask(int network_ignore_mask) { - // TODO(phoglund): implement support for other types than loopback. - // See https://code.google.com/p/webrtc/issues/detail?id=4288. - // Then remove set_network_ignore_list. - network_ignore_mask_ = network_ignore_mask; - } - - int network_ignore_mask() const { return network_ignore_mask_; } - #if defined(WEBRTC_LINUX) // Sets the flag for ignoring non-default routes. void set_ignore_non_default_routes(bool value) { @@ -209,6 +218,7 @@ #if defined(WEBRTC_POSIX) // Separated from CreateNetworks for tests. void ConvertIfAddrs(ifaddrs* interfaces, + IfAddrsConverter* converter, bool include_ignored, NetworkList* networks) const; #endif // defined(WEBRTC_POSIX) @@ -220,6 +230,11 @@ // based on the network's property instead of any individual IP. bool IsIgnoredNetwork(const Network& network) const; + // This function connects a UDP socket to a public address and returns the + // local address associated it. Since it binds to the "any" address + // internally, it returns the default local address on a multi-homed endpoint. + IPAddress QueryDefaultLocalAddress(int family) const; + private: friend class NetworkTest; @@ -239,7 +254,6 @@ bool sent_first_update_; int start_count_; std::vector<std::string> network_ignore_list_; - int network_ignore_mask_; bool ignore_non_default_routes_; scoped_ptr<NetworkMonitorInterface> network_monitor_; }; @@ -247,13 +261,26 @@ // Represents a Unix-type network interface, with a name and single address. class Network { public: - Network(const std::string& name, const std::string& description, - const IPAddress& prefix, int prefix_length); + Network(const std::string& name, + const std::string& description, + const IPAddress& prefix, + int prefix_length); - Network(const std::string& name, const std::string& description, - const IPAddress& prefix, int prefix_length, AdapterType type); + Network(const std::string& name, + const std::string& description, + const IPAddress& prefix, + int prefix_length, + AdapterType type); ~Network(); + const DefaultLocalAddressProvider* default_local_address_provider() { + return default_local_address_provider_; + } + void set_default_local_address_provider( + const DefaultLocalAddressProvider* provider) { + default_local_address_provider_ = provider; + } + // Returns the name of the interface this network is associated wtih. const std::string& name() const { return name_; } @@ -319,10 +346,17 @@ int preference() const { return preference_; } void set_preference(int preference) { preference_ = preference; } + // When we enumerate networks and find a previously-seen network is missing, + // we do not remove it (because it may be used elsewhere). Instead, we mark + // it inactive, so that we can detect network changes properly. + bool active() const { return active_; } + void set_active(bool active) { active_ = active; } + // Debugging description of this network std::string ToString() const; private: + const DefaultLocalAddressProvider* default_local_address_provider_ = nullptr; std::string name_; std::string description_; IPAddress prefix_; @@ -333,6 +367,7 @@ bool ignored_; AdapterType type_; int preference_; + bool active_ = true; friend class NetworkManager; };
diff --git a/webrtc/base/network_unittest.cc b/webrtc/base/network_unittest.cc index 4362221..7dd400b 100644 --- a/webrtc/base/network_unittest.cc +++ b/webrtc/base/network_unittest.cc
@@ -10,16 +10,14 @@ #include "webrtc/base/network.h" +#include "webrtc/base/nethelpers.h" #include "webrtc/base/networkmonitor.h" #include <vector> #if defined(WEBRTC_POSIX) #include <sys/types.h> -#if !defined(WEBRTC_ANDROID) -#include <ifaddrs.h> -#else -#include "webrtc/base/ifaddrs-android.h" -#endif -#endif +#include <net/if.h> +#include "webrtc/base/ifaddrs_converter.h" +#endif // defined(WEBRTC_POSIX) #include "webrtc/base/gunit.h" #if defined(WEBRTC_WIN) #include "webrtc/base/logging.h" // For LOG_GLE @@ -27,6 +25,8 @@ namespace rtc { +namespace { + class FakeNetworkMonitor : public NetworkMonitorBase { public: void Start() override {} @@ -41,6 +41,8 @@ } }; +} // namespace + class NetworkTest : public testing::Test, public sigslot::has_slots<> { public: NetworkTest() : callback_called_(false) {} @@ -88,7 +90,51 @@ struct ifaddrs* interfaces, bool include_ignored, NetworkManager::NetworkList* networks) { - network_manager.ConvertIfAddrs(interfaces, include_ignored, networks); + // Use the base IfAddrsConverter for test cases. + rtc::scoped_ptr<IfAddrsConverter> ifaddrs_converter(new IfAddrsConverter()); + network_manager.ConvertIfAddrs(interfaces, ifaddrs_converter.get(), + include_ignored, networks); + } + + struct sockaddr_in6* CreateIpv6Addr(const std::string& ip_string, + uint32_t scope_id) { + struct sockaddr_in6* ipv6_addr = new struct sockaddr_in6; + memset(ipv6_addr, 0, sizeof(struct sockaddr_in6)); + ipv6_addr->sin6_family = AF_INET6; + ipv6_addr->sin6_scope_id = scope_id; + IPAddress ip; + IPFromString(ip_string, &ip); + ipv6_addr->sin6_addr = ip.ipv6_address(); + return ipv6_addr; + } + + // Pointers created here need to be released via ReleaseIfAddrs. + struct ifaddrs* AddIpv6Address(struct ifaddrs* list, + char* if_name, + const std::string& ipv6_address, + const std::string& ipv6_netmask, + uint32_t scope_id) { + struct ifaddrs* if_addr = new struct ifaddrs; + memset(if_addr, 0, sizeof(struct ifaddrs)); + if_addr->ifa_name = if_name; + if_addr->ifa_addr = reinterpret_cast<struct sockaddr*>( + CreateIpv6Addr(ipv6_address, scope_id)); + if_addr->ifa_netmask = + reinterpret_cast<struct sockaddr*>(CreateIpv6Addr(ipv6_netmask, 0)); + if_addr->ifa_next = list; + if_addr->ifa_flags = IFF_RUNNING; + return if_addr; + } + + void ReleaseIfAddrs(struct ifaddrs* list) { + struct ifaddrs* if_addr = list; + while (if_addr != nullptr) { + struct ifaddrs* next_addr = if_addr->ifa_next; + delete if_addr->ifa_addr; + delete if_addr->ifa_netmask; + delete if_addr; + if_addr = next_addr; + } } #endif // defined(WEBRTC_POSIX) @@ -96,6 +142,12 @@ bool callback_called_; }; +class TestBasicNetworkManager : public BasicNetworkManager { + public: + using BasicNetworkManager::QueryDefaultLocalAddress; + using BasicNetworkManager::set_default_local_addresses; +}; + // Test that the Network ctor works properly. TEST_F(NetworkTest, TestNetworkConstruct) { Network ipv4_network1("test_eth0", "Test Network Adapter 1", @@ -107,26 +159,6 @@ EXPECT_FALSE(ipv4_network1.ignored()); } -// Tests that our ignore function works properly. -TEST_F(NetworkTest, TestIsIgnoredNetworkIgnoresOnlyLoopbackByDefault) { - Network ipv4_network1("test_eth0", "Test Network Adapter 1", - IPAddress(0x12345600U), 24, ADAPTER_TYPE_ETHERNET); - Network ipv4_network2("test_wlan0", "Test Network Adapter 2", - IPAddress(0x12345601U), 16, ADAPTER_TYPE_WIFI); - Network ipv4_network3("test_cell0", "Test Network Adapter 3", - IPAddress(0x12345602U), 16, ADAPTER_TYPE_CELLULAR); - Network ipv4_network4("test_vpn0", "Test Network Adapter 4", - IPAddress(0x12345603U), 16, ADAPTER_TYPE_VPN); - Network ipv4_network5("test_lo", "Test Network Adapter 5", - IPAddress(0x12345604U), 16, ADAPTER_TYPE_LOOPBACK); - BasicNetworkManager network_manager; - EXPECT_FALSE(IsIgnoredNetwork(network_manager, ipv4_network1)); - EXPECT_FALSE(IsIgnoredNetwork(network_manager, ipv4_network2)); - EXPECT_FALSE(IsIgnoredNetwork(network_manager, ipv4_network3)); - EXPECT_FALSE(IsIgnoredNetwork(network_manager, ipv4_network4)); - EXPECT_TRUE(IsIgnoredNetwork(network_manager, ipv4_network5)); -} - TEST_F(NetworkTest, TestIsIgnoredNetworkIgnoresIPsStartingWith0) { Network ipv4_network1("test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24, ADAPTER_TYPE_ETHERNET); @@ -137,21 +169,6 @@ EXPECT_TRUE(IsIgnoredNetwork(network_manager, ipv4_network2)); } -TEST_F(NetworkTest, TestIsIgnoredNetworkIgnoresNetworksAccordingToIgnoreMask) { - Network ipv4_network1("test_eth0", "Test Network Adapter 1", - IPAddress(0x12345600U), 24, ADAPTER_TYPE_ETHERNET); - Network ipv4_network2("test_wlan0", "Test Network Adapter 2", - IPAddress(0x12345601U), 16, ADAPTER_TYPE_WIFI); - Network ipv4_network3("test_cell0", "Test Network Adapter 3", - IPAddress(0x12345602U), 16, ADAPTER_TYPE_CELLULAR); - BasicNetworkManager network_manager; - network_manager.set_network_ignore_mask( - ADAPTER_TYPE_ETHERNET | ADAPTER_TYPE_LOOPBACK | ADAPTER_TYPE_WIFI); - EXPECT_TRUE(IsIgnoredNetwork(network_manager, ipv4_network1)); - EXPECT_TRUE(IsIgnoredNetwork(network_manager, ipv4_network2)); - EXPECT_FALSE(IsIgnoredNetwork(network_manager, ipv4_network3)); -} - // TODO(phoglund): Remove when ignore list goes away. TEST_F(NetworkTest, TestIgnoreList) { Network ignore_me("ignore_me", "Ignore me please!", @@ -583,10 +600,13 @@ } } -// Test that DumpNetworks works. -TEST_F(NetworkTest, TestDumpNetworks) { +// Test that DumpNetworks does not crash. +TEST_F(NetworkTest, TestCreateAndDumpNetworks) { BasicNetworkManager manager; - manager.DumpNetworks(true); + NetworkManager::NetworkList list = GetNetworks(manager, true); + bool changed; + MergeNetworkList(manager, list, &changed); + manager.DumpNetworks(); } // Test that we can toggle IPv6 on and off. @@ -693,6 +713,40 @@ CallConvertIfAddrs(manager, &list, true, &result); EXPECT_TRUE(result.empty()); } + +// Verify that if there are two addresses on one interface, only one network +// is generated. +TEST_F(NetworkTest, TestConvertIfAddrsMultiAddressesOnOneInterface) { + char if_name[20] = "rmnet0"; + ifaddrs* list = nullptr; + list = AddIpv6Address(list, if_name, "1000:2000:3000:4000:0:0:0:1", + "FFFF:FFFF:FFFF:FFFF::", 0); + list = AddIpv6Address(list, if_name, "1000:2000:3000:4000:0:0:0:2", + "FFFF:FFFF:FFFF:FFFF::", 0); + NetworkManager::NetworkList result; + BasicNetworkManager manager; + CallConvertIfAddrs(manager, list, true, &result); + EXPECT_EQ(1U, result.size()); + bool changed; + // This ensures we release the objects created in CallConvertIfAddrs. + MergeNetworkList(manager, result, &changed); + ReleaseIfAddrs(list); +} + +TEST_F(NetworkTest, TestConvertIfAddrsNotRunning) { + ifaddrs list; + memset(&list, 0, sizeof(list)); + list.ifa_name = const_cast<char*>("test_iface"); + sockaddr ifa_addr; + sockaddr ifa_netmask; + list.ifa_addr = &ifa_addr; + list.ifa_netmask = &ifa_netmask; + + NetworkManager::NetworkList result; + BasicNetworkManager manager; + CallConvertIfAddrs(manager, &list, true, &result); + EXPECT_TRUE(result.empty()); +} #endif // defined(WEBRTC_POSIX) #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) @@ -776,6 +830,49 @@ EXPECT_EQ(list2[0]->GetIPs()[1], ip2); } +// Test that MergeNetworkList successfully detects the change if +// a network becomes inactive and then active again. +TEST_F(NetworkTest, TestMergeNetworkListWithInactiveNetworks) { + BasicNetworkManager manager; + Network network1("test_wifi", "Test Network Adapter 1", + IPAddress(0x12345600U), 24); + Network network2("test_eth0", "Test Network Adapter 2", + IPAddress(0x00010000U), 16); + network1.AddIP(IPAddress(0x12345678)); + network2.AddIP(IPAddress(0x00010004)); + NetworkManager::NetworkList list; + Network* net1 = new Network(network1); + list.push_back(net1); + bool changed; + MergeNetworkList(manager, list, &changed); + EXPECT_TRUE(changed); + list.clear(); + manager.GetNetworks(&list); + ASSERT_EQ(1U, list.size()); + EXPECT_EQ(net1, list[0]); + + list.clear(); + Network* net2 = new Network(network2); + list.push_back(net2); + MergeNetworkList(manager, list, &changed); + EXPECT_TRUE(changed); + list.clear(); + manager.GetNetworks(&list); + ASSERT_EQ(1U, list.size()); + EXPECT_EQ(net2, list[0]); + + // Now network1 is inactive. Try to merge it again. + list.clear(); + list.push_back(new Network(network1)); + MergeNetworkList(manager, list, &changed); + EXPECT_TRUE(changed); + list.clear(); + manager.GetNetworks(&list); + ASSERT_EQ(1U, list.size()); + EXPECT_TRUE(list[0]->active()); + EXPECT_EQ(net1, list[0]); +} + // Test that the filtering logic follows the defined ruleset in network.h. TEST_F(NetworkTest, TestIPv6Selection) { InterfaceAddress ip; @@ -842,4 +939,35 @@ NetworkMonitorFactory::ReleaseFactory(factory); } +TEST_F(NetworkTest, DefaultLocalAddress) { + TestBasicNetworkManager manager; + manager.StartUpdating(); + IPAddress ip; + + // GetDefaultLocalAddress should return false when not set. + EXPECT_FALSE(manager.GetDefaultLocalAddress(AF_INET, &ip)); + EXPECT_FALSE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); + + // Make sure we can query default local address when an address for such + // address family exists. + std::vector<Network*> networks; + manager.GetNetworks(&networks); + for (auto& network : networks) { + if (network->GetBestIP().family() == AF_INET) { + EXPECT_TRUE(manager.QueryDefaultLocalAddress(AF_INET) != IPAddress()); + } else if (network->GetBestIP().family() == AF_INET6) { + EXPECT_TRUE(manager.QueryDefaultLocalAddress(AF_INET6) != IPAddress()); + } + } + + // GetDefaultLocalAddress should return the valid default address after set. + manager.set_default_local_addresses(GetLoopbackIP(AF_INET), + GetLoopbackIP(AF_INET6)); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET, &ip)); + EXPECT_EQ(ip, GetLoopbackIP(AF_INET)); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); + EXPECT_EQ(ip, GetLoopbackIP(AF_INET6)); + manager.StopUpdating(); +} + } // namespace rtc
diff --git a/webrtc/base/nullsocketserver_unittest.cc b/webrtc/base/nullsocketserver_unittest.cc index 2aa38b4..4f22c38 100644 --- a/webrtc/base/nullsocketserver_unittest.cc +++ b/webrtc/base/nullsocketserver_unittest.cc
@@ -10,7 +10,6 @@ #include "webrtc/base/gunit.h" #include "webrtc/base/nullsocketserver.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace rtc {
diff --git a/webrtc/base/objc/NSString+StdString.h b/webrtc/base/objc/NSString+StdString.h new file mode 100644 index 0000000..8bf6cc9 --- /dev/null +++ b/webrtc/base/objc/NSString+StdString.h
@@ -0,0 +1,26 @@ +/* + * 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 <string> + +NS_ASSUME_NONNULL_BEGIN + +@interface NSString (StdString) + +@property(nonatomic, readonly) std::string stdString; + ++ (std::string)stdStringForString:(NSString *)nsString; ++ (NSString *)stringForStdString:(const std::string&)stdString; + +@end + +NS_ASSUME_NONNULL_END
diff --git a/webrtc/base/objc/NSString+StdString.mm b/webrtc/base/objc/NSString+StdString.mm new file mode 100644 index 0000000..3210ff0 --- /dev/null +++ b/webrtc/base/objc/NSString+StdString.mm
@@ -0,0 +1,33 @@ +/* + * 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 "NSString+StdString.h" + +@implementation NSString (StdString) + +- (std::string)stdString { + return [NSString stdStringForString:self]; +} + ++ (std::string)stdStringForString:(NSString *)nsString { + NSData *charData = [nsString dataUsingEncoding:NSUTF8StringEncoding]; + return std::string(reinterpret_cast<const char *>(charData.bytes), + charData.length); +} + ++ (NSString *)stringForStdString:(const std::string&)stdString { + // std::string may contain null termination character so we construct + // using length. + return [[NSString alloc] initWithBytes:stdString.data() + length:stdString.length() + encoding:NSUTF8StringEncoding]; +} + +@end
diff --git a/webrtc/base/objc/OWNERS b/webrtc/base/objc/OWNERS new file mode 100644 index 0000000..cd06158 --- /dev/null +++ b/webrtc/base/objc/OWNERS
@@ -0,0 +1 @@ +tkchin@webrtc.org
diff --git a/webrtc/base/objc/RTCCameraPreviewView.h b/webrtc/base/objc/RTCCameraPreviewView.h new file mode 100644 index 0000000..03e94c2 --- /dev/null +++ b/webrtc/base/objc/RTCCameraPreviewView.h
@@ -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> +#import <UIKit/UIKit.h> + +@class AVCaptureSession; +@class RTCAVFoundationVideoSource; + +/** RTCCameraPreviewView is a view that renders local video from an + * AVCaptureSession. + */ +@interface RTCCameraPreviewView : UIView + +/** The capture session being rendered in the view. Capture session + * is assigned to AVCaptureVideoPreviewLayer async in the same + * queue that the AVCaptureSession is started/stopped. + */ +@property(nonatomic, strong) AVCaptureSession *captureSession; + +@end
diff --git a/webrtc/base/objc/RTCCameraPreviewView.m b/webrtc/base/objc/RTCCameraPreviewView.m new file mode 100644 index 0000000..5a57483 --- /dev/null +++ b/webrtc/base/objc/RTCCameraPreviewView.m
@@ -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. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "webrtc/base/objc/RTCCameraPreviewView.h" + +#import <AVFoundation/AVFoundation.h> + +#import "webrtc/base/objc/RTCDispatcher.h" + +@implementation RTCCameraPreviewView + +@synthesize captureSession = _captureSession; + ++ (Class)layerClass { + return [AVCaptureVideoPreviewLayer class]; +} + +- (void)setCaptureSession:(AVCaptureSession *)captureSession { + if (_captureSession == captureSession) { + return; + } + _captureSession = captureSession; + AVCaptureVideoPreviewLayer *previewLayer = [self previewLayer]; + [RTCDispatcher dispatchAsyncOnType:RTCDispatcherTypeCaptureSession + block:^{ + previewLayer.session = captureSession; + }]; +} + +#pragma mark - Private + +- (AVCaptureVideoPreviewLayer *)previewLayer { + return (AVCaptureVideoPreviewLayer *)self.layer; +} + +@end
diff --git a/webrtc/base/objc/RTCDispatcher.h b/webrtc/base/objc/RTCDispatcher.h new file mode 100644 index 0000000..c32b93d --- /dev/null +++ b/webrtc/base/objc/RTCDispatcher.h
@@ -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> + +typedef NS_ENUM(NSInteger, RTCDispatcherQueueType) { + // Main dispatcher queue. + RTCDispatcherTypeMain, + // Used for starting/stopping AVCaptureSession, and assigning + // capture session to AVCaptureVideoPreviewLayer. + RTCDispatcherTypeCaptureSession, +}; + +/** Dispatcher that asynchronously dispatches blocks to a specific + * shared dispatch queue. + */ +@interface RTCDispatcher : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Dispatch the block asynchronously on the queue for dispatchType. + * @param dispatchType The queue type to dispatch on. + * @param block The block to dispatch asynchronously. + */ ++ (void)dispatchAsyncOnType:(RTCDispatcherQueueType)dispatchType + block:(dispatch_block_t)block; + +@end
diff --git a/webrtc/base/objc/RTCDispatcher.m b/webrtc/base/objc/RTCDispatcher.m new file mode 100644 index 0000000..065705a --- /dev/null +++ b/webrtc/base/objc/RTCDispatcher.m
@@ -0,0 +1,46 @@ +/* + * 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 "RTCDispatcher.h" + +static dispatch_queue_t kCaptureSessionQueue = nil; + +@implementation RTCDispatcher { + dispatch_queue_t _captureSessionQueue; +} + ++ (void)initialize { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + kCaptureSessionQueue = dispatch_queue_create( + "org.webrtc.RTCDispatcherCaptureSession", + DISPATCH_QUEUE_SERIAL); + }); +} + ++ (void)dispatchAsyncOnType:(RTCDispatcherQueueType)dispatchType + block:(dispatch_block_t)block { + dispatch_queue_t queue = [self dispatchQueueForType:dispatchType]; + dispatch_async(queue, block); +} + +#pragma mark - Private + ++ (dispatch_queue_t)dispatchQueueForType:(RTCDispatcherQueueType)dispatchType { + switch (dispatchType) { + case RTCDispatcherTypeMain: + return dispatch_get_main_queue(); + case RTCDispatcherTypeCaptureSession: + return kCaptureSessionQueue; + } +} + +@end +
diff --git a/webrtc/base/objc/RTCLogging.h b/webrtc/base/objc/RTCLogging.h new file mode 100644 index 0000000..19fade5 --- /dev/null +++ b/webrtc/base/objc/RTCLogging.h
@@ -0,0 +1,75 @@ +/* + * 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> + +// Subset of rtc::LoggingSeverity. +typedef NS_ENUM(NSInteger, RTCLoggingSeverity) { + kRTCLoggingSeverityVerbose, + kRTCLoggingSeverityInfo, + kRTCLoggingSeverityWarning, + kRTCLoggingSeverityError, +}; + +#if defined(__cplusplus) +extern "C" void RTCLogEx(RTCLoggingSeverity severity, NSString* log_string); +extern "C" void RTCSetMinDebugLogLevel(RTCLoggingSeverity severity); +extern "C" NSString* RTCFileName(const char* filePath); +#else + +// Wrapper for C++ LOG(sev) macros. +// Logs the log string to the webrtc logstream for the given severity. +extern void RTCLogEx(RTCLoggingSeverity severity, NSString* log_string); + +// Wrapper for rtc::LogMessage::LogToDebug. +// Sets the minimum severity to be logged to console. +extern void RTCSetMinDebugLogLevel(RTCLoggingSeverity severity); + +// Returns the filename with the path prefix removed. +extern NSString* RTCFileName(const char* filePath); + +#endif + +// Some convenience macros. + +#define RTCLogString(format, ...) \ + [NSString stringWithFormat:@"(%@:%d %s): " format, \ + RTCFileName(__FILE__), \ + __LINE__, \ + __FUNCTION__, \ + ##__VA_ARGS__] + +#define RTCLogFormat(severity, format, ...) \ + do { \ + NSString* log_string = RTCLogString(format, ##__VA_ARGS__); \ + RTCLogEx(severity, log_string); \ + } while (false) + +#define RTCLogVerbose(format, ...) \ + RTCLogFormat(kRTCLoggingSeverityVerbose, format, ##__VA_ARGS__) \ + +#define RTCLogInfo(format, ...) \ + RTCLogFormat(kRTCLoggingSeverityInfo, format, ##__VA_ARGS__) \ + +#define RTCLogWarning(format, ...) \ + RTCLogFormat(kRTCLoggingSeverityWarning, format, ##__VA_ARGS__) \ + +#define RTCLogError(format, ...) \ + RTCLogFormat(kRTCLoggingSeverityError, format, ##__VA_ARGS__) \ + +#if !defined(NDEBUG) +#define RTCLogDebug(format, ...) RTCLogInfo(format, ##__VA_ARGS__) +#else +#define RTCLogDebug(format, ...) \ + do { \ + } while (false) +#endif + +#define RTCLog(format, ...) RTCLogInfo(format, ##__VA_ARGS__)
diff --git a/webrtc/base/objc/RTCLogging.mm b/webrtc/base/objc/RTCLogging.mm new file mode 100644 index 0000000..e9afe72 --- /dev/null +++ b/webrtc/base/objc/RTCLogging.mm
@@ -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 "RTCLogging.h" + +#include "webrtc/base/logging.h" + +rtc::LoggingSeverity RTCGetNativeLoggingSeverity(RTCLoggingSeverity severity) { + switch (severity) { + case kRTCLoggingSeverityVerbose: + return rtc::LS_VERBOSE; + case kRTCLoggingSeverityInfo: + return rtc::LS_INFO; + case kRTCLoggingSeverityWarning: + return rtc::LS_WARNING; + case kRTCLoggingSeverityError: + return rtc::LS_ERROR; + } +} + +void RTCLogEx(RTCLoggingSeverity severity, NSString* log_string) { + if (log_string.length) { + const char* utf8_string = log_string.UTF8String; + LOG_V(RTCGetNativeLoggingSeverity(severity)) << utf8_string; + } +} + +void RTCSetMinDebugLogLevel(RTCLoggingSeverity severity) { + rtc::LogMessage::LogToDebug(RTCGetNativeLoggingSeverity(severity)); +} + +NSString* RTCFileName(const char* file_path) { + NSString* ns_file_path = + [[NSString alloc] initWithBytesNoCopy:const_cast<char*>(file_path) + length:strlen(file_path) + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + return ns_file_path.lastPathComponent; +} +
diff --git a/webrtc/base/openssladapter.cc b/webrtc/base/openssladapter.cc index c906ebb..1f5fbbc 100644 --- a/webrtc/base/openssladapter.cc +++ b/webrtc/base/openssladapter.cc
@@ -31,6 +31,7 @@ #include "config.h" #endif // HAVE_CONFIG_H +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" #include "webrtc/base/openssl.h" @@ -835,7 +836,7 @@ return ok; } -#if _DEBUG +#if !defined(NDEBUG) // We only use this for tracing and so it is only needed in debug mode @@ -864,11 +865,11 @@ } } -#endif // _DEBUG +#endif int OpenSSLAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) { -#if _DEBUG +#if !defined(NDEBUG) if (!ok) { char data[256]; X509* cert = X509_STORE_CTX_get_current_cert(store); @@ -915,7 +916,7 @@ bool OpenSSLAdapter::ConfigureTrustedRootCertificates(SSL_CTX* ctx) { // Add the root cert that we care about to the SSL context int count_of_added_certs = 0; - for (int i = 0; i < ARRAY_SIZE(kSSLCertCertificateList); i++) { + for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) { const unsigned char* cert_buffer = kSSLCertCertificateList[i]; size_t cert_buffer_len = kSSLCertCertificateSizeList[i]; X509* cert = d2i_X509(NULL, &cert_buffer, @@ -949,7 +950,7 @@ return NULL; } -#ifdef _DEBUG +#if !defined(NDEBUG) SSL_CTX_set_info_callback(ctx, SSLInfoCallback); #endif
diff --git a/webrtc/base/openssladapter.h b/webrtc/base/openssladapter.h index 3dcb1c5..cdf45e6 100644 --- a/webrtc/base/openssladapter.h +++ b/webrtc/base/openssladapter.h
@@ -67,9 +67,9 @@ static bool VerifyServerName(SSL* ssl, const char* host, bool ignore_bad_cert); bool SSLPostConnectionCheck(SSL* ssl, const char* host); -#if _DEBUG +#if !defined(NDEBUG) static void SSLInfoCallback(const SSL* s, int where, int ret); -#endif // !_DEBUG +#endif static int SSLVerifyCallback(int ok, X509_STORE_CTX* store); static VerificationCallback custom_verify_callback_; friend class OpenSSLStreamAdapter; // for custom_verify_callback_;
diff --git a/webrtc/base/opensslidentity.cc b/webrtc/base/opensslidentity.cc index feda674..7185571 100644 --- a/webrtc/base/opensslidentity.cc +++ b/webrtc/base/opensslidentity.cc
@@ -96,6 +96,7 @@ X509* x509 = NULL; BIGNUM* serial_number = NULL; X509_NAME* name = NULL; + time_t epoch_off = 0; // Time offset since epoch. if ((x509=X509_new()) == NULL) goto error; @@ -130,8 +131,8 @@ !X509_set_issuer_name(x509, name)) goto error; - if (!X509_gmtime_adj(X509_get_notBefore(x509), params.not_before) || - !X509_gmtime_adj(X509_get_notAfter(x509), params.not_after)) + if (!X509_time_adj(X509_get_notBefore(x509), params.not_before, &epoch_off) || + !X509_time_adj(X509_get_notAfter(x509), params.not_after, &epoch_off)) goto error; if (!X509_sign(x509, pkey, EVP_sha256())) @@ -186,7 +187,7 @@ #endif } -#ifdef _DEBUG +#if !defined(NDEBUG) // Print a certificate to the log, for debugging. static void PrintCert(X509* x509) { BIO* temp_memory_bio = BIO_new(BIO_s_mem()); @@ -215,7 +216,7 @@ LogSSLErrors("Generating certificate"); return NULL; } -#ifdef _DEBUG +#if !defined(NDEBUG) PrintCert(x509); #endif OpenSSLCertificate* ret = new OpenSSLCertificate(x509); @@ -373,6 +374,22 @@ #endif } +// Documented in sslidentity.h. +int64_t OpenSSLCertificate::CertificateExpirationTime() const { + ASN1_TIME* expire_time = X509_get_notAfter(x509_); + bool long_format; + + if (expire_time->type == V_ASN1_UTCTIME) { + long_format = false; + } else if (expire_time->type == V_ASN1_GENERALIZEDTIME) { + long_format = true; + } else { + return -1; + } + + return ASN1TimeToSec(expire_time->data, expire_time->length, long_format); +} + OpenSSLIdentity::OpenSSLIdentity(OpenSSLKeyPair* key_pair, OpenSSLCertificate* certificate) : key_pair_(key_pair), certificate_(certificate) { @@ -401,8 +418,9 @@ SSLIdentityParams params; params.key_params = key_params; params.common_name = common_name; - params.not_before = CERTIFICATE_WINDOW; - params.not_after = CERTIFICATE_LIFETIME; + time_t now = time(NULL); + params.not_before = now + CERTIFICATE_WINDOW; + params.not_after = now + CERTIFICATE_LIFETIME; return GenerateInternal(params); }
diff --git a/webrtc/base/opensslidentity.h b/webrtc/base/opensslidentity.h index f957ef2..c8aa69a 100644 --- a/webrtc/base/opensslidentity.h +++ b/webrtc/base/opensslidentity.h
@@ -87,6 +87,8 @@ bool GetSignatureDigestAlgorithm(std::string* algorithm) const override; bool GetChain(SSLCertChain** chain) const override; + int64_t CertificateExpirationTime() const override; + private: void AddReference() const;
diff --git a/webrtc/base/opensslstreamadapter.cc b/webrtc/base/opensslstreamadapter.cc index 67ed5db..7563f17 100644 --- a/webrtc/base/opensslstreamadapter.cc +++ b/webrtc/base/opensslstreamadapter.cc
@@ -43,17 +43,19 @@ #endif #ifdef HAVE_DTLS_SRTP -// SRTP cipher suite table +// SRTP cipher suite table. |internal_name| is used to construct a +// colon-separated profile strings which is needed by +// SSL_CTX_set_tlsext_use_srtp(). struct SrtpCipherMapEntry { - const char* external_name; const char* internal_name; + const int id; }; // This isn't elegant, but it's better than an external reference static SrtpCipherMapEntry SrtpCipherMap[] = { - {CS_AES_CM_128_HMAC_SHA1_80, "SRTP_AES128_CM_SHA1_80"}, - {CS_AES_CM_128_HMAC_SHA1_32, "SRTP_AES128_CM_SHA1_32"}, - {NULL, NULL}}; + {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80}, + {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32}, + {nullptr, 0}}; #endif #ifndef OPENSSL_IS_BORINGSSL @@ -158,10 +160,12 @@ static int kDefaultSslEcCipher12 = static_cast<uint16_t>(TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256); // Fallback cipher for DTLS 1.2 if hardware-accelerated AES-GCM is unavailable. +// TODO(davidben): Switch to the standardized CHACHA20_POLY1305 variant when +// available. static int kDefaultSslCipher12NoAesGcm = - static_cast<uint16_t>(TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305); + static_cast<uint16_t>(TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD); static int kDefaultSslEcCipher12NoAesGcm = - static_cast<uint16_t>(TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305); + static_cast<uint16_t>(TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD); #else // !OPENSSL_IS_BORINGSSL // OpenSSL sorts differently than BoringSSL, so the default cipher doesn't // change between TLS 1.0 and TLS 1.2 with the current setup. @@ -297,12 +301,13 @@ : SSLStreamAdapter(stream), state_(SSL_NONE), role_(SSL_CLIENT), - ssl_read_needs_write_(false), ssl_write_needs_read_(false), - ssl_(NULL), ssl_ctx_(NULL), + ssl_read_needs_write_(false), + ssl_write_needs_read_(false), + ssl_(NULL), + ssl_ctx_(NULL), custom_verification_succeeded_(false), ssl_mode_(SSL_MODE_TLS), - ssl_max_version_(SSL_PROTOCOL_TLS_11) { -} + ssl_max_version_(SSL_PROTOCOL_TLS_12) {} OpenSSLStreamAdapter::~OpenSSLStreamAdapter() { Cleanup(); @@ -348,9 +353,9 @@ return true; } -std::string OpenSSLStreamAdapter::GetSslCipherSuiteName(int cipher) { +std::string OpenSSLStreamAdapter::SslCipherSuiteToName(int cipher_suite) { #ifdef OPENSSL_IS_BORINGSSL - const SSL_CIPHER* ssl_cipher = SSL_get_cipher_by_value(cipher); + const SSL_CIPHER* ssl_cipher = SSL_get_cipher_by_value(cipher_suite); if (!ssl_cipher) { return std::string(); } @@ -361,7 +366,7 @@ #else for (const SslCipherMapEntry* entry = kSslCipherMap; entry->rfc_name; ++entry) { - if (cipher == entry->openssl_id) { + if (cipher_suite == static_cast<int>(entry->openssl_id)) { return entry->rfc_name; } } @@ -369,7 +374,7 @@ #endif } -bool OpenSSLStreamAdapter::GetSslCipherSuite(int* cipher) { +bool OpenSSLStreamAdapter::GetSslCipherSuite(int* cipher_suite) { if (state_ != SSL_CONNECTED) return false; @@ -378,7 +383,7 @@ return false; } - *cipher = static_cast<uint16_t>(SSL_CIPHER_get_id(current_cipher)); + *cipher_suite = static_cast<uint16_t>(SSL_CIPHER_get_id(current_cipher)); return true; } @@ -405,20 +410,20 @@ #endif } -bool OpenSSLStreamAdapter::SetDtlsSrtpCiphers( - const std::vector<std::string>& ciphers) { +bool OpenSSLStreamAdapter::SetDtlsSrtpCryptoSuites( + const std::vector<int>& ciphers) { #ifdef HAVE_DTLS_SRTP std::string internal_ciphers; if (state_ != SSL_NONE) return false; - for (std::vector<std::string>::const_iterator cipher = ciphers.begin(); + for (std::vector<int>::const_iterator cipher = ciphers.begin(); cipher != ciphers.end(); ++cipher) { bool found = false; - for (SrtpCipherMapEntry *entry = SrtpCipherMap; entry->internal_name; + for (SrtpCipherMapEntry* entry = SrtpCipherMap; entry->internal_name; ++entry) { - if (*cipher == entry->external_name) { + if (*cipher == entry->id) { found = true; if (!internal_ciphers.empty()) internal_ciphers += ":"; @@ -443,7 +448,7 @@ #endif } -bool OpenSSLStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) { +bool OpenSSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) { #ifdef HAVE_DTLS_SRTP ASSERT(state_ == SSL_CONNECTED); if (state_ != SSL_CONNECTED) @@ -455,17 +460,9 @@ if (!srtp_profile) return false; - for (SrtpCipherMapEntry *entry = SrtpCipherMap; - entry->internal_name; ++entry) { - if (!strcmp(entry->internal_name, srtp_profile->name)) { - *cipher = entry->external_name; - return true; - } - } - - ASSERT(false); // This should never happen - - return false; + *crypto_suite = srtp_profile->id; + ASSERT(!SrtpCryptoSuiteToName(*crypto_suite).empty()); + return true; #else return false; #endif @@ -994,7 +991,7 @@ return NULL; } -#ifdef _DEBUG +#if !defined(NDEBUG) SSL_CTX_set_info_callback(ctx, OpenSSLAdapter::SSLInfoCallback); #endif
diff --git a/webrtc/base/opensslstreamadapter.h b/webrtc/base/opensslstreamadapter.h index 0f3ded9..e57b2a3 100644 --- a/webrtc/base/opensslstreamadapter.h +++ b/webrtc/base/opensslstreamadapter.h
@@ -88,7 +88,7 @@ StreamState GetState() const override; // TODO(guoweis): Move this away from a static class method. - static std::string GetSslCipherSuiteName(int cipher); + static std::string SslCipherSuiteToName(int crypto_suite); bool GetSslCipherSuite(int* cipher) override; @@ -101,8 +101,8 @@ size_t result_len) override; // DTLS-SRTP interface - bool SetDtlsSrtpCiphers(const std::vector<std::string>& ciphers) override; - bool GetDtlsSrtpCipher(std::string* cipher) override; + bool SetDtlsSrtpCryptoSuites(const std::vector<int>& crypto_suites) override; + bool GetDtlsSrtpCryptoSuite(int* crypto_suite) override; // Capabilities interfaces static bool HaveDtls();
diff --git a/webrtc/base/optional.h b/webrtc/base/optional.h new file mode 100644 index 0000000..b8071e6 --- /dev/null +++ b/webrtc/base/optional.h
@@ -0,0 +1,139 @@ +/* + * 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_OPTIONAL_H_ +#define WEBRTC_BASE_OPTIONAL_H_ + +#include <algorithm> +#include <utility> + +#include "webrtc/base/checks.h" + +namespace rtc { + +// Simple std::experimental::optional-wannabe. It either contains a T or not. +// In order to keep the implementation simple and portable, this implementation +// actually contains a (default-constructed) T even when it supposedly doesn't +// contain a value; use e.g. rtc::scoped_ptr<T> instead if that's too +// expensive. +// +// A moved-from Optional<T> may only be destroyed, and assigned to if T allows +// being assigned to after having been moved from. Specifically, you may not +// assume that it just doesn't contain a value anymore. +// +// Examples of good places to use Optional: +// +// - As a class or struct member, when the member doesn't always have a value: +// struct Prisoner { +// std::string name; +// Optional<int> cell_number; // Empty if not currently incarcerated. +// }; +// +// - As a return value for functions that may fail to return a value on all +// allowed inputs. For example, a function that searches an array might +// return an Optional<size_t> (the index where it found the element, or +// nothing if it didn't find it); and a function that parses numbers might +// return Optional<double> (the parsed number, or nothing if parsing failed). +// +// Examples of bad places to use Optional: +// +// - As a return value for functions that may fail because of disallowed +// inputs. For example, a string length function should not return +// Optional<size_t> so that it can return nothing in case the caller passed +// it a null pointer; the function should probably use RTC_[D]CHECK instead, +// and return plain size_t. +// +// - As a return value for functions that may fail to return a value on all +// allowed inputs, but need to tell the caller what went wrong. Returning +// Optional<double> when parsing a single number as in the example above +// might make sense, but any larger parse job is probably going to need to +// tell the caller what the problem was, not just that there was one. +// +// TODO(kwiberg): Get rid of this class when the standard library has +// std::optional (and we're allowed to use it). +template <typename T> +class Optional final { + public: + // Construct an empty Optional. + Optional() : has_value_(false) {} + + // Construct an Optional that contains a value. + explicit Optional(const T& val) : value_(val), has_value_(true) {} + explicit Optional(T&& val) : value_(std::move(val)), has_value_(true) {} + + // Copy and move constructors. + // TODO(kwiberg): =default the move constructor when MSVC supports it. + Optional(const Optional&) = default; + Optional(Optional&& m) + : value_(std::move(m.value_)), has_value_(m.has_value_) {} + + // Assignment. + // TODO(kwiberg): =default the move assignment op when MSVC supports it. + Optional& operator=(const Optional&) = default; + Optional& operator=(Optional&& m) { + value_ = std::move(m.value_); + has_value_ = m.has_value_; + return *this; + } + + friend void swap(Optional& m1, Optional& m2) { + using std::swap; + swap(m1.value_, m2.value_); + swap(m1.has_value_, m2.has_value_); + } + + // Conversion to bool to test if we have a value. + explicit operator bool() const { return has_value_; } + + // Dereferencing. Only allowed if we have a value. + const T* operator->() const { + RTC_DCHECK(has_value_); + return &value_; + } + T* operator->() { + RTC_DCHECK(has_value_); + return &value_; + } + const T& operator*() const { + RTC_DCHECK(has_value_); + return value_; + } + T& operator*() { + RTC_DCHECK(has_value_); + return value_; + } + + // Dereference with a default value in case we don't have a value. + const T& value_or(const T& default_val) const { + return has_value_ ? value_ : default_val; + } + + // Equality tests. Two Optionals are equal if they contain equivalent values, + // or + // if they're both empty. + friend bool operator==(const Optional& m1, const Optional& m2) { + return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ + : m1.has_value_ == m2.has_value_; + } + friend bool operator!=(const Optional& m1, const Optional& m2) { + return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ + : m1.has_value_ != m2.has_value_; + } + + private: + // Invariant: Unless *this has been moved from, value_ is default-initialized + // (or copied or moved from a default-initialized T) if !has_value_. + T value_; + bool has_value_; +}; + +} // namespace rtc + +#endif // WEBRTC_BASE_OPTIONAL_H_
diff --git a/webrtc/base/optional_unittest.cc b/webrtc/base/optional_unittest.cc new file mode 100644 index 0000000..eabf091 --- /dev/null +++ b/webrtc/base/optional_unittest.cc
@@ -0,0 +1,489 @@ +/* + * 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 <sstream> +#include <string> +#include <utility> +#include <vector> + +#include "webrtc/base/gunit.h" +#include "webrtc/base/optional.h" + +namespace rtc { + +namespace { + +// Class whose instances logs various method calls (constructor, destructor, +// etc.). Each instance has a unique ID (a simple global sequence number) and +// an origin ID. When a copy is made, the new object gets a fresh ID but copies +// the origin ID from the original. When a new Logger is created from scratch, +// it gets a fresh ID, and the origin ID is the same as the ID (default +// constructor) or given as an argument (explicit constructor). +class Logger { + public: + Logger() : id_(next_id_++), origin_(id_) { Log("default constructor"); } + explicit Logger(int origin) : id_(next_id_++), origin_(origin) { + Log("explicit constructor"); + } + Logger(const Logger& other) : id_(next_id_++), origin_(other.origin_) { + LogFrom("copy constructor", other); + } + Logger(Logger&& other) : id_(next_id_++), origin_(other.origin_) { + LogFrom("move constructor", other); + } + ~Logger() { Log("destructor"); } + Logger& operator=(const Logger& other) { + origin_ = other.origin_; + LogFrom("operator= copy", other); + return *this; + } + Logger& operator=(Logger&& other) { + origin_ = other.origin_; + LogFrom("operator= move", other); + return *this; + } + friend void swap(Logger& a, Logger& b) { + using std::swap; + swap(a.origin_, b.origin_); + Log2("swap", a, b); + } + friend bool operator==(const Logger& a, const Logger& b) { + Log2("operator==", a, b); + return a.origin_ == b.origin_; + } + friend bool operator!=(const Logger& a, const Logger& b) { + Log2("operator!=", a, b); + return a.origin_ != b.origin_; + } + void Foo() { Log("Foo()"); } + void Foo() const { Log("Foo() const"); } + static rtc::scoped_ptr<std::vector<std::string>> Setup() { + auto s = rtc_make_scoped_ptr(new std::vector<std::string>); + Logger::log_ = s.get(); + Logger::next_id_ = 0; + return s; + } + + private: + int id_; + int origin_; + static std::vector<std::string>* log_; + static int next_id_; + void Log(const char* msg) const { + std::ostringstream oss; + oss << id_ << ':' << origin_ << ". " << msg; + log_->push_back(oss.str()); + } + void LogFrom(const char* msg, const Logger& other) const { + std::ostringstream oss; + oss << id_ << ':' << origin_ << ". " << msg << " (from " << other.id_ << ':' + << other.origin_ << ")"; + log_->push_back(oss.str()); + } + static void Log2(const char* msg, const Logger& a, const Logger& b) { + std::ostringstream oss; + oss << msg << ' ' << a.id_ << ':' << a.origin_ << ", " << b.id_ << ':' + << b.origin_; + log_->push_back(oss.str()); + } +}; + +std::vector<std::string>* Logger::log_ = nullptr; +int Logger::next_id_ = 0; + +// Append all the other args to the vector pointed to by the first arg. +template <typename T> +void VectorAppend(std::vector<T>* v) {} +template <typename T, typename... Ts> +void VectorAppend(std::vector<T>* v, const T& e, Ts... es) { + v->push_back(e); + VectorAppend(v, es...); +} + +// Create a vector of strings. Because we're not allowed to use +// std::initializer_list. +template <typename... Ts> +std::vector<std::string> V(Ts... es) { + std::vector<std::string> strings; + VectorAppend(&strings, static_cast<std::string>(es)...); + return strings; +} + +} // namespace + +TEST(OptionalTest, TestConstructDefault) { + auto log = Logger::Setup(); + { + Optional<Logger> x; + EXPECT_FALSE(x); + } + EXPECT_EQ(V("0:0. default constructor", "0:0. destructor"), *log); +} + +TEST(OptionalTest, TestConstructCopyEmpty) { + auto log = Logger::Setup(); + { + Optional<Logger> x; + EXPECT_FALSE(x); + auto y = x; + EXPECT_FALSE(y); + } + EXPECT_EQ(V("0:0. default constructor", "1:0. copy constructor (from 0:0)", + "1:0. destructor", "0:0. destructor"), + *log); +} + +TEST(OptionalTest, TestConstructCopyFull) { + auto log = Logger::Setup(); + { + Logger a; + Optional<Logger> x(a); + EXPECT_TRUE(x); + log->push_back("---"); + auto y = x; + EXPECT_TRUE(y); + log->push_back("---"); + } + EXPECT_EQ(V("0:0. default constructor", "1:0. copy constructor (from 0:0)", + "---", "2:0. copy constructor (from 1:0)", "---", + "2:0. destructor", "1:0. destructor", "0:0. destructor"), + *log); +} + +TEST(OptionalTest, TestConstructMoveEmpty) { + auto log = Logger::Setup(); + { + Optional<Logger> x; + EXPECT_FALSE(x); + auto y = std::move(x); + EXPECT_FALSE(y); + } + EXPECT_EQ(V("0:0. default constructor", "1:0. move constructor (from 0:0)", + "1:0. destructor", "0:0. destructor"), + *log); +} + +TEST(OptionalTest, TestConstructMoveFull) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(17)); + EXPECT_TRUE(x); + log->push_back("---"); + auto y = std::move(x); + EXPECT_TRUE(x); + EXPECT_TRUE(y); + log->push_back("---"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", + "0:17. destructor", "---", "2:17. move constructor (from 1:17)", "---", + "2:17. destructor", "1:17. destructor"), + *log); +} + +TEST(OptionalTest, TestCopyAssignToEmptyFromEmpty) { + auto log = Logger::Setup(); + { + Optional<Logger> x, y; + x = y; + } + EXPECT_EQ( + V("0:0. default constructor", "1:1. default constructor", + "0:1. operator= copy (from 1:1)", "1:1. destructor", "0:1. destructor"), + *log); +} + +TEST(OptionalTest, TestCopyAssignToFullFromEmpty) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(17)); + Optional<Logger> y; + log->push_back("---"); + x = y; + log->push_back("---"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", + "0:17. destructor", "2:2. default constructor", "---", + "1:2. operator= copy (from 2:2)", "---", "2:2. destructor", + "1:2. destructor"), + *log); +} + +TEST(OptionalTest, TestCopyAssignToEmptyFromFull) { + auto log = Logger::Setup(); + { + Optional<Logger> x; + Optional<Logger> y(Logger(17)); + log->push_back("---"); + x = y; + log->push_back("---"); + } + EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", + "2:17. move constructor (from 1:17)", "1:17. destructor", "---", + "0:17. operator= copy (from 2:17)", "---", "2:17. destructor", + "0:17. destructor"), + *log); +} + +TEST(OptionalTest, TestCopyAssignToFullFromFull) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(17)); + Optional<Logger> y(Logger(42)); + log->push_back("---"); + x = y; + log->push_back("---"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", + "0:17. destructor", "2:42. explicit constructor", + "3:42. move constructor (from 2:42)", "2:42. destructor", "---", + "1:42. operator= copy (from 3:42)", "---", "3:42. destructor", + "1:42. destructor"), + *log); +} + +TEST(OptionalTest, TestCopyAssignToEmptyFromT) { + auto log = Logger::Setup(); + { + Optional<Logger> x; + Logger y(17); + log->push_back("---"); + x = Optional<Logger>(y); + log->push_back("---"); + } + EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", "---", + "2:17. copy constructor (from 1:17)", + "0:17. operator= move (from 2:17)", "2:17. destructor", "---", + "1:17. destructor", "0:17. destructor"), + *log); +} + +TEST(OptionalTest, TestCopyAssignToFullFromT) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(17)); + Logger y(42); + log->push_back("---"); + x = Optional<Logger>(y); + log->push_back("---"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", + "0:17. destructor", "2:42. explicit constructor", "---", + "3:42. copy constructor (from 2:42)", + "1:42. operator= move (from 3:42)", "3:42. destructor", "---", + "2:42. destructor", "1:42. destructor"), + *log); +} + +TEST(OptionalTest, TestMoveAssignToEmptyFromEmpty) { + auto log = Logger::Setup(); + { + Optional<Logger> x, y; + x = std::move(y); + } + EXPECT_EQ( + V("0:0. default constructor", "1:1. default constructor", + "0:1. operator= move (from 1:1)", "1:1. destructor", "0:1. destructor"), + *log); +} + +TEST(OptionalTest, TestMoveAssignToFullFromEmpty) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(17)); + Optional<Logger> y; + log->push_back("---"); + x = std::move(y); + log->push_back("---"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", + "0:17. destructor", "2:2. default constructor", "---", + "1:2. operator= move (from 2:2)", "---", "2:2. destructor", + "1:2. destructor"), + *log); +} + +TEST(OptionalTest, TestMoveAssignToEmptyFromFull) { + auto log = Logger::Setup(); + { + Optional<Logger> x; + Optional<Logger> y(Logger(17)); + log->push_back("---"); + x = std::move(y); + log->push_back("---"); + } + EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", + "2:17. move constructor (from 1:17)", "1:17. destructor", "---", + "0:17. operator= move (from 2:17)", "---", "2:17. destructor", + "0:17. destructor"), + *log); +} + +TEST(OptionalTest, TestMoveAssignToFullFromFull) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(17)); + Optional<Logger> y(Logger(42)); + log->push_back("---"); + x = std::move(y); + log->push_back("---"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", + "0:17. destructor", "2:42. explicit constructor", + "3:42. move constructor (from 2:42)", "2:42. destructor", "---", + "1:42. operator= move (from 3:42)", "---", "3:42. destructor", + "1:42. destructor"), + *log); +} + +TEST(OptionalTest, TestMoveAssignToEmptyFromT) { + auto log = Logger::Setup(); + { + Optional<Logger> x; + Logger y(17); + log->push_back("---"); + x = Optional<Logger>(std::move(y)); + log->push_back("---"); + } + EXPECT_EQ(V("0:0. default constructor", "1:17. explicit constructor", "---", + "2:17. move constructor (from 1:17)", + "0:17. operator= move (from 2:17)", "2:17. destructor", "---", + "1:17. destructor", "0:17. destructor"), + *log); +} + +TEST(OptionalTest, TestMoveAssignToFullFromT) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(17)); + Logger y(42); + log->push_back("---"); + x = Optional<Logger>(std::move(y)); + log->push_back("---"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", + "0:17. destructor", "2:42. explicit constructor", "---", + "3:42. move constructor (from 2:42)", + "1:42. operator= move (from 3:42)", "3:42. destructor", "---", + "2:42. destructor", "1:42. destructor"), + *log); +} + +TEST(OptionalTest, TestDereference) { + auto log = Logger::Setup(); + { + Optional<Logger> x(Logger(42)); + const auto& y = x; + log->push_back("---"); + x->Foo(); + y->Foo(); + std::move(x)->Foo(); + std::move(y)->Foo(); + log->push_back("---"); + (*x).Foo(); + (*y).Foo(); + (*std::move(x)).Foo(); + (*std::move(y)).Foo(); + log->push_back("---"); + } + EXPECT_EQ(V("0:42. explicit constructor", + "1:42. move constructor (from 0:42)", "0:42. destructor", "---", + "1:42. Foo()", "1:42. Foo() const", "1:42. Foo()", + "1:42. Foo() const", "---", "1:42. Foo()", "1:42. Foo() const", + "1:42. Foo()", "1:42. Foo() const", "---", "1:42. destructor"), + *log); +} + +TEST(OptionalTest, TestDereferenceWithDefault) { + auto log = Logger::Setup(); + { + const Logger a(17), b(42); + Optional<Logger> x(a); + Optional<Logger> y; + log->push_back("-1-"); + EXPECT_EQ(a, x.value_or(Logger(42))); + log->push_back("-2-"); + EXPECT_EQ(b, y.value_or(Logger(42))); + log->push_back("-3-"); + EXPECT_EQ(a, Optional<Logger>(Logger(17)).value_or(b)); + log->push_back("-4-"); + EXPECT_EQ(b, Optional<Logger>().value_or(b)); + log->push_back("-5-"); + } + EXPECT_EQ( + V("0:17. explicit constructor", "1:42. explicit constructor", + "2:17. copy constructor (from 0:17)", "3:3. default constructor", "-1-", + "4:42. explicit constructor", "operator== 0:17, 2:17", + "4:42. destructor", "-2-", "5:42. explicit constructor", + "operator== 1:42, 5:42", "5:42. destructor", "-3-", + "6:17. explicit constructor", "7:17. move constructor (from 6:17)", + "operator== 0:17, 7:17", "7:17. destructor", "6:17. destructor", "-4-", + "8:8. default constructor", "operator== 1:42, 1:42", "8:8. destructor", + "-5-", "3:3. destructor", "2:17. destructor", "1:42. destructor", + "0:17. destructor"), + *log); +} + +TEST(OptionalTest, TestEquality) { + auto log = Logger::Setup(); + { + Logger a(17), b(42); + Optional<Logger> ma1(a), ma2(a), mb(b), me1, me2; + log->push_back("---"); + EXPECT_EQ(ma1, ma1); + EXPECT_EQ(ma1, ma2); + EXPECT_NE(ma1, mb); + EXPECT_NE(ma1, me1); + EXPECT_EQ(me1, me1); + EXPECT_EQ(me1, me2); + log->push_back("---"); + } + EXPECT_EQ(V("0:17. explicit constructor", "1:42. explicit constructor", + "2:17. copy constructor (from 0:17)", + "3:17. copy constructor (from 0:17)", + "4:42. copy constructor (from 1:42)", "5:5. default constructor", + "6:6. default constructor", "---", "operator== 2:17, 2:17", + "operator== 2:17, 3:17", "operator!= 2:17, 4:42", "---", + "6:6. destructor", "5:5. destructor", "4:42. destructor", + "3:17. destructor", "2:17. destructor", "1:42. destructor", + "0:17. destructor"), + *log); +} + +TEST(OptionalTest, TestSwap) { + auto log = Logger::Setup(); + { + Logger a(17), b(42); + Optional<Logger> x1(a), x2(b), y1(a), y2, z1, z2; + log->push_back("---"); + swap(x1, x2); // Swap full <-> full. + swap(y1, y2); // Swap full <-> empty. + swap(z1, z2); // Swap empty <-> empty. + log->push_back("---"); + } + EXPECT_EQ(V("0:17. explicit constructor", "1:42. explicit constructor", + "2:17. copy constructor (from 0:17)", + "3:42. copy constructor (from 1:42)", + "4:17. copy constructor (from 0:17)", "5:5. default constructor", + "6:6. default constructor", "7:7. default constructor", "---", + "swap 2:42, 3:17", "swap 4:5, 5:17", "swap 6:7, 7:6", "---", + "7:6. destructor", "6:7. destructor", "5:17. destructor", + "4:5. destructor", "3:17. destructor", "2:42. destructor", + "1:42. destructor", "0:17. destructor"), + *log); +} + +} // namespace rtc
diff --git a/webrtc/base/physicalsocketserver.cc b/webrtc/base/physicalsocketserver.cc index 86abcf2..3e45452 100644 --- a/webrtc/base/physicalsocketserver.cc +++ b/webrtc/base/physicalsocketserver.cc
@@ -39,11 +39,11 @@ #include <algorithm> #include <map> +#include "webrtc/base/arraysize.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/byteorder.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" -#include "webrtc/base/nethelpers.h" #include "webrtc/base/physicalsocketserver.h" #include "webrtc/base/timeutils.h" #include "webrtc/base/winping.h" @@ -96,463 +96,669 @@ static const int ICMP_PING_TIMEOUT_MILLIS = 10000u; #endif -class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> { - public: - PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET) - : ss_(ss), s_(s), enabled_events_(0), error_(0), - state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED), - resolver_(NULL) { +PhysicalSocket::PhysicalSocket(PhysicalSocketServer* ss, SOCKET s) + : ss_(ss), s_(s), enabled_events_(0), error_(0), + state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED), + resolver_(nullptr) { #if defined(WEBRTC_WIN) - // EnsureWinsockInit() ensures that winsock is initialized. The default - // version of this function doesn't do anything because winsock is - // initialized by constructor of a static object. If neccessary libjingle - // users can link it with a different version of this function by replacing - // win32socketinit.cc. See win32socketinit.cc for more details. - EnsureWinsockInit(); + // EnsureWinsockInit() ensures that winsock is initialized. The default + // version of this function doesn't do anything because winsock is + // initialized by constructor of a static object. If neccessary libjingle + // users can link it with a different version of this function by replacing + // win32socketinit.cc. See win32socketinit.cc for more details. + EnsureWinsockInit(); #endif - if (s_ != INVALID_SOCKET) { - enabled_events_ = DE_READ | DE_WRITE; + if (s_ != INVALID_SOCKET) { + enabled_events_ = DE_READ | DE_WRITE; - int type = SOCK_STREAM; - socklen_t len = sizeof(type); - VERIFY(0 == getsockopt(s_, SOL_SOCKET, SO_TYPE, (SockOptArg)&type, &len)); - udp_ = (SOCK_DGRAM == type); - } - } - - ~PhysicalSocket() override { - Close(); - } - - // Creates the underlying OS socket (same as the "socket" function). - virtual bool Create(int family, int type) { - Close(); - s_ = ::socket(family, type, 0); + int type = SOCK_STREAM; + socklen_t len = sizeof(type); + VERIFY(0 == getsockopt(s_, SOL_SOCKET, SO_TYPE, (SockOptArg)&type, &len)); udp_ = (SOCK_DGRAM == type); - UpdateLastError(); - if (udp_) - enabled_events_ = DE_READ | DE_WRITE; - return s_ != INVALID_SOCKET; } +} - SocketAddress GetLocalAddress() const override { - sockaddr_storage addr_storage = {0}; - socklen_t addrlen = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int result = ::getsockname(s_, addr, &addrlen); - SocketAddress address; - if (result >= 0) { - SocketAddressFromSockAddrStorage(addr_storage, &address); - } else { - LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket=" - << s_; - } - return address; +PhysicalSocket::~PhysicalSocket() { + Close(); +} + +bool PhysicalSocket::Create(int family, int type) { + Close(); + s_ = ::socket(family, type, 0); + udp_ = (SOCK_DGRAM == type); + UpdateLastError(); + if (udp_) + enabled_events_ = DE_READ | DE_WRITE; + return s_ != INVALID_SOCKET; +} + +SocketAddress PhysicalSocket::GetLocalAddress() const { + sockaddr_storage addr_storage = {0}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int result = ::getsockname(s_, addr, &addrlen); + SocketAddress address; + if (result >= 0) { + SocketAddressFromSockAddrStorage(addr_storage, &address); + } else { + LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket=" + << s_; } + return address; +} - SocketAddress GetRemoteAddress() const override { - sockaddr_storage addr_storage = {0}; - socklen_t addrlen = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int result = ::getpeername(s_, addr, &addrlen); - SocketAddress address; - if (result >= 0) { - SocketAddressFromSockAddrStorage(addr_storage, &address); - } else { - LOG(LS_WARNING) << "GetRemoteAddress: unable to get remote addr, socket=" - << s_; - } - return address; +SocketAddress PhysicalSocket::GetRemoteAddress() const { + sockaddr_storage addr_storage = {0}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int result = ::getpeername(s_, addr, &addrlen); + SocketAddress address; + if (result >= 0) { + SocketAddressFromSockAddrStorage(addr_storage, &address); + } else { + LOG(LS_WARNING) << "GetRemoteAddress: unable to get remote addr, socket=" + << s_; } + return address; +} - int Bind(const SocketAddress& bind_addr) override { - sockaddr_storage addr_storage; - size_t len = bind_addr.ToSockAddrStorage(&addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int err = ::bind(s_, addr, static_cast<int>(len)); - UpdateLastError(); -#ifdef _DEBUG - if (0 == err) { - dbg_addr_ = "Bound @ "; - dbg_addr_.append(GetLocalAddress().ToString()); - } -#endif // _DEBUG - return err; +int PhysicalSocket::Bind(const SocketAddress& bind_addr) { + sockaddr_storage addr_storage; + size_t len = bind_addr.ToSockAddrStorage(&addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int err = ::bind(s_, addr, static_cast<int>(len)); + UpdateLastError(); +#if !defined(NDEBUG) + if (0 == err) { + dbg_addr_ = "Bound @ "; + dbg_addr_.append(GetLocalAddress().ToString()); } +#endif + return err; +} - int Connect(const SocketAddress& addr) override { - // TODO: Implicit creation is required to reconnect... - // ...but should we make it more explicit? - if (state_ != CS_CLOSED) { - SetError(EALREADY); - return SOCKET_ERROR; - } - if (addr.IsUnresolved()) { - LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect"; - resolver_ = new AsyncResolver(); - resolver_->SignalDone.connect(this, &PhysicalSocket::OnResolveResult); - resolver_->Start(addr); - state_ = CS_CONNECTING; - return 0; - } - - return DoConnect(addr); +int PhysicalSocket::Connect(const SocketAddress& addr) { + // TODO(pthatcher): Implicit creation is required to reconnect... + // ...but should we make it more explicit? + if (state_ != CS_CLOSED) { + SetError(EALREADY); + return SOCKET_ERROR; } - - int DoConnect(const SocketAddress& connect_addr) { - if ((s_ == INVALID_SOCKET) && - !Create(connect_addr.family(), SOCK_STREAM)) { - return SOCKET_ERROR; - } - sockaddr_storage addr_storage; - size_t len = connect_addr.ToSockAddrStorage(&addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int err = ::connect(s_, addr, static_cast<int>(len)); - UpdateLastError(); - if (err == 0) { - state_ = CS_CONNECTED; - } else if (IsBlockingError(GetError())) { - state_ = CS_CONNECTING; - enabled_events_ |= DE_CONNECT; - } else { - return SOCKET_ERROR; - } - - enabled_events_ |= DE_READ | DE_WRITE; + if (addr.IsUnresolvedIP()) { + LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect"; + resolver_ = new AsyncResolver(); + resolver_->SignalDone.connect(this, &PhysicalSocket::OnResolveResult); + resolver_->Start(addr); + state_ = CS_CONNECTING; return 0; } - int GetError() const override { - CritScope cs(&crit_); - return error_; + return DoConnect(addr); +} + +int PhysicalSocket::DoConnect(const SocketAddress& connect_addr) { + if ((s_ == INVALID_SOCKET) && + !Create(connect_addr.family(), SOCK_STREAM)) { + return SOCKET_ERROR; + } + sockaddr_storage addr_storage; + size_t len = connect_addr.ToSockAddrStorage(&addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int err = ::connect(s_, addr, static_cast<int>(len)); + UpdateLastError(); + if (err == 0) { + state_ = CS_CONNECTED; + } else if (IsBlockingError(GetError())) { + state_ = CS_CONNECTING; + enabled_events_ |= DE_CONNECT; + } else { + return SOCKET_ERROR; } - void SetError(int error) override { - CritScope cs(&crit_); - error_ = error; - } + enabled_events_ |= DE_READ | DE_WRITE; + return 0; +} - ConnState GetState() const override { return state_; } +int PhysicalSocket::GetError() const { + CritScope cs(&crit_); + return error_; +} - int GetOption(Option opt, int* value) override { - int slevel; - int sopt; - if (TranslateOption(opt, &slevel, &sopt) == -1) - return -1; - socklen_t optlen = sizeof(*value); - int ret = ::getsockopt(s_, slevel, sopt, (SockOptArg)value, &optlen); - if (ret != -1 && opt == OPT_DONTFRAGMENT) { +void PhysicalSocket::SetError(int error) { + CritScope cs(&crit_); + error_ = error; +} + +AsyncSocket::ConnState PhysicalSocket::GetState() const { + return state_; +} + +int PhysicalSocket::GetOption(Option opt, int* value) { + int slevel; + int sopt; + if (TranslateOption(opt, &slevel, &sopt) == -1) + return -1; + socklen_t optlen = sizeof(*value); + int ret = ::getsockopt(s_, slevel, sopt, (SockOptArg)value, &optlen); + if (ret != -1 && opt == OPT_DONTFRAGMENT) { #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - *value = (*value != IP_PMTUDISC_DONT) ? 1 : 0; + *value = (*value != IP_PMTUDISC_DONT) ? 1 : 0; #endif - } - return ret; } + return ret; +} - int SetOption(Option opt, int value) override { - int slevel; - int sopt; - if (TranslateOption(opt, &slevel, &sopt) == -1) - return -1; - if (opt == OPT_DONTFRAGMENT) { +int PhysicalSocket::SetOption(Option opt, int value) { + int slevel; + int sopt; + if (TranslateOption(opt, &slevel, &sopt) == -1) + return -1; + if (opt == OPT_DONTFRAGMENT) { #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - value = (value) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; + value = (value) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; #endif - } - return ::setsockopt(s_, slevel, sopt, (SockOptArg)&value, sizeof(value)); } + return ::setsockopt(s_, slevel, sopt, (SockOptArg)&value, sizeof(value)); +} - int Send(const void* pv, size_t cb) override { - int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb, +int PhysicalSocket::Send(const void* pv, size_t cb) { + int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb, #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - // Suppress SIGPIPE. Without this, attempting to send on a socket whose - // other end is closed will result in a SIGPIPE signal being raised to - // our process, which by default will terminate the process, which we - // don't want. By specifying this flag, we'll just get the error EPIPE - // instead and can handle the error gracefully. - MSG_NOSIGNAL + // Suppress SIGPIPE. Without this, attempting to send on a socket whose + // other end is closed will result in a SIGPIPE signal being raised to + // our process, which by default will terminate the process, which we + // don't want. By specifying this flag, we'll just get the error EPIPE + // instead and can handle the error gracefully. + MSG_NOSIGNAL #else - 0 + 0 #endif - ); - UpdateLastError(); - MaybeRemapSendError(); - // We have seen minidumps where this may be false. - ASSERT(sent <= static_cast<int>(cb)); - if ((sent < 0) && IsBlockingError(GetError())) { - enabled_events_ |= DE_WRITE; - } - return sent; + ); + UpdateLastError(); + MaybeRemapSendError(); + // We have seen minidumps where this may be false. + ASSERT(sent <= static_cast<int>(cb)); + if ((sent < 0) && IsBlockingError(GetError())) { + enabled_events_ |= DE_WRITE; } + return sent; +} - int SendTo(const void* buffer, - size_t length, - const SocketAddress& addr) override { - sockaddr_storage saddr; - size_t len = addr.ToSockAddrStorage(&saddr); - int sent = ::sendto( - s_, static_cast<const char *>(buffer), static_cast<int>(length), +int PhysicalSocket::SendTo(const void* buffer, + size_t length, + const SocketAddress& addr) { + sockaddr_storage saddr; + size_t len = addr.ToSockAddrStorage(&saddr); + int sent = ::sendto( + s_, static_cast<const char *>(buffer), static_cast<int>(length), #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - // Suppress SIGPIPE. See above for explanation. - MSG_NOSIGNAL, + // Suppress SIGPIPE. See above for explanation. + MSG_NOSIGNAL, #else - 0, + 0, #endif - reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len)); - UpdateLastError(); - MaybeRemapSendError(); - // We have seen minidumps where this may be false. - ASSERT(sent <= static_cast<int>(length)); - if ((sent < 0) && IsBlockingError(GetError())) { - enabled_events_ |= DE_WRITE; - } - return sent; + reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len)); + UpdateLastError(); + MaybeRemapSendError(); + // We have seen minidumps where this may be false. + ASSERT(sent <= static_cast<int>(length)); + if ((sent < 0) && IsBlockingError(GetError())) { + enabled_events_ |= DE_WRITE; } + return sent; +} - int Recv(void* buffer, size_t length) override { - int received = ::recv(s_, static_cast<char*>(buffer), - static_cast<int>(length), 0); - if ((received == 0) && (length != 0)) { - // Note: on graceful shutdown, recv can return 0. In this case, we - // pretend it is blocking, and then signal close, so that simplifying - // assumptions can be made about Recv. - LOG(LS_WARNING) << "EOF from socket; deferring close event"; - // Must turn this back on so that the select() loop will notice the close - // event. - enabled_events_ |= DE_READ; - SetError(EWOULDBLOCK); - return SOCKET_ERROR; - } - UpdateLastError(); - int error = GetError(); - bool success = (received >= 0) || IsBlockingError(error); - if (udp_ || success) { - enabled_events_ |= DE_READ; - } - if (!success) { - LOG_F(LS_VERBOSE) << "Error = " << error; - } - return received; +int PhysicalSocket::Recv(void* buffer, size_t length) { + int received = ::recv(s_, static_cast<char*>(buffer), + static_cast<int>(length), 0); + if ((received == 0) && (length != 0)) { + // Note: on graceful shutdown, recv can return 0. In this case, we + // pretend it is blocking, and then signal close, so that simplifying + // assumptions can be made about Recv. + LOG(LS_WARNING) << "EOF from socket; deferring close event"; + // Must turn this back on so that the select() loop will notice the close + // event. + enabled_events_ |= DE_READ; + SetError(EWOULDBLOCK); + return SOCKET_ERROR; } - - int RecvFrom(void* buffer, size_t length, SocketAddress* out_addr) override { - sockaddr_storage addr_storage; - socklen_t addr_len = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int received = ::recvfrom(s_, static_cast<char*>(buffer), - static_cast<int>(length), 0, addr, &addr_len); - UpdateLastError(); - if ((received >= 0) && (out_addr != NULL)) - SocketAddressFromSockAddrStorage(addr_storage, out_addr); - int error = GetError(); - bool success = (received >= 0) || IsBlockingError(error); - if (udp_ || success) { - enabled_events_ |= DE_READ; - } - if (!success) { - LOG_F(LS_VERBOSE) << "Error = " << error; - } - return received; + UpdateLastError(); + int error = GetError(); + bool success = (received >= 0) || IsBlockingError(error); + if (udp_ || success) { + enabled_events_ |= DE_READ; } - - int Listen(int backlog) override { - int err = ::listen(s_, backlog); - UpdateLastError(); - if (err == 0) { - state_ = CS_CONNECTING; - enabled_events_ |= DE_ACCEPT; -#ifdef _DEBUG - dbg_addr_ = "Listening @ "; - dbg_addr_.append(GetLocalAddress().ToString()); -#endif // _DEBUG - } - return err; + if (!success) { + LOG_F(LS_VERBOSE) << "Error = " << error; } + return received; +} - AsyncSocket* Accept(SocketAddress* out_addr) override { - sockaddr_storage addr_storage; - socklen_t addr_len = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - SOCKET s = ::accept(s_, addr, &addr_len); - UpdateLastError(); - if (s == INVALID_SOCKET) - return NULL; +int PhysicalSocket::RecvFrom(void* buffer, + size_t length, + SocketAddress* out_addr) { + sockaddr_storage addr_storage; + socklen_t addr_len = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int received = ::recvfrom(s_, static_cast<char*>(buffer), + static_cast<int>(length), 0, addr, &addr_len); + UpdateLastError(); + if ((received >= 0) && (out_addr != nullptr)) + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + int error = GetError(); + bool success = (received >= 0) || IsBlockingError(error); + if (udp_ || success) { + enabled_events_ |= DE_READ; + } + if (!success) { + LOG_F(LS_VERBOSE) << "Error = " << error; + } + return received; +} + +int PhysicalSocket::Listen(int backlog) { + int err = ::listen(s_, backlog); + UpdateLastError(); + if (err == 0) { + state_ = CS_CONNECTING; enabled_events_ |= DE_ACCEPT; - if (out_addr != NULL) - SocketAddressFromSockAddrStorage(addr_storage, out_addr); - return ss_->WrapSocket(s); +#if !defined(NDEBUG) + dbg_addr_ = "Listening @ "; + dbg_addr_.append(GetLocalAddress().ToString()); +#endif } + return err; +} - int Close() override { - if (s_ == INVALID_SOCKET) - return 0; - int err = ::closesocket(s_); - UpdateLastError(); - s_ = INVALID_SOCKET; - state_ = CS_CLOSED; - enabled_events_ = 0; - if (resolver_) { - resolver_->Destroy(false); - resolver_ = NULL; - } - return err; +AsyncSocket* PhysicalSocket::Accept(SocketAddress* out_addr) { + // Always re-subscribe DE_ACCEPT to make sure new incoming connections will + // trigger an event even if DoAccept returns an error here. + enabled_events_ |= DE_ACCEPT; + sockaddr_storage addr_storage; + socklen_t addr_len = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + SOCKET s = DoAccept(s_, addr, &addr_len); + UpdateLastError(); + if (s == INVALID_SOCKET) + return nullptr; + if (out_addr != nullptr) + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + return ss_->WrapSocket(s); +} + +int PhysicalSocket::Close() { + if (s_ == INVALID_SOCKET) + return 0; + int err = ::closesocket(s_); + UpdateLastError(); + s_ = INVALID_SOCKET; + state_ = CS_CLOSED; + enabled_events_ = 0; + if (resolver_) { + resolver_->Destroy(false); + resolver_ = nullptr; } + return err; +} - int EstimateMTU(uint16_t* mtu) override { - SocketAddress addr = GetRemoteAddress(); - if (addr.IsAnyIP()) { - SetError(ENOTCONN); - return -1; - } +int PhysicalSocket::EstimateMTU(uint16_t* mtu) { + SocketAddress addr = GetRemoteAddress(); + if (addr.IsAnyIP()) { + SetError(ENOTCONN); + return -1; + } #if defined(WEBRTC_WIN) - // Gets the interface MTU (TTL=1) for the interface used to reach |addr|. - WinPing ping; - if (!ping.IsValid()) { + // Gets the interface MTU (TTL=1) for the interface used to reach |addr|. + WinPing ping; + if (!ping.IsValid()) { + SetError(EINVAL); // can't think of a better error ID + return -1; + } + int header_size = ICMP_HEADER_SIZE; + if (addr.family() == AF_INET6) { + header_size += IPV6_HEADER_SIZE; + } else if (addr.family() == AF_INET) { + header_size += IP_HEADER_SIZE; + } + + for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { + int32_t size = PACKET_MAXIMUMS[level] - header_size; + WinPing::PingResult result = ping.Ping(addr.ipaddr(), size, + ICMP_PING_TIMEOUT_MILLIS, + 1, false); + if (result == WinPing::PING_FAIL) { SetError(EINVAL); // can't think of a better error ID return -1; + } else if (result != WinPing::PING_TOO_LARGE) { + *mtu = PACKET_MAXIMUMS[level]; + return 0; } - int header_size = ICMP_HEADER_SIZE; - if (addr.family() == AF_INET6) { - header_size += IPV6_HEADER_SIZE; - } else if (addr.family() == AF_INET) { - header_size += IP_HEADER_SIZE; - } + } - for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { - int32_t size = PACKET_MAXIMUMS[level] - header_size; - WinPing::PingResult result = ping.Ping(addr.ipaddr(), size, - ICMP_PING_TIMEOUT_MILLIS, - 1, false); - if (result == WinPing::PING_FAIL) { - SetError(EINVAL); // can't think of a better error ID - return -1; - } else if (result != WinPing::PING_TOO_LARGE) { - *mtu = PACKET_MAXIMUMS[level]; - return 0; - } - } - - ASSERT(false); - return -1; + ASSERT(false); + return -1; #elif defined(WEBRTC_MAC) - // No simple way to do this on Mac OS X. - // SIOCGIFMTU would work if we knew which interface would be used, but - // figuring that out is pretty complicated. For now we'll return an error - // and let the caller pick a default MTU. - SetError(EINVAL); - return -1; + // No simple way to do this on Mac OS X. + // SIOCGIFMTU would work if we knew which interface would be used, but + // figuring that out is pretty complicated. For now we'll return an error + // and let the caller pick a default MTU. + SetError(EINVAL); + return -1; #elif defined(WEBRTC_LINUX) - // Gets the path MTU. - int value; - socklen_t vlen = sizeof(value); - int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen); - if (err < 0) { - UpdateLastError(); - return err; - } + // Gets the path MTU. + int value; + socklen_t vlen = sizeof(value); + int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen); + if (err < 0) { + UpdateLastError(); + return err; + } - ASSERT((0 <= value) && (value <= 65536)); - *mtu = value; - return 0; + ASSERT((0 <= value) && (value <= 65536)); + *mtu = value; + return 0; #elif defined(__native_client__) - // Most socket operations, including this, will fail in NaCl's sandbox. - error_ = EACCES; - return -1; + // Most socket operations, including this, will fail in NaCl's sandbox. + error_ = EACCES; + return -1; #endif +} + + +SOCKET PhysicalSocket::DoAccept(SOCKET socket, + sockaddr* addr, + socklen_t* addrlen) { + return ::accept(socket, addr, addrlen); +} + +void PhysicalSocket::OnResolveResult(AsyncResolverInterface* resolver) { + if (resolver != resolver_) { + return; } - SocketServer* socketserver() { return ss_; } - - protected: - void OnResolveResult(AsyncResolverInterface* resolver) { - if (resolver != resolver_) { - return; - } - - int error = resolver_->GetError(); - if (error == 0) { - error = DoConnect(resolver_->address()); - } else { - Close(); - } - - if (error) { - SetError(error); - SignalCloseEvent(this, error); - } + int error = resolver_->GetError(); + if (error == 0) { + error = DoConnect(resolver_->address()); + } else { + Close(); } - void UpdateLastError() { - SetError(LAST_SYSTEM_ERROR); + if (error) { + SetError(error); + SignalCloseEvent(this, error); } +} - void MaybeRemapSendError() { +void PhysicalSocket::UpdateLastError() { + SetError(LAST_SYSTEM_ERROR); +} + +void PhysicalSocket::MaybeRemapSendError() { #if defined(WEBRTC_MAC) - // https://developer.apple.com/library/mac/documentation/Darwin/ - // Reference/ManPages/man2/sendto.2.html - // ENOBUFS - The output queue for a network interface is full. - // This generally indicates that the interface has stopped sending, - // but may be caused by transient congestion. - if (GetError() == ENOBUFS) { - SetError(EWOULDBLOCK); - } -#endif + // https://developer.apple.com/library/mac/documentation/Darwin/ + // Reference/ManPages/man2/sendto.2.html + // ENOBUFS - The output queue for a network interface is full. + // This generally indicates that the interface has stopped sending, + // but may be caused by transient congestion. + if (GetError() == ENOBUFS) { + SetError(EWOULDBLOCK); } +#endif +} - static int TranslateOption(Option opt, int* slevel, int* sopt) { - switch (opt) { - case OPT_DONTFRAGMENT: +int PhysicalSocket::TranslateOption(Option opt, int* slevel, int* sopt) { + switch (opt) { + case OPT_DONTFRAGMENT: #if defined(WEBRTC_WIN) - *slevel = IPPROTO_IP; - *sopt = IP_DONTFRAGMENT; - break; + *slevel = IPPROTO_IP; + *sopt = IP_DONTFRAGMENT; + break; #elif defined(WEBRTC_MAC) || defined(BSD) || defined(__native_client__) - LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported."; - return -1; + LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported."; + return -1; #elif defined(WEBRTC_POSIX) - *slevel = IPPROTO_IP; - *sopt = IP_MTU_DISCOVER; - break; + *slevel = IPPROTO_IP; + *sopt = IP_MTU_DISCOVER; + break; #endif - case OPT_RCVBUF: - *slevel = SOL_SOCKET; - *sopt = SO_RCVBUF; - break; - case OPT_SNDBUF: - *slevel = SOL_SOCKET; - *sopt = SO_SNDBUF; - break; - case OPT_NODELAY: - *slevel = IPPROTO_TCP; - *sopt = TCP_NODELAY; - break; - case OPT_DSCP: - LOG(LS_WARNING) << "Socket::OPT_DSCP not supported."; - return -1; - case OPT_RTP_SENDTIME_EXTN_ID: - return -1; // No logging is necessary as this not a OS socket option. - default: - ASSERT(false); - return -1; - } - return 0; + case OPT_RCVBUF: + *slevel = SOL_SOCKET; + *sopt = SO_RCVBUF; + break; + case OPT_SNDBUF: + *slevel = SOL_SOCKET; + *sopt = SO_SNDBUF; + break; + case OPT_NODELAY: + *slevel = IPPROTO_TCP; + *sopt = TCP_NODELAY; + break; + case OPT_DSCP: + LOG(LS_WARNING) << "Socket::OPT_DSCP not supported."; + return -1; + case OPT_RTP_SENDTIME_EXTN_ID: + return -1; // No logging is necessary as this not a OS socket option. + default: + ASSERT(false); + return -1; } + return 0; +} - PhysicalSocketServer* ss_; - SOCKET s_; - uint8_t enabled_events_; - bool udp_; - int error_; - // Protects |error_| that is accessed from different threads. - mutable CriticalSection crit_; - ConnState state_; - AsyncResolver* resolver_; +SocketDispatcher::SocketDispatcher(PhysicalSocketServer *ss) +#if defined(WEBRTC_WIN) + : PhysicalSocket(ss), id_(0), signal_close_(false) +#else + : PhysicalSocket(ss) +#endif +{ +} -#ifdef _DEBUG - std::string dbg_addr_; -#endif // _DEBUG; -}; +SocketDispatcher::SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) +#if defined(WEBRTC_WIN) + : PhysicalSocket(ss, s), id_(0), signal_close_(false) +#else + : PhysicalSocket(ss, s) +#endif +{ +} + +SocketDispatcher::~SocketDispatcher() { + Close(); +} + +bool SocketDispatcher::Initialize() { + ASSERT(s_ != INVALID_SOCKET); + // Must be a non-blocking +#if defined(WEBRTC_WIN) + u_long argp = 1; + ioctlsocket(s_, FIONBIO, &argp); +#elif defined(WEBRTC_POSIX) + fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); +#endif + ss_->Add(this); + return true; +} + +bool SocketDispatcher::Create(int type) { + return Create(AF_INET, type); +} + +bool SocketDispatcher::Create(int family, int type) { + // Change the socket to be non-blocking. + if (!PhysicalSocket::Create(family, type)) + return false; + + if (!Initialize()) + return false; + +#if defined(WEBRTC_WIN) + do { id_ = ++next_id_; } while (id_ == 0); +#endif + return true; +} + +#if defined(WEBRTC_WIN) + +WSAEVENT SocketDispatcher::GetWSAEvent() { + return WSA_INVALID_EVENT; +} + +SOCKET SocketDispatcher::GetSocket() { + return s_; +} + +bool SocketDispatcher::CheckSignalClose() { + if (!signal_close_) + return false; + + char ch; + if (recv(s_, &ch, 1, MSG_PEEK) > 0) + return false; + + state_ = CS_CLOSED; + signal_close_ = false; + SignalCloseEvent(this, signal_err_); + return true; +} + +int SocketDispatcher::next_id_ = 0; + +#elif defined(WEBRTC_POSIX) + +int SocketDispatcher::GetDescriptor() { + return s_; +} + +bool SocketDispatcher::IsDescriptorClosed() { + // We don't have a reliable way of distinguishing end-of-stream + // from readability. So test on each readable call. Is this + // inefficient? Probably. + char ch; + ssize_t res = ::recv(s_, &ch, 1, MSG_PEEK); + if (res > 0) { + // Data available, so not closed. + return false; + } else if (res == 0) { + // EOF, so closed. + return true; + } else { // error + switch (errno) { + // Returned if we've already closed s_. + case EBADF: + // Returned during ungraceful peer shutdown. + case ECONNRESET: + return true; + default: + // Assume that all other errors are just blocking errors, meaning the + // connection is still good but we just can't read from it right now. + // This should only happen when connecting (and at most once), because + // in all other cases this function is only called if the file + // descriptor is already known to be in the readable state. However, + // it's not necessary a problem if we spuriously interpret a + // "connection lost"-type error as a blocking error, because typically + // the next recv() will get EOF, so we'll still eventually notice that + // the socket is closed. + LOG_ERR(LS_WARNING) << "Assuming benign blocking error"; + return false; + } + } +} + +#endif // WEBRTC_POSIX + +uint32_t SocketDispatcher::GetRequestedEvents() { + return enabled_events_; +} + +void SocketDispatcher::OnPreEvent(uint32_t ff) { + if ((ff & DE_CONNECT) != 0) + state_ = CS_CONNECTED; + +#if defined(WEBRTC_WIN) + // We set CS_CLOSED from CheckSignalClose. +#elif defined(WEBRTC_POSIX) + if ((ff & DE_CLOSE) != 0) + state_ = CS_CLOSED; +#endif +} + +#if defined(WEBRTC_WIN) + +void SocketDispatcher::OnEvent(uint32_t ff, int err) { + int cache_id = id_; + // Make sure we deliver connect/accept first. Otherwise, consumers may see + // something like a READ followed by a CONNECT, which would be odd. + if (((ff & DE_CONNECT) != 0) && (id_ == cache_id)) { + if (ff != DE_CONNECT) + LOG(LS_VERBOSE) << "Signalled with DE_CONNECT: " << ff; + enabled_events_ &= ~DE_CONNECT; +#if !defined(NDEBUG) + dbg_addr_ = "Connected @ "; + dbg_addr_.append(GetRemoteAddress().ToString()); +#endif + SignalConnectEvent(this); + } + if (((ff & DE_ACCEPT) != 0) && (id_ == cache_id)) { + enabled_events_ &= ~DE_ACCEPT; + SignalReadEvent(this); + } + if ((ff & DE_READ) != 0) { + enabled_events_ &= ~DE_READ; + SignalReadEvent(this); + } + if (((ff & DE_WRITE) != 0) && (id_ == cache_id)) { + enabled_events_ &= ~DE_WRITE; + SignalWriteEvent(this); + } + if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) { + signal_close_ = true; + signal_err_ = err; + } +} + +#elif defined(WEBRTC_POSIX) + +void SocketDispatcher::OnEvent(uint32_t ff, int err) { + // Make sure we deliver connect/accept first. Otherwise, consumers may see + // something like a READ followed by a CONNECT, which would be odd. + if ((ff & DE_CONNECT) != 0) { + enabled_events_ &= ~DE_CONNECT; + SignalConnectEvent(this); + } + if ((ff & DE_ACCEPT) != 0) { + enabled_events_ &= ~DE_ACCEPT; + SignalReadEvent(this); + } + if ((ff & DE_READ) != 0) { + enabled_events_ &= ~DE_READ; + SignalReadEvent(this); + } + if ((ff & DE_WRITE) != 0) { + enabled_events_ &= ~DE_WRITE; + SignalWriteEvent(this); + } + if ((ff & DE_CLOSE) != 0) { + // The socket is now dead to us, so stop checking it. + enabled_events_ = 0; + SignalCloseEvent(this, err); + } +} + +#endif // WEBRTC_POSIX + +int SocketDispatcher::Close() { + if (s_ == INVALID_SOCKET) + return 0; + +#if defined(WEBRTC_WIN) + id_ = 0; + signal_close_ = false; +#endif + ss_->Remove(this); + return PhysicalSocket::Close(); +} #if defined(WEBRTC_POSIX) class EventDispatcher : public Dispatcher { @@ -628,8 +834,8 @@ // Returns true if the given signal number is set. bool IsSignalSet(int signum) const { - ASSERT(signum < ARRAY_SIZE(received_signal_)); - if (signum < ARRAY_SIZE(received_signal_)) { + ASSERT(signum < static_cast<int>(arraysize(received_signal_))); + if (signum < static_cast<int>(arraysize(received_signal_))) { return received_signal_[signum]; } else { return false; @@ -638,8 +844,8 @@ // Clears the given signal number. void ClearSignal(int signum) { - ASSERT(signum < ARRAY_SIZE(received_signal_)); - if (signum < ARRAY_SIZE(received_signal_)) { + ASSERT(signum < static_cast<int>(arraysize(received_signal_))); + if (signum < static_cast<int>(arraysize(received_signal_))) { received_signal_[signum] = false; } } @@ -654,7 +860,7 @@ // user-level state of the process, since the handler could be executed at any // time on any thread. void OnPosixSignalReceived(int signum) { - if (signum >= ARRAY_SIZE(received_signal_)) { + if (signum >= static_cast<int>(arraysize(received_signal_))) { // We don't have space in our array for this. return; } @@ -790,116 +996,6 @@ PhysicalSocketServer *owner_; }; -class SocketDispatcher : public Dispatcher, public PhysicalSocket { - public: - explicit SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) { - } - SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) { - } - - ~SocketDispatcher() override { - Close(); - } - - bool Initialize() { - ss_->Add(this); - fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); - return true; - } - - virtual bool Create(int type) { - return Create(AF_INET, type); - } - - bool Create(int family, int type) override { - // Change the socket to be non-blocking. - if (!PhysicalSocket::Create(family, type)) - return false; - - return Initialize(); - } - - int GetDescriptor() override { return s_; } - - bool IsDescriptorClosed() override { - // We don't have a reliable way of distinguishing end-of-stream - // from readability. So test on each readable call. Is this - // inefficient? Probably. - char ch; - ssize_t res = ::recv(s_, &ch, 1, MSG_PEEK); - if (res > 0) { - // Data available, so not closed. - return false; - } else if (res == 0) { - // EOF, so closed. - return true; - } else { // error - switch (errno) { - // Returned if we've already closed s_. - case EBADF: - // Returned during ungraceful peer shutdown. - case ECONNRESET: - return true; - default: - // Assume that all other errors are just blocking errors, meaning the - // connection is still good but we just can't read from it right now. - // This should only happen when connecting (and at most once), because - // in all other cases this function is only called if the file - // descriptor is already known to be in the readable state. However, - // it's not necessary a problem if we spuriously interpret a - // "connection lost"-type error as a blocking error, because typically - // the next recv() will get EOF, so we'll still eventually notice that - // the socket is closed. - LOG_ERR(LS_WARNING) << "Assuming benign blocking error"; - return false; - } - } - } - - uint32_t GetRequestedEvents() override { return enabled_events_; } - - void OnPreEvent(uint32_t ff) override { - if ((ff & DE_CONNECT) != 0) - state_ = CS_CONNECTED; - if ((ff & DE_CLOSE) != 0) - state_ = CS_CLOSED; - } - - void OnEvent(uint32_t ff, int err) override { - // Make sure we deliver connect/accept first. Otherwise, consumers may see - // something like a READ followed by a CONNECT, which would be odd. - if ((ff & DE_CONNECT) != 0) { - enabled_events_ &= ~DE_CONNECT; - SignalConnectEvent(this); - } - if ((ff & DE_ACCEPT) != 0) { - enabled_events_ &= ~DE_ACCEPT; - SignalReadEvent(this); - } - if ((ff & DE_READ) != 0) { - enabled_events_ &= ~DE_READ; - SignalReadEvent(this); - } - if ((ff & DE_WRITE) != 0) { - enabled_events_ &= ~DE_WRITE; - SignalWriteEvent(this); - } - if ((ff & DE_CLOSE) != 0) { - // The socket is now dead to us, so stop checking it. - enabled_events_ = 0; - SignalCloseEvent(this, err); - } - } - - int Close() override { - if (s_ == INVALID_SOCKET) - return 0; - - ss_->Remove(this); - return PhysicalSocket::Close(); - } -}; - class FileDispatcher: public Dispatcher, public AsyncFile { public: FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) { @@ -1013,130 +1109,6 @@ PhysicalSocketServer* ss_; WSAEVENT hev_; }; - -class SocketDispatcher : public Dispatcher, public PhysicalSocket { - public: - static int next_id_; - int id_; - bool signal_close_; - int signal_err_; - - SocketDispatcher(PhysicalSocketServer* ss) - : PhysicalSocket(ss), - id_(0), - signal_close_(false) { - } - - SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) - : PhysicalSocket(ss, s), - id_(0), - signal_close_(false) { - } - - virtual ~SocketDispatcher() { - Close(); - } - - bool Initialize() { - ASSERT(s_ != INVALID_SOCKET); - // Must be a non-blocking - u_long argp = 1; - ioctlsocket(s_, FIONBIO, &argp); - ss_->Add(this); - return true; - } - - virtual bool Create(int type) { - return Create(AF_INET, type); - } - - virtual bool Create(int family, int type) { - // Create socket - if (!PhysicalSocket::Create(family, type)) - return false; - - if (!Initialize()) - return false; - - do { id_ = ++next_id_; } while (id_ == 0); - return true; - } - - virtual int Close() { - if (s_ == INVALID_SOCKET) - return 0; - - id_ = 0; - signal_close_ = false; - ss_->Remove(this); - return PhysicalSocket::Close(); - } - - virtual uint32_t GetRequestedEvents() { return enabled_events_; } - - virtual void OnPreEvent(uint32_t ff) { - if ((ff & DE_CONNECT) != 0) - state_ = CS_CONNECTED; - // We set CS_CLOSED from CheckSignalClose. - } - - virtual void OnEvent(uint32_t ff, int err) { - int cache_id = id_; - // Make sure we deliver connect/accept first. Otherwise, consumers may see - // something like a READ followed by a CONNECT, which would be odd. - if (((ff & DE_CONNECT) != 0) && (id_ == cache_id)) { - if (ff != DE_CONNECT) - LOG(LS_VERBOSE) << "Signalled with DE_CONNECT: " << ff; - enabled_events_ &= ~DE_CONNECT; -#ifdef _DEBUG - dbg_addr_ = "Connected @ "; - dbg_addr_.append(GetRemoteAddress().ToString()); -#endif // _DEBUG - SignalConnectEvent(this); - } - if (((ff & DE_ACCEPT) != 0) && (id_ == cache_id)) { - enabled_events_ &= ~DE_ACCEPT; - SignalReadEvent(this); - } - if ((ff & DE_READ) != 0) { - enabled_events_ &= ~DE_READ; - SignalReadEvent(this); - } - if (((ff & DE_WRITE) != 0) && (id_ == cache_id)) { - enabled_events_ &= ~DE_WRITE; - SignalWriteEvent(this); - } - if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) { - signal_close_ = true; - signal_err_ = err; - } - } - - virtual WSAEVENT GetWSAEvent() { - return WSA_INVALID_EVENT; - } - - virtual SOCKET GetSocket() { - return s_; - } - - virtual bool CheckSignalClose() { - if (!signal_close_) - return false; - - char ch; - if (recv(s_, &ch, 1, MSG_PEEK) > 0) - return false; - - state_ = CS_CLOSED; - signal_close_ = false; - SignalCloseEvent(this, signal_err_); - return true; - } -}; - -int SocketDispatcher::next_id_ = 0; - #endif // WEBRTC_WIN // Sets the value of a boolean value to false when signaled. @@ -1189,7 +1161,7 @@ return socket; } else { delete socket; - return 0; + return nullptr; } } @@ -1203,7 +1175,7 @@ return dispatcher; } else { delete dispatcher; - return 0; + return nullptr; } } @@ -1213,7 +1185,7 @@ return dispatcher; } else { delete dispatcher; - return 0; + return nullptr; } } @@ -1342,7 +1314,7 @@ int errcode = 0; // Reap any error code, which can be signaled through reads or writes. - // TODO: Should we set errcode if getsockopt fails? + // TODO(pthatcher): Should we set errcode if getsockopt fails? if (FD_ISSET(fd, &fdsRead) || FD_ISSET(fd, &fdsWrite)) { socklen_t len = sizeof(errcode); ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &len); @@ -1351,7 +1323,7 @@ // Check readable descriptors. If we're waiting on an accept, signal // that. Otherwise we're waiting for data, check to see if we're // readable or really closed. - // TODO: Only peek at TCP descriptors. + // TODO(pthatcher): Only peek at TCP descriptors. if (FD_ISSET(fd, &fdsRead)) { FD_CLR(fd, &fdsRead); if (pdispatcher->GetRequestedEvents() & DE_ACCEPT) { @@ -1525,7 +1497,7 @@ if (dw == WSA_WAIT_FAILED) { // Failed? - // TODO: need a better strategy than this! + // TODO(pthatcher): need a better strategy than this! WSAGetLastError(); ASSERT(false); return false;
diff --git a/webrtc/base/physicalsocketserver.h b/webrtc/base/physicalsocketserver.h index af09e0b..ae1f10f 100644 --- a/webrtc/base/physicalsocketserver.h +++ b/webrtc/base/physicalsocketserver.h
@@ -14,6 +14,7 @@ #include <vector> #include "webrtc/base/asyncfile.h" +#include "webrtc/base/nethelpers.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/socketserver.h" #include "webrtc/base/criticalsection.h" @@ -115,6 +116,107 @@ #endif }; +class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> { + public: + PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET); + ~PhysicalSocket() override; + + // Creates the underlying OS socket (same as the "socket" function). + virtual bool Create(int family, int type); + + SocketAddress GetLocalAddress() const override; + SocketAddress GetRemoteAddress() const override; + + int Bind(const SocketAddress& bind_addr) override; + int Connect(const SocketAddress& addr) override; + + int GetError() const override; + void SetError(int error) override; + + ConnState GetState() const override; + + int GetOption(Option opt, int* value) override; + int SetOption(Option opt, int value) override; + + int Send(const void* pv, size_t cb) override; + int SendTo(const void* buffer, + size_t length, + const SocketAddress& addr) override; + + int Recv(void* buffer, size_t length) override; + int RecvFrom(void* buffer, size_t length, SocketAddress* out_addr) override; + + int Listen(int backlog) override; + AsyncSocket* Accept(SocketAddress* out_addr) override; + + int Close() override; + + int EstimateMTU(uint16_t* mtu) override; + + SocketServer* socketserver() { return ss_; } + + protected: + int DoConnect(const SocketAddress& connect_addr); + + // Make virtual so ::accept can be overwritten in tests. + virtual SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen); + + void OnResolveResult(AsyncResolverInterface* resolver); + + void UpdateLastError(); + void MaybeRemapSendError(); + + static int TranslateOption(Option opt, int* slevel, int* sopt); + + PhysicalSocketServer* ss_; + SOCKET s_; + uint8_t enabled_events_; + bool udp_; + mutable CriticalSection crit_; + int error_ GUARDED_BY(crit_); + ConnState state_; + AsyncResolver* resolver_; + +#if !defined(NDEBUG) + std::string dbg_addr_; +#endif +}; + +class SocketDispatcher : public Dispatcher, public PhysicalSocket { + public: + explicit SocketDispatcher(PhysicalSocketServer *ss); + SocketDispatcher(SOCKET s, PhysicalSocketServer *ss); + ~SocketDispatcher() override; + + bool Initialize(); + + virtual bool Create(int type); + bool Create(int family, int type) override; + +#if defined(WEBRTC_WIN) + WSAEVENT GetWSAEvent() override; + SOCKET GetSocket() override; + bool CheckSignalClose() override; +#elif defined(WEBRTC_POSIX) + int GetDescriptor() override; + bool IsDescriptorClosed() override; +#endif + + uint32_t GetRequestedEvents() override; + void OnPreEvent(uint32_t ff) override; + void OnEvent(uint32_t ff, int err) override; + + int Close() override; + +#if defined(WEBRTC_WIN) + private: + static int next_id_; + int id_; + bool signal_close_; + int signal_err_; +#endif // WEBRTC_WIN +}; + } // namespace rtc #endif // WEBRTC_BASE_PHYSICALSOCKETSERVER_H__
diff --git a/webrtc/base/physicalsocketserver_unittest.cc b/webrtc/base/physicalsocketserver_unittest.cc index 6c7be9f..a2fde80 100644 --- a/webrtc/base/physicalsocketserver_unittest.cc +++ b/webrtc/base/physicalsocketserver_unittest.cc
@@ -18,13 +18,85 @@ #include "webrtc/base/socket_unittest.h" #include "webrtc/base/testutils.h" #include "webrtc/base/thread.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace rtc { -class PhysicalSocketTest : public SocketTest { +class PhysicalSocketTest; + +class FakeSocketDispatcher : public SocketDispatcher { + public: + explicit FakeSocketDispatcher(PhysicalSocketServer* ss) + : SocketDispatcher(ss) { + } + + protected: + SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen) override; }; +class FakePhysicalSocketServer : public PhysicalSocketServer { + public: + explicit FakePhysicalSocketServer(PhysicalSocketTest* test) + : test_(test) { + } + + AsyncSocket* CreateAsyncSocket(int type) override { + SocketDispatcher* dispatcher = new FakeSocketDispatcher(this); + if (dispatcher->Create(type)) { + return dispatcher; + } else { + delete dispatcher; + return nullptr; + } + } + + AsyncSocket* CreateAsyncSocket(int family, int type) override { + SocketDispatcher* dispatcher = new FakeSocketDispatcher(this); + if (dispatcher->Create(family, type)) { + return dispatcher; + } else { + delete dispatcher; + return nullptr; + } + } + + PhysicalSocketTest* GetTest() const { return test_; } + + private: + PhysicalSocketTest* test_; +}; + +class PhysicalSocketTest : public SocketTest { + public: + // Set flag to simluate failures when calling "::accept" on a AsyncSocket. + void SetFailAccept(bool fail) { fail_accept_ = fail; } + bool FailAccept() const { return fail_accept_; } + + protected: + PhysicalSocketTest() + : server_(new FakePhysicalSocketServer(this)), + scope_(server_.get()), + fail_accept_(false) { + } + + void ConnectInternalAcceptError(const IPAddress& loopback); + + rtc::scoped_ptr<FakePhysicalSocketServer> server_; + SocketServerScope scope_; + bool fail_accept_; +}; + +SOCKET FakeSocketDispatcher::DoAccept(SOCKET socket, + sockaddr* addr, + socklen_t* addrlen) { + FakePhysicalSocketServer* ss = + static_cast<FakePhysicalSocketServer*>(socketserver()); + if (ss->GetTest()->FailAccept()) { + return INVALID_SOCKET; + } + + return SocketDispatcher::DoAccept(socket, addr, addrlen); +} + TEST_F(PhysicalSocketTest, TestConnectIPv4) { SocketTest::TestConnectIPv4(); } @@ -51,6 +123,92 @@ SocketTest::TestConnectFailIPv4(); } +void PhysicalSocketTest::ConnectInternalAcceptError(const IPAddress& loopback) { + testing::StreamSink sink; + SocketAddress accept_addr; + + // Create two clients. + scoped_ptr<AsyncSocket> client1(server_->CreateAsyncSocket(loopback.family(), + SOCK_STREAM)); + sink.Monitor(client1.get()); + EXPECT_EQ(AsyncSocket::CS_CLOSED, client1->GetState()); + EXPECT_PRED1(IsUnspecOrEmptyIP, client1->GetLocalAddress().ipaddr()); + + scoped_ptr<AsyncSocket> client2(server_->CreateAsyncSocket(loopback.family(), + SOCK_STREAM)); + sink.Monitor(client2.get()); + EXPECT_EQ(AsyncSocket::CS_CLOSED, client2->GetState()); + EXPECT_PRED1(IsUnspecOrEmptyIP, client2->GetLocalAddress().ipaddr()); + + // Create server and listen. + scoped_ptr<AsyncSocket> server( + server_->CreateAsyncSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + EXPECT_EQ(AsyncSocket::CS_CONNECTING, server->GetState()); + + // Ensure no pending server connections, since we haven't done anything yet. + EXPECT_FALSE(sink.Check(server.get(), testing::SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_TRUE(accept_addr.IsNil()); + + // Attempt first connect to listening socket. + EXPECT_EQ(0, client1->Connect(server->GetLocalAddress())); + EXPECT_FALSE(client1->GetLocalAddress().IsNil()); + EXPECT_NE(server->GetLocalAddress(), client1->GetLocalAddress()); + + // Client is connecting, outcome not yet determined. + EXPECT_EQ(AsyncSocket::CS_CONNECTING, client1->GetState()); + EXPECT_FALSE(sink.Check(client1.get(), testing::SSE_OPEN)); + EXPECT_FALSE(sink.Check(client1.get(), testing::SSE_CLOSE)); + + // Server has pending connection, try to accept it (will fail). + EXPECT_TRUE_WAIT((sink.Check(server.get(), testing::SSE_READ)), kTimeout); + // Simulate "::accept" returning an error. + SetFailAccept(true); + scoped_ptr<AsyncSocket> accepted(server->Accept(&accept_addr)); + EXPECT_FALSE(accepted); + ASSERT_TRUE(accept_addr.IsNil()); + + // Ensure no more pending server connections. + EXPECT_FALSE(sink.Check(server.get(), testing::SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_TRUE(accept_addr.IsNil()); + + // Attempt second connect to listening socket. + EXPECT_EQ(0, client2->Connect(server->GetLocalAddress())); + EXPECT_FALSE(client2->GetLocalAddress().IsNil()); + EXPECT_NE(server->GetLocalAddress(), client2->GetLocalAddress()); + + // Client is connecting, outcome not yet determined. + EXPECT_EQ(AsyncSocket::CS_CONNECTING, client2->GetState()); + EXPECT_FALSE(sink.Check(client2.get(), testing::SSE_OPEN)); + EXPECT_FALSE(sink.Check(client2.get(), testing::SSE_CLOSE)); + + // Server has pending connection, try to accept it (will succeed). + EXPECT_TRUE_WAIT((sink.Check(server.get(), testing::SSE_READ)), kTimeout); + SetFailAccept(false); + scoped_ptr<AsyncSocket> accepted2(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted2); + EXPECT_FALSE(accept_addr.IsNil()); + EXPECT_EQ(accepted2->GetRemoteAddress(), accept_addr); +} + +TEST_F(PhysicalSocketTest, TestConnectAcceptErrorIPv4) { + ConnectInternalAcceptError(kIPv4Loopback); +} + +// Crashes on Linux. See webrtc:4923. +#if defined(WEBRTC_LINUX) +#define MAYBE_TestConnectAcceptErrorIPv6 DISABLED_TestConnectAcceptErrorIPv6 +#else +#define MAYBE_TestConnectAcceptErrorIPv6 TestConnectAcceptErrorIPv6 +#endif +TEST_F(PhysicalSocketTest, MAYBE_TestConnectAcceptErrorIPv6) { + ConnectInternalAcceptError(kIPv6Loopback); +} + // Crashes on Linux. See webrtc:4923. #if defined(WEBRTC_LINUX) #define MAYBE_TestConnectFailIPv6 DISABLED_TestConnectFailIPv6 @@ -215,8 +373,11 @@ // https://code.google.com/p/webrtc/issues/detail?id=4958 // TODO(deadbeef): Enable again once test is reimplemented to be unflaky. // Also disable for ASan. +// Disabled on Android: https://code.google.com/p/webrtc/issues/detail?id=4364 +// Disabled on Linux: https://bugs.chromium.org/p/webrtc/issues/detail?id=5233 #if defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) || \ - defined(ADDRESS_SANITIZER) + defined(ADDRESS_SANITIZER) || defined(WEBRTC_ANDROID) || \ + defined(WEBRTC_LINUX) #define MAYBE_TestUdpReadyToSendIPv4 DISABLED_TestUdpReadyToSendIPv4 #else #define MAYBE_TestUdpReadyToSendIPv4 TestUdpReadyToSendIPv4
diff --git a/webrtc/base/platform_thread.cc b/webrtc/base/platform_thread.cc index 4167392..05b7a25 100644 --- a/webrtc/base/platform_thread.cc +++ b/webrtc/base/platform_thread.cc
@@ -10,8 +10,6 @@ #include "webrtc/base/platform_thread.h" -#include <string.h> - #include "webrtc/base/checks.h" #if defined(WEBRTC_LINUX) @@ -58,7 +56,6 @@ } void SetCurrentThreadName(const char* name) { - RTC_DCHECK(strlen(name) < 64); #if defined(WEBRTC_WIN) struct { DWORD dwType; @@ -79,4 +76,175 @@ #endif } +namespace { +#if defined(WEBRTC_WIN) +void CALLBACK RaiseFlag(ULONG_PTR param) { + *reinterpret_cast<bool*>(param) = true; +} +#else +struct ThreadAttributes { + ThreadAttributes() { pthread_attr_init(&attr); } + ~ThreadAttributes() { pthread_attr_destroy(&attr); } + pthread_attr_t* operator&() { return &attr; } + pthread_attr_t attr; +}; +#endif // defined(WEBRTC_WIN) +} + +PlatformThread::PlatformThread(ThreadRunFunction func, + void* obj, + const char* thread_name) + : run_function_(func), + obj_(obj), + name_(thread_name ? thread_name : "webrtc"), +#if defined(WEBRTC_WIN) + stop_(false), + thread_(NULL) { +#else + stop_event_(false, false), + thread_(0) { +#endif // defined(WEBRTC_WIN) + RTC_DCHECK(func); + RTC_DCHECK(name_.length() < 64); +} + +PlatformThread::~PlatformThread() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +#if defined(WEBRTC_WIN) + RTC_DCHECK(!thread_); +#endif // defined(WEBRTC_WIN) +} + +#if defined(WEBRTC_WIN) +DWORD WINAPI PlatformThread::StartThread(void* param) { + static_cast<PlatformThread*>(param)->Run(); + return 0; +} +#else +void* PlatformThread::StartThread(void* param) { + static_cast<PlatformThread*>(param)->Run(); + return 0; +} +#endif // defined(WEBRTC_WIN) + +void PlatformThread::Start() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(!thread_) << "Thread already started?"; +#if defined(WEBRTC_WIN) + stop_ = false; + + // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION. + // Set the reserved stack stack size to 1M, which is the default on Windows + // and Linux. + DWORD thread_id; + thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this, + STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id); + RTC_CHECK(thread_) << "CreateThread failed"; +#else + ThreadAttributes attr; + // Set the stack stack size to 1M. + pthread_attr_setstacksize(&attr, 1024 * 1024); + RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this)); +#endif // defined(WEBRTC_WIN) +} + +bool PlatformThread::IsRunning() const { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +#if defined(WEBRTC_WIN) + return thread_ != nullptr; +#else + return thread_ != 0; +#endif // defined(WEBRTC_WIN) +} + +void PlatformThread::Stop() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (!IsRunning()) + return; + +#if defined(WEBRTC_WIN) + // Set stop_ to |true| on the worker thread. + QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_)); + WaitForSingleObject(thread_, INFINITE); + CloseHandle(thread_); + thread_ = nullptr; +#else + stop_event_.Set(); + RTC_CHECK_EQ(0, pthread_join(thread_, nullptr)); + thread_ = 0; +#endif // defined(WEBRTC_WIN) +} + +void PlatformThread::Run() { + if (!name_.empty()) + rtc::SetCurrentThreadName(name_.c_str()); + do { + // The interface contract of Start/Stop is that for a successfull call to + // Start, there should be at least one call to the run function. So we + // call the function before checking |stop_|. + if (!run_function_(obj_)) + break; +#if defined(WEBRTC_WIN) + // Alertable sleep to permit RaiseFlag to run and update |stop_|. + SleepEx(0, true); + } while (!stop_); +#else + } while (!stop_event_.Wait(0)); +#endif // defined(WEBRTC_WIN) +} + +bool PlatformThread::SetPriority(ThreadPriority priority) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(IsRunning()); +#if defined(WEBRTC_WIN) + return SetThreadPriority(thread_, priority) != FALSE; +#elif defined(__native_client__) + // Setting thread priorities is not supported in NaCl. + return true; +#elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX) + // TODO(tommi): Switch to the same mechanism as Chromium uses for changing + // thread priorities. + return true; +#else +#ifdef WEBRTC_THREAD_RR + const int policy = SCHED_RR; +#else + const int policy = SCHED_FIFO; +#endif + const int min_prio = sched_get_priority_min(policy); + const int max_prio = sched_get_priority_max(policy); + if (min_prio == -1 || max_prio == -1) { + return false; + } + + if (max_prio - min_prio <= 2) + return false; + + // Convert webrtc priority to system priorities: + sched_param param; + const int top_prio = max_prio - 1; + const int low_prio = min_prio + 1; + switch (priority) { + case kLowPriority: + param.sched_priority = low_prio; + break; + case kNormalPriority: + // The -1 ensures that the kHighPriority is always greater or equal to + // kNormalPriority. + param.sched_priority = (low_prio + top_prio - 1) / 2; + break; + case kHighPriority: + param.sched_priority = std::max(top_prio - 2, low_prio); + break; + case kHighestPriority: + param.sched_priority = std::max(top_prio - 1, low_prio); + break; + case kRealtimePriority: + param.sched_priority = top_prio; + break; + } + return pthread_setschedparam(thread_, policy, ¶m) == 0; +#endif // defined(WEBRTC_WIN) +} + } // namespace rtc
diff --git a/webrtc/base/platform_thread.h b/webrtc/base/platform_thread.h index 50033b3..53465e4 100644 --- a/webrtc/base/platform_thread.h +++ b/webrtc/base/platform_thread.h
@@ -11,24 +11,16 @@ #ifndef WEBRTC_BASE_PLATFORM_THREAD_H_ #define WEBRTC_BASE_PLATFORM_THREAD_H_ -#if defined(WEBRTC_WIN) -#include <winsock2.h> -#include <windows.h> -#elif defined(WEBRTC_POSIX) -#include <pthread.h> -#include <unistd.h> -#endif +#include <string> + +#include "webrtc/base/constructormagic.h" +#include "webrtc/base/event.h" +#include "webrtc/base/platform_thread_types.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/thread_checker.h" namespace rtc { -#if defined(WEBRTC_WIN) -typedef DWORD PlatformThreadId; -typedef DWORD PlatformThreadRef; -#elif defined(WEBRTC_POSIX) -typedef pid_t PlatformThreadId; -typedef pthread_t PlatformThreadRef; -#endif - PlatformThreadId CurrentThreadId(); PlatformThreadRef CurrentThreadRef(); @@ -38,6 +30,71 @@ // Sets the current thread name. void SetCurrentThreadName(const char* name); +// Callback function that the spawned thread will enter once spawned. +// A return value of false is interpreted as that the function has no +// more work to do and that the thread can be released. +typedef bool (*ThreadRunFunction)(void*); + +enum ThreadPriority { +#ifdef WEBRTC_WIN + kLowPriority = THREAD_PRIORITY_BELOW_NORMAL, + kNormalPriority = THREAD_PRIORITY_NORMAL, + kHighPriority = THREAD_PRIORITY_ABOVE_NORMAL, + kHighestPriority = THREAD_PRIORITY_HIGHEST, + kRealtimePriority = THREAD_PRIORITY_TIME_CRITICAL +#else + kLowPriority = 1, + kNormalPriority = 2, + kHighPriority = 3, + kHighestPriority = 4, + kRealtimePriority = 5 +#endif +}; + +// Represents a simple worker thread. The implementation must be assumed +// to be single threaded, meaning that all methods of the class, must be +// called from the same thread, including instantiation. +class PlatformThread { + public: + PlatformThread(ThreadRunFunction func, void* obj, const char* thread_name); + virtual ~PlatformThread(); + + // Spawns a thread and tries to set thread priority according to the priority + // from when CreateThread was called. + void Start(); + + bool IsRunning() const; + + // Stops (joins) the spawned thread. + void Stop(); + + // Set the priority of the thread. Must be called when thread is running. + bool SetPriority(ThreadPriority priority); + + private: + void Run(); + + ThreadRunFunction const run_function_; + void* const obj_; + // TODO(pbos): Make sure call sites use string literals and update to a const + // char* instead of a std::string. + const std::string name_; + rtc::ThreadChecker thread_checker_; +#if defined(WEBRTC_WIN) + static DWORD WINAPI StartThread(void* param); + + bool stop_; + HANDLE thread_; +#else + static void* StartThread(void* param); + + rtc::Event stop_event_; + + pthread_t thread_; +#endif // defined(WEBRTC_WIN) + RTC_DISALLOW_COPY_AND_ASSIGN(PlatformThread); +}; + } // namespace rtc #endif // WEBRTC_BASE_PLATFORM_THREAD_H_
diff --git a/webrtc/base/platform_thread_types.h b/webrtc/base/platform_thread_types.h new file mode 100644 index 0000000..546fffd --- /dev/null +++ b/webrtc/base/platform_thread_types.h
@@ -0,0 +1,32 @@ +/* + * 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_BASE_PLATFORM_THREAD_TYPES_H_ +#define WEBRTC_BASE_PLATFORM_THREAD_TYPES_H_ + +#if defined(WEBRTC_WIN) +#include <winsock2.h> +#include <windows.h> +#elif defined(WEBRTC_POSIX) +#include <pthread.h> +#include <unistd.h> +#endif + +namespace rtc { +#if defined(WEBRTC_WIN) +typedef DWORD PlatformThreadId; +typedef DWORD PlatformThreadRef; +#elif defined(WEBRTC_POSIX) +typedef pid_t PlatformThreadId; +typedef pthread_t PlatformThreadRef; +#endif +} // namespace rtc + +#endif // WEBRTC_BASE_PLATFORM_THREAD_TYPES_H_
diff --git a/webrtc/base/platform_thread_unittest.cc b/webrtc/base/platform_thread_unittest.cc new file mode 100644 index 0000000..f9db8e3 --- /dev/null +++ b/webrtc/base/platform_thread_unittest.cc
@@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/base/platform_thread.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/system_wrappers/include/sleep.h" + +namespace webrtc { + +// Function that does nothing, and reports success. +bool NullRunFunction(void* obj) { + SleepMs(0); // Hand over timeslice, prevents busy looping. + return true; +} + +TEST(PlatformThreadTest, StartStop) { + rtc::PlatformThread thread(&NullRunFunction, nullptr, "PlatformThreadTest"); + thread.Start(); + thread.Stop(); +} + +// Function that sets a boolean. +bool SetFlagRunFunction(void* obj) { + bool* obj_as_bool = static_cast<bool*>(obj); + *obj_as_bool = true; + SleepMs(0); // Hand over timeslice, prevents busy looping. + return true; +} + +TEST(PlatformThreadTest, RunFunctionIsCalled) { + bool flag = false; + rtc::PlatformThread thread(&SetFlagRunFunction, &flag, "RunFunctionIsCalled"); + thread.Start(); + + // At this point, the flag may be either true or false. + thread.Stop(); + + // We expect the thread to have run at least once. + EXPECT_TRUE(flag); +} + +} // namespace webrtc
diff --git a/webrtc/base/proxy_unittest.cc b/webrtc/base/proxy_unittest.cc index 03dc154..d8a523f 100644 --- a/webrtc/base/proxy_unittest.cc +++ b/webrtc/base/proxy_unittest.cc
@@ -17,7 +17,6 @@ #include "webrtc/base/testclient.h" #include "webrtc/base/testechoserver.h" #include "webrtc/base/virtualsocketserver.h" -#include "webrtc/test/testsupport/gtest_disable.h" using rtc::Socket; using rtc::Thread;
diff --git a/webrtc/base/proxydetect.cc b/webrtc/base/proxydetect.cc index b144d20..30959ca 100644 --- a/webrtc/base/proxydetect.cc +++ b/webrtc/base/proxydetect.cc
@@ -34,6 +34,7 @@ #include <map> +#include "webrtc/base/arraysize.h" #include "webrtc/base/fileutils.h" #include "webrtc/base/httpcommon.h" #include "webrtc/base/httpcommon-inl.h" @@ -222,7 +223,7 @@ uint32_t mask = (m == 0) ? 0 : (~0UL) << (32 - m); SocketAddress addr(url.host(), 0); // TODO: Support IPv6 proxyitems. This code block is IPv4 only anyway. - return !addr.IsUnresolved() && + return !addr.IsUnresolvedIP() && ((addr.ipaddr().v4AddressAsHostOrderInteger() & mask) == (ip & mask)); } @@ -398,7 +399,7 @@ } char buffer[NAME_MAX + 1]; if (0 != FSRefMakePath(&fr, reinterpret_cast<uint8_t*>(buffer), - ARRAY_SIZE(buffer))) { + arraysize(buffer))) { LOG(LS_ERROR) << "FSRefMakePath failed"; return false; }
diff --git a/webrtc/base/random.cc b/webrtc/base/random.cc new file mode 100644 index 0000000..14a9faf --- /dev/null +++ b/webrtc/base/random.cc
@@ -0,0 +1,86 @@ +/* + * 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/base/random.h" + +#include <math.h> + +#include "webrtc/base/checks.h" + +namespace webrtc { + +Random::Random(uint64_t seed) { + RTC_DCHECK(seed != 0x0ull); + state_ = seed; +} + +uint32_t Random::Rand(uint32_t t) { + // Casting the output to 32 bits will give an almost uniform number. + // Pr[x=0] = (2^32-1) / (2^64-1) + // Pr[x=k] = 2^32 / (2^64-1) for k!=0 + // Uniform would be Pr[x=k] = 2^32 / 2^64 for all 32-bit integers k. + uint32_t x = NextOutput(); + // If x / 2^32 is uniform on [0,1), then x / 2^32 * (t+1) is uniform on + // the interval [0,t+1), so the integer part is uniform on [0,t]. + uint64_t result = x * (static_cast<uint64_t>(t) + 1); + result >>= 32; + return result; +} + +uint32_t Random::Rand(uint32_t low, uint32_t high) { + RTC_DCHECK(low <= high); + return Rand(high - low) + low; +} + +int32_t Random::Rand(int32_t low, int32_t high) { + RTC_DCHECK(low <= high); + // We rely on subtraction (and addition) to be the same for signed and + // unsigned numbers in two-complement representation. Thus, although + // high - low might be negative as an int, it is the correct difference + // when interpreted as an unsigned. + return Rand(high - low) + low; +} + +template <> +float Random::Rand<float>() { + double result = NextOutput() - 1; + result = result / 0xFFFFFFFFFFFFFFFEull; + return static_cast<float>(result); +} + +template <> +double Random::Rand<double>() { + double result = NextOutput() - 1; + result = result / 0xFFFFFFFFFFFFFFFEull; + return result; +} + +template <> +bool Random::Rand<bool>() { + return Rand(0, 1) == 1; +} + +double Random::Gaussian(double mean, double standard_deviation) { + // Creating a Normal distribution variable from two independent uniform + // variables based on the Box-Muller transform, which is defined on the + // interval (0, 1]. Note that we rely on NextOutput to generate integers + // in the range [1, 2^64-1]. Normally this behavior is a bit frustrating, + // but here it is exactly what we need. + const double kPi = 3.14159265358979323846; + double u1 = static_cast<double>(NextOutput()) / 0xFFFFFFFFFFFFFFFFull; + double u2 = static_cast<double>(NextOutput()) / 0xFFFFFFFFFFFFFFFFull; + return mean + standard_deviation * sqrt(-2 * log(u1)) * cos(2 * kPi * u2); +} + +double Random::Exponential(double lambda) { + double uniform = Rand<double>(); + return -log(uniform) / lambda; +} + +} // namespace webrtc
diff --git a/webrtc/base/random.h b/webrtc/base/random.h new file mode 100644 index 0000000..647b84c --- /dev/null +++ b/webrtc/base/random.h
@@ -0,0 +1,82 @@ +/* + * 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_BASE_RANDOM_H_ +#define WEBRTC_BASE_RANDOM_H_ + +#include <limits> + +#include "webrtc/typedefs.h" +#include "webrtc/base/constructormagic.h" +#include "webrtc/base/checks.h" + +namespace webrtc { + +class Random { + public: + explicit Random(uint64_t seed); + + // Return pseudo-random integer of the specified type. + // We need to limit the size to 32 bits to keep the output close to uniform. + template <typename T> + T Rand() { + static_assert(std::numeric_limits<T>::is_integer && + std::numeric_limits<T>::radix == 2 && + std::numeric_limits<T>::digits <= 32, + "Rand is only supported for built-in integer types that are " + "32 bits or smaller."); + return static_cast<T>(NextOutput()); + } + + // Uniformly distributed pseudo-random number in the interval [0, t]. + uint32_t Rand(uint32_t t); + + // Uniformly distributed pseudo-random number in the interval [low, high]. + uint32_t Rand(uint32_t low, uint32_t high); + + // Uniformly distributed pseudo-random number in the interval [low, high]. + int32_t Rand(int32_t low, int32_t high); + + // Normal Distribution. + double Gaussian(double mean, double standard_deviation); + + // Exponential Distribution. + double Exponential(double lambda); + + private: + // Outputs a nonzero 64-bit random number. + uint64_t NextOutput() { + state_ ^= state_ >> 12; + state_ ^= state_ << 25; + state_ ^= state_ >> 27; + RTC_DCHECK(state_ != 0x0ULL); + return state_ * 2685821657736338717ull; + } + + uint64_t state_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Random); +}; + +// Return pseudo-random number in the interval [0.0, 1.0). +template <> +float Random::Rand<float>(); + +// Return pseudo-random number in the interval [0.0, 1.0). +template <> +double Random::Rand<double>(); + +// Return pseudo-random boolean value. +template <> +bool Random::Rand<bool>(); + +} // namespace webrtc + +#endif // WEBRTC_BASE_RANDOM_H_
diff --git a/webrtc/base/random_unittest.cc b/webrtc/base/random_unittest.cc new file mode 100644 index 0000000..febae1c --- /dev/null +++ b/webrtc/base/random_unittest.cc
@@ -0,0 +1,302 @@ +/* + * 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 <math.h> + +#include <limits> +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/random.h" + +namespace webrtc { + +namespace { +// Computes the positive remainder of x/n. +template <typename T> +T fdiv_remainder(T x, T n) { + RTC_CHECK_GE(n, static_cast<T>(0)); + T remainder = x % n; + if (remainder < 0) + remainder += n; + return remainder; +} +} // namespace + +// Sample a number of random integers of type T. Divide them into buckets +// based on the remainder when dividing by bucket_count and check that each +// bucket gets roughly the expected number of elements. +template <typename T> +void UniformBucketTest(T bucket_count, int samples, Random* prng) { + std::vector<int> buckets(bucket_count, 0); + + uint64_t total_values = 1ull << (std::numeric_limits<T>::digits + + std::numeric_limits<T>::is_signed); + T upper_limit = + std::numeric_limits<T>::max() - + static_cast<T>(total_values % static_cast<uint64_t>(bucket_count)); + ASSERT_GT(upper_limit, std::numeric_limits<T>::max() / 2); + + for (int i = 0; i < samples; i++) { + T sample; + do { + // We exclude a few numbers from the range so that it is divisible by + // the number of buckets. If we are unlucky and hit one of the excluded + // numbers we just resample. Note that if the number of buckets is a + // power of 2, then we don't have to exclude anything. + sample = prng->Rand<T>(); + } while (sample > upper_limit); + buckets[fdiv_remainder(sample, bucket_count)]++; + } + + for (T i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean. + EXPECT_NEAR(buckets[i], samples / bucket_count, + 3 * sqrt(samples / bucket_count)); + } +} + +TEST(RandomNumberGeneratorTest, BucketTestSignedChar) { + Random prng(7297352569824ull); + UniformBucketTest<signed char>(64, 640000, &prng); + UniformBucketTest<signed char>(11, 440000, &prng); + UniformBucketTest<signed char>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestUnsignedChar) { + Random prng(7297352569824ull); + UniformBucketTest<unsigned char>(64, 640000, &prng); + UniformBucketTest<unsigned char>(11, 440000, &prng); + UniformBucketTest<unsigned char>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestSignedShort) { + Random prng(7297352569824ull); + UniformBucketTest<int16_t>(64, 640000, &prng); + UniformBucketTest<int16_t>(11, 440000, &prng); + UniformBucketTest<int16_t>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestUnsignedShort) { + Random prng(7297352569824ull); + UniformBucketTest<uint16_t>(64, 640000, &prng); + UniformBucketTest<uint16_t>(11, 440000, &prng); + UniformBucketTest<uint16_t>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestSignedInt) { + Random prng(7297352569824ull); + UniformBucketTest<signed int>(64, 640000, &prng); + UniformBucketTest<signed int>(11, 440000, &prng); + UniformBucketTest<signed int>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestUnsignedInt) { + Random prng(7297352569824ull); + UniformBucketTest<unsigned int>(64, 640000, &prng); + UniformBucketTest<unsigned int>(11, 440000, &prng); + UniformBucketTest<unsigned int>(3, 270000, &prng); +} + +// The range of the random numbers is divided into bucket_count intervals +// of consecutive numbers. Check that approximately equally many numbers +// from each inteval are generated. +void BucketTestSignedInterval(unsigned int bucket_count, + unsigned int samples, + int32_t low, + int32_t high, + int sigma_level, + Random* prng) { + std::vector<unsigned int> buckets(bucket_count, 0); + + ASSERT_GE(high, low); + ASSERT_GE(bucket_count, 2u); + uint32_t interval = static_cast<uint32_t>(high - low + 1); + uint32_t numbers_per_bucket; + if (interval == 0) { + // The computation high - low + 1 should be 2^32 but overflowed + // Hence, bucket_count must be a power of 2 + ASSERT_EQ(bucket_count & (bucket_count - 1), 0u); + numbers_per_bucket = (0x80000000u / bucket_count) * 2; + } else { + ASSERT_EQ(interval % bucket_count, 0u); + numbers_per_bucket = interval / bucket_count; + } + + for (unsigned int i = 0; i < samples; i++) { + int32_t sample = prng->Rand(low, high); + EXPECT_LE(low, sample); + EXPECT_GE(high, sample); + buckets[static_cast<uint32_t>(sample - low) / numbers_per_bucket]++; + } + + for (unsigned int i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean, + // or more generally, within sigma_level standard deviations of the mean. + double mean = static_cast<double>(samples) / bucket_count; + EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean)); + } +} + +// The range of the random numbers is divided into bucket_count intervals +// of consecutive numbers. Check that approximately equally many numbers +// from each inteval are generated. +void BucketTestUnsignedInterval(unsigned int bucket_count, + unsigned int samples, + uint32_t low, + uint32_t high, + int sigma_level, + Random* prng) { + std::vector<unsigned int> buckets(bucket_count, 0); + + ASSERT_GE(high, low); + ASSERT_GE(bucket_count, 2u); + uint32_t interval = static_cast<uint32_t>(high - low + 1); + uint32_t numbers_per_bucket; + if (interval == 0) { + // The computation high - low + 1 should be 2^32 but overflowed + // Hence, bucket_count must be a power of 2 + ASSERT_EQ(bucket_count & (bucket_count - 1), 0u); + numbers_per_bucket = (0x80000000u / bucket_count) * 2; + } else { + ASSERT_EQ(interval % bucket_count, 0u); + numbers_per_bucket = interval / bucket_count; + } + + for (unsigned int i = 0; i < samples; i++) { + uint32_t sample = prng->Rand(low, high); + EXPECT_LE(low, sample); + EXPECT_GE(high, sample); + buckets[static_cast<uint32_t>(sample - low) / numbers_per_bucket]++; + } + + for (unsigned int i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean, + // or more generally, within sigma_level standard deviations of the mean. + double mean = static_cast<double>(samples) / bucket_count; + EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean)); + } +} + +TEST(RandomNumberGeneratorTest, UniformUnsignedInterval) { + Random prng(299792458ull); + BucketTestUnsignedInterval(2, 100000, 0, 1, 3, &prng); + BucketTestUnsignedInterval(7, 100000, 1, 14, 3, &prng); + BucketTestUnsignedInterval(11, 100000, 1000, 1010, 3, &prng); + BucketTestUnsignedInterval(100, 100000, 0, 99, 3, &prng); + BucketTestUnsignedInterval(2, 100000, 0, 4294967295, 3, &prng); + BucketTestUnsignedInterval(17, 100000, 455, 2147484110, 3, &prng); + // 99.7% of all samples will be within 3 standard deviations of the mean, + // but since we test 1000 buckets we allow an interval of 4 sigma. + BucketTestUnsignedInterval(1000, 1000000, 0, 2147483999, 4, &prng); +} + +TEST(RandomNumberGeneratorTest, UniformSignedInterval) { + Random prng(66260695729ull); + BucketTestSignedInterval(2, 100000, 0, 1, 3, &prng); + BucketTestSignedInterval(7, 100000, -2, 4, 3, &prng); + BucketTestSignedInterval(11, 100000, 1000, 1010, 3, &prng); + BucketTestSignedInterval(100, 100000, 0, 99, 3, &prng); + BucketTestSignedInterval(2, 100000, std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::max(), 3, &prng); + BucketTestSignedInterval(17, 100000, -1073741826, 1073741829, 3, &prng); + // 99.7% of all samples will be within 3 standard deviations of the mean, + // but since we test 1000 buckets we allow an interval of 4 sigma. + BucketTestSignedInterval(1000, 1000000, -352, 2147483647, 4, &prng); +} + +// The range of the random numbers is divided into bucket_count intervals +// of consecutive numbers. Check that approximately equally many numbers +// from each inteval are generated. +void BucketTestFloat(unsigned int bucket_count, + unsigned int samples, + int sigma_level, + Random* prng) { + ASSERT_GE(bucket_count, 2u); + std::vector<unsigned int> buckets(bucket_count, 0); + + for (unsigned int i = 0; i < samples; i++) { + uint32_t sample = bucket_count * prng->Rand<float>(); + EXPECT_LE(0u, sample); + EXPECT_GE(bucket_count - 1, sample); + buckets[sample]++; + } + + for (unsigned int i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean, + // or more generally, within sigma_level standard deviations of the mean. + double mean = static_cast<double>(samples) / bucket_count; + EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean)); + } +} + +TEST(RandomNumberGeneratorTest, UniformFloatInterval) { + Random prng(1380648813ull); + BucketTestFloat(100, 100000, 3, &prng); + // 99.7% of all samples will be within 3 standard deviations of the mean, + // but since we test 1000 buckets we allow an interval of 4 sigma. + // BucketTestSignedInterval(1000, 1000000, -352, 2147483647, 4, &prng); +} + +TEST(RandomNumberGeneratorTest, SignedHasSameBitPattern) { + Random prng_signed(66738480ull), prng_unsigned(66738480ull); + + for (int i = 0; i < 1000; i++) { + signed int s = prng_signed.Rand<signed int>(); + unsigned int u = prng_unsigned.Rand<unsigned int>(); + EXPECT_EQ(u, static_cast<unsigned int>(s)); + } + + for (int i = 0; i < 1000; i++) { + int16_t s = prng_signed.Rand<int16_t>(); + uint16_t u = prng_unsigned.Rand<uint16_t>(); + EXPECT_EQ(u, static_cast<uint16_t>(s)); + } + + for (int i = 0; i < 1000; i++) { + signed char s = prng_signed.Rand<signed char>(); + unsigned char u = prng_unsigned.Rand<unsigned char>(); + EXPECT_EQ(u, static_cast<unsigned char>(s)); + } +} + +TEST(RandomNumberGeneratorTest, Gaussian) { + const int kN = 100000; + const int kBuckets = 100; + const double kMean = 49; + const double kStddev = 10; + + Random prng(1256637061); + + std::vector<unsigned int> buckets(kBuckets, 0); + for (int i = 0; i < kN; i++) { + int index = prng.Gaussian(kMean, kStddev) + 0.5; + if (index >= 0 && index < kBuckets) { + buckets[index]++; + } + } + + const double kPi = 3.14159265358979323846; + const double kScale = 1 / (kStddev * sqrt(2.0 * kPi)); + const double kDiv = -2.0 * kStddev * kStddev; + for (int n = 0; n < kBuckets; ++n) { + // Use Simpsons rule to estimate the probability that a random gaussian + // sample is in the interval [n-0.5, n+0.5]. + double f_left = kScale * exp((n - kMean - 0.5) * (n - kMean - 0.5) / kDiv); + double f_mid = kScale * exp((n - kMean) * (n - kMean) / kDiv); + double f_right = kScale * exp((n - kMean + 0.5) * (n - kMean + 0.5) / kDiv); + double normal_dist = (f_left + 4 * f_mid + f_right) / 6; + // Expect the number of samples to be within 3 standard deviations + // (rounded up) of the expected number of samples in the bucket. + EXPECT_NEAR(buckets[n], kN * normal_dist, 3 * sqrt(kN * normal_dist) + 1); + } +} + +} // namespace webrtc
diff --git a/webrtc/base/ratetracker.cc b/webrtc/base/ratetracker.cc index 5cb4490..35521a8 100644 --- a/webrtc/base/ratetracker.cc +++ b/webrtc/base/ratetracker.cc
@@ -73,8 +73,9 @@ size_t start_bucket = NextBucketIndex(current_bucket_ + buckets_to_skip); // Only count a portion of the first bucket according to how much of the // first bucket is within the current interval. - size_t total_samples = sample_buckets_[start_bucket] * - (bucket_milliseconds_ - milliseconds_to_skip) / + size_t total_samples = ((sample_buckets_[start_bucket] * + (bucket_milliseconds_ - milliseconds_to_skip)) + + (bucket_milliseconds_ >> 1)) / bucket_milliseconds_; // All other buckets in the interval are counted in their entirety. for (size_t i = NextBucketIndex(start_bucket);
diff --git a/webrtc/base/rtccertificate.cc b/webrtc/base/rtccertificate.cc index a176d90..7b764bd 100644 --- a/webrtc/base/rtccertificate.cc +++ b/webrtc/base/rtccertificate.cc
@@ -11,7 +11,6 @@ #include "webrtc/base/rtccertificate.h" #include "webrtc/base/checks.h" -#include "webrtc/base/timeutils.h" namespace rtc { @@ -28,13 +27,16 @@ RTCCertificate::~RTCCertificate() { } -uint64_t RTCCertificate::expires_timestamp_ns() const { - // TODO(hbos): Update once SSLIdentity/SSLCertificate supports expires field. - return 0; +uint64_t RTCCertificate::Expires() const { + int64_t expires = ssl_certificate().CertificateExpirationTime(); + if (expires != -1) + return static_cast<uint64_t>(expires) * kNumMillisecsPerSec; + // If the expiration time could not be retrieved return an expired timestamp. + return 0; // = 1970-01-01 } -bool RTCCertificate::HasExpired() const { - return expires_timestamp_ns() <= TimeNanos(); +bool RTCCertificate::HasExpired(uint64_t now) const { + return Expires() <= now; } const SSLCertificate& RTCCertificate::ssl_certificate() const {
diff --git a/webrtc/base/rtccertificate.h b/webrtc/base/rtccertificate.h index d238938..600739b 100644 --- a/webrtc/base/rtccertificate.h +++ b/webrtc/base/rtccertificate.h
@@ -27,8 +27,11 @@ // Takes ownership of |identity|. static scoped_refptr<RTCCertificate> Create(scoped_ptr<SSLIdentity> identity); - uint64_t expires_timestamp_ns() const; - bool HasExpired() const; + // Returns the expiration time in ms relative to epoch, 1970-01-01T00:00:00Z. + uint64_t Expires() const; + // Checks if the certificate has expired, where |now| is expressed in ms + // relative to epoch, 1970-01-01T00:00:00Z. + bool HasExpired(uint64_t now) const; const SSLCertificate& ssl_certificate() const; // TODO(hbos): If possible, remove once RTCCertificate and its
diff --git a/webrtc/base/rtccertificate_unittests.cc b/webrtc/base/rtccertificate_unittests.cc new file mode 100644 index 0000000..84c8544 --- /dev/null +++ b/webrtc/base/rtccertificate_unittests.cc
@@ -0,0 +1,118 @@ +/* + * 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 <utility> + +#include "webrtc/base/checks.h" +#include "webrtc/base/fakesslidentity.h" +#include "webrtc/base/gunit.h" +#include "webrtc/base/logging.h" +#include "webrtc/base/rtccertificate.h" +#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/sslidentity.h" +#include "webrtc/base/thread.h" +#include "webrtc/base/timeutils.h" + +namespace rtc { + +namespace { + +static const char* kTestCertCommonName = "RTCCertificateTest's certificate"; + +} // namespace + +class RTCCertificateTest : public testing::Test { + public: + RTCCertificateTest() {} + ~RTCCertificateTest() {} + + protected: + // Timestamp note: + // All timestamps in this unittest are expressed in number of seconds since + // epoch, 1970-01-01T00:00:00Z (UTC). The RTCCertificate interface uses ms, + // but only seconds-precision is supported by SSLCertificate. To make the + // tests clearer we convert everything to seconds since the precision matters + // when generating certificates or comparing timestamps. + // As a result, ExpiresSeconds and HasExpiredSeconds are used instead of + // RTCCertificate::Expires and ::HasExpired for ms -> s conversion. + + uint64_t NowSeconds() const { + return TimeNanos() / kNumNanosecsPerSec; + } + + uint64_t ExpiresSeconds(const scoped_refptr<RTCCertificate>& cert) const { + uint64_t exp_ms = cert->Expires(); + uint64_t exp_s = exp_ms / kNumMillisecsPerSec; + // Make sure this did not result in loss of precision. + RTC_CHECK_EQ(exp_s * kNumMillisecsPerSec, exp_ms); + return exp_s; + } + + bool HasExpiredSeconds(const scoped_refptr<RTCCertificate>& cert, + uint64_t now_s) const { + return cert->HasExpired(now_s * kNumMillisecsPerSec); + } + + // An RTC_CHECK ensures that |expires_s| this is in valid range of time_t as + // is required by SSLIdentityParams. On some 32-bit systems time_t is limited + // to < 2^31. On such systems this will fail for expiration times of year 2038 + // or later. + scoped_refptr<RTCCertificate> GenerateCertificateWithExpires( + uint64_t expires_s) const { + RTC_CHECK(IsValueInRangeForNumericType<time_t>(expires_s)); + + SSLIdentityParams params; + params.common_name = kTestCertCommonName; + params.not_before = 0; + params.not_after = static_cast<time_t>(expires_s); + // Certificate type does not matter for our purposes, using ECDSA because it + // is fast to generate. + params.key_params = KeyParams::ECDSA(); + + scoped_ptr<SSLIdentity> identity(SSLIdentity::GenerateForTest(params)); + return RTCCertificate::Create(std::move(identity)); + } +}; + +TEST_F(RTCCertificateTest, NewCertificateNotExpired) { + // Generate a real certificate without specifying the expiration time. + // Certificate type doesn't matter, using ECDSA because it's fast to generate. + scoped_ptr<SSLIdentity> identity( + SSLIdentity::Generate(kTestCertCommonName, KeyParams::ECDSA())); + scoped_refptr<RTCCertificate> certificate = + RTCCertificate::Create(std::move(identity)); + + uint64_t now = NowSeconds(); + EXPECT_FALSE(HasExpiredSeconds(certificate, now)); + // Even without specifying the expiration time we would expect it to be valid + // for at least half an hour. + EXPECT_FALSE(HasExpiredSeconds(certificate, now + 30*60)); +} + +TEST_F(RTCCertificateTest, UsesExpiresAskedFor) { + uint64_t now = NowSeconds(); + scoped_refptr<RTCCertificate> certificate = + GenerateCertificateWithExpires(now); + EXPECT_EQ(now, ExpiresSeconds(certificate)); +} + +TEST_F(RTCCertificateTest, ExpiresInOneSecond) { + // Generate a certificate that expires in 1s. + uint64_t now = NowSeconds(); + scoped_refptr<RTCCertificate> certificate = + GenerateCertificateWithExpires(now + 1); + // Now it should not have expired. + EXPECT_FALSE(HasExpiredSeconds(certificate, now)); + // In 2s it should have expired. + EXPECT_TRUE(HasExpiredSeconds(certificate, now + 2)); +} + +} // namespace rtc
diff --git a/webrtc/base/scoped_ptr.h b/webrtc/base/scoped_ptr.h index 4266d05..c4603c3 100644 --- a/webrtc/base/scoped_ptr.h +++ b/webrtc/base/scoped_ptr.h
@@ -42,55 +42,39 @@ // } // // These scopers also implement part of the functionality of C++11 unique_ptr -// in that they are "movable but not copyable." You can use the scopers in -// the parameter and return types of functions to signify ownership transfer -// in to and out of a function. When calling a function that has a scoper -// as the argument type, it must be called with the result of an analogous -// scoper's Pass() function or another function that generates a temporary; -// passing by copy will NOT work. Here is an example using scoped_ptr: +// in that they are "movable but not copyable." You can use the scopers in the +// parameter and return types of functions to signify ownership transfer in to +// and out of a function. When calling a function that has a scoper as the +// argument type, it must be called with the result of calling std::move on an +// analogous scoper, or another function that generates a temporary; passing by +// copy will NOT work. Here is an example using scoped_ptr: // // void TakesOwnership(scoped_ptr<Foo> arg) { // // Do something with arg // } // scoped_ptr<Foo> CreateFoo() { -// // No need for calling Pass() because we are constructing a temporary +// // No need for calling std::move because we are constructing a temporary // // for the return value. // return scoped_ptr<Foo>(new Foo("new")); // } // scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) { -// return arg.Pass(); +// return std::move(arg); // } // // { // scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay"). -// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay"). +// TakesOwnership(std::move(ptr)); // ptr no longer owns Foo("yay"). // scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo. // scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2. -// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr. +// PassThru(std::move(ptr2)); // ptr2 is correspondingly nullptr. // } // -// Notice that if you do not call Pass() when returning from PassThru(), or +// Notice that if you do not call std::move when returning from PassThru(), or // when invoking TakesOwnership(), the code will not compile because scopers // are not copyable; they only implement move semantics which require calling -// the Pass() function to signify a destructive transfer of state. CreateFoo() -// is different though because we are constructing a temporary on the return -// line and thus can avoid needing to call Pass(). -// -// Pass() properly handles upcast in initialization, i.e. you can use a -// scoped_ptr<Child> to initialize a scoped_ptr<Parent>: -// -// scoped_ptr<Foo> foo(new Foo()); -// scoped_ptr<FooParent> parent(foo.Pass()); -// -// PassAs<>() should be used to upcast return value in return statement: -// -// scoped_ptr<Foo> CreateFoo() { -// scoped_ptr<FooChild> result(new FooChild()); -// return result.PassAs<Foo>(); -// } -// -// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for -// scoped_ptr<T[]>. This is because casting array pointers may not be safe. +// std::move to signify a destructive transfer of state. CreateFoo() is +// different though because we are constructing a temporary on the return line +// and thus can avoid needing to call std::move. #ifndef WEBRTC_BASE_SCOPED_PTR_H__ #define WEBRTC_BASE_SCOPED_PTR_H__ @@ -103,8 +87,10 @@ #include <stdlib.h> #include <algorithm> // For std::swap(). +#include <cstddef> #include "webrtc/base/constructormagic.h" +#include "webrtc/base/deprecation.h" #include "webrtc/base/template_util.h" #include "webrtc/typedefs.h" @@ -342,7 +328,7 @@ scoped_ptr(element_type* p, const D& d) : impl_(p, d) {} // Constructor. Allows construction from a nullptr. - scoped_ptr(decltype(nullptr)) : impl_(nullptr) {} + scoped_ptr(std::nullptr_t) : impl_(nullptr) {} // Constructor. Allows construction from a scoped_ptr rvalue for a // convertible type and deleter. @@ -379,7 +365,7 @@ // operator=. Allows assignment from a nullptr. Deletes the currently owned // object, if any. - scoped_ptr& operator=(decltype(nullptr)) { + scoped_ptr& operator=(std::nullptr_t) { reset(); return *this; } @@ -389,7 +375,10 @@ scoped_ptr& operator=(const scoped_ptr& other) = delete; // Get an rvalue reference. (sp.Pass() does the same thing as std::move(sp).) - scoped_ptr&& Pass() { return static_cast<scoped_ptr&&>(*this); } + // Deprecated; remove in March 2016 (bug 5373). + RTC_DEPRECATED scoped_ptr&& Pass() { + return std::move(*this); + } // Reset. Deletes the currently owned object, if any. // Then takes ownership of a new object, if given. @@ -499,7 +488,7 @@ explicit scoped_ptr(element_type* array) : impl_(array) {} // Constructor. Allows construction from a nullptr. - scoped_ptr(decltype(nullptr)) : impl_(nullptr) {} + scoped_ptr(std::nullptr_t) : impl_(nullptr) {} // Constructor. Allows construction from a scoped_ptr rvalue. scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {} @@ -512,7 +501,7 @@ // operator=. Allows assignment from a nullptr. Deletes the currently owned // array, if any. - scoped_ptr& operator=(decltype(nullptr)) { + scoped_ptr& operator=(std::nullptr_t) { reset(); return *this; } @@ -522,7 +511,10 @@ scoped_ptr& operator=(const scoped_ptr& other) = delete; // Get an rvalue reference. (sp.Pass() does the same thing as std::move(sp).) - scoped_ptr&& Pass() { return static_cast<scoped_ptr&&>(*this); } + // Deprecated; remove in March 2016 (bug 5373). + RTC_DEPRECATED scoped_ptr&& Pass() { + return std::move(*this); + } // Reset. Deletes the currently owned array, if any. // Then takes ownership of a new object, if given.
diff --git a/webrtc/base/sec_buffer.h b/webrtc/base/sec_buffer.h index d4cda00..e6ffea4 100644 --- a/webrtc/base/sec_buffer.h +++ b/webrtc/base/sec_buffer.h
@@ -119,7 +119,7 @@ } // Accessor for the descriptor - const PSecBufferDesc desc() const { + PSecBufferDesc desc() const { return &desc_; }
diff --git a/webrtc/base/sharedexclusivelock_unittest.cc b/webrtc/base/sharedexclusivelock_unittest.cc index 2857e00..9b64ed7 100644 --- a/webrtc/base/sharedexclusivelock_unittest.cc +++ b/webrtc/base/sharedexclusivelock_unittest.cc
@@ -16,7 +16,6 @@ #include "webrtc/base/sharedexclusivelock.h" #include "webrtc/base/thread.h" #include "webrtc/base/timeutils.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace rtc {
diff --git a/webrtc/base/signalthread.cc b/webrtc/base/signalthread.cc index d03f386..75f7b77 100644 --- a/webrtc/base/signalthread.cc +++ b/webrtc/base/signalthread.cc
@@ -39,13 +39,6 @@ return worker_.SetName(name, obj); } -bool SignalThread::SetPriority(ThreadPriority priority) { - EnterExit ee(this); - ASSERT(main_->IsCurrent()); - ASSERT(kInit == state_); - return worker_.SetPriority(priority); -} - void SignalThread::Start() { EnterExit ee(this); ASSERT(main_->IsCurrent());
diff --git a/webrtc/base/signalthread.h b/webrtc/base/signalthread.h index 4dda889..ec250c6 100644 --- a/webrtc/base/signalthread.h +++ b/webrtc/base/signalthread.h
@@ -45,9 +45,6 @@ // Context: Main Thread. Call before Start to change the worker's name. bool SetName(const std::string& name, const void* obj); - // Context: Main Thread. Call before Start to change the worker's priority. - bool SetPriority(ThreadPriority priority); - // Context: Main Thread. Call to begin the worker thread. void Start();
diff --git a/webrtc/base/signalthread_unittest.cc b/webrtc/base/signalthread_unittest.cc index fe6c602..a583aef 100644 --- a/webrtc/base/signalthread_unittest.cc +++ b/webrtc/base/signalthread_unittest.cc
@@ -11,7 +11,6 @@ #include "webrtc/base/gunit.h" #include "webrtc/base/signalthread.h" #include "webrtc/base/thread.h" -#include "webrtc/test/testsupport/gtest_disable.h" using namespace rtc;
diff --git a/webrtc/base/sigslot.h b/webrtc/base/sigslot.h index d9b12b0..a5fd5f7 100644 --- a/webrtc/base/sigslot.h +++ b/webrtc/base/sigslot.h
@@ -532,7 +532,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -686,7 +686,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -825,7 +825,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -963,7 +963,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -1101,7 +1101,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -1241,7 +1241,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -1381,7 +1381,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -1521,7 +1521,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this); @@ -1662,7 +1662,7 @@ m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool connected(has_slots_interface* pclass) { lock_block<mt_policy> lock(this);
diff --git a/webrtc/base/socket_unittest.cc b/webrtc/base/socket_unittest.cc index d078d7c..8143823 100644 --- a/webrtc/base/socket_unittest.cc +++ b/webrtc/base/socket_unittest.cc
@@ -10,6 +10,7 @@ #include "webrtc/base/socket_unittest.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/asyncudpsocket.h" #include "webrtc/base/gunit.h" #include "webrtc/base/nethelpers.h" @@ -827,7 +828,7 @@ // Fill the socket buffer. char buf[1024 * 16] = {0}; int sends = 0; - while (++sends && accepted->Send(&buf, ARRAY_SIZE(buf)) != -1) {} + while (++sends && accepted->Send(&buf, arraysize(buf)) != -1) {} EXPECT_TRUE(accepted->IsBlocking()); // Wait until data is available. @@ -835,7 +836,7 @@ // Pull data. for (int i = 0; i < sends; ++i) { - client->Recv(buf, ARRAY_SIZE(buf)); + client->Recv(buf, arraysize(buf)); } // Expect at least one additional writable callback. @@ -845,7 +846,7 @@ // callbacks. int extras = 0; for (int i = 0; i < 100; ++i) { - accepted->Send(&buf, ARRAY_SIZE(buf)); + accepted->Send(&buf, arraysize(buf)); rtc::Thread::Current()->ProcessMessages(1); if (sink.Check(accepted.get(), testing::SSE_WRITE)) { extras++;
diff --git a/webrtc/base/socket_unittest.h b/webrtc/base/socket_unittest.h index d368afb..e4a6b32 100644 --- a/webrtc/base/socket_unittest.h +++ b/webrtc/base/socket_unittest.h
@@ -21,8 +21,9 @@ // socketserver, and call the SocketTest test methods. class SocketTest : public testing::Test { protected: - SocketTest() : ss_(NULL), kIPv4Loopback(INADDR_LOOPBACK), - kIPv6Loopback(in6addr_loopback) {} + SocketTest() : kIPv4Loopback(INADDR_LOOPBACK), + kIPv6Loopback(in6addr_loopback), + ss_(nullptr) {} virtual void SetUp() { ss_ = Thread::Current()->socketserver(); } void TestConnectIPv4(); void TestConnectIPv6(); @@ -57,6 +58,10 @@ void TestGetSetOptionsIPv4(); void TestGetSetOptionsIPv6(); + static const int kTimeout = 5000; // ms + const IPAddress kIPv4Loopback; + const IPAddress kIPv6Loopback; + private: void ConnectInternal(const IPAddress& loopback); void ConnectWithDnsLookupInternal(const IPAddress& loopback, @@ -77,12 +82,13 @@ void UdpReadyToSend(const IPAddress& loopback); void GetSetOptionsInternal(const IPAddress& loopback); - static const int kTimeout = 5000; // ms SocketServer* ss_; - const IPAddress kIPv4Loopback; - const IPAddress kIPv6Loopback; }; +// For unbound sockets, GetLocalAddress / GetRemoteAddress return AF_UNSPEC +// values on Windows, but an empty address of the same family on Linux/MacOS X. +bool IsUnspecOrEmptyIP(const IPAddress& address); + } // namespace rtc #endif // WEBRTC_BASE_SOCKET_UNITTEST_H_
diff --git a/webrtc/base/socketadapters.cc b/webrtc/base/socketadapters.cc index af2efb8..2b513dc 100644 --- a/webrtc/base/socketadapters.cc +++ b/webrtc/base/socketadapters.cc
@@ -688,7 +688,7 @@ request.WriteUInt8(5); // Socks Version request.WriteUInt8(1); // CONNECT request.WriteUInt8(0); // Reserved - if (dest_.IsUnresolved()) { + if (dest_.IsUnresolvedIP()) { std::string hostname = dest_.hostname(); request.WriteUInt8(3); // DOMAINNAME request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
diff --git a/webrtc/base/socketaddress.cc b/webrtc/base/socketaddress.cc index 79ede80..c5fd798 100644 --- a/webrtc/base/socketaddress.cc +++ b/webrtc/base/socketaddress.cc
@@ -307,39 +307,6 @@ return ToSockAddrStorageHelper(addr, ip_, port_, scope_id_); } -bool SocketAddress::StringToIP(const std::string& hostname, uint32_t* ip) { - in_addr addr; - if (rtc::inet_pton(AF_INET, hostname.c_str(), &addr) == 0) - return false; - *ip = NetworkToHost32(addr.s_addr); - return true; -} - -bool SocketAddress::StringToIP(const std::string& hostname, IPAddress* ip) { - in_addr addr4; - if (rtc::inet_pton(AF_INET, hostname.c_str(), &addr4) > 0) { - if (ip) { - *ip = IPAddress(addr4); - } - return true; - } - - in6_addr addr6; - if (rtc::inet_pton(AF_INET6, hostname.c_str(), &addr6) > 0) { - if (ip) { - *ip = IPAddress(addr6); - } - return true; - } - return false; -} - -uint32_t SocketAddress::StringToIP(const std::string& hostname) { - uint32_t ip = 0; - StringToIP(hostname, &ip); - return ip; -} - bool SocketAddressFromSockAddrStorage(const sockaddr_storage& addr, SocketAddress* out) { if (!out) {
diff --git a/webrtc/base/socketaddress.h b/webrtc/base/socketaddress.h index 1d975a1..175d7a9 100644 --- a/webrtc/base/socketaddress.h +++ b/webrtc/base/socketaddress.h
@@ -141,7 +141,6 @@ // Determines whether the hostname has been resolved to an IP. bool IsUnresolvedIP() const; - inline bool IsUnresolved() const { return IsUnresolvedIP(); } // deprecated // Determines whether this address is identical to the given one. bool operator ==(const SocketAddress& addr) const; @@ -177,16 +176,6 @@ size_t ToDualStackSockAddrStorage(sockaddr_storage* saddr) const; size_t ToSockAddrStorage(sockaddr_storage* saddr) const; - // Converts the IP address given in dotted form into compact form. - // Only dotted names (A.B.C.D) are converted. - // Output integer is returned in host byte order. - // TODO: Deprecate, replace wth agnostic versions. - static bool StringToIP(const std::string& str, uint32_t* ip); - static uint32_t StringToIP(const std::string& str); - - // Converts the IP address given in printable form into an IPAddress. - static bool StringToIP(const std::string& str, IPAddress* ip); - private: std::string hostname_; IPAddress ip_;
diff --git a/webrtc/base/socketaddress_unittest.cc b/webrtc/base/socketaddress_unittest.cc index 6e9f089..e235447 100644 --- a/webrtc/base/socketaddress_unittest.cc +++ b/webrtc/base/socketaddress_unittest.cc
@@ -27,10 +27,11 @@ 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04} } }; const std::string kTestV6AddrString = "2001:db8:1020:3040:5060:7080:90a0:b0c0"; -const std::string kTestV6AddrAnonymizedString = "2001:db8:1020::"; +const std::string kTestV6AddrAnonymizedString = "2001:db8:1020:x:x:x:x:x"; const std::string kTestV6AddrFullString = "[2001:db8:1020:3040:5060:7080:90a0:b0c0]:5678"; -const std::string kTestV6AddrFullAnonymizedString = "[2001:db8:1020::]:5678"; +const std::string kTestV6AddrFullAnonymizedString = + "[2001:db8:1020:x:x:x:x:x]:5678"; TEST(SocketAddressTest, TestDefaultCtor) { SocketAddress addr; @@ -325,23 +326,26 @@ SocketAddress addr_v4("1.2.3.4", 5678); EXPECT_EQ("1.2.3.4", addr_v4.HostAsURIString()); EXPECT_EQ("1.2.3.4:5678", addr_v4.ToString()); - EXPECT_EQ("1.2.3.4", addr_v4.HostAsSensitiveURIString()); - EXPECT_EQ("1.2.3.4:5678", addr_v4.ToSensitiveString()); - IPAddress::set_strip_sensitive(true); + +#if defined(NDEBUG) EXPECT_EQ("1.2.3.x", addr_v4.HostAsSensitiveURIString()); EXPECT_EQ("1.2.3.x:5678", addr_v4.ToSensitiveString()); - IPAddress::set_strip_sensitive(false); +#else + EXPECT_EQ("1.2.3.4", addr_v4.HostAsSensitiveURIString()); + EXPECT_EQ("1.2.3.4:5678", addr_v4.ToSensitiveString()); +#endif // defined(NDEBUG) SocketAddress addr_v6(kTestV6AddrString, 5678); EXPECT_EQ("[" + kTestV6AddrString + "]", addr_v6.HostAsURIString()); EXPECT_EQ(kTestV6AddrFullString, addr_v6.ToString()); - EXPECT_EQ("[" + kTestV6AddrString + "]", addr_v6.HostAsSensitiveURIString()); - EXPECT_EQ(kTestV6AddrFullString, addr_v6.ToSensitiveString()); - IPAddress::set_strip_sensitive(true); +#if defined(NDEBUG) EXPECT_EQ("[" + kTestV6AddrAnonymizedString + "]", addr_v6.HostAsSensitiveURIString()); EXPECT_EQ(kTestV6AddrFullAnonymizedString, addr_v6.ToSensitiveString()); - IPAddress::set_strip_sensitive(false); +#else + EXPECT_EQ("[" + kTestV6AddrString + "]", addr_v6.HostAsSensitiveURIString()); + EXPECT_EQ(kTestV6AddrFullString, addr_v6.ToSensitiveString()); +#endif // defined(NDEBUG) } } // namespace rtc
diff --git a/webrtc/base/sslidentity.cc b/webrtc/base/sslidentity.cc index 180e60c..5f6b686 100644 --- a/webrtc/base/sslidentity.cc +++ b/webrtc/base/sslidentity.cc
@@ -15,6 +15,7 @@ #include "webrtc/base/sslidentity.h" +#include <ctime> #include <string> #include "webrtc/base/base64.h" @@ -177,4 +178,74 @@ #endif // SSL_USE_OPENSSL +// Read |n| bytes from ASN1 number string at *|pp| and return the numeric value. +// Update *|pp| and *|np| to reflect number of read bytes. +static inline int ASN1ReadInt(const unsigned char** pp, size_t* np, size_t n) { + const unsigned char* p = *pp; + int x = 0; + for (size_t i = 0; i < n; i++) + x = 10 * x + p[i] - '0'; + *pp = p + n; + *np = *np - n; + return x; +} + +int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format) { + size_t bytes_left = length; + + // Make sure the string ends with Z. Doing it here protects the strspn call + // from running off the end of the string in Z's absense. + if (length == 0 || s[length - 1] != 'Z') + return -1; + + // Make sure we only have ASCII digits so that we don't need to clutter the + // code below and ASN1ReadInt with error checking. + size_t n = strspn(reinterpret_cast<const char*>(s), "0123456789"); + if (n + 1 != length) + return -1; + + int year; + + // Read out ASN1 year, in either 2-char "UTCTIME" or 4-char "GENERALIZEDTIME" + // format. Both format use UTC in this context. + if (long_format) { + // ASN1 format: yyyymmddhh[mm[ss[.fff]]]Z where the Z is literal, but + // RFC 5280 requires us to only support exactly yyyymmddhhmmssZ. + + if (bytes_left < 11) + return -1; + + year = ASN1ReadInt(&s, &bytes_left, 4); + year -= 1900; + } else { + // ASN1 format: yymmddhhmm[ss]Z where the Z is literal, but RFC 5280 + // requires us to only support exactly yymmddhhmmssZ. + + if (bytes_left < 9) + return -1; + + year = ASN1ReadInt(&s, &bytes_left, 2); + if (year < 50) // Per RFC 5280 4.1.2.5.1 + year += 100; + } + + std::tm tm; + tm.tm_year = year; + + // Read out remaining ASN1 time data and store it in |tm| in documented + // std::tm format. + tm.tm_mon = ASN1ReadInt(&s, &bytes_left, 2) - 1; + tm.tm_mday = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_hour = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_min = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_sec = ASN1ReadInt(&s, &bytes_left, 2); + + if (bytes_left != 1) { + // Now just Z should remain. Its existence was asserted above. + return -1; + } + + return TmToSeconds(tm); +} + } // namespace rtc
diff --git a/webrtc/base/sslidentity.h b/webrtc/base/sslidentity.h index cf99426..a143ee4 100644 --- a/webrtc/base/sslidentity.h +++ b/webrtc/base/sslidentity.h
@@ -19,6 +19,7 @@ #include "webrtc/base/buffer.h" #include "webrtc/base/messagedigest.h" +#include "webrtc/base/timeutils.h" namespace rtc { @@ -68,6 +69,10 @@ unsigned char* digest, size_t size, size_t* length) const = 0; + + // Returns the time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC), + // or -1 if an expiration time could not be retrieved. + virtual int64_t CertificateExpirationTime() const = 0; }; // SSLCertChain is a simple wrapper for a vector of SSLCertificates. It serves @@ -168,8 +173,8 @@ // random string will be used. struct SSLIdentityParams { std::string common_name; - int not_before; // offset from current time in seconds. - int not_after; // offset from current time in seconds. + time_t not_before; // Absolute time since epoch in seconds. + time_t not_after; // Absolute time since epoch in seconds. KeyParams key_params; }; @@ -217,6 +222,11 @@ size_t length); }; +// Convert from ASN1 time as restricted by RFC 5280 to seconds from 1970-01-01 +// 00.00 ("epoch"). If the ASN1 time cannot be read, return -1. The data at +// |s| is not 0-terminated; its char count is defined by |length|. +int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format); + extern const char kPemTypeCertificate[]; extern const char kPemTypeRsaPrivateKey[]; extern const char kPemTypeEcPrivateKey[];
diff --git a/webrtc/base/sslidentity_unittest.cc b/webrtc/base/sslidentity_unittest.cc index e8df415..3582edb 100644 --- a/webrtc/base/sslidentity_unittest.cc +++ b/webrtc/base/sslidentity_unittest.cc
@@ -11,6 +11,7 @@ #include <string> #include "webrtc/base/gunit.h" +#include "webrtc/base/helpers.h" #include "webrtc/base/ssladapter.h" #include "webrtc/base/sslidentity.h" @@ -295,3 +296,119 @@ TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) { TestGetSignatureDigestAlgorithm(); } + +class SSLIdentityExpirationTest : public testing::Test { + public: + SSLIdentityExpirationTest() { + // Set use of the test RNG to get deterministic expiration timestamp. + rtc::SetRandomTestMode(true); + } + ~SSLIdentityExpirationTest() { + // Put it back for the next test. + rtc::SetRandomTestMode(false); + } + + void TestASN1TimeToSec() { + struct asn_example { + const char* string; + bool long_format; + int64_t want; + } static const data[] = { + // Valid examples. + {"19700101000000Z", true, 0}, + {"700101000000Z", false, 0}, + {"19700101000001Z", true, 1}, + {"700101000001Z", false, 1}, + {"19700101000100Z", true, 60}, + {"19700101000101Z", true, 61}, + {"19700101010000Z", true, 3600}, + {"19700101010001Z", true, 3601}, + {"19700101010100Z", true, 3660}, + {"19700101010101Z", true, 3661}, + {"710911012345Z", false, 53400225}, + {"20000101000000Z", true, 946684800}, + {"20000101000000Z", true, 946684800}, + {"20151130140156Z", true, 1448892116}, + {"151130140156Z", false, 1448892116}, + {"20491231235959Z", true, 2524607999}, + {"491231235959Z", false, 2524607999}, + {"20500101000000Z", true, 2524607999+1}, + {"20700101000000Z", true, 3155760000}, + {"21000101000000Z", true, 4102444800}, + {"24000101000000Z", true, 13569465600}, + + // Invalid examples. + {"19700101000000", true, -1}, // missing Z long format + {"19700101000000X", true, -1}, // X instead of Z long format + {"197001010000000", true, -1}, // 0 instead of Z long format + {"1970010100000000Z", true, -1}, // excess digits long format + {"700101000000", false, -1}, // missing Z short format + {"700101000000X", false, -1}, // X instead of Z short format + {"7001010000000", false, -1}, // 0 instead of Z short format + {"70010100000000Z", false, -1}, // excess digits short format + {":9700101000000Z", true, -1}, // invalid character + {"1:700101000001Z", true, -1}, // invalid character + {"19:00101000100Z", true, -1}, // invalid character + {"197:0101000101Z", true, -1}, // invalid character + {"1970:101010000Z", true, -1}, // invalid character + {"19700:01010001Z", true, -1}, // invalid character + {"197001:1010100Z", true, -1}, // invalid character + {"1970010:010101Z", true, -1}, // invalid character + {"70010100:000Z", false, -1}, // invalid character + {"700101000:01Z", false, -1}, // invalid character + {"2000010100:000Z", true, -1}, // invalid character + {"21000101000:00Z", true, -1}, // invalid character + {"240001010000:0Z", true, -1}, // invalid character + {"500101000000Z", false, -1}, // but too old for epoch + {"691231235959Z", false, -1}, // too old for epoch + {"19611118043000Z", false, -1}, // way too old for epoch + }; + + unsigned char buf[20]; + + // Run all examples and check for the expected result. + for (const auto& entry : data) { + size_t length = strlen(entry.string); + memcpy(buf, entry.string, length); // Copy the ASN1 string... + buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk. + int64_t res = rtc::ASN1TimeToSec(buf, length, entry.long_format); + LOG(LS_VERBOSE) << entry.string; + ASSERT_EQ(entry.want, res); + } + // Run all examples again, but with an invalid length. + for (const auto& entry : data) { + size_t length = strlen(entry.string); + memcpy(buf, entry.string, length); // Copy the ASN1 string... + buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk. + int64_t res = rtc::ASN1TimeToSec(buf, length - 1, entry.long_format); + LOG(LS_VERBOSE) << entry.string; + ASSERT_EQ(-1, res); + } + } + + void TestExpireTime(int times) { + for (int i = 0; i < times; i++) { + rtc::SSLIdentityParams params; + params.common_name = ""; + params.not_before = 0; + // We limit the time to < 2^31 here, i.e., we stay before 2038, since else + // we hit time offset limitations in OpenSSL on some 32-bit systems. + params.not_after = rtc::CreateRandomId() % 0x80000000; + // We test just ECDSA here since what we're out to exercise here is the + // code for expiration setting and reading. + params.key_params = rtc::KeyParams::ECDSA(rtc::EC_NIST_P256); + SSLIdentity* identity = rtc::SSLIdentity::GenerateForTest(params); + EXPECT_EQ(params.not_after, + identity->certificate().CertificateExpirationTime()); + delete identity; + } + } +}; + +TEST_F(SSLIdentityExpirationTest, TestASN1TimeToSec) { + TestASN1TimeToSec(); +} + +TEST_F(SSLIdentityExpirationTest, TestExpireTime) { + TestExpireTime(500); +}
diff --git a/webrtc/base/sslroots.h b/webrtc/base/sslroots.h index 31d601c..0464ac8 100644 --- a/webrtc/base/sslroots.h +++ b/webrtc/base/sslroots.h
@@ -2,83 +2,813 @@ // Google. // It was generated with the following command line: -// > python //depot/googleclient/talk/tools/generate_sslroots.py -// //depot/google3/security/cacerts/for_connecting_to_google/roots.pem +// > python tools/sslroots/generate_sslroots.py +// https://pki.google.com/roots.pem -/* subject:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */ -/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */ +/* subject:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ +/* issuer :/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ -namespace rtc { -const unsigned char AddTrust_External_Root_certificate[1082]={ -0x30,0x82,0x04,0x36,0x30,0x82,0x03,0x1E,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +const unsigned char GlobalSign_Root_CA_certificate[889]={ +0x30,0x82,0x03,0x75,0x30,0x82,0x02,0x5D,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x15,0x4B,0x5A,0xC3,0x94,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76, +0x2D,0x73,0x61,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F, +0x6F,0x74,0x20,0x43,0x41,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x43,0x41,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x39,0x30,0x31,0x31,0x32,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x32,0x38,0x30,0x31,0x32,0x38,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x30,0x57,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, +0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62, +0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76,0x2D,0x73,0x61,0x31,0x10,0x30,0x0E, +0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDA,0x0E,0xE6,0x99, +0x8D,0xCE,0xA3,0xE3,0x4F,0x8A,0x7E,0xFB,0xF1,0x8B,0x83,0x25,0x6B,0xEA,0x48,0x1F, +0xF1,0x2A,0xB0,0xB9,0x95,0x11,0x04,0xBD,0xF0,0x63,0xD1,0xE2,0x67,0x66,0xCF,0x1C, +0xDD,0xCF,0x1B,0x48,0x2B,0xEE,0x8D,0x89,0x8E,0x9A,0xAF,0x29,0x80,0x65,0xAB,0xE9, +0xC7,0x2D,0x12,0xCB,0xAB,0x1C,0x4C,0x70,0x07,0xA1,0x3D,0x0A,0x30,0xCD,0x15,0x8D, +0x4F,0xF8,0xDD,0xD4,0x8C,0x50,0x15,0x1C,0xEF,0x50,0xEE,0xC4,0x2E,0xF7,0xFC,0xE9, +0x52,0xF2,0x91,0x7D,0xE0,0x6D,0xD5,0x35,0x30,0x8E,0x5E,0x43,0x73,0xF2,0x41,0xE9, +0xD5,0x6A,0xE3,0xB2,0x89,0x3A,0x56,0x39,0x38,0x6F,0x06,0x3C,0x88,0x69,0x5B,0x2A, +0x4D,0xC5,0xA7,0x54,0xB8,0x6C,0x89,0xCC,0x9B,0xF9,0x3C,0xCA,0xE5,0xFD,0x89,0xF5, +0x12,0x3C,0x92,0x78,0x96,0xD6,0xDC,0x74,0x6E,0x93,0x44,0x61,0xD1,0x8D,0xC7,0x46, +0xB2,0x75,0x0E,0x86,0xE8,0x19,0x8A,0xD5,0x6D,0x6C,0xD5,0x78,0x16,0x95,0xA2,0xE9, +0xC8,0x0A,0x38,0xEB,0xF2,0x24,0x13,0x4F,0x73,0x54,0x93,0x13,0x85,0x3A,0x1B,0xBC, +0x1E,0x34,0xB5,0x8B,0x05,0x8C,0xB9,0x77,0x8B,0xB1,0xDB,0x1F,0x20,0x91,0xAB,0x09, +0x53,0x6E,0x90,0xCE,0x7B,0x37,0x74,0xB9,0x70,0x47,0x91,0x22,0x51,0x63,0x16,0x79, +0xAE,0xB1,0xAE,0x41,0x26,0x08,0xC8,0x19,0x2B,0xD1,0x46,0xAA,0x48,0xD6,0x64,0x2A, +0xD7,0x83,0x34,0xFF,0x2C,0x2A,0xC1,0x6C,0x19,0x43,0x4A,0x07,0x85,0xE7,0xD3,0x7C, +0xF6,0x21,0x68,0xEF,0xEA,0xF2,0x52,0x9F,0x7F,0x93,0x90,0xCF,0x02,0x03,0x01,0x00, +0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04, +0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x60,0x7B,0x66,0x1A,0x45,0x0D,0x97,0xCA,0x89,0x50,0x2F,0x7D,0x04,0xCD,0x34, +0xA8,0xFF,0xFC,0xFD,0x4B,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xD6,0x73,0xE7,0x7C,0x4F,0x76,0xD0, +0x8D,0xBF,0xEC,0xBA,0xA2,0xBE,0x34,0xC5,0x28,0x32,0xB5,0x7C,0xFC,0x6C,0x9C,0x2C, +0x2B,0xBD,0x09,0x9E,0x53,0xBF,0x6B,0x5E,0xAA,0x11,0x48,0xB6,0xE5,0x08,0xA3,0xB3, +0xCA,0x3D,0x61,0x4D,0xD3,0x46,0x09,0xB3,0x3E,0xC3,0xA0,0xE3,0x63,0x55,0x1B,0xF2, +0xBA,0xEF,0xAD,0x39,0xE1,0x43,0xB9,0x38,0xA3,0xE6,0x2F,0x8A,0x26,0x3B,0xEF,0xA0, +0x50,0x56,0xF9,0xC6,0x0A,0xFD,0x38,0xCD,0xC4,0x0B,0x70,0x51,0x94,0x97,0x98,0x04, +0xDF,0xC3,0x5F,0x94,0xD5,0x15,0xC9,0x14,0x41,0x9C,0xC4,0x5D,0x75,0x64,0x15,0x0D, +0xFF,0x55,0x30,0xEC,0x86,0x8F,0xFF,0x0D,0xEF,0x2C,0xB9,0x63,0x46,0xF6,0xAA,0xFC, +0xDF,0xBC,0x69,0xFD,0x2E,0x12,0x48,0x64,0x9A,0xE0,0x95,0xF0,0xA6,0xEF,0x29,0x8F, +0x01,0xB1,0x15,0xB5,0x0C,0x1D,0xA5,0xFE,0x69,0x2C,0x69,0x24,0x78,0x1E,0xB3,0xA7, +0x1C,0x71,0x62,0xEE,0xCA,0xC8,0x97,0xAC,0x17,0x5D,0x8A,0xC2,0xF8,0x47,0x86,0x6E, +0x2A,0xC4,0x56,0x31,0x95,0xD0,0x67,0x89,0x85,0x2B,0xF9,0x6C,0xA6,0x5D,0x46,0x9D, +0x0C,0xAA,0x82,0xE4,0x99,0x51,0xDD,0x70,0xB7,0xDB,0x56,0x3D,0x61,0xE4,0x6A,0xE1, +0x5C,0xD6,0xF6,0xFE,0x3D,0xDE,0x41,0xCC,0x07,0xAE,0x63,0x52,0xBF,0x53,0x53,0xF4, +0x2B,0xE9,0xC7,0xFD,0xB6,0xF7,0x82,0x5F,0x85,0xD2,0x41,0x18,0xDB,0x81,0xB3,0x04, +0x1C,0xC5,0x1F,0xA4,0x80,0x6F,0x15,0x20,0xC9,0xDE,0x0C,0x88,0x0A,0x1D,0xD6,0x66, +0x55,0xE2,0xFC,0x48,0xC9,0x29,0x26,0x69,0xE0, +}; + + +/* subject:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority */ +/* issuer :/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority */ + + +const unsigned char USERTrust_RSA_Certification_Authority_certificate[1506]={ +0x30,0x82,0x05,0xDE,0x30,0x82,0x03,0xC6,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x01, +0xFD,0x6D,0x30,0xFC,0xA3,0xCA,0x51,0xA8,0x1B,0xBC,0x64,0x0E,0x35,0x03,0x2D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81, +0x88,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13, +0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x13,0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72, +0x73,0x65,0x79,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65, +0x72,0x73,0x65,0x79,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55, +0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53, +0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55, +0x04,0x03,0x13,0x25,0x55,0x53,0x45,0x52,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x53, +0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30, +0x32,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31, +0x31,0x38,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x88,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x08,0x13,0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72,0x73,0x65,0x79,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65,0x72,0x73,0x65,0x79,0x20, +0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, +0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x03,0x13,0x25,0x55, +0x53,0x45,0x52,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x53,0x41,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x30,0x82,0x02,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A, +0x02,0x82,0x02,0x01,0x00,0x80,0x12,0x65,0x17,0x36,0x0E,0xC3,0xDB,0x08,0xB3,0xD0, +0xAC,0x57,0x0D,0x76,0xED,0xCD,0x27,0xD3,0x4C,0xAD,0x50,0x83,0x61,0xE2,0xAA,0x20, +0x4D,0x09,0x2D,0x64,0x09,0xDC,0xCE,0x89,0x9F,0xCC,0x3D,0xA9,0xEC,0xF6,0xCF,0xC1, +0xDC,0xF1,0xD3,0xB1,0xD6,0x7B,0x37,0x28,0x11,0x2B,0x47,0xDA,0x39,0xC6,0xBC,0x3A, +0x19,0xB4,0x5F,0xA6,0xBD,0x7D,0x9D,0xA3,0x63,0x42,0xB6,0x76,0xF2,0xA9,0x3B,0x2B, +0x91,0xF8,0xE2,0x6F,0xD0,0xEC,0x16,0x20,0x90,0x09,0x3E,0xE2,0xE8,0x74,0xC9,0x18, +0xB4,0x91,0xD4,0x62,0x64,0xDB,0x7F,0xA3,0x06,0xF1,0x88,0x18,0x6A,0x90,0x22,0x3C, +0xBC,0xFE,0x13,0xF0,0x87,0x14,0x7B,0xF6,0xE4,0x1F,0x8E,0xD4,0xE4,0x51,0xC6,0x11, +0x67,0x46,0x08,0x51,0xCB,0x86,0x14,0x54,0x3F,0xBC,0x33,0xFE,0x7E,0x6C,0x9C,0xFF, +0x16,0x9D,0x18,0xBD,0x51,0x8E,0x35,0xA6,0xA7,0x66,0xC8,0x72,0x67,0xDB,0x21,0x66, +0xB1,0xD4,0x9B,0x78,0x03,0xC0,0x50,0x3A,0xE8,0xCC,0xF0,0xDC,0xBC,0x9E,0x4C,0xFE, +0xAF,0x05,0x96,0x35,0x1F,0x57,0x5A,0xB7,0xFF,0xCE,0xF9,0x3D,0xB7,0x2C,0xB6,0xF6, +0x54,0xDD,0xC8,0xE7,0x12,0x3A,0x4D,0xAE,0x4C,0x8A,0xB7,0x5C,0x9A,0xB4,0xB7,0x20, +0x3D,0xCA,0x7F,0x22,0x34,0xAE,0x7E,0x3B,0x68,0x66,0x01,0x44,0xE7,0x01,0x4E,0x46, +0x53,0x9B,0x33,0x60,0xF7,0x94,0xBE,0x53,0x37,0x90,0x73,0x43,0xF3,0x32,0xC3,0x53, +0xEF,0xDB,0xAA,0xFE,0x74,0x4E,0x69,0xC7,0x6B,0x8C,0x60,0x93,0xDE,0xC4,0xC7,0x0C, +0xDF,0xE1,0x32,0xAE,0xCC,0x93,0x3B,0x51,0x78,0x95,0x67,0x8B,0xEE,0x3D,0x56,0xFE, +0x0C,0xD0,0x69,0x0F,0x1B,0x0F,0xF3,0x25,0x26,0x6B,0x33,0x6D,0xF7,0x6E,0x47,0xFA, +0x73,0x43,0xE5,0x7E,0x0E,0xA5,0x66,0xB1,0x29,0x7C,0x32,0x84,0x63,0x55,0x89,0xC4, +0x0D,0xC1,0x93,0x54,0x30,0x19,0x13,0xAC,0xD3,0x7D,0x37,0xA7,0xEB,0x5D,0x3A,0x6C, +0x35,0x5C,0xDB,0x41,0xD7,0x12,0xDA,0xA9,0x49,0x0B,0xDF,0xD8,0x80,0x8A,0x09,0x93, +0x62,0x8E,0xB5,0x66,0xCF,0x25,0x88,0xCD,0x84,0xB8,0xB1,0x3F,0xA4,0x39,0x0F,0xD9, +0x02,0x9E,0xEB,0x12,0x4C,0x95,0x7C,0xF3,0x6B,0x05,0xA9,0x5E,0x16,0x83,0xCC,0xB8, +0x67,0xE2,0xE8,0x13,0x9D,0xCC,0x5B,0x82,0xD3,0x4C,0xB3,0xED,0x5B,0xFF,0xDE,0xE5, +0x73,0xAC,0x23,0x3B,0x2D,0x00,0xBF,0x35,0x55,0x74,0x09,0x49,0xD8,0x49,0x58,0x1A, +0x7F,0x92,0x36,0xE6,0x51,0x92,0x0E,0xF3,0x26,0x7D,0x1C,0x4D,0x17,0xBC,0xC9,0xEC, +0x43,0x26,0xD0,0xBF,0x41,0x5F,0x40,0xA9,0x44,0x44,0xF4,0x99,0xE7,0x57,0x87,0x9E, +0x50,0x1F,0x57,0x54,0xA8,0x3E,0xFD,0x74,0x63,0x2F,0xB1,0x50,0x65,0x09,0xE6,0x58, +0x42,0x2E,0x43,0x1A,0x4C,0xB4,0xF0,0x25,0x47,0x59,0xFA,0x04,0x1E,0x93,0xD4,0x26, +0x46,0x4A,0x50,0x81,0xB2,0xDE,0xBE,0x78,0xB7,0xFC,0x67,0x15,0xE1,0xC9,0x57,0x84, +0x1E,0x0F,0x63,0xD6,0xE9,0x62,0xBA,0xD6,0x5F,0x55,0x2E,0xEA,0x5C,0xC6,0x28,0x08, +0x04,0x25,0x39,0xB8,0x0E,0x2B,0xA9,0xF2,0x4C,0x97,0x1C,0x07,0x3F,0x0D,0x52,0xF5, +0xED,0xEF,0x2F,0x82,0x0F,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x53,0x79,0xBF,0x5A,0xAA,0x2B,0x4A, +0xCF,0x54,0x80,0xE1,0xD8,0x9B,0xC0,0x9D,0xF2,0xB2,0x03,0x66,0xCB,0x30,0x0E,0x06, +0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02, +0x01,0x00,0x5C,0xD4,0x7C,0x0D,0xCF,0xF7,0x01,0x7D,0x41,0x99,0x65,0x0C,0x73,0xC5, +0x52,0x9F,0xCB,0xF8,0xCF,0x99,0x06,0x7F,0x1B,0xDA,0x43,0x15,0x9F,0x9E,0x02,0x55, +0x57,0x96,0x14,0xF1,0x52,0x3C,0x27,0x87,0x94,0x28,0xED,0x1F,0x3A,0x01,0x37,0xA2, +0x76,0xFC,0x53,0x50,0xC0,0x84,0x9B,0xC6,0x6B,0x4E,0xBA,0x8C,0x21,0x4F,0xA2,0x8E, +0x55,0x62,0x91,0xF3,0x69,0x15,0xD8,0xBC,0x88,0xE3,0xC4,0xAA,0x0B,0xFD,0xEF,0xA8, +0xE9,0x4B,0x55,0x2A,0x06,0x20,0x6D,0x55,0x78,0x29,0x19,0xEE,0x5F,0x30,0x5C,0x4B, +0x24,0x11,0x55,0xFF,0x24,0x9A,0x6E,0x5E,0x2A,0x2B,0xEE,0x0B,0x4D,0x9F,0x7F,0xF7, +0x01,0x38,0x94,0x14,0x95,0x43,0x07,0x09,0xFB,0x60,0xA9,0xEE,0x1C,0xAB,0x12,0x8C, +0xA0,0x9A,0x5E,0xA7,0x98,0x6A,0x59,0x6D,0x8B,0x3F,0x08,0xFB,0xC8,0xD1,0x45,0xAF, +0x18,0x15,0x64,0x90,0x12,0x0F,0x73,0x28,0x2E,0xC5,0xE2,0x24,0x4E,0xFC,0x58,0xEC, +0xF0,0xF4,0x45,0xFE,0x22,0xB3,0xEB,0x2F,0x8E,0xD2,0xD9,0x45,0x61,0x05,0xC1,0x97, +0x6F,0xA8,0x76,0x72,0x8F,0x8B,0x8C,0x36,0xAF,0xBF,0x0D,0x05,0xCE,0x71,0x8D,0xE6, +0xA6,0x6F,0x1F,0x6C,0xA6,0x71,0x62,0xC5,0xD8,0xD0,0x83,0x72,0x0C,0xF1,0x67,0x11, +0x89,0x0C,0x9C,0x13,0x4C,0x72,0x34,0xDF,0xBC,0xD5,0x71,0xDF,0xAA,0x71,0xDD,0xE1, +0xB9,0x6C,0x8C,0x3C,0x12,0x5D,0x65,0xDA,0xBD,0x57,0x12,0xB6,0x43,0x6B,0xFF,0xE5, +0xDE,0x4D,0x66,0x11,0x51,0xCF,0x99,0xAE,0xEC,0x17,0xB6,0xE8,0x71,0x91,0x8C,0xDE, +0x49,0xFE,0xDD,0x35,0x71,0xA2,0x15,0x27,0x94,0x1C,0xCF,0x61,0xE3,0x26,0xBB,0x6F, +0xA3,0x67,0x25,0x21,0x5D,0xE6,0xDD,0x1D,0x0B,0x2E,0x68,0x1B,0x3B,0x82,0xAF,0xEC, +0x83,0x67,0x85,0xD4,0x98,0x51,0x74,0xB1,0xB9,0x99,0x80,0x89,0xFF,0x7F,0x78,0x19, +0x5C,0x79,0x4A,0x60,0x2E,0x92,0x40,0xAE,0x4C,0x37,0x2A,0x2C,0xC9,0xC7,0x62,0xC8, +0x0E,0x5D,0xF7,0x36,0x5B,0xCA,0xE0,0x25,0x25,0x01,0xB4,0xDD,0x1A,0x07,0x9C,0x77, +0x00,0x3F,0xD0,0xDC,0xD5,0xEC,0x3D,0xD4,0xFA,0xBB,0x3F,0xCC,0x85,0xD6,0x6F,0x7F, +0xA9,0x2D,0xDF,0xB9,0x02,0xF7,0xF5,0x97,0x9A,0xB5,0x35,0xDA,0xC3,0x67,0xB0,0x87, +0x4A,0xA9,0x28,0x9E,0x23,0x8E,0xFF,0x5C,0x27,0x6B,0xE1,0xB0,0x4F,0xF3,0x07,0xEE, +0x00,0x2E,0xD4,0x59,0x87,0xCB,0x52,0x41,0x95,0xEA,0xF4,0x47,0xD7,0xEE,0x64,0x41, +0x55,0x7C,0x8D,0x59,0x02,0x95,0xDD,0x62,0x9D,0xC2,0xB9,0xEE,0x5A,0x28,0x74,0x84, +0xA5,0x9B,0xB7,0x90,0xC7,0x0C,0x07,0xDF,0xF5,0x89,0x36,0x74,0x32,0xD6,0x28,0xC1, +0xB0,0xB0,0x0B,0xE0,0x9C,0x4C,0xC3,0x1C,0xD6,0xFC,0xE3,0x69,0xB5,0x47,0x46,0x81, +0x2F,0xA2,0x82,0xAB,0xD3,0x63,0x44,0x70,0xC4,0x8D,0xFF,0x2D,0x33,0xBA,0xAD,0x8F, +0x7B,0xB5,0x70,0x88,0xAE,0x3E,0x19,0xCF,0x40,0x28,0xD8,0xFC,0xC8,0x90,0xBB,0x5D, +0x99,0x22,0xF5,0x52,0xE6,0x58,0xC5,0x1F,0x88,0x31,0x43,0xEE,0x88,0x1D,0xD7,0xC6, +0x8E,0x3C,0x43,0x6A,0x1D,0xA7,0x18,0xDE,0x7D,0x3D,0x16,0xF1,0x62,0xF9,0xCA,0x90, +0xA8,0xFD, +}; + + +/* subject:/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority */ +/* issuer :/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority */ + + +const unsigned char Starfield_Class_2_CA_certificate[1043]={ +0x30,0x82,0x04,0x0F,0x30,0x82,0x02,0xF7,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14, -0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73, -0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41, -0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C, -0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30,0x20, -0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20, -0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74, -0x30,0x1E,0x17,0x0D,0x30,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38, -0x5A,0x17,0x0D,0x32,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38,0x5A, -0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31, -0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75, -0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D, -0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61, -0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30, -0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74, -0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F, -0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, -0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01, -0x01,0x00,0xB7,0xF7,0x1A,0x33,0xE6,0xF2,0x00,0x04,0x2D,0x39,0xE0,0x4E,0x5B,0xED, -0x1F,0xBC,0x6C,0x0F,0xCD,0xB5,0xFA,0x23,0xB6,0xCE,0xDE,0x9B,0x11,0x33,0x97,0xA4, -0x29,0x4C,0x7D,0x93,0x9F,0xBD,0x4A,0xBC,0x93,0xED,0x03,0x1A,0xE3,0x8F,0xCF,0xE5, -0x6D,0x50,0x5A,0xD6,0x97,0x29,0x94,0x5A,0x80,0xB0,0x49,0x7A,0xDB,0x2E,0x95,0xFD, -0xB8,0xCA,0xBF,0x37,0x38,0x2D,0x1E,0x3E,0x91,0x41,0xAD,0x70,0x56,0xC7,0xF0,0x4F, -0x3F,0xE8,0x32,0x9E,0x74,0xCA,0xC8,0x90,0x54,0xE9,0xC6,0x5F,0x0F,0x78,0x9D,0x9A, -0x40,0x3C,0x0E,0xAC,0x61,0xAA,0x5E,0x14,0x8F,0x9E,0x87,0xA1,0x6A,0x50,0xDC,0xD7, -0x9A,0x4E,0xAF,0x05,0xB3,0xA6,0x71,0x94,0x9C,0x71,0xB3,0x50,0x60,0x0A,0xC7,0x13, -0x9D,0x38,0x07,0x86,0x02,0xA8,0xE9,0xA8,0x69,0x26,0x18,0x90,0xAB,0x4C,0xB0,0x4F, -0x23,0xAB,0x3A,0x4F,0x84,0xD8,0xDF,0xCE,0x9F,0xE1,0x69,0x6F,0xBB,0xD7,0x42,0xD7, -0x6B,0x44,0xE4,0xC7,0xAD,0xEE,0x6D,0x41,0x5F,0x72,0x5A,0x71,0x08,0x37,0xB3,0x79, -0x65,0xA4,0x59,0xA0,0x94,0x37,0xF7,0x00,0x2F,0x0D,0xC2,0x92,0x72,0xDA,0xD0,0x38, -0x72,0xDB,0x14,0xA8,0x45,0xC4,0x5D,0x2A,0x7D,0xB7,0xB4,0xD6,0xC4,0xEE,0xAC,0xCD, -0x13,0x44,0xB7,0xC9,0x2B,0xDD,0x43,0x00,0x25,0xFA,0x61,0xB9,0x69,0x6A,0x58,0x23, -0x11,0xB7,0xA7,0x33,0x8F,0x56,0x75,0x59,0xF5,0xCD,0x29,0xD7,0x46,0xB7,0x0A,0x2B, -0x65,0xB6,0xD3,0x42,0x6F,0x15,0xB2,0xB8,0x7B,0xFB,0xEF,0xE9,0x5D,0x53,0xD5,0x34, -0x5A,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xDC,0x30,0x81,0xD9,0x30,0x1D,0x06, -0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4,0x26,0xF7, -0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0x30,0x0B,0x06,0x03, -0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13, -0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x99,0x06,0x03,0x55, -0x1D,0x23,0x04,0x81,0x91,0x30,0x81,0x8E,0x80,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4, -0x26,0xF7,0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0xA1,0x73, -0xA4,0x71,0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53, -0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54, -0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, -0x13,0x1D,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72, -0x6E,0x61,0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31, -0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75, -0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52, -0x6F,0x6F,0x74,0x82,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xB0,0x9B,0xE0,0x85,0x25,0xC2, -0xD6,0x23,0xE2,0x0F,0x96,0x06,0x92,0x9D,0x41,0x98,0x9C,0xD9,0x84,0x79,0x81,0xD9, -0x1E,0x5B,0x14,0x07,0x23,0x36,0x65,0x8F,0xB0,0xD8,0x77,0xBB,0xAC,0x41,0x6C,0x47, -0x60,0x83,0x51,0xB0,0xF9,0x32,0x3D,0xE7,0xFC,0xF6,0x26,0x13,0xC7,0x80,0x16,0xA5, -0xBF,0x5A,0xFC,0x87,0xCF,0x78,0x79,0x89,0x21,0x9A,0xE2,0x4C,0x07,0x0A,0x86,0x35, -0xBC,0xF2,0xDE,0x51,0xC4,0xD2,0x96,0xB7,0xDC,0x7E,0x4E,0xEE,0x70,0xFD,0x1C,0x39, -0xEB,0x0C,0x02,0x51,0x14,0x2D,0x8E,0xBD,0x16,0xE0,0xC1,0xDF,0x46,0x75,0xE7,0x24, -0xAD,0xEC,0xF4,0x42,0xB4,0x85,0x93,0x70,0x10,0x67,0xBA,0x9D,0x06,0x35,0x4A,0x18, -0xD3,0x2B,0x7A,0xCC,0x51,0x42,0xA1,0x7A,0x63,0xD1,0xE6,0xBB,0xA1,0xC5,0x2B,0xC2, -0x36,0xBE,0x13,0x0D,0xE6,0xBD,0x63,0x7E,0x79,0x7B,0xA7,0x09,0x0D,0x40,0xAB,0x6A, -0xDD,0x8F,0x8A,0xC3,0xF6,0xF6,0x8C,0x1A,0x42,0x05,0x51,0xD4,0x45,0xF5,0x9F,0xA7, -0x62,0x21,0x68,0x15,0x20,0x43,0x3C,0x99,0xE7,0x7C,0xBD,0x24,0xD8,0xA9,0x91,0x17, -0x73,0x88,0x3F,0x56,0x1B,0x31,0x38,0x18,0xB4,0x71,0x0F,0x9A,0xCD,0xC8,0x0E,0x9E, -0x8E,0x2E,0x1B,0xE1,0x8C,0x98,0x83,0xCB,0x1F,0x31,0xF1,0x44,0x4C,0xC6,0x04,0x73, -0x49,0x76,0x60,0x0F,0xC7,0xF8,0xBD,0x17,0x80,0x6B,0x2E,0xE9,0xCC,0x4C,0x0E,0x5A, -0x9A,0x79,0x0F,0x20,0x0A,0x2E,0xD5,0x9E,0x63,0x26,0x1E,0x55,0x92,0x94,0xD8,0x82, -0x17,0x5A,0x7B,0xD0,0xBC,0xC7,0x8F,0x4E,0x86,0x04, +0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25, +0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65, +0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29, +0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, +0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30, +0x36,0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36, +0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, +0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, +0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, +0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D,0x00,0x30,0x82,0x01,0x08,0x02, +0x82,0x01,0x01,0x00,0xB7,0x32,0xC8,0xFE,0xE9,0x71,0xA6,0x04,0x85,0xAD,0x0C,0x11, +0x64,0xDF,0xCE,0x4D,0xEF,0xC8,0x03,0x18,0x87,0x3F,0xA1,0xAB,0xFB,0x3C,0xA6,0x9F, +0xF0,0xC3,0xA1,0xDA,0xD4,0xD8,0x6E,0x2B,0x53,0x90,0xFB,0x24,0xA4,0x3E,0x84,0xF0, +0x9E,0xE8,0x5F,0xEC,0xE5,0x27,0x44,0xF5,0x28,0xA6,0x3F,0x7B,0xDE,0xE0,0x2A,0xF0, +0xC8,0xAF,0x53,0x2F,0x9E,0xCA,0x05,0x01,0x93,0x1E,0x8F,0x66,0x1C,0x39,0xA7,0x4D, +0xFA,0x5A,0xB6,0x73,0x04,0x25,0x66,0xEB,0x77,0x7F,0xE7,0x59,0xC6,0x4A,0x99,0x25, +0x14,0x54,0xEB,0x26,0xC7,0xF3,0x7F,0x19,0xD5,0x30,0x70,0x8F,0xAF,0xB0,0x46,0x2A, +0xFF,0xAD,0xEB,0x29,0xED,0xD7,0x9F,0xAA,0x04,0x87,0xA3,0xD4,0xF9,0x89,0xA5,0x34, +0x5F,0xDB,0x43,0x91,0x82,0x36,0xD9,0x66,0x3C,0xB1,0xB8,0xB9,0x82,0xFD,0x9C,0x3A, +0x3E,0x10,0xC8,0x3B,0xEF,0x06,0x65,0x66,0x7A,0x9B,0x19,0x18,0x3D,0xFF,0x71,0x51, +0x3C,0x30,0x2E,0x5F,0xBE,0x3D,0x77,0x73,0xB2,0x5D,0x06,0x6C,0xC3,0x23,0x56,0x9A, +0x2B,0x85,0x26,0x92,0x1C,0xA7,0x02,0xB3,0xE4,0x3F,0x0D,0xAF,0x08,0x79,0x82,0xB8, +0x36,0x3D,0xEA,0x9C,0xD3,0x35,0xB3,0xBC,0x69,0xCA,0xF5,0xCC,0x9D,0xE8,0xFD,0x64, +0x8D,0x17,0x80,0x33,0x6E,0x5E,0x4A,0x5D,0x99,0xC9,0x1E,0x87,0xB4,0x9D,0x1A,0xC0, +0xD5,0x6E,0x13,0x35,0x23,0x5E,0xDF,0x9B,0x5F,0x3D,0xEF,0xD6,0xF7,0x76,0xC2,0xEA, +0x3E,0xBB,0x78,0x0D,0x1C,0x42,0x67,0x6B,0x04,0xD8,0xF8,0xD6,0xDA,0x6F,0x8B,0xF2, +0x44,0xA0,0x01,0xAB,0x02,0x01,0x03,0xA3,0x81,0xC5,0x30,0x81,0xC2,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBF,0x5F,0xB7,0xD1,0xCE,0xDD,0x1F,0x86, +0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7,0x30,0x81,0x92,0x06, +0x03,0x55,0x1D,0x23,0x04,0x81,0x8A,0x30,0x81,0x87,0x80,0x14,0xBF,0x5F,0xB7,0xD1, +0xCE,0xDD,0x1F,0x86,0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7, +0xA1,0x6C,0xA4,0x6A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74, +0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F, +0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03, +0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43, +0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82,0x01, +0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x05,0x9D,0x3F,0x88,0x9D,0xD1,0xC9,0x1A,0x55,0xA1,0xAC,0x69,0xF3, +0xF3,0x59,0xDA,0x9B,0x01,0x87,0x1A,0x4F,0x57,0xA9,0xA1,0x79,0x09,0x2A,0xDB,0xF7, +0x2F,0xB2,0x1E,0xCC,0xC7,0x5E,0x6A,0xD8,0x83,0x87,0xA1,0x97,0xEF,0x49,0x35,0x3E, +0x77,0x06,0x41,0x58,0x62,0xBF,0x8E,0x58,0xB8,0x0A,0x67,0x3F,0xEC,0xB3,0xDD,0x21, +0x66,0x1F,0xC9,0x54,0xFA,0x72,0xCC,0x3D,0x4C,0x40,0xD8,0x81,0xAF,0x77,0x9E,0x83, +0x7A,0xBB,0xA2,0xC7,0xF5,0x34,0x17,0x8E,0xD9,0x11,0x40,0xF4,0xFC,0x2C,0x2A,0x4D, +0x15,0x7F,0xA7,0x62,0x5D,0x2E,0x25,0xD3,0x00,0x0B,0x20,0x1A,0x1D,0x68,0xF9,0x17, +0xB8,0xF4,0xBD,0x8B,0xED,0x28,0x59,0xDD,0x4D,0x16,0x8B,0x17,0x83,0xC8,0xB2,0x65, +0xC7,0x2D,0x7A,0xA5,0xAA,0xBC,0x53,0x86,0x6D,0xDD,0x57,0xA4,0xCA,0xF8,0x20,0x41, +0x0B,0x68,0xF0,0xF4,0xFB,0x74,0xBE,0x56,0x5D,0x7A,0x79,0xF5,0xF9,0x1D,0x85,0xE3, +0x2D,0x95,0xBE,0xF5,0x71,0x90,0x43,0xCC,0x8D,0x1F,0x9A,0x00,0x0A,0x87,0x29,0xE9, +0x55,0x22,0x58,0x00,0x23,0xEA,0xE3,0x12,0x43,0x29,0x5B,0x47,0x08,0xDD,0x8C,0x41, +0x6A,0x65,0x06,0xA8,0xE5,0x21,0xAA,0x41,0xB4,0x95,0x21,0x95,0xB9,0x7D,0xD1,0x34, +0xAB,0x13,0xD6,0xAD,0xBC,0xDC,0xE2,0x3D,0x39,0xCD,0xBD,0x3E,0x75,0x70,0xA1,0x18, +0x59,0x03,0xC9,0x22,0xB4,0x8F,0x9C,0xD5,0x5E,0x2A,0xD7,0xA5,0xB6,0xD4,0x0A,0x6D, +0xF8,0xB7,0x40,0x11,0x46,0x9A,0x1F,0x79,0x0E,0x62,0xBF,0x0F,0x97,0xEC,0xE0,0x2F, +0x1F,0x17,0x94, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G3 */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G3 */ + + +const unsigned char Verisign_Class_3_Public_Primary_Certification_Authority___G3_certificate[1054]={ +0x30,0x82,0x04,0x1A,0x30,0x82,0x03,0x02,0x02,0x11,0x00,0x9B,0x7E,0x06,0x49,0xA3, +0x3E,0x62,0xB9,0xD5,0xEE,0x90,0x48,0x71,0x29,0xEF,0x57,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xCA,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65, +0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, +0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, +0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C, +0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x2D,0x20,0x47,0x33,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31,0x30,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31,0x36, +0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E, +0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20, +0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72, +0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45,0x30, +0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, +0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x33,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xCB,0xBA,0x9C,0x52,0xFC,0x78,0x1F,0x1A,0x1E,0x6F,0x1B, +0x37,0x73,0xBD,0xF8,0xC9,0x6B,0x94,0x12,0x30,0x4F,0xF0,0x36,0x47,0xF5,0xD0,0x91, +0x0A,0xF5,0x17,0xC8,0xA5,0x61,0xC1,0x16,0x40,0x4D,0xFB,0x8A,0x61,0x90,0xE5,0x76, +0x20,0xC1,0x11,0x06,0x7D,0xAB,0x2C,0x6E,0xA6,0xF5,0x11,0x41,0x8E,0xFA,0x2D,0xAD, +0x2A,0x61,0x59,0xA4,0x67,0x26,0x4C,0xD0,0xE8,0xBC,0x52,0x5B,0x70,0x20,0x04,0x58, +0xD1,0x7A,0xC9,0xA4,0x69,0xBC,0x83,0x17,0x64,0xAD,0x05,0x8B,0xBC,0xD0,0x58,0xCE, +0x8D,0x8C,0xF5,0xEB,0xF0,0x42,0x49,0x0B,0x9D,0x97,0x27,0x67,0x32,0x6E,0xE1,0xAE, +0x93,0x15,0x1C,0x70,0xBC,0x20,0x4D,0x2F,0x18,0xDE,0x92,0x88,0xE8,0x6C,0x85,0x57, +0x11,0x1A,0xE9,0x7E,0xE3,0x26,0x11,0x54,0xA2,0x45,0x96,0x55,0x83,0xCA,0x30,0x89, +0xE8,0xDC,0xD8,0xA3,0xED,0x2A,0x80,0x3F,0x7F,0x79,0x65,0x57,0x3E,0x15,0x20,0x66, +0x08,0x2F,0x95,0x93,0xBF,0xAA,0x47,0x2F,0xA8,0x46,0x97,0xF0,0x12,0xE2,0xFE,0xC2, +0x0A,0x2B,0x51,0xE6,0x76,0xE6,0xB7,0x46,0xB7,0xE2,0x0D,0xA6,0xCC,0xA8,0xC3,0x4C, +0x59,0x55,0x89,0xE6,0xE8,0x53,0x5C,0x1C,0xEA,0x9D,0xF0,0x62,0x16,0x0B,0xA7,0xC9, +0x5F,0x0C,0xF0,0xDE,0xC2,0x76,0xCE,0xAF,0xF7,0x6A,0xF2,0xFA,0x41,0xA6,0xA2,0x33, +0x14,0xC9,0xE5,0x7A,0x63,0xD3,0x9E,0x62,0x37,0xD5,0x85,0x65,0x9E,0x0E,0xE6,0x53, +0x24,0x74,0x1B,0x5E,0x1D,0x12,0x53,0x5B,0xC7,0x2C,0xE7,0x83,0x49,0x3B,0x15,0xAE, +0x8A,0x68,0xB9,0x57,0x97,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x11,0x14, +0x96,0xC1,0xAB,0x92,0x08,0xF7,0x3F,0x2F,0xC9,0xB2,0xFE,0xE4,0x5A,0x9F,0x64,0xDE, +0xDB,0x21,0x4F,0x86,0x99,0x34,0x76,0x36,0x57,0xDD,0xD0,0x15,0x2F,0xC5,0xAD,0x7F, +0x15,0x1F,0x37,0x62,0x73,0x3E,0xD4,0xE7,0x5F,0xCE,0x17,0x03,0xDB,0x35,0xFA,0x2B, +0xDB,0xAE,0x60,0x09,0x5F,0x1E,0x5F,0x8F,0x6E,0xBB,0x0B,0x3D,0xEA,0x5A,0x13,0x1E, +0x0C,0x60,0x6F,0xB5,0xC0,0xB5,0x23,0x22,0x2E,0x07,0x0B,0xCB,0xA9,0x74,0xCB,0x47, +0xBB,0x1D,0xC1,0xD7,0xA5,0x6B,0xCC,0x2F,0xD2,0x42,0xFD,0x49,0xDD,0xA7,0x89,0xCF, +0x53,0xBA,0xDA,0x00,0x5A,0x28,0xBF,0x82,0xDF,0xF8,0xBA,0x13,0x1D,0x50,0x86,0x82, +0xFD,0x8E,0x30,0x8F,0x29,0x46,0xB0,0x1E,0x3D,0x35,0xDA,0x38,0x62,0x16,0x18,0x4A, +0xAD,0xE6,0xB6,0x51,0x6C,0xDE,0xAF,0x62,0xEB,0x01,0xD0,0x1E,0x24,0xFE,0x7A,0x8F, +0x12,0x1A,0x12,0x68,0xB8,0xFB,0x66,0x99,0x14,0x14,0x45,0x5C,0xAE,0xE7,0xAE,0x69, +0x17,0x81,0x2B,0x5A,0x37,0xC9,0x5E,0x2A,0xF4,0xC6,0xE2,0xA1,0x5C,0x54,0x9B,0xA6, +0x54,0x00,0xCF,0xF0,0xF1,0xC1,0xC7,0x98,0x30,0x1A,0x3B,0x36,0x16,0xDB,0xA3,0x6E, +0xEA,0xFD,0xAD,0xB2,0xC2,0xDA,0xEF,0x02,0x47,0x13,0x8A,0xC0,0xF1,0xB3,0x31,0xAD, +0x4F,0x1C,0xE1,0x4F,0x9C,0xAF,0x0F,0x0C,0x9D,0xF7,0x78,0x0D,0xD8,0xF4,0x35,0x56, +0x80,0xDA,0xB7,0x6D,0x17,0x8F,0x9D,0x1E,0x81,0x64,0xE1,0xFE,0xC5,0x45,0xBA,0xAD, +0x6B,0xB9,0x0A,0x7A,0x4E,0x4F,0x4B,0x84,0xEE,0x4B,0xF1,0x7D,0xDD,0x11, +}; + + +/* subject:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust ECC Certification Authority */ +/* issuer :/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust ECC Certification Authority */ + + +const unsigned char USERTrust_ECC_Certification_Authority_certificate[659]={ +0x30,0x82,0x02,0x8F,0x30,0x82,0x02,0x15,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x5C, +0x8B,0x99,0xC5,0x5A,0x94,0xC5,0xD2,0x71,0x56,0xDE,0xCD,0x89,0x80,0xCC,0x26,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x88,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x08,0x13,0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72,0x73,0x65,0x79, +0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65,0x72,0x73,0x65, +0x79,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13, +0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E, +0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x03,0x13, +0x25,0x55,0x53,0x45,0x52,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x43,0x43,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30,0x32,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, +0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x88,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x13, +0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72,0x73,0x65,0x79,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65,0x72,0x73,0x65,0x79,0x20,0x43,0x69,0x74, +0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20, +0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x03,0x13,0x25,0x55,0x53,0x45,0x52, +0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74,0x69,0x66, +0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x1A,0xAC,0x54,0x5A,0xA9,0xF9,0x68, +0x23,0xE7,0x7A,0xD5,0x24,0x6F,0x53,0xC6,0x5A,0xD8,0x4B,0xAB,0xC6,0xD5,0xB6,0xD1, +0xE6,0x73,0x71,0xAE,0xDD,0x9C,0xD6,0x0C,0x61,0xFD,0xDB,0xA0,0x89,0x03,0xB8,0x05, +0x14,0xEC,0x57,0xCE,0xEE,0x5D,0x3F,0xE2,0x21,0xB3,0xCE,0xF7,0xD4,0x8A,0x79,0xE0, +0xA3,0x83,0x7E,0x2D,0x97,0xD0,0x61,0xC4,0xF1,0x99,0xDC,0x25,0x91,0x63,0xAB,0x7F, +0x30,0xA3,0xB4,0x70,0xE2,0xC7,0xA1,0x33,0x9C,0xF3,0xBF,0x2E,0x5C,0x53,0xB1,0x5F, +0xB3,0x7D,0x32,0x7F,0x8A,0x34,0xE3,0x79,0x79,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x3A,0xE1,0x09,0x86,0xD4,0xCF,0x19,0xC2, +0x96,0x76,0x74,0x49,0x76,0xDC,0xE0,0x35,0xC6,0x63,0x63,0x9A,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x30, +0x36,0x67,0xA1,0x16,0x08,0xDC,0xE4,0x97,0x00,0x41,0x1D,0x4E,0xBE,0xE1,0x63,0x01, +0xCF,0x3B,0xAA,0x42,0x11,0x64,0xA0,0x9D,0x94,0x39,0x02,0x11,0x79,0x5C,0x7B,0x1D, +0xFA,0x64,0xB9,0xEE,0x16,0x42,0xB3,0xBF,0x8A,0xC2,0x09,0xC4,0xEC,0xE4,0xB1,0x4D, +0x02,0x31,0x00,0xE9,0x2A,0x61,0x47,0x8C,0x52,0x4A,0x4B,0x4E,0x18,0x70,0xF6,0xD6, +0x44,0xD6,0x6E,0xF5,0x83,0xBA,0x6D,0x58,0xBD,0x24,0xD9,0x56,0x48,0xEA,0xEF,0xC4, +0xA2,0x46,0x81,0x88,0x6A,0x3A,0x46,0xD1,0xA9,0x9B,0x4D,0xC9,0x61,0xDA,0xD1,0x5D, +0x57,0x6A,0x18, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ + + +const unsigned char GeoTrust_Global_CA_certificate[856]={ +0x30,0x82,0x03,0x54,0x30,0x82,0x02,0x3C,0xA0,0x03,0x02,0x01,0x02,0x02,0x03,0x02, +0x34,0x56,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05, +0x00,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72, +0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04, +0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62, +0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x32,0x30,0x35,0x32,0x31,0x30, +0x34,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x32,0x30,0x35,0x32,0x31,0x30,0x34, +0x30,0x30,0x30,0x30,0x5A,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47, +0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19, +0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, +0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDA,0xCC,0x18,0x63,0x30,0xFD, +0xF4,0x17,0x23,0x1A,0x56,0x7E,0x5B,0xDF,0x3C,0x6C,0x38,0xE4,0x71,0xB7,0x78,0x91, +0xD4,0xBC,0xA1,0xD8,0x4C,0xF8,0xA8,0x43,0xB6,0x03,0xE9,0x4D,0x21,0x07,0x08,0x88, +0xDA,0x58,0x2F,0x66,0x39,0x29,0xBD,0x05,0x78,0x8B,0x9D,0x38,0xE8,0x05,0xB7,0x6A, +0x7E,0x71,0xA4,0xE6,0xC4,0x60,0xA6,0xB0,0xEF,0x80,0xE4,0x89,0x28,0x0F,0x9E,0x25, +0xD6,0xED,0x83,0xF3,0xAD,0xA6,0x91,0xC7,0x98,0xC9,0x42,0x18,0x35,0x14,0x9D,0xAD, +0x98,0x46,0x92,0x2E,0x4F,0xCA,0xF1,0x87,0x43,0xC1,0x16,0x95,0x57,0x2D,0x50,0xEF, +0x89,0x2D,0x80,0x7A,0x57,0xAD,0xF2,0xEE,0x5F,0x6B,0xD2,0x00,0x8D,0xB9,0x14,0xF8, +0x14,0x15,0x35,0xD9,0xC0,0x46,0xA3,0x7B,0x72,0xC8,0x91,0xBF,0xC9,0x55,0x2B,0xCD, +0xD0,0x97,0x3E,0x9C,0x26,0x64,0xCC,0xDF,0xCE,0x83,0x19,0x71,0xCA,0x4E,0xE6,0xD4, +0xD5,0x7B,0xA9,0x19,0xCD,0x55,0xDE,0xC8,0xEC,0xD2,0x5E,0x38,0x53,0xE5,0x5C,0x4F, +0x8C,0x2D,0xFE,0x50,0x23,0x36,0xFC,0x66,0xE6,0xCB,0x8E,0xA4,0x39,0x19,0x00,0xB7, +0x95,0x02,0x39,0x91,0x0B,0x0E,0xFE,0x38,0x2E,0xD1,0x1D,0x05,0x9A,0xF6,0x4D,0x3E, +0x6F,0x0F,0x07,0x1D,0xAF,0x2C,0x1E,0x8F,0x60,0x39,0xE2,0xFA,0x36,0x53,0x13,0x39, +0xD4,0x5E,0x26,0x2B,0xDB,0x3D,0xA8,0x14,0xBD,0x32,0xEB,0x18,0x03,0x28,0x52,0x04, +0x71,0xE5,0xAB,0x33,0x3D,0xE1,0x38,0xBB,0x07,0x36,0x84,0x62,0x9C,0x79,0xEA,0x16, +0x30,0xF4,0x5F,0xC0,0x2B,0xE8,0x71,0x6B,0xE4,0xF9,0x02,0x03,0x01,0x00,0x01,0xA3, +0x53,0x30,0x51,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC0, +0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,0x7D,0xAA,0x7D,0x65,0xB8, +0xCA,0xCC,0x4E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0xC0,0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,0x7D,0xAA,0x7D,0x65, +0xB8,0xCA,0xCC,0x4E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x35,0xE3,0x29,0x6A,0xE5,0x2F,0x5D,0x54, +0x8E,0x29,0x50,0x94,0x9F,0x99,0x1A,0x14,0xE4,0x8F,0x78,0x2A,0x62,0x94,0xA2,0x27, +0x67,0x9E,0xD0,0xCF,0x1A,0x5E,0x47,0xE9,0xC1,0xB2,0xA4,0xCF,0xDD,0x41,0x1A,0x05, +0x4E,0x9B,0x4B,0xEE,0x4A,0x6F,0x55,0x52,0xB3,0x24,0xA1,0x37,0x0A,0xEB,0x64,0x76, +0x2A,0x2E,0x2C,0xF3,0xFD,0x3B,0x75,0x90,0xBF,0xFA,0x71,0xD8,0xC7,0x3D,0x37,0xD2, +0xB5,0x05,0x95,0x62,0xB9,0xA6,0xDE,0x89,0x3D,0x36,0x7B,0x38,0x77,0x48,0x97,0xAC, +0xA6,0x20,0x8F,0x2E,0xA6,0xC9,0x0C,0xC2,0xB2,0x99,0x45,0x00,0xC7,0xCE,0x11,0x51, +0x22,0x22,0xE0,0xA5,0xEA,0xB6,0x15,0x48,0x09,0x64,0xEA,0x5E,0x4F,0x74,0xF7,0x05, +0x3E,0xC7,0x8A,0x52,0x0C,0xDB,0x15,0xB4,0xBD,0x6D,0x9B,0xE5,0xC6,0xB1,0x54,0x68, +0xA9,0xE3,0x69,0x90,0xB6,0x9A,0xA5,0x0F,0xB8,0xB9,0x3F,0x20,0x7D,0xAE,0x4A,0xB5, +0xB8,0x9C,0xE4,0x1D,0xB6,0xAB,0xE6,0x94,0xA5,0xC1,0xC7,0x83,0xAD,0xDB,0xF5,0x27, +0x87,0x0E,0x04,0x6C,0xD5,0xFF,0xDD,0xA0,0x5D,0xED,0x87,0x52,0xB7,0x2B,0x15,0x02, +0xAE,0x39,0xA6,0x6A,0x74,0xE9,0xDA,0xC4,0xE7,0xBC,0x4D,0x34,0x1E,0xA9,0x5C,0x4D, +0x33,0x5F,0x92,0x09,0x2F,0x88,0x66,0x5D,0x77,0x97,0xC7,0x1D,0x76,0x13,0xA9,0xD5, +0xE5,0xF1,0x16,0x09,0x11,0x35,0xD5,0xAC,0xDB,0x24,0x71,0x70,0x2C,0x98,0x56,0x0B, +0xD9,0x17,0xB4,0xD1,0xE3,0x51,0x2B,0x5E,0x75,0xE8,0xD5,0xD0,0xDC,0x4F,0x34,0xED, +0xC2,0x05,0x66,0x80,0xA1,0xCB,0xE6,0x33, +}; + + +/* subject:/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Root Certificate Authority - G2 */ +/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Root Certificate Authority - G2 */ + + +const unsigned char Starfield_Root_Certificate_Authority___G2_certificate[993]={ +0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, +0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, +0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13, +0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E, +0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30, +0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C, +0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47, +0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39, +0x5A,0x30,0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A, +0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63, +0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, +0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, +0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, +0x65,0x6C,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69, +0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D, +0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02, +0x82,0x01,0x01,0x00,0xBD,0xED,0xC1,0x03,0xFC,0xF6,0x8F,0xFC,0x02,0xB1,0x6F,0x5B, +0x9F,0x48,0xD9,0x9D,0x79,0xE2,0xA2,0xB7,0x03,0x61,0x56,0x18,0xC3,0x47,0xB6,0xD7, +0xCA,0x3D,0x35,0x2E,0x89,0x43,0xF7,0xA1,0x69,0x9B,0xDE,0x8A,0x1A,0xFD,0x13,0x20, +0x9C,0xB4,0x49,0x77,0x32,0x29,0x56,0xFD,0xB9,0xEC,0x8C,0xDD,0x22,0xFA,0x72,0xDC, +0x27,0x61,0x97,0xEE,0xF6,0x5A,0x84,0xEC,0x6E,0x19,0xB9,0x89,0x2C,0xDC,0x84,0x5B, +0xD5,0x74,0xFB,0x6B,0x5F,0xC5,0x89,0xA5,0x10,0x52,0x89,0x46,0x55,0xF4,0xB8,0x75, +0x1C,0xE6,0x7F,0xE4,0x54,0xAE,0x4B,0xF8,0x55,0x72,0x57,0x02,0x19,0xF8,0x17,0x71, +0x59,0xEB,0x1E,0x28,0x07,0x74,0xC5,0x9D,0x48,0xBE,0x6C,0xB4,0xF4,0xA4,0xB0,0xF3, +0x64,0x37,0x79,0x92,0xC0,0xEC,0x46,0x5E,0x7F,0xE1,0x6D,0x53,0x4C,0x62,0xAF,0xCD, +0x1F,0x0B,0x63,0xBB,0x3A,0x9D,0xFB,0xFC,0x79,0x00,0x98,0x61,0x74,0xCF,0x26,0x82, +0x40,0x63,0xF3,0xB2,0x72,0x6A,0x19,0x0D,0x99,0xCA,0xD4,0x0E,0x75,0xCC,0x37,0xFB, +0x8B,0x89,0xC1,0x59,0xF1,0x62,0x7F,0x5F,0xB3,0x5F,0x65,0x30,0xF8,0xA7,0xB7,0x4D, +0x76,0x5A,0x1E,0x76,0x5E,0x34,0xC0,0xE8,0x96,0x56,0x99,0x8A,0xB3,0xF0,0x7F,0xA4, +0xCD,0xBD,0xDC,0x32,0x31,0x7C,0x91,0xCF,0xE0,0x5F,0x11,0xF8,0x6B,0xAA,0x49,0x5C, +0xD1,0x99,0x94,0xD1,0xA2,0xE3,0x63,0x5B,0x09,0x76,0xB5,0x56,0x62,0xE1,0x4B,0x74, +0x1D,0x96,0xD4,0x26,0xD4,0x08,0x04,0x59,0xD0,0x98,0x0E,0x0E,0xE6,0xDE,0xFC,0xC3, +0xEC,0x1F,0x90,0xF1,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7C,0x0C,0x32,0x1F,0xA7,0xD9,0x30, +0x7F,0xC4,0x7D,0x68,0xA3,0x62,0xA8,0xA1,0xCE,0xAB,0x07,0x5B,0x27,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x11,0x59,0xFA,0x25,0x4F,0x03,0x6F,0x94,0x99,0x3B,0x9A,0x1F,0x82,0x85,0x39, +0xD4,0x76,0x05,0x94,0x5E,0xE1,0x28,0x93,0x6D,0x62,0x5D,0x09,0xC2,0xA0,0xA8,0xD4, +0xB0,0x75,0x38,0xF1,0x34,0x6A,0x9D,0xE4,0x9F,0x8A,0x86,0x26,0x51,0xE6,0x2C,0xD1, +0xC6,0x2D,0x6E,0x95,0x20,0x4A,0x92,0x01,0xEC,0xB8,0x8A,0x67,0x7B,0x31,0xE2,0x67, +0x2E,0x8C,0x95,0x03,0x26,0x2E,0x43,0x9D,0x4A,0x31,0xF6,0x0E,0xB5,0x0C,0xBB,0xB7, +0xE2,0x37,0x7F,0x22,0xBA,0x00,0xA3,0x0E,0x7B,0x52,0xFB,0x6B,0xBB,0x3B,0xC4,0xD3, +0x79,0x51,0x4E,0xCD,0x90,0xF4,0x67,0x07,0x19,0xC8,0x3C,0x46,0x7A,0x0D,0x01,0x7D, +0xC5,0x58,0xE7,0x6D,0xE6,0x85,0x30,0x17,0x9A,0x24,0xC4,0x10,0xE0,0x04,0xF7,0xE0, +0xF2,0x7F,0xD4,0xAA,0x0A,0xFF,0x42,0x1D,0x37,0xED,0x94,0xE5,0x64,0x59,0x12,0x20, +0x77,0x38,0xD3,0x32,0x3E,0x38,0x81,0x75,0x96,0x73,0xFA,0x68,0x8F,0xB1,0xCB,0xCE, +0x1F,0xC5,0xEC,0xFA,0x9C,0x7E,0xCF,0x7E,0xB1,0xF1,0x07,0x2D,0xB6,0xFC,0xBF,0xCA, +0xA4,0xBF,0xD0,0x97,0x05,0x4A,0xBC,0xEA,0x18,0x28,0x02,0x90,0xBD,0x54,0x78,0x09, +0x21,0x71,0xD3,0xD1,0x7D,0x1D,0xD9,0x16,0xB0,0xA9,0x61,0x3D,0xD0,0x0A,0x00,0x22, +0xFC,0xC7,0x7B,0xCB,0x09,0x64,0x45,0x0B,0x3B,0x40,0x81,0xF7,0x7D,0x7C,0x32,0xF5, +0x98,0xCA,0x58,0x8E,0x7D,0x2A,0xEE,0x90,0x59,0x73,0x64,0xF9,0x36,0x74,0x5E,0x25, +0xA1,0xF5,0x66,0x05,0x2E,0x7F,0x39,0x15,0xA9,0x2A,0xFB,0x50,0x8B,0x8E,0x85,0x69, +0xF4, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root G3 */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root G3 */ + + +const unsigned char DigiCert_Global_Root_G3_certificate[579]={ +0x30,0x82,0x02,0x3F,0x30,0x82,0x01,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x05, +0x55,0x56,0xBC,0xF2,0x5E,0xA4,0x35,0x35,0xC3,0xA4,0x0F,0xD5,0xAB,0x45,0x72,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x61,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E, +0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E, +0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x20,0x30,0x1E, +0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47,0x33,0x30,0x1E, +0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30,0x30,0x30,0x5A,0x17, +0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30,0x30,0x5A,0x30,0x61, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47, +0x33,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0xDD,0xA7,0xD9,0xBB,0x8A,0xB8,0x0B, +0xFB,0x0B,0x7F,0x21,0xD2,0xF0,0xBE,0xBE,0x73,0xF3,0x33,0x5D,0x1A,0xBC,0x34,0xEA, +0xDE,0xC6,0x9B,0xBC,0xD0,0x95,0xF6,0xF0,0xCC,0xD0,0x0B,0xBA,0x61,0x5B,0x51,0x46, +0x7E,0x9E,0x2D,0x9F,0xEE,0x8E,0x63,0x0C,0x17,0xEC,0x07,0x70,0xF5,0xCF,0x84,0x2E, +0x40,0x83,0x9C,0xE8,0x3F,0x41,0x6D,0x3B,0xAD,0xD3,0xA4,0x14,0x59,0x36,0x78,0x9D, +0x03,0x43,0xEE,0x10,0x13,0x6C,0x72,0xDE,0xAE,0x88,0xA7,0xA1,0x6B,0xB5,0x43,0xCE, +0x67,0xDC,0x23,0xFF,0x03,0x1C,0xA3,0xE2,0x3E,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB3,0xDB,0x48,0xA4,0xF9,0xA1,0xC5, +0xD8,0xAE,0x36,0x41,0xCC,0x11,0x63,0x69,0x62,0x29,0xBC,0x4B,0xC6,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31, +0x00,0xAD,0xBC,0xF2,0x6C,0x3F,0x12,0x4A,0xD1,0x2D,0x39,0xC3,0x0A,0x09,0x97,0x73, +0xF4,0x88,0x36,0x8C,0x88,0x27,0xBB,0xE6,0x88,0x8D,0x50,0x85,0xA7,0x63,0xF9,0x9E, +0x32,0xDE,0x66,0x93,0x0F,0xF1,0xCC,0xB1,0x09,0x8F,0xDD,0x6C,0xAB,0xFA,0x6B,0x7F, +0xA0,0x02,0x30,0x39,0x66,0x5B,0xC2,0x64,0x8D,0xB8,0x9E,0x50,0xDC,0xA8,0xD5,0x49, +0xA2,0xED,0xC7,0xDC,0xD1,0x49,0x7F,0x17,0x01,0xB8,0xC8,0x86,0x8F,0x4E,0x8C,0x88, +0x2B,0xA8,0x9A,0xA9,0x8A,0xC5,0xD1,0x00,0xBD,0xF8,0x54,0xE2,0x9A,0xE5,0x5B,0x7C, +0xB3,0x27,0x17, +}; + + +/* subject:/C=US/O=thawte, Inc./OU=(c) 2007 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G2 */ +/* issuer :/C=US/O=thawte, Inc./OU=(c) 2007 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G2 */ + + +const unsigned char thawte_Primary_Root_CA___G2_certificate[652]={ +0x30,0x82,0x02,0x88,0x30,0x82,0x02,0x0D,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x35, +0xFC,0x26,0x5C,0xD9,0x84,0x4F,0xC9,0x3D,0x26,0x3D,0x57,0x9B,0xAE,0xD7,0x56,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x84,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29, +0x20,0x32,0x30,0x30,0x37,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69, +0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x24,0x30,0x22, +0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72, +0x69,0x6D,0x61,0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20, +0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31,0x30,0x35,0x30,0x30,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32,0x33,0x35,0x39,0x35, +0x39,0x5A,0x30,0x81,0x84,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61, +0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x38,0x30,0x36,0x06,0x03,0x55, +0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x74,0x68,0x61, +0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20, +0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F, +0x6E,0x6C,0x79,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x74,0x68, +0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x47,0x32,0x30,0x76,0x30,0x10,0x06,0x07,0x2A, +0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00, +0x04,0xA2,0xD5,0x9C,0x82,0x7B,0x95,0x9D,0xF1,0x52,0x78,0x87,0xFE,0x8A,0x16,0xBF, +0x05,0xE6,0xDF,0xA3,0x02,0x4F,0x0D,0x07,0xC6,0x00,0x51,0xBA,0x0C,0x02,0x52,0x2D, +0x22,0xA4,0x42,0x39,0xC4,0xFE,0x8F,0xEA,0xC9,0xC1,0xBE,0xD4,0x4D,0xFF,0x9F,0x7A, +0x9E,0xE2,0xB1,0x7C,0x9A,0xAD,0xA7,0x86,0x09,0x73,0x87,0xD1,0xE7,0x9A,0xE3,0x7A, +0xA5,0xAA,0x6E,0xFB,0xBA,0xB3,0x70,0xC0,0x67,0x88,0xA2,0x35,0xD4,0xA3,0x9A,0xB1, +0xFD,0xAD,0xC2,0xEF,0x31,0xFA,0xA8,0xB9,0xF3,0xFB,0x08,0xC6,0x91,0xD1,0xFB,0x29, +0x95,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x9A,0xD8,0x00,0x30,0x00,0xE7,0x6B,0x7F,0x85,0x18,0xEE,0x8B,0xB6,0xCE,0x8A, +0x0C,0xF8,0x11,0xE1,0xBB,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03, +0x03,0x03,0x69,0x00,0x30,0x66,0x02,0x31,0x00,0xDD,0xF8,0xE0,0x57,0x47,0x5B,0xA7, +0xE6,0x0A,0xC3,0xBD,0xF5,0x80,0x8A,0x97,0x35,0x0D,0x1B,0x89,0x3C,0x54,0x86,0x77, +0x28,0xCA,0xA1,0xF4,0x79,0xDE,0xB5,0xE6,0x38,0xB0,0xF0,0x65,0x70,0x8C,0x7F,0x02, +0x54,0xC2,0xBF,0xFF,0xD8,0xA1,0x3E,0xD9,0xCF,0x02,0x31,0x00,0xC4,0x8D,0x94,0xFC, +0xDC,0x53,0xD2,0xDC,0x9D,0x78,0x16,0x1F,0x15,0x33,0x23,0x53,0x52,0xE3,0x5A,0x31, +0x5D,0x9D,0xCA,0xAE,0xBD,0x13,0x29,0x44,0x0D,0x27,0x5B,0xA8,0xE7,0x68,0x9C,0x12, +0xF7,0x58,0x3F,0x2E,0x72,0x02,0x57,0xA3,0x8F,0xA1,0x14,0x2E, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2008 VeriSign, Inc. - For authorized use only/CN=VeriSign Universal Root Certification Authority */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2008 VeriSign, Inc. - For authorized use only/CN=VeriSign Universal Root Certification Authority */ + + +const unsigned char VeriSign_Universal_Root_Certification_Authority_certificate[1213]={ +0x30,0x82,0x04,0xB9,0x30,0x82,0x03,0xA1,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x40, +0x1A,0xC4,0x64,0x21,0xB3,0x13,0x21,0x03,0x0E,0xBB,0xE4,0x12,0x1A,0xC5,0x1D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81, +0xBD,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74, +0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04, +0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x38,0x20,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72, +0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20, +0x6F,0x6E,0x6C,0x79,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61, +0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E, +0x17,0x0D,0x30,0x38,0x30,0x34,0x30,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17, +0x0D,0x33,0x37,0x31,0x32,0x30,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81, +0xBD,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74, +0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04, +0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x38,0x20,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72, +0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20, +0x6F,0x6E,0x6C,0x79,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61, +0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82, +0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05, +0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC7, +0x61,0x37,0x5E,0xB1,0x01,0x34,0xDB,0x62,0xD7,0x15,0x9B,0xFF,0x58,0x5A,0x8C,0x23, +0x23,0xD6,0x60,0x8E,0x91,0xD7,0x90,0x98,0x83,0x7A,0xE6,0x58,0x19,0x38,0x8C,0xC5, +0xF6,0xE5,0x64,0x85,0xB4,0xA2,0x71,0xFB,0xED,0xBD,0xB9,0xDA,0xCD,0x4D,0x00,0xB4, +0xC8,0x2D,0x73,0xA5,0xC7,0x69,0x71,0x95,0x1F,0x39,0x3C,0xB2,0x44,0x07,0x9C,0xE8, +0x0E,0xFA,0x4D,0x4A,0xC4,0x21,0xDF,0x29,0x61,0x8F,0x32,0x22,0x61,0x82,0xC5,0x87, +0x1F,0x6E,0x8C,0x7C,0x5F,0x16,0x20,0x51,0x44,0xD1,0x70,0x4F,0x57,0xEA,0xE3,0x1C, +0xE3,0xCC,0x79,0xEE,0x58,0xD8,0x0E,0xC2,0xB3,0x45,0x93,0xC0,0x2C,0xE7,0x9A,0x17, +0x2B,0x7B,0x00,0x37,0x7A,0x41,0x33,0x78,0xE1,0x33,0xE2,0xF3,0x10,0x1A,0x7F,0x87, +0x2C,0xBE,0xF6,0xF5,0xF7,0x42,0xE2,0xE5,0xBF,0x87,0x62,0x89,0x5F,0x00,0x4B,0xDF, +0xC5,0xDD,0xE4,0x75,0x44,0x32,0x41,0x3A,0x1E,0x71,0x6E,0x69,0xCB,0x0B,0x75,0x46, +0x08,0xD1,0xCA,0xD2,0x2B,0x95,0xD0,0xCF,0xFB,0xB9,0x40,0x6B,0x64,0x8C,0x57,0x4D, +0xFC,0x13,0x11,0x79,0x84,0xED,0x5E,0x54,0xF6,0x34,0x9F,0x08,0x01,0xF3,0x10,0x25, +0x06,0x17,0x4A,0xDA,0xF1,0x1D,0x7A,0x66,0x6B,0x98,0x60,0x66,0xA4,0xD9,0xEF,0xD2, +0x2E,0x82,0xF1,0xF0,0xEF,0x09,0xEA,0x44,0xC9,0x15,0x6A,0xE2,0x03,0x6E,0x33,0xD3, +0xAC,0x9F,0x55,0x00,0xC7,0xF6,0x08,0x6A,0x94,0xB9,0x5F,0xDC,0xE0,0x33,0xF1,0x84, +0x60,0xF9,0x5B,0x27,0x11,0xB4,0xFC,0x16,0xF2,0xBB,0x56,0x6A,0x80,0x25,0x8D,0x02, +0x03,0x01,0x00,0x01,0xA3,0x81,0xB2,0x30,0x81,0xAF,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, +0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x6D,0x06,0x08,0x2B, +0x06,0x01,0x05,0x05,0x07,0x01,0x0C,0x04,0x61,0x30,0x5F,0xA1,0x5D,0xA0,0x5B,0x30, +0x59,0x30,0x57,0x30,0x55,0x16,0x09,0x69,0x6D,0x61,0x67,0x65,0x2F,0x67,0x69,0x66, +0x30,0x21,0x30,0x1F,0x30,0x07,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x04,0x14,0x8F, +0xE5,0xD3,0x1A,0x86,0xAC,0x8D,0x8E,0x6B,0xC3,0xCF,0x80,0x6A,0xD4,0x48,0x18,0x2C, +0x7B,0x19,0x2E,0x30,0x25,0x16,0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6C,0x6F, +0x67,0x6F,0x2E,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F, +0x76,0x73,0x6C,0x6F,0x67,0x6F,0x2E,0x67,0x69,0x66,0x30,0x1D,0x06,0x03,0x55,0x1D, +0x0E,0x04,0x16,0x04,0x14,0xB6,0x77,0xFA,0x69,0x48,0x47,0x9F,0x53,0x12,0xD5,0xC2, +0xEA,0x07,0x32,0x76,0x07,0xD1,0x97,0x07,0x19,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x4A,0xF8,0xF8, +0xB0,0x03,0xE6,0x2C,0x67,0x7B,0xE4,0x94,0x77,0x63,0xCC,0x6E,0x4C,0xF9,0x7D,0x0E, +0x0D,0xDC,0xC8,0xB9,0x35,0xB9,0x70,0x4F,0x63,0xFA,0x24,0xFA,0x6C,0x83,0x8C,0x47, +0x9D,0x3B,0x63,0xF3,0x9A,0xF9,0x76,0x32,0x95,0x91,0xB1,0x77,0xBC,0xAC,0x9A,0xBE, +0xB1,0xE4,0x31,0x21,0xC6,0x81,0x95,0x56,0x5A,0x0E,0xB1,0xC2,0xD4,0xB1,0xA6,0x59, +0xAC,0xF1,0x63,0xCB,0xB8,0x4C,0x1D,0x59,0x90,0x4A,0xEF,0x90,0x16,0x28,0x1F,0x5A, +0xAE,0x10,0xFB,0x81,0x50,0x38,0x0C,0x6C,0xCC,0xF1,0x3D,0xC3,0xF5,0x63,0xE3,0xB3, +0xE3,0x21,0xC9,0x24,0x39,0xE9,0xFD,0x15,0x66,0x46,0xF4,0x1B,0x11,0xD0,0x4D,0x73, +0xA3,0x7D,0x46,0xF9,0x3D,0xED,0xA8,0x5F,0x62,0xD4,0xF1,0x3F,0xF8,0xE0,0x74,0x57, +0x2B,0x18,0x9D,0x81,0xB4,0xC4,0x28,0xDA,0x94,0x97,0xA5,0x70,0xEB,0xAC,0x1D,0xBE, +0x07,0x11,0xF0,0xD5,0xDB,0xDD,0xE5,0x8C,0xF0,0xD5,0x32,0xB0,0x83,0xE6,0x57,0xE2, +0x8F,0xBF,0xBE,0xA1,0xAA,0xBF,0x3D,0x1D,0xB5,0xD4,0x38,0xEA,0xD7,0xB0,0x5C,0x3A, +0x4F,0x6A,0x3F,0x8F,0xC0,0x66,0x6C,0x63,0xAA,0xE9,0xD9,0xA4,0x16,0xF4,0x81,0xD1, +0x95,0x14,0x0E,0x7D,0xCD,0x95,0x34,0xD9,0xD2,0x8F,0x70,0x73,0x81,0x7B,0x9C,0x7E, +0xBD,0x98,0x61,0xD8,0x45,0x87,0x98,0x90,0xC5,0xEB,0x86,0x30,0xC6,0x35,0xBF,0xF0, +0xFF,0xC3,0x55,0x88,0x83,0x4B,0xEF,0x05,0x92,0x06,0x71,0xF2,0xB8,0x98,0x93,0xB7, +0xEC,0xCD,0x82,0x61,0xF1,0x38,0xE6,0x4F,0x97,0x98,0x2A,0x5A,0x8D, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2007 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G4 */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2007 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G4 */ + + +const unsigned char VeriSign_Class_3_Public_Primary_Certification_Authority___G4_certificate[904]={ +0x30,0x82,0x03,0x84,0x30,0x82,0x03,0x0A,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x2F, +0x80,0xFE,0x23,0x8C,0x0E,0x22,0x0F,0x48,0x67,0x12,0x28,0x91,0x87,0xAC,0xB3,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0xCA,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20, +0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65, +0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75, +0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C, +0x79,0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62, +0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x34,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31, +0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31, +0x38,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F, +0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29, +0x20,0x32,0x30,0x30,0x37,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20, +0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F, +0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45, +0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63, +0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69, +0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, +0x20,0x2D,0x20,0x47,0x34,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D, +0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0xA7,0x56,0x7A, +0x7C,0x52,0xDA,0x64,0x9B,0x0E,0x2D,0x5C,0xD8,0x5E,0xAC,0x92,0x3D,0xFE,0x01,0xE6, +0x19,0x4A,0x3D,0x14,0x03,0x4B,0xFA,0x60,0x27,0x20,0xD9,0x83,0x89,0x69,0xFA,0x54, +0xC6,0x9A,0x18,0x5E,0x55,0x2A,0x64,0xDE,0x06,0xF6,0x8D,0x4A,0x3B,0xAD,0x10,0x3C, +0x65,0x3D,0x90,0x88,0x04,0x89,0xE0,0x30,0x61,0xB3,0xAE,0x5D,0x01,0xA7,0x7B,0xDE, +0x7C,0xB2,0xBE,0xCA,0x65,0x61,0x00,0x86,0xAE,0xDA,0x8F,0x7B,0xD0,0x89,0xAD,0x4D, +0x1D,0x59,0x9A,0x41,0xB1,0xBC,0x47,0x80,0xDC,0x9E,0x62,0xC3,0xF9,0xA3,0x81,0xB2, +0x30,0x81,0xAF,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x6D,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0C, +0x04,0x61,0x30,0x5F,0xA1,0x5D,0xA0,0x5B,0x30,0x59,0x30,0x57,0x30,0x55,0x16,0x09, +0x69,0x6D,0x61,0x67,0x65,0x2F,0x67,0x69,0x66,0x30,0x21,0x30,0x1F,0x30,0x07,0x06, +0x05,0x2B,0x0E,0x03,0x02,0x1A,0x04,0x14,0x8F,0xE5,0xD3,0x1A,0x86,0xAC,0x8D,0x8E, +0x6B,0xC3,0xCF,0x80,0x6A,0xD4,0x48,0x18,0x2C,0x7B,0x19,0x2E,0x30,0x25,0x16,0x23, +0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6C,0x6F,0x67,0x6F,0x2E,0x76,0x65,0x72,0x69, +0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x76,0x73,0x6C,0x6F,0x67,0x6F,0x2E, +0x67,0x69,0x66,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB3,0x16, +0x91,0xFD,0xEE,0xA6,0x6E,0xE4,0xB5,0x2E,0x49,0x8F,0x87,0x78,0x81,0x80,0xEC,0xE5, +0xB1,0xB5,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68, +0x00,0x30,0x65,0x02,0x30,0x66,0x21,0x0C,0x18,0x26,0x60,0x5A,0x38,0x7B,0x56,0x42, +0xE0,0xA7,0xFC,0x36,0x84,0x51,0x91,0x20,0x2C,0x76,0x4D,0x43,0x3D,0xC4,0x1D,0x84, +0x23,0xD0,0xAC,0xD6,0x7C,0x35,0x06,0xCE,0xCD,0x69,0xBD,0x90,0x0D,0xDB,0x6C,0x48, +0x42,0x1D,0x0E,0xAA,0x42,0x02,0x31,0x00,0x9C,0x3D,0x48,0x39,0x23,0x39,0x58,0x1A, +0x15,0x12,0x59,0x6A,0x9E,0xEF,0xD5,0x59,0xB2,0x1D,0x52,0x2C,0x99,0x71,0xCD,0xC7, +0x29,0xDF,0x1B,0x2A,0x61,0x7B,0x71,0xD1,0xDE,0xF3,0xC0,0xE5,0x0D,0x3A,0x4A,0xAA, +0x2D,0xA7,0xD8,0x86,0x2A,0xDD,0x2E,0x10, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root G2 */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root G2 */ + + +const unsigned char DigiCert_Global_Root_G2_certificate[914]={ +0x30,0x82,0x03,0x8E,0x30,0x82,0x02,0x76,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x03, +0x3A,0xF1,0xE6,0xA7,0x11,0xA9,0xA0,0xBB,0x28,0x64,0xB1,0x1D,0x09,0xFA,0xE5,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x61, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47, +0x32,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30,0x30, +0x5A,0x30,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43, +0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B, +0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63, +0x6F,0x6D,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67, +0x69,0x43,0x65,0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xBB,0x37,0xCD,0x34,0xDC,0x7B,0x6B,0xC9,0xB2,0x68,0x90, +0xAD,0x4A,0x75,0xFF,0x46,0xBA,0x21,0x0A,0x08,0x8D,0xF5,0x19,0x54,0xC9,0xFB,0x88, +0xDB,0xF3,0xAE,0xF2,0x3A,0x89,0x91,0x3C,0x7A,0xE6,0xAB,0x06,0x1A,0x6B,0xCF,0xAC, +0x2D,0xE8,0x5E,0x09,0x24,0x44,0xBA,0x62,0x9A,0x7E,0xD6,0xA3,0xA8,0x7E,0xE0,0x54, +0x75,0x20,0x05,0xAC,0x50,0xB7,0x9C,0x63,0x1A,0x6C,0x30,0xDC,0xDA,0x1F,0x19,0xB1, +0xD7,0x1E,0xDE,0xFD,0xD7,0xE0,0xCB,0x94,0x83,0x37,0xAE,0xEC,0x1F,0x43,0x4E,0xDD, +0x7B,0x2C,0xD2,0xBD,0x2E,0xA5,0x2F,0xE4,0xA9,0xB8,0xAD,0x3A,0xD4,0x99,0xA4,0xB6, +0x25,0xE9,0x9B,0x6B,0x00,0x60,0x92,0x60,0xFF,0x4F,0x21,0x49,0x18,0xF7,0x67,0x90, +0xAB,0x61,0x06,0x9C,0x8F,0xF2,0xBA,0xE9,0xB4,0xE9,0x92,0x32,0x6B,0xB5,0xF3,0x57, +0xE8,0x5D,0x1B,0xCD,0x8C,0x1D,0xAB,0x95,0x04,0x95,0x49,0xF3,0x35,0x2D,0x96,0xE3, +0x49,0x6D,0xDD,0x77,0xE3,0xFB,0x49,0x4B,0xB4,0xAC,0x55,0x07,0xA9,0x8F,0x95,0xB3, +0xB4,0x23,0xBB,0x4C,0x6D,0x45,0xF0,0xF6,0xA9,0xB2,0x95,0x30,0xB4,0xFD,0x4C,0x55, +0x8C,0x27,0x4A,0x57,0x14,0x7C,0x82,0x9D,0xCD,0x73,0x92,0xD3,0x16,0x4A,0x06,0x0C, +0x8C,0x50,0xD1,0x8F,0x1E,0x09,0xBE,0x17,0xA1,0xE6,0x21,0xCA,0xFD,0x83,0xE5,0x10, +0xBC,0x83,0xA5,0x0A,0xC4,0x67,0x28,0xF6,0x73,0x14,0x14,0x3D,0x46,0x76,0xC3,0x87, +0x14,0x89,0x21,0x34,0x4D,0xAF,0x0F,0x45,0x0C,0xA6,0x49,0xA1,0xBA,0xBB,0x9C,0xC5, +0xB1,0x33,0x83,0x29,0x85,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4E,0x22,0x54,0x20,0x18,0x95, +0xE6,0xE3,0x6E,0xE6,0x0F,0xFA,0xFA,0xB9,0x12,0xED,0x06,0x17,0x8F,0x39,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x60,0x67,0x28,0x94,0x6F,0x0E,0x48,0x63,0xEB,0x31,0xDD,0xEA,0x67,0x18, +0xD5,0x89,0x7D,0x3C,0xC5,0x8B,0x4A,0x7F,0xE9,0xBE,0xDB,0x2B,0x17,0xDF,0xB0,0x5F, +0x73,0x77,0x2A,0x32,0x13,0x39,0x81,0x67,0x42,0x84,0x23,0xF2,0x45,0x67,0x35,0xEC, +0x88,0xBF,0xF8,0x8F,0xB0,0x61,0x0C,0x34,0xA4,0xAE,0x20,0x4C,0x84,0xC6,0xDB,0xF8, +0x35,0xE1,0x76,0xD9,0xDF,0xA6,0x42,0xBB,0xC7,0x44,0x08,0x86,0x7F,0x36,0x74,0x24, +0x5A,0xDA,0x6C,0x0D,0x14,0x59,0x35,0xBD,0xF2,0x49,0xDD,0xB6,0x1F,0xC9,0xB3,0x0D, +0x47,0x2A,0x3D,0x99,0x2F,0xBB,0x5C,0xBB,0xB5,0xD4,0x20,0xE1,0x99,0x5F,0x53,0x46, +0x15,0xDB,0x68,0x9B,0xF0,0xF3,0x30,0xD5,0x3E,0x31,0xE2,0x8D,0x84,0x9E,0xE3,0x8A, +0xDA,0xDA,0x96,0x3E,0x35,0x13,0xA5,0x5F,0xF0,0xF9,0x70,0x50,0x70,0x47,0x41,0x11, +0x57,0x19,0x4E,0xC0,0x8F,0xAE,0x06,0xC4,0x95,0x13,0x17,0x2F,0x1B,0x25,0x9F,0x75, +0xF2,0xB1,0x8E,0x99,0xA1,0x6F,0x13,0xB1,0x41,0x71,0xFE,0x88,0x2A,0xC8,0x4F,0x10, +0x20,0x55,0xD7,0xF3,0x14,0x45,0xE5,0xE0,0x44,0xF4,0xEA,0x87,0x95,0x32,0x93,0x0E, +0xFE,0x53,0x46,0xFA,0x2C,0x9D,0xFF,0x8B,0x22,0xB9,0x4B,0xD9,0x09,0x45,0xA4,0xDE, +0xA4,0xB8,0x9A,0x58,0xDD,0x1B,0x7D,0x52,0x9F,0x8E,0x59,0x43,0x88,0x81,0xA4,0x9E, +0x26,0xD5,0x6F,0xAD,0xDD,0x0D,0xC6,0x37,0x7D,0xED,0x03,0x92,0x1B,0xE5,0x77,0x5F, +0x76,0xEE,0x3C,0x8D,0xC4,0x5D,0x56,0x5B,0xA2,0xD9,0x66,0x6E,0xB3,0x35,0x37,0xE5, +0x32,0xB6, }; @@ -156,6 +886,196 @@ }; +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Premium ECC */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Premium ECC */ + + +const unsigned char AffirmTrust_Premium_ECC_certificate[514]={ +0x30,0x82,0x01,0xFE,0x30,0x82,0x01,0x85,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x74, +0x97,0x25,0x8A,0xC7,0x3F,0x7A,0x54,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, +0x04,0x03,0x03,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66, +0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04, +0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x50, +0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43,0x43,0x30,0x1E,0x17,0x0D,0x31,0x30, +0x30,0x31,0x32,0x39,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x17,0x0D,0x34,0x30,0x31, +0x32,0x33,0x31,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55, +0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D, +0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43, +0x43,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x0D,0x30,0x5E,0x1B,0x15,0x9D,0x03, +0xD0,0xA1,0x79,0x35,0xB7,0x3A,0x3C,0x92,0x7A,0xCA,0x15,0x1C,0xCD,0x62,0xF3,0x9C, +0x26,0x5C,0x07,0x3D,0xE5,0x54,0xFA,0xA3,0xD6,0xCC,0x12,0xEA,0xF4,0x14,0x5F,0xE8, +0x8E,0x19,0xAB,0x2F,0x2E,0x48,0xE6,0xAC,0x18,0x43,0x78,0xAC,0xD0,0x37,0xC3,0xBD, +0xB2,0xCD,0x2C,0xE6,0x47,0xE2,0x1A,0xE6,0x63,0xB8,0x3D,0x2E,0x2F,0x78,0xC4,0x4F, +0xDB,0xF4,0x0F,0xA4,0x68,0x4C,0x55,0x72,0x6B,0x95,0x1D,0x4E,0x18,0x42,0x95,0x78, +0xCC,0x37,0x3C,0x91,0xE2,0x9B,0x65,0x2B,0x29,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9A,0xAF,0x29,0x7A,0xC0,0x11,0x35,0x35, +0x26,0x51,0x30,0x00,0xC3,0x6A,0xFE,0x40,0xD5,0xAE,0xD6,0x3C,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06, +0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30, +0x17,0x09,0xF3,0x87,0x88,0x50,0x5A,0xAF,0xC8,0xC0,0x42,0xBF,0x47,0x5F,0xF5,0x6C, +0x6A,0x86,0xE0,0xC4,0x27,0x74,0xE4,0x38,0x53,0xD7,0x05,0x7F,0x1B,0x34,0xE3,0xC6, +0x2F,0xB3,0xCA,0x09,0x3C,0x37,0x9D,0xD7,0xE7,0xB8,0x46,0xF1,0xFD,0xA1,0xE2,0x71, +0x02,0x30,0x42,0x59,0x87,0x43,0xD4,0x51,0xDF,0xBA,0xD3,0x09,0x32,0x5A,0xCE,0x88, +0x7E,0x57,0x3D,0x9C,0x5F,0x42,0x6B,0xF5,0x07,0x2D,0xB5,0xF0,0x82,0x93,0xF9,0x59, +0x6F,0xAE,0x64,0xFA,0x58,0xE5,0x8B,0x1E,0xE3,0x63,0xBE,0xB5,0x81,0xCD,0x6F,0x02, +0x8C,0x79, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 4 Public Primary Certification Authority - G3 */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 4 Public Primary Certification Authority - G3 */ + + +const unsigned char Verisign_Class_4_Public_Primary_Certification_Authority___G3_certificate[1054]={ +0x30,0x82,0x04,0x1A,0x30,0x82,0x03,0x02,0x02,0x11,0x00,0xEC,0xA0,0xA7,0x8B,0x6E, +0x75,0x6A,0x01,0xCF,0xC4,0x7C,0xCC,0x2F,0x94,0x5E,0xD7,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xCA,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65, +0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, +0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, +0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x34,0x20,0x50,0x75,0x62,0x6C, +0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x2D,0x20,0x47,0x33,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31,0x30,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31,0x36, +0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E, +0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20, +0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72, +0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45,0x30, +0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x34,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, +0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x33,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xAD,0xCB,0xA5,0x11,0x69,0xC6,0x59,0xAB,0xF1,0x8F,0xB5, +0x19,0x0F,0x56,0xCE,0xCC,0xB5,0x1F,0x20,0xE4,0x9E,0x26,0x25,0x4B,0xE0,0x73,0x65, +0x89,0x59,0xDE,0xD0,0x83,0xE4,0xF5,0x0F,0xB5,0xBB,0xAD,0xF1,0x7C,0xE8,0x21,0xFC, +0xE4,0xE8,0x0C,0xEE,0x7C,0x45,0x22,0x19,0x76,0x92,0xB4,0x13,0xB7,0x20,0x5B,0x09, +0xFA,0x61,0xAE,0xA8,0xF2,0xA5,0x8D,0x85,0xC2,0x2A,0xD6,0xDE,0x66,0x36,0xD2,0x9B, +0x02,0xF4,0xA8,0x92,0x60,0x7C,0x9C,0x69,0xB4,0x8F,0x24,0x1E,0xD0,0x86,0x52,0xF6, +0x32,0x9C,0x41,0x58,0x1E,0x22,0xBD,0xCD,0x45,0x62,0x95,0x08,0x6E,0xD0,0x66,0xDD, +0x53,0xA2,0xCC,0xF0,0x10,0xDC,0x54,0x73,0x8B,0x04,0xA1,0x46,0x33,0x33,0x5C,0x17, +0x40,0xB9,0x9E,0x4D,0xD3,0xF3,0xBE,0x55,0x83,0xE8,0xB1,0x89,0x8E,0x5A,0x7C,0x9A, +0x96,0x22,0x90,0x3B,0x88,0x25,0xF2,0xD2,0x53,0x88,0x02,0x0C,0x0B,0x78,0xF2,0xE6, +0x37,0x17,0x4B,0x30,0x46,0x07,0xE4,0x80,0x6D,0xA6,0xD8,0x96,0x2E,0xE8,0x2C,0xF8, +0x11,0xB3,0x38,0x0D,0x66,0xA6,0x9B,0xEA,0xC9,0x23,0x5B,0xDB,0x8E,0xE2,0xF3,0x13, +0x8E,0x1A,0x59,0x2D,0xAA,0x02,0xF0,0xEC,0xA4,0x87,0x66,0xDC,0xC1,0x3F,0xF5,0xD8, +0xB9,0xF4,0xEC,0x82,0xC6,0xD2,0x3D,0x95,0x1D,0xE5,0xC0,0x4F,0x84,0xC9,0xD9,0xA3, +0x44,0x28,0x06,0x6A,0xD7,0x45,0xAC,0xF0,0x6B,0x6A,0xEF,0x4E,0x5F,0xF8,0x11,0x82, +0x1E,0x38,0x63,0x34,0x66,0x50,0xD4,0x3E,0x93,0x73,0xFA,0x30,0xC3,0x66,0xAD,0xFF, +0x93,0x2D,0x97,0xEF,0x03,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x8F,0xFA, +0x25,0x6B,0x4F,0x5B,0xE4,0xA4,0x4E,0x27,0x55,0xAB,0x22,0x15,0x59,0x3C,0xCA,0xB5, +0x0A,0xD4,0x4A,0xDB,0xAB,0xDD,0xA1,0x5F,0x53,0xC5,0xA0,0x57,0x39,0xC2,0xCE,0x47, +0x2B,0xBE,0x3A,0xC8,0x56,0xBF,0xC2,0xD9,0x27,0x10,0x3A,0xB1,0x05,0x3C,0xC0,0x77, +0x31,0xBB,0x3A,0xD3,0x05,0x7B,0x6D,0x9A,0x1C,0x30,0x8C,0x80,0xCB,0x93,0x93,0x2A, +0x83,0xAB,0x05,0x51,0x82,0x02,0x00,0x11,0x67,0x6B,0xF3,0x88,0x61,0x47,0x5F,0x03, +0x93,0xD5,0x5B,0x0D,0xE0,0xF1,0xD4,0xA1,0x32,0x35,0x85,0xB2,0x3A,0xDB,0xB0,0x82, +0xAB,0xD1,0xCB,0x0A,0xBC,0x4F,0x8C,0x5B,0xC5,0x4B,0x00,0x3B,0x1F,0x2A,0x82,0xA6, +0x7E,0x36,0x85,0xDC,0x7E,0x3C,0x67,0x00,0xB5,0xE4,0x3B,0x52,0xE0,0xA8,0xEB,0x5D, +0x15,0xF9,0xC6,0x6D,0xF0,0xAD,0x1D,0x0E,0x85,0xB7,0xA9,0x9A,0x73,0x14,0x5A,0x5B, +0x8F,0x41,0x28,0xC0,0xD5,0xE8,0x2D,0x4D,0xA4,0x5E,0xCD,0xAA,0xD9,0xED,0xCE,0xDC, +0xD8,0xD5,0x3C,0x42,0x1D,0x17,0xC1,0x12,0x5D,0x45,0x38,0xC3,0x38,0xF3,0xFC,0x85, +0x2E,0x83,0x46,0x48,0xB2,0xD7,0x20,0x5F,0x92,0x36,0x8F,0xE7,0x79,0x0F,0x98,0x5E, +0x99,0xE8,0xF0,0xD0,0xA4,0xBB,0xF5,0x53,0xBD,0x2A,0xCE,0x59,0xB0,0xAF,0x6E,0x7F, +0x6C,0xBB,0xD2,0x1E,0x00,0xB0,0x21,0xED,0xF8,0x41,0x62,0x82,0xB9,0xD8,0xB2,0xC4, +0xBB,0x46,0x50,0xF3,0x31,0xC5,0x8F,0x01,0xA8,0x74,0xEB,0xF5,0x78,0x27,0xDA,0xE7, +0xF7,0x66,0x43,0xF3,0x9E,0x83,0x3E,0x20,0xAA,0xC3,0x35,0x60,0x91,0xCE, +}; + + +/* subject:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA */ +/* issuer :/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA */ + + +const unsigned char thawte_Primary_Root_CA_certificate[1060]={ +0x30,0x82,0x04,0x20,0x30,0x82,0x03,0x08,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x34, +0x4E,0xD5,0x57,0x20,0xD5,0xED,0xEC,0x49,0xF4,0x2F,0xCE,0x37,0xDB,0x2B,0x6D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0xA9,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15, +0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65, +0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31, +0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30, +0x30,0x36,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20, +0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64, +0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55, +0x04,0x03,0x13,0x16,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61, +0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36, +0x31,0x31,0x31,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30, +0x37,0x31,0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xA9,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63, +0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31,0x38,0x30,0x36,0x06, +0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x74, +0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F, +0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65, +0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16, +0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x52, +0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, +0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAC,0xA0,0xF0,0xFB,0x80,0x59,0xD4,0x9C,0xC7, +0xA4,0xCF,0x9D,0xA1,0x59,0x73,0x09,0x10,0x45,0x0C,0x0D,0x2C,0x6E,0x68,0xF1,0x6C, +0x5B,0x48,0x68,0x49,0x59,0x37,0xFC,0x0B,0x33,0x19,0xC2,0x77,0x7F,0xCC,0x10,0x2D, +0x95,0x34,0x1C,0xE6,0xEB,0x4D,0x09,0xA7,0x1C,0xD2,0xB8,0xC9,0x97,0x36,0x02,0xB7, +0x89,0xD4,0x24,0x5F,0x06,0xC0,0xCC,0x44,0x94,0x94,0x8D,0x02,0x62,0x6F,0xEB,0x5A, +0xDD,0x11,0x8D,0x28,0x9A,0x5C,0x84,0x90,0x10,0x7A,0x0D,0xBD,0x74,0x66,0x2F,0x6A, +0x38,0xA0,0xE2,0xD5,0x54,0x44,0xEB,0x1D,0x07,0x9F,0x07,0xBA,0x6F,0xEE,0xE9,0xFD, +0x4E,0x0B,0x29,0xF5,0x3E,0x84,0xA0,0x01,0xF1,0x9C,0xAB,0xF8,0x1C,0x7E,0x89,0xA4, +0xE8,0xA1,0xD8,0x71,0x65,0x0D,0xA3,0x51,0x7B,0xEE,0xBC,0xD2,0x22,0x60,0x0D,0xB9, +0x5B,0x9D,0xDF,0xBA,0xFC,0x51,0x5B,0x0B,0xAF,0x98,0xB2,0xE9,0x2E,0xE9,0x04,0xE8, +0x62,0x87,0xDE,0x2B,0xC8,0xD7,0x4E,0xC1,0x4C,0x64,0x1E,0xDD,0xCF,0x87,0x58,0xBA, +0x4A,0x4F,0xCA,0x68,0x07,0x1D,0x1C,0x9D,0x4A,0xC6,0xD5,0x2F,0x91,0xCC,0x7C,0x71, +0x72,0x1C,0xC5,0xC0,0x67,0xEB,0x32,0xFD,0xC9,0x92,0x5C,0x94,0xDA,0x85,0xC0,0x9B, +0xBF,0x53,0x7D,0x2B,0x09,0xF4,0x8C,0x9D,0x91,0x1F,0x97,0x6A,0x52,0xCB,0xDE,0x09, +0x36,0xA4,0x77,0xD8,0x7B,0x87,0x50,0x44,0xD5,0x3E,0x6E,0x29,0x69,0xFB,0x39,0x49, +0x26,0x1E,0x09,0xA5,0x80,0x7B,0x40,0x2D,0xEB,0xE8,0x27,0x85,0xC9,0xFE,0x61,0xFD, +0x7E,0xE6,0x7C,0x97,0x1D,0xD5,0x9D,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40, +0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01, +0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7B,0x5B,0x45,0xCF, +0xAF,0xCE,0xCB,0x7A,0xFD,0x31,0x92,0x1A,0x6A,0xB6,0xF3,0x46,0xEB,0x57,0x48,0x50, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, +0x82,0x01,0x01,0x00,0x79,0x11,0xC0,0x4B,0xB3,0x91,0xB6,0xFC,0xF0,0xE9,0x67,0xD4, +0x0D,0x6E,0x45,0xBE,0x55,0xE8,0x93,0xD2,0xCE,0x03,0x3F,0xED,0xDA,0x25,0xB0,0x1D, +0x57,0xCB,0x1E,0x3A,0x76,0xA0,0x4C,0xEC,0x50,0x76,0xE8,0x64,0x72,0x0C,0xA4,0xA9, +0xF1,0xB8,0x8B,0xD6,0xD6,0x87,0x84,0xBB,0x32,0xE5,0x41,0x11,0xC0,0x77,0xD9,0xB3, +0x60,0x9D,0xEB,0x1B,0xD5,0xD1,0x6E,0x44,0x44,0xA9,0xA6,0x01,0xEC,0x55,0x62,0x1D, +0x77,0xB8,0x5C,0x8E,0x48,0x49,0x7C,0x9C,0x3B,0x57,0x11,0xAC,0xAD,0x73,0x37,0x8E, +0x2F,0x78,0x5C,0x90,0x68,0x47,0xD9,0x60,0x60,0xE6,0xFC,0x07,0x3D,0x22,0x20,0x17, +0xC4,0xF7,0x16,0xE9,0xC4,0xD8,0x72,0xF9,0xC8,0x73,0x7C,0xDF,0x16,0x2F,0x15,0xA9, +0x3E,0xFD,0x6A,0x27,0xB6,0xA1,0xEB,0x5A,0xBA,0x98,0x1F,0xD5,0xE3,0x4D,0x64,0x0A, +0x9D,0x13,0xC8,0x61,0xBA,0xF5,0x39,0x1C,0x87,0xBA,0xB8,0xBD,0x7B,0x22,0x7F,0xF6, +0xFE,0xAC,0x40,0x79,0xE5,0xAC,0x10,0x6F,0x3D,0x8F,0x1B,0x79,0x76,0x8B,0xC4,0x37, +0xB3,0x21,0x18,0x84,0xE5,0x36,0x00,0xEB,0x63,0x20,0x99,0xB9,0xE9,0xFE,0x33,0x04, +0xBB,0x41,0xC8,0xC1,0x02,0xF9,0x44,0x63,0x20,0x9E,0x81,0xCE,0x42,0xD3,0xD6,0x3F, +0x2C,0x76,0xD3,0x63,0x9C,0x59,0xDD,0x8F,0xA6,0xE1,0x0E,0xA0,0x2E,0x41,0xF7,0x2E, +0x95,0x47,0xCF,0xBC,0xFD,0x33,0xF3,0xF6,0x0B,0x61,0x7E,0x7E,0x91,0x2B,0x81,0x47, +0xC2,0x27,0x30,0xEE,0xA7,0x10,0x5D,0x37,0x8F,0x5C,0x39,0x2B,0xE4,0x04,0xF0,0x7B, +0x8D,0x56,0x8C,0x68, +}; + + /* subject:/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Public CA Root */ /* issuer :/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Public CA Root */ @@ -305,1822 +1225,6 @@ }; -/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Commercial */ -/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Commercial */ - - -const unsigned char AffirmTrust_Commercial_certificate[848]={ -0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x77, -0x77,0x06,0x27,0x26,0xA9,0xB1,0x7C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, -0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, -0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, -0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, -0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69,0x61,0x6C,0x30,0x1E,0x17,0x0D, -0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x17,0x0D,0x33, -0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x30,0x44,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, -0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, -0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, -0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69, -0x61,0x6C,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, -0x01,0x01,0x00,0xF6,0x1B,0x4F,0x67,0x07,0x2B,0xA1,0x15,0xF5,0x06,0x22,0xCB,0x1F, -0x01,0xB2,0xE3,0x73,0x45,0x06,0x44,0x49,0x2C,0xBB,0x49,0x25,0x14,0xD6,0xCE,0xC3, -0xB7,0xAB,0x2C,0x4F,0xC6,0x41,0x32,0x94,0x57,0xFA,0x12,0xA7,0x5B,0x0E,0xE2,0x8F, -0x1F,0x1E,0x86,0x19,0xA7,0xAA,0xB5,0x2D,0xB9,0x5F,0x0D,0x8A,0xC2,0xAF,0x85,0x35, -0x79,0x32,0x2D,0xBB,0x1C,0x62,0x37,0xF2,0xB1,0x5B,0x4A,0x3D,0xCA,0xCD,0x71,0x5F, -0xE9,0x42,0xBE,0x94,0xE8,0xC8,0xDE,0xF9,0x22,0x48,0x64,0xC6,0xE5,0xAB,0xC6,0x2B, -0x6D,0xAD,0x05,0xF0,0xFA,0xD5,0x0B,0xCF,0x9A,0xE5,0xF0,0x50,0xA4,0x8B,0x3B,0x47, -0xA5,0x23,0x5B,0x7A,0x7A,0xF8,0x33,0x3F,0xB8,0xEF,0x99,0x97,0xE3,0x20,0xC1,0xD6, -0x28,0x89,0xCF,0x94,0xFB,0xB9,0x45,0xED,0xE3,0x40,0x17,0x11,0xD4,0x74,0xF0,0x0B, -0x31,0xE2,0x2B,0x26,0x6A,0x9B,0x4C,0x57,0xAE,0xAC,0x20,0x3E,0xBA,0x45,0x7A,0x05, -0xF3,0xBD,0x9B,0x69,0x15,0xAE,0x7D,0x4E,0x20,0x63,0xC4,0x35,0x76,0x3A,0x07,0x02, -0xC9,0x37,0xFD,0xC7,0x47,0xEE,0xE8,0xF1,0x76,0x1D,0x73,0x15,0xF2,0x97,0xA4,0xB5, -0xC8,0x7A,0x79,0xD9,0x42,0xAA,0x2B,0x7F,0x5C,0xFE,0xCE,0x26,0x4F,0xA3,0x66,0x81, -0x35,0xAF,0x44,0xBA,0x54,0x1E,0x1C,0x30,0x32,0x65,0x9D,0xE6,0x3C,0x93,0x5E,0x50, -0x4E,0x7A,0xE3,0x3A,0xD4,0x6E,0xCC,0x1A,0xFB,0xF9,0xD2,0x37,0xAE,0x24,0x2A,0xAB, -0x57,0x03,0x22,0x28,0x0D,0x49,0x75,0x7F,0xB7,0x28,0xDA,0x75,0xBF,0x8E,0xE3,0xDC, -0x0E,0x79,0x31,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, -0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9D,0x93,0xC6,0x53,0x8B,0x5E,0xCA,0xAF,0x3F, -0x9F,0x1E,0x0F,0xE5,0x99,0x95,0xBC,0x24,0xF6,0x94,0x8F,0x30,0x0F,0x06,0x03,0x55, -0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, -0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00, -0x58,0xAC,0xF4,0x04,0x0E,0xCD,0xC0,0x0D,0xFF,0x0A,0xFD,0xD4,0xBA,0x16,0x5F,0x29, -0xBD,0x7B,0x68,0x99,0x58,0x49,0xD2,0xB4,0x1D,0x37,0x4D,0x7F,0x27,0x7D,0x46,0x06, -0x5D,0x43,0xC6,0x86,0x2E,0x3E,0x73,0xB2,0x26,0x7D,0x4F,0x93,0xA9,0xB6,0xC4,0x2A, -0x9A,0xAB,0x21,0x97,0x14,0xB1,0xDE,0x8C,0xD3,0xAB,0x89,0x15,0xD8,0x6B,0x24,0xD4, -0xF1,0x16,0xAE,0xD8,0xA4,0x5C,0xD4,0x7F,0x51,0x8E,0xED,0x18,0x01,0xB1,0x93,0x63, -0xBD,0xBC,0xF8,0x61,0x80,0x9A,0x9E,0xB1,0xCE,0x42,0x70,0xE2,0xA9,0x7D,0x06,0x25, -0x7D,0x27,0xA1,0xFE,0x6F,0xEC,0xB3,0x1E,0x24,0xDA,0xE3,0x4B,0x55,0x1A,0x00,0x3B, -0x35,0xB4,0x3B,0xD9,0xD7,0x5D,0x30,0xFD,0x81,0x13,0x89,0xF2,0xC2,0x06,0x2B,0xED, -0x67,0xC4,0x8E,0xC9,0x43,0xB2,0x5C,0x6B,0x15,0x89,0x02,0xBC,0x62,0xFC,0x4E,0xF2, -0xB5,0x33,0xAA,0xB2,0x6F,0xD3,0x0A,0xA2,0x50,0xE3,0xF6,0x3B,0xE8,0x2E,0x44,0xC2, -0xDB,0x66,0x38,0xA9,0x33,0x56,0x48,0xF1,0x6D,0x1B,0x33,0x8D,0x0D,0x8C,0x3F,0x60, -0x37,0x9D,0xD3,0xCA,0x6D,0x7E,0x34,0x7E,0x0D,0x9F,0x72,0x76,0x8B,0x1B,0x9F,0x72, -0xFD,0x52,0x35,0x41,0x45,0x02,0x96,0x2F,0x1C,0xB2,0x9A,0x73,0x49,0x21,0xB1,0x49, -0x47,0x45,0x47,0xB4,0xEF,0x6A,0x34,0x11,0xC9,0x4D,0x9A,0xCC,0x59,0xB7,0xD6,0x02, -0x9E,0x5A,0x4E,0x65,0xB5,0x94,0xAE,0x1B,0xDF,0x29,0xB0,0x16,0xF1,0xBF,0x00,0x9E, -0x07,0x3A,0x17,0x64,0xB5,0x04,0xB5,0x23,0x21,0x99,0x0A,0x95,0x3B,0x97,0x7C,0xEF, -}; - - -/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Networking */ -/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Networking */ - - -const unsigned char AffirmTrust_Networking_certificate[848]={ -0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x7C, -0x4F,0x04,0x39,0x1C,0xD4,0x99,0x2D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, -0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, -0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, -0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, -0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69,0x6E,0x67,0x30,0x1E,0x17,0x0D, -0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x17,0x0D,0x33, -0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x30,0x44,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, -0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, -0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, -0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69, -0x6E,0x67,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, -0x01,0x01,0x00,0xB4,0x84,0xCC,0x33,0x17,0x2E,0x6B,0x94,0x6C,0x6B,0x61,0x52,0xA0, -0xEB,0xA3,0xCF,0x79,0x94,0x4C,0xE5,0x94,0x80,0x99,0xCB,0x55,0x64,0x44,0x65,0x8F, -0x67,0x64,0xE2,0x06,0xE3,0x5C,0x37,0x49,0xF6,0x2F,0x9B,0x84,0x84,0x1E,0x2D,0xF2, -0x60,0x9D,0x30,0x4E,0xCC,0x84,0x85,0xE2,0x2C,0xCF,0x1E,0x9E,0xFE,0x36,0xAB,0x33, -0x77,0x35,0x44,0xD8,0x35,0x96,0x1A,0x3D,0x36,0xE8,0x7A,0x0E,0xD8,0xD5,0x47,0xA1, -0x6A,0x69,0x8B,0xD9,0xFC,0xBB,0x3A,0xAE,0x79,0x5A,0xD5,0xF4,0xD6,0x71,0xBB,0x9A, -0x90,0x23,0x6B,0x9A,0xB7,0x88,0x74,0x87,0x0C,0x1E,0x5F,0xB9,0x9E,0x2D,0xFA,0xAB, -0x53,0x2B,0xDC,0xBB,0x76,0x3E,0x93,0x4C,0x08,0x08,0x8C,0x1E,0xA2,0x23,0x1C,0xD4, -0x6A,0xAD,0x22,0xBA,0x99,0x01,0x2E,0x6D,0x65,0xCB,0xBE,0x24,0x66,0x55,0x24,0x4B, -0x40,0x44,0xB1,0x1B,0xD7,0xE1,0xC2,0x85,0xC0,0xDE,0x10,0x3F,0x3D,0xED,0xB8,0xFC, -0xF1,0xF1,0x23,0x53,0xDC,0xBF,0x65,0x97,0x6F,0xD9,0xF9,0x40,0x71,0x8D,0x7D,0xBD, -0x95,0xD4,0xCE,0xBE,0xA0,0x5E,0x27,0x23,0xDE,0xFD,0xA6,0xD0,0x26,0x0E,0x00,0x29, -0xEB,0x3C,0x46,0xF0,0x3D,0x60,0xBF,0x3F,0x50,0xD2,0xDC,0x26,0x41,0x51,0x9E,0x14, -0x37,0x42,0x04,0xA3,0x70,0x57,0xA8,0x1B,0x87,0xED,0x2D,0xFA,0x7B,0xEE,0x8C,0x0A, -0xE3,0xA9,0x66,0x89,0x19,0xCB,0x41,0xF9,0xDD,0x44,0x36,0x61,0xCF,0xE2,0x77,0x46, -0xC8,0x7D,0xF6,0xF4,0x92,0x81,0x36,0xFD,0xDB,0x34,0xF1,0x72,0x7E,0xF3,0x0C,0x16, -0xBD,0xB4,0x15,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, -0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x07,0x1F,0xD2,0xE7,0x9C,0xDA,0xC2,0x6E,0xA2, -0x40,0xB4,0xB0,0x7A,0x50,0x10,0x50,0x74,0xC4,0xC8,0xBD,0x30,0x0F,0x06,0x03,0x55, -0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, -0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, -0x89,0x57,0xB2,0x16,0x7A,0xA8,0xC2,0xFD,0xD6,0xD9,0x9B,0x9B,0x34,0xC2,0x9C,0xB4, -0x32,0x14,0x4D,0xA7,0xA4,0xDF,0xEC,0xBE,0xA7,0xBE,0xF8,0x43,0xDB,0x91,0x37,0xCE, -0xB4,0x32,0x2E,0x50,0x55,0x1A,0x35,0x4E,0x76,0x43,0x71,0x20,0xEF,0x93,0x77,0x4E, -0x15,0x70,0x2E,0x87,0xC3,0xC1,0x1D,0x6D,0xDC,0xCB,0xB5,0x27,0xD4,0x2C,0x56,0xD1, -0x52,0x53,0x3A,0x44,0xD2,0x73,0xC8,0xC4,0x1B,0x05,0x65,0x5A,0x62,0x92,0x9C,0xEE, -0x41,0x8D,0x31,0xDB,0xE7,0x34,0xEA,0x59,0x21,0xD5,0x01,0x7A,0xD7,0x64,0xB8,0x64, -0x39,0xCD,0xC9,0xED,0xAF,0xED,0x4B,0x03,0x48,0xA7,0xA0,0x99,0x01,0x80,0xDC,0x65, -0xA3,0x36,0xAE,0x65,0x59,0x48,0x4F,0x82,0x4B,0xC8,0x65,0xF1,0x57,0x1D,0xE5,0x59, -0x2E,0x0A,0x3F,0x6C,0xD8,0xD1,0xF5,0xE5,0x09,0xB4,0x6C,0x54,0x00,0x0A,0xE0,0x15, -0x4D,0x87,0x75,0x6D,0xB7,0x58,0x96,0x5A,0xDD,0x6D,0xD2,0x00,0xA0,0xF4,0x9B,0x48, -0xBE,0xC3,0x37,0xA4,0xBA,0x36,0xE0,0x7C,0x87,0x85,0x97,0x1A,0x15,0xA2,0xDE,0x2E, -0xA2,0x5B,0xBD,0xAF,0x18,0xF9,0x90,0x50,0xCD,0x70,0x59,0xF8,0x27,0x67,0x47,0xCB, -0xC7,0xA0,0x07,0x3A,0x7D,0xD1,0x2C,0x5D,0x6C,0x19,0x3A,0x66,0xB5,0x7D,0xFD,0x91, -0x6F,0x82,0xB1,0xBE,0x08,0x93,0xDB,0x14,0x47,0xF1,0xA2,0x37,0xC7,0x45,0x9E,0x3C, -0xC7,0x77,0xAF,0x64,0xA8,0x93,0xDF,0xF6,0x69,0x83,0x82,0x60,0xF2,0x49,0x42,0x34, -0xED,0x5A,0x00,0x54,0x85,0x1C,0x16,0x36,0x92,0x0C,0x5C,0xFA,0xA6,0xAD,0xBF,0xDB, -}; - - -/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Premium */ -/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Premium */ - - -const unsigned char AffirmTrust_Premium_certificate[1354]={ -0x30,0x82,0x05,0x46,0x30,0x82,0x03,0x2E,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x6D, -0x8C,0x14,0x46,0xB1,0xA6,0x0A,0xEE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, -0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, -0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C,0x30,0x1A,0x06, -0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, -0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30, -0x31,0x32,0x39,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x17,0x0D,0x34,0x30,0x31,0x32, -0x33,0x31,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x30,0x41,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, -0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C, -0x30,0x1A,0x06,0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54, -0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x82,0x02,0x22, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, -0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xC4,0x12,0xDF, -0xA9,0x5F,0xFE,0x41,0xDD,0xDD,0xF5,0x9F,0x8A,0xE3,0xF6,0xAC,0xE1,0x3C,0x78,0x9A, -0xBC,0xD8,0xF0,0x7F,0x7A,0xA0,0x33,0x2A,0xDC,0x8D,0x20,0x5B,0xAE,0x2D,0x6F,0xE7, -0x93,0xD9,0x36,0x70,0x6A,0x68,0xCF,0x8E,0x51,0xA3,0x85,0x5B,0x67,0x04,0xA0,0x10, -0x24,0x6F,0x5D,0x28,0x82,0xC1,0x97,0x57,0xD8,0x48,0x29,0x13,0xB6,0xE1,0xBE,0x91, -0x4D,0xDF,0x85,0x0C,0x53,0x18,0x9A,0x1E,0x24,0xA2,0x4F,0x8F,0xF0,0xA2,0x85,0x0B, -0xCB,0xF4,0x29,0x7F,0xD2,0xA4,0x58,0xEE,0x26,0x4D,0xC9,0xAA,0xA8,0x7B,0x9A,0xD9, -0xFA,0x38,0xDE,0x44,0x57,0x15,0xE5,0xF8,0x8C,0xC8,0xD9,0x48,0xE2,0x0D,0x16,0x27, -0x1D,0x1E,0xC8,0x83,0x85,0x25,0xB7,0xBA,0xAA,0x55,0x41,0xCC,0x03,0x22,0x4B,0x2D, -0x91,0x8D,0x8B,0xE6,0x89,0xAF,0x66,0xC7,0xE9,0xFF,0x2B,0xE9,0x3C,0xAC,0xDA,0xD2, -0xB3,0xC3,0xE1,0x68,0x9C,0x89,0xF8,0x7A,0x00,0x56,0xDE,0xF4,0x55,0x95,0x6C,0xFB, -0xBA,0x64,0xDD,0x62,0x8B,0xDF,0x0B,0x77,0x32,0xEB,0x62,0xCC,0x26,0x9A,0x9B,0xBB, -0xAA,0x62,0x83,0x4C,0xB4,0x06,0x7A,0x30,0xC8,0x29,0xBF,0xED,0x06,0x4D,0x97,0xB9, -0x1C,0xC4,0x31,0x2B,0xD5,0x5F,0xBC,0x53,0x12,0x17,0x9C,0x99,0x57,0x29,0x66,0x77, -0x61,0x21,0x31,0x07,0x2E,0x25,0x49,0x9D,0x18,0xF2,0xEE,0xF3,0x2B,0x71,0x8C,0xB5, -0xBA,0x39,0x07,0x49,0x77,0xFC,0xEF,0x2E,0x92,0x90,0x05,0x8D,0x2D,0x2F,0x77,0x7B, -0xEF,0x43,0xBF,0x35,0xBB,0x9A,0xD8,0xF9,0x73,0xA7,0x2C,0xF2,0xD0,0x57,0xEE,0x28, -0x4E,0x26,0x5F,0x8F,0x90,0x68,0x09,0x2F,0xB8,0xF8,0xDC,0x06,0xE9,0x2E,0x9A,0x3E, -0x51,0xA7,0xD1,0x22,0xC4,0x0A,0xA7,0x38,0x48,0x6C,0xB3,0xF9,0xFF,0x7D,0xAB,0x86, -0x57,0xE3,0xBA,0xD6,0x85,0x78,0x77,0xBA,0x43,0xEA,0x48,0x7F,0xF6,0xD8,0xBE,0x23, -0x6D,0x1E,0xBF,0xD1,0x36,0x6C,0x58,0x5C,0xF1,0xEE,0xA4,0x19,0x54,0x1A,0xF5,0x03, -0xD2,0x76,0xE6,0xE1,0x8C,0xBD,0x3C,0xB3,0xD3,0x48,0x4B,0xE2,0xC8,0xF8,0x7F,0x92, -0xA8,0x76,0x46,0x9C,0x42,0x65,0x3E,0xA4,0x1E,0xC1,0x07,0x03,0x5A,0x46,0x2D,0xB8, -0x97,0xF3,0xB7,0xD5,0xB2,0x55,0x21,0xEF,0xBA,0xDC,0x4C,0x00,0x97,0xFB,0x14,0x95, -0x27,0x33,0xBF,0xE8,0x43,0x47,0x46,0xD2,0x08,0x99,0x16,0x60,0x3B,0x9A,0x7E,0xD2, -0xE6,0xED,0x38,0xEA,0xEC,0x01,0x1E,0x3C,0x48,0x56,0x49,0x09,0xC7,0x4C,0x37,0x00, -0x9E,0x88,0x0E,0xC0,0x73,0xE1,0x6F,0x66,0xE9,0x72,0x47,0x30,0x3E,0x10,0xE5,0x0B, -0x03,0xC9,0x9A,0x42,0x00,0x6C,0xC5,0x94,0x7E,0x61,0xC4,0x8A,0xDF,0x7F,0x82,0x1A, -0x0B,0x59,0xC4,0x59,0x32,0x77,0xB3,0xBC,0x60,0x69,0x56,0x39,0xFD,0xB4,0x06,0x7B, -0x2C,0xD6,0x64,0x36,0xD9,0xBD,0x48,0xED,0x84,0x1F,0x7E,0xA5,0x22,0x8F,0x2A,0xB8, -0x42,0xF4,0x82,0xB7,0xD4,0x53,0x90,0x78,0x4E,0x2D,0x1A,0xFD,0x81,0x6F,0x44,0xD7, -0x3B,0x01,0x74,0x96,0x42,0xE0,0x00,0xE2,0x2E,0x6B,0xEA,0xC5,0xEE,0x72,0xAC,0xBB, -0xBF,0xFE,0xEA,0xAA,0xA8,0xF8,0xDC,0xF6,0xB2,0x79,0x8A,0xB6,0x67,0x02,0x03,0x01, -0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, -0x14,0x9D,0xC0,0x67,0xA6,0x0C,0x22,0xD9,0x26,0xF5,0x45,0xAB,0xA6,0x65,0x52,0x11, -0x27,0xD8,0x45,0xAC,0x63,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, -0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, -0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0xB3,0x57,0x4D,0x10,0x62,0x4E, -0x3A,0xE4,0xAC,0xEA,0xB8,0x1C,0xAF,0x32,0x23,0xC8,0xB3,0x49,0x5A,0x51,0x9C,0x76, -0x28,0x8D,0x79,0xAA,0x57,0x46,0x17,0xD5,0xF5,0x52,0xF6,0xB7,0x44,0xE8,0x08,0x44, -0xBF,0x18,0x84,0xD2,0x0B,0x80,0xCD,0xC5,0x12,0xFD,0x00,0x55,0x05,0x61,0x87,0x41, -0xDC,0xB5,0x24,0x9E,0x3C,0xC4,0xD8,0xC8,0xFB,0x70,0x9E,0x2F,0x78,0x96,0x83,0x20, -0x36,0xDE,0x7C,0x0F,0x69,0x13,0x88,0xA5,0x75,0x36,0x98,0x08,0xA6,0xC6,0xDF,0xAC, -0xCE,0xE3,0x58,0xD6,0xB7,0x3E,0xDE,0xBA,0xF3,0xEB,0x34,0x40,0xD8,0xA2,0x81,0xF5, -0x78,0x3F,0x2F,0xD5,0xA5,0xFC,0xD9,0xA2,0xD4,0x5E,0x04,0x0E,0x17,0xAD,0xFE,0x41, -0xF0,0xE5,0xB2,0x72,0xFA,0x44,0x82,0x33,0x42,0xE8,0x2D,0x58,0xF7,0x56,0x8C,0x62, -0x3F,0xBA,0x42,0xB0,0x9C,0x0C,0x5C,0x7E,0x2E,0x65,0x26,0x5C,0x53,0x4F,0x00,0xB2, -0x78,0x7E,0xA1,0x0D,0x99,0x2D,0x8D,0xB8,0x1D,0x8E,0xA2,0xC4,0xB0,0xFD,0x60,0xD0, -0x30,0xA4,0x8E,0xC8,0x04,0x62,0xA9,0xC4,0xED,0x35,0xDE,0x7A,0x97,0xED,0x0E,0x38, -0x5E,0x92,0x2F,0x93,0x70,0xA5,0xA9,0x9C,0x6F,0xA7,0x7D,0x13,0x1D,0x7E,0xC6,0x08, -0x48,0xB1,0x5E,0x67,0xEB,0x51,0x08,0x25,0xE9,0xE6,0x25,0x6B,0x52,0x29,0x91,0x9C, -0xD2,0x39,0x73,0x08,0x57,0xDE,0x99,0x06,0xB4,0x5B,0x9D,0x10,0x06,0xE1,0xC2,0x00, -0xA8,0xB8,0x1C,0x4A,0x02,0x0A,0x14,0xD0,0xC1,0x41,0xCA,0xFB,0x8C,0x35,0x21,0x7D, -0x82,0x38,0xF2,0xA9,0x54,0x91,0x19,0x35,0x93,0x94,0x6D,0x6A,0x3A,0xC5,0xB2,0xD0, -0xBB,0x89,0x86,0x93,0xE8,0x9B,0xC9,0x0F,0x3A,0xA7,0x7A,0xB8,0xA1,0xF0,0x78,0x46, -0xFA,0xFC,0x37,0x2F,0xE5,0x8A,0x84,0xF3,0xDF,0xFE,0x04,0xD9,0xA1,0x68,0xA0,0x2F, -0x24,0xE2,0x09,0x95,0x06,0xD5,0x95,0xCA,0xE1,0x24,0x96,0xEB,0x7C,0xF6,0x93,0x05, -0xBB,0xED,0x73,0xE9,0x2D,0xD1,0x75,0x39,0xD7,0xE7,0x24,0xDB,0xD8,0x4E,0x5F,0x43, -0x8F,0x9E,0xD0,0x14,0x39,0xBF,0x55,0x70,0x48,0x99,0x57,0x31,0xB4,0x9C,0xEE,0x4A, -0x98,0x03,0x96,0x30,0x1F,0x60,0x06,0xEE,0x1B,0x23,0xFE,0x81,0x60,0x23,0x1A,0x47, -0x62,0x85,0xA5,0xCC,0x19,0x34,0x80,0x6F,0xB3,0xAC,0x1A,0xE3,0x9F,0xF0,0x7B,0x48, -0xAD,0xD5,0x01,0xD9,0x67,0xB6,0xA9,0x72,0x93,0xEA,0x2D,0x66,0xB5,0xB2,0xB8,0xE4, -0x3D,0x3C,0xB2,0xEF,0x4C,0x8C,0xEA,0xEB,0x07,0xBF,0xAB,0x35,0x9A,0x55,0x86,0xBC, -0x18,0xA6,0xB5,0xA8,0x5E,0xB4,0x83,0x6C,0x6B,0x69,0x40,0xD3,0x9F,0xDC,0xF1,0xC3, -0x69,0x6B,0xB9,0xE1,0x6D,0x09,0xF4,0xF1,0xAA,0x50,0x76,0x0A,0x7A,0x7D,0x7A,0x17, -0xA1,0x55,0x96,0x42,0x99,0x31,0x09,0xDD,0x60,0x11,0x8D,0x05,0x30,0x7E,0xE6,0x8E, -0x46,0xD1,0x9D,0x14,0xDA,0xC7,0x17,0xE4,0x05,0x96,0x8C,0xC4,0x24,0xB5,0x1B,0xCF, -0x14,0x07,0xB2,0x40,0xF8,0xA3,0x9E,0x41,0x86,0xBC,0x04,0xD0,0x6B,0x96,0xC8,0x2A, -0x80,0x34,0xFD,0xBF,0xEF,0x06,0xA3,0xDD,0x58,0xC5,0x85,0x3D,0x3E,0x8F,0xFE,0x9E, -0x29,0xE0,0xB6,0xB8,0x09,0x68,0x19,0x1C,0x18,0x43, -}; - - -/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Premium ECC */ -/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Premium ECC */ - - -const unsigned char AffirmTrust_Premium_ECC_certificate[514]={ -0x30,0x82,0x01,0xFE,0x30,0x82,0x01,0x85,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x74, -0x97,0x25,0x8A,0xC7,0x3F,0x7A,0x54,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, -0x04,0x03,0x03,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, -0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66, -0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04, -0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x50, -0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43,0x43,0x30,0x1E,0x17,0x0D,0x31,0x30, -0x30,0x31,0x32,0x39,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x17,0x0D,0x34,0x30,0x31, -0x32,0x33,0x31,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09, -0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55, -0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31, -0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D, -0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43, -0x43,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, -0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x0D,0x30,0x5E,0x1B,0x15,0x9D,0x03, -0xD0,0xA1,0x79,0x35,0xB7,0x3A,0x3C,0x92,0x7A,0xCA,0x15,0x1C,0xCD,0x62,0xF3,0x9C, -0x26,0x5C,0x07,0x3D,0xE5,0x54,0xFA,0xA3,0xD6,0xCC,0x12,0xEA,0xF4,0x14,0x5F,0xE8, -0x8E,0x19,0xAB,0x2F,0x2E,0x48,0xE6,0xAC,0x18,0x43,0x78,0xAC,0xD0,0x37,0xC3,0xBD, -0xB2,0xCD,0x2C,0xE6,0x47,0xE2,0x1A,0xE6,0x63,0xB8,0x3D,0x2E,0x2F,0x78,0xC4,0x4F, -0xDB,0xF4,0x0F,0xA4,0x68,0x4C,0x55,0x72,0x6B,0x95,0x1D,0x4E,0x18,0x42,0x95,0x78, -0xCC,0x37,0x3C,0x91,0xE2,0x9B,0x65,0x2B,0x29,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06, -0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9A,0xAF,0x29,0x7A,0xC0,0x11,0x35,0x35, -0x26,0x51,0x30,0x00,0xC3,0x6A,0xFE,0x40,0xD5,0xAE,0xD6,0x3C,0x30,0x0F,0x06,0x03, -0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06, -0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0A,0x06, -0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30, -0x17,0x09,0xF3,0x87,0x88,0x50,0x5A,0xAF,0xC8,0xC0,0x42,0xBF,0x47,0x5F,0xF5,0x6C, -0x6A,0x86,0xE0,0xC4,0x27,0x74,0xE4,0x38,0x53,0xD7,0x05,0x7F,0x1B,0x34,0xE3,0xC6, -0x2F,0xB3,0xCA,0x09,0x3C,0x37,0x9D,0xD7,0xE7,0xB8,0x46,0xF1,0xFD,0xA1,0xE2,0x71, -0x02,0x30,0x42,0x59,0x87,0x43,0xD4,0x51,0xDF,0xBA,0xD3,0x09,0x32,0x5A,0xCE,0x88, -0x7E,0x57,0x3D,0x9C,0x5F,0x42,0x6B,0xF5,0x07,0x2D,0xB5,0xF0,0x82,0x93,0xF9,0x59, -0x6F,0xAE,0x64,0xFA,0x58,0xE5,0x8B,0x1E,0xE3,0x63,0xBE,0xB5,0x81,0xCD,0x6F,0x02, -0x8C,0x79, -}; - - -/* subject:/C=US/O=America Online Inc./CN=America Online Root Certification Authority 1 */ -/* issuer :/C=US/O=America Online Inc./CN=America Online Root Certification Authority 1 */ - - -const unsigned char America_Online_Root_Certification_Authority_1_certificate[936]={ -0x30,0x82,0x03,0xA4,0x30,0x82,0x02,0x8C,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, -0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D,0x65,0x72,0x69,0x63,0x61, -0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x36,0x30,0x34, -0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72,0x69,0x63,0x61,0x20,0x4F, -0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x20,0x31,0x30,0x1E,0x17,0x0D,0x30,0x32,0x30,0x35,0x32,0x38,0x30,0x36, -0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x31,0x31,0x39,0x32,0x30,0x34, -0x33,0x30,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D, -0x65,0x72,0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63, -0x2E,0x31,0x36,0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72, -0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20, -0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75, -0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x31,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, -0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xA8,0x2F,0xE8,0xA4,0x69,0x06, -0x03,0x47,0xC3,0xE9,0x2A,0x98,0xFF,0x19,0xA2,0x70,0x9A,0xC6,0x50,0xB2,0x7E,0xA5, -0xDF,0x68,0x4D,0x1B,0x7C,0x0F,0xB6,0x97,0x68,0x7D,0x2D,0xA6,0x8B,0x97,0xE9,0x64, -0x86,0xC9,0xA3,0xEF,0xA0,0x86,0xBF,0x60,0x65,0x9C,0x4B,0x54,0x88,0xC2,0x48,0xC5, -0x4A,0x39,0xBF,0x14,0xE3,0x59,0x55,0xE5,0x19,0xB4,0x74,0xC8,0xB4,0x05,0x39,0x5C, -0x16,0xA5,0xE2,0x95,0x05,0xE0,0x12,0xAE,0x59,0x8B,0xA2,0x33,0x68,0x58,0x1C,0xA6, -0xD4,0x15,0xB7,0xD8,0x9F,0xD7,0xDC,0x71,0xAB,0x7E,0x9A,0xBF,0x9B,0x8E,0x33,0x0F, -0x22,0xFD,0x1F,0x2E,0xE7,0x07,0x36,0xEF,0x62,0x39,0xC5,0xDD,0xCB,0xBA,0x25,0x14, -0x23,0xDE,0x0C,0xC6,0x3D,0x3C,0xCE,0x82,0x08,0xE6,0x66,0x3E,0xDA,0x51,0x3B,0x16, -0x3A,0xA3,0x05,0x7F,0xA0,0xDC,0x87,0xD5,0x9C,0xFC,0x72,0xA9,0xA0,0x7D,0x78,0xE4, -0xB7,0x31,0x55,0x1E,0x65,0xBB,0xD4,0x61,0xB0,0x21,0x60,0xED,0x10,0x32,0x72,0xC5, -0x92,0x25,0x1E,0xF8,0x90,0x4A,0x18,0x78,0x47,0xDF,0x7E,0x30,0x37,0x3E,0x50,0x1B, -0xDB,0x1C,0xD3,0x6B,0x9A,0x86,0x53,0x07,0xB0,0xEF,0xAC,0x06,0x78,0xF8,0x84,0x99, -0xFE,0x21,0x8D,0x4C,0x80,0xB6,0x0C,0x82,0xF6,0x66,0x70,0x79,0x1A,0xD3,0x4F,0xA3, -0xCF,0xF1,0xCF,0x46,0xB0,0x4B,0x0F,0x3E,0xDD,0x88,0x62,0xB8,0x8C,0xA9,0x09,0x28, -0x3B,0x7A,0xC7,0x97,0xE1,0x1E,0xE5,0xF4,0x9F,0xC0,0xC0,0xAE,0x24,0xA0,0xC8,0xA1, -0xD9,0x0F,0xD6,0x7B,0x26,0x82,0x69,0x32,0x3D,0xA7,0x02,0x03,0x01,0x00,0x01,0xA3, -0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, -0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x00, -0xAD,0xD9,0xA3,0xF6,0x79,0xF6,0x6E,0x74,0xA9,0x7F,0x33,0x3D,0x81,0x17,0xD7,0x4C, -0xCF,0x33,0xDE,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, -0x00,0xAD,0xD9,0xA3,0xF6,0x79,0xF6,0x6E,0x74,0xA9,0x7F,0x33,0x3D,0x81,0x17,0xD7, -0x4C,0xCF,0x33,0xDE,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, -0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x7C,0x8A,0xD1,0x1F,0x18,0x37,0x82,0xE0, -0xB8,0xB0,0xA3,0xED,0x56,0x95,0xC8,0x62,0x61,0x9C,0x05,0xA2,0xCD,0xC2,0x62,0x26, -0x61,0xCD,0x10,0x16,0xD7,0xCC,0xB4,0x65,0x34,0xD0,0x11,0x8A,0xAD,0xA8,0xA9,0x05, -0x66,0xEF,0x74,0xF3,0x6D,0x5F,0x9D,0x99,0xAF,0xF6,0x8B,0xFB,0xEB,0x52,0xB2,0x05, -0x98,0xA2,0x6F,0x2A,0xC5,0x54,0xBD,0x25,0xBD,0x5F,0xAE,0xC8,0x86,0xEA,0x46,0x2C, -0xC1,0xB3,0xBD,0xC1,0xE9,0x49,0x70,0x18,0x16,0x97,0x08,0x13,0x8C,0x20,0xE0,0x1B, -0x2E,0x3A,0x47,0xCB,0x1E,0xE4,0x00,0x30,0x95,0x5B,0xF4,0x45,0xA3,0xC0,0x1A,0xB0, -0x01,0x4E,0xAB,0xBD,0xC0,0x23,0x6E,0x63,0x3F,0x80,0x4A,0xC5,0x07,0xED,0xDC,0xE2, -0x6F,0xC7,0xC1,0x62,0xF1,0xE3,0x72,0xD6,0x04,0xC8,0x74,0x67,0x0B,0xFA,0x88,0xAB, -0xA1,0x01,0xC8,0x6F,0xF0,0x14,0xAF,0xD2,0x99,0xCD,0x51,0x93,0x7E,0xED,0x2E,0x38, -0xC7,0xBD,0xCE,0x46,0x50,0x3D,0x72,0xE3,0x79,0x25,0x9D,0x9B,0x88,0x2B,0x10,0x20, -0xDD,0xA5,0xB8,0x32,0x9F,0x8D,0xE0,0x29,0xDF,0x21,0x74,0x86,0x82,0xDB,0x2F,0x82, -0x30,0xC6,0xC7,0x35,0x86,0xB3,0xF9,0x96,0x5F,0x46,0xDB,0x0C,0x45,0xFD,0xF3,0x50, -0xC3,0x6F,0xC6,0xC3,0x48,0xAD,0x46,0xA6,0xE1,0x27,0x47,0x0A,0x1D,0x0E,0x9B,0xB6, -0xC2,0x77,0x7F,0x63,0xF2,0xE0,0x7D,0x1A,0xBE,0xFC,0xE0,0xDF,0xD7,0xC7,0xA7,0x6C, -0xB0,0xF9,0xAE,0xBA,0x3C,0xFD,0x74,0xB4,0x11,0xE8,0x58,0x0D,0x80,0xBC,0xD3,0xA8, -0x80,0x3A,0x99,0xED,0x75,0xCC,0x46,0x7B, -}; - - -/* subject:/C=US/O=America Online Inc./CN=America Online Root Certification Authority 2 */ -/* issuer :/C=US/O=America Online Inc./CN=America Online Root Certification Authority 2 */ - - -const unsigned char America_Online_Root_Certification_Authority_2_certificate[1448]={ -0x30,0x82,0x05,0xA4,0x30,0x82,0x03,0x8C,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, -0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D,0x65,0x72,0x69,0x63,0x61, -0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x36,0x30,0x34, -0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72,0x69,0x63,0x61,0x20,0x4F, -0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x20,0x32,0x30,0x1E,0x17,0x0D,0x30,0x32,0x30,0x35,0x32,0x38,0x30,0x36, -0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x30,0x39,0x32,0x39,0x31,0x34,0x30, -0x38,0x30,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D, -0x65,0x72,0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63, -0x2E,0x31,0x36,0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72, -0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20, -0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75, -0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x32,0x30,0x82,0x02,0x22,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F, -0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xCC,0x41,0x45,0x1D,0xE9,0x3D, -0x4D,0x10,0xF6,0x8C,0xB1,0x41,0xC9,0xE0,0x5E,0xCB,0x0D,0xB7,0xBF,0x47,0x73,0xD3, -0xF0,0x55,0x4D,0xDD,0xC6,0x0C,0xFA,0xB1,0x66,0x05,0x6A,0xCD,0x78,0xB4,0xDC,0x02, -0xDB,0x4E,0x81,0xF3,0xD7,0xA7,0x7C,0x71,0xBC,0x75,0x63,0xA0,0x5D,0xE3,0x07,0x0C, -0x48,0xEC,0x25,0xC4,0x03,0x20,0xF4,0xFF,0x0E,0x3B,0x12,0xFF,0x9B,0x8D,0xE1,0xC6, -0xD5,0x1B,0xB4,0x6D,0x22,0xE3,0xB1,0xDB,0x7F,0x21,0x64,0xAF,0x86,0xBC,0x57,0x22, -0x2A,0xD6,0x47,0x81,0x57,0x44,0x82,0x56,0x53,0xBD,0x86,0x14,0x01,0x0B,0xFC,0x7F, -0x74,0xA4,0x5A,0xAE,0xF1,0xBA,0x11,0xB5,0x9B,0x58,0x5A,0x80,0xB4,0x37,0x78,0x09, -0x33,0x7C,0x32,0x47,0x03,0x5C,0xC4,0xA5,0x83,0x48,0xF4,0x57,0x56,0x6E,0x81,0x36, -0x27,0x18,0x4F,0xEC,0x9B,0x28,0xC2,0xD4,0xB4,0xD7,0x7C,0x0C,0x3E,0x0C,0x2B,0xDF, -0xCA,0x04,0xD7,0xC6,0x8E,0xEA,0x58,0x4E,0xA8,0xA4,0xA5,0x18,0x1C,0x6C,0x45,0x98, -0xA3,0x41,0xD1,0x2D,0xD2,0xC7,0x6D,0x8D,0x19,0xF1,0xAD,0x79,0xB7,0x81,0x3F,0xBD, -0x06,0x82,0x27,0x2D,0x10,0x58,0x05,0xB5,0x78,0x05,0xB9,0x2F,0xDB,0x0C,0x6B,0x90, -0x90,0x7E,0x14,0x59,0x38,0xBB,0x94,0x24,0x13,0xE5,0xD1,0x9D,0x14,0xDF,0xD3,0x82, -0x4D,0x46,0xF0,0x80,0x39,0x52,0x32,0x0F,0xE3,0x84,0xB2,0x7A,0x43,0xF2,0x5E,0xDE, -0x5F,0x3F,0x1D,0xDD,0xE3,0xB2,0x1B,0xA0,0xA1,0x2A,0x23,0x03,0x6E,0x2E,0x01,0x15, -0x87,0x5C,0xA6,0x75,0x75,0xC7,0x97,0x61,0xBE,0xDE,0x86,0xDC,0xD4,0x48,0xDB,0xBD, -0x2A,0xBF,0x4A,0x55,0xDA,0xE8,0x7D,0x50,0xFB,0xB4,0x80,0x17,0xB8,0x94,0xBF,0x01, -0x3D,0xEA,0xDA,0xBA,0x7C,0xE0,0x58,0x67,0x17,0xB9,0x58,0xE0,0x88,0x86,0x46,0x67, -0x6C,0x9D,0x10,0x47,0x58,0x32,0xD0,0x35,0x7C,0x79,0x2A,0x90,0xA2,0x5A,0x10,0x11, -0x23,0x35,0xAD,0x2F,0xCC,0xE4,0x4A,0x5B,0xA7,0xC8,0x27,0xF2,0x83,0xDE,0x5E,0xBB, -0x5E,0x77,0xE7,0xE8,0xA5,0x6E,0x63,0xC2,0x0D,0x5D,0x61,0xD0,0x8C,0xD2,0x6C,0x5A, -0x21,0x0E,0xCA,0x28,0xA3,0xCE,0x2A,0xE9,0x95,0xC7,0x48,0xCF,0x96,0x6F,0x1D,0x92, -0x25,0xC8,0xC6,0xC6,0xC1,0xC1,0x0C,0x05,0xAC,0x26,0xC4,0xD2,0x75,0xD2,0xE1,0x2A, -0x67,0xC0,0x3D,0x5B,0xA5,0x9A,0xEB,0xCF,0x7B,0x1A,0xA8,0x9D,0x14,0x45,0xE5,0x0F, -0xA0,0x9A,0x65,0xDE,0x2F,0x28,0xBD,0xCE,0x6F,0x94,0x66,0x83,0x48,0x29,0xD8,0xEA, -0x65,0x8C,0xAF,0x93,0xD9,0x64,0x9F,0x55,0x57,0x26,0xBF,0x6F,0xCB,0x37,0x31,0x99, -0xA3,0x60,0xBB,0x1C,0xAD,0x89,0x34,0x32,0x62,0xB8,0x43,0x21,0x06,0x72,0x0C,0xA1, -0x5C,0x6D,0x46,0xC5,0xFA,0x29,0xCF,0x30,0xDE,0x89,0xDC,0x71,0x5B,0xDD,0xB6,0x37, -0x3E,0xDF,0x50,0xF5,0xB8,0x07,0x25,0x26,0xE5,0xBC,0xB5,0xFE,0x3C,0x02,0xB3,0xB7, -0xF8,0xBE,0x43,0xC1,0x87,0x11,0x94,0x9E,0x23,0x6C,0x17,0x8A,0xB8,0x8A,0x27,0x0C, -0x54,0x47,0xF0,0xA9,0xB3,0xC0,0x80,0x8C,0xA0,0x27,0xEB,0x1D,0x19,0xE3,0x07,0x8E, -0x77,0x70,0xCA,0x2B,0xF4,0x7D,0x76,0xE0,0x78,0x67,0x02,0x03,0x01,0x00,0x01,0xA3, -0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, -0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4D, -0x45,0xC1,0x68,0x38,0xBB,0x73,0xA9,0x69,0xA1,0x20,0xE7,0xED,0xF5,0x22,0xA1,0x23, -0x14,0xD7,0x9E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, -0x4D,0x45,0xC1,0x68,0x38,0xBB,0x73,0xA9,0x69,0xA1,0x20,0xE7,0xED,0xF5,0x22,0xA1, -0x23,0x14,0xD7,0x9E,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, -0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x05,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x67,0x6B,0x06,0xB9,0x5F,0x45,0x3B,0x2A, -0x4B,0x33,0xB3,0xE6,0x1B,0x6B,0x59,0x4E,0x22,0xCC,0xB9,0xB7,0xA4,0x25,0xC9,0xA7, -0xC4,0xF0,0x54,0x96,0x0B,0x64,0xF3,0xB1,0x58,0x4F,0x5E,0x51,0xFC,0xB2,0x97,0x7B, -0x27,0x65,0xC2,0xE5,0xCA,0xE7,0x0D,0x0C,0x25,0x7B,0x62,0xE3,0xFA,0x9F,0xB4,0x87, -0xB7,0x45,0x46,0xAF,0x83,0xA5,0x97,0x48,0x8C,0xA5,0xBD,0xF1,0x16,0x2B,0x9B,0x76, -0x2C,0x7A,0x35,0x60,0x6C,0x11,0x80,0x97,0xCC,0xA9,0x92,0x52,0xE6,0x2B,0xE6,0x69, -0xED,0xA9,0xF8,0x36,0x2D,0x2C,0x77,0xBF,0x61,0x48,0xD1,0x63,0x0B,0xB9,0x5B,0x52, -0xED,0x18,0xB0,0x43,0x42,0x22,0xA6,0xB1,0x77,0xAE,0xDE,0x69,0xC5,0xCD,0xC7,0x1C, -0xA1,0xB1,0xA5,0x1C,0x10,0xFB,0x18,0xBE,0x1A,0x70,0xDD,0xC1,0x92,0x4B,0xBE,0x29, -0x5A,0x9D,0x3F,0x35,0xBE,0xE5,0x7D,0x51,0xF8,0x55,0xE0,0x25,0x75,0x23,0x87,0x1E, -0x5C,0xDC,0xBA,0x9D,0xB0,0xAC,0xB3,0x69,0xDB,0x17,0x83,0xC9,0xF7,0xDE,0x0C,0xBC, -0x08,0xDC,0x91,0x9E,0xA8,0xD0,0xD7,0x15,0x37,0x73,0xA5,0x35,0xB8,0xFC,0x7E,0xC5, -0x44,0x40,0x06,0xC3,0xEB,0xF8,0x22,0x80,0x5C,0x47,0xCE,0x02,0xE3,0x11,0x9F,0x44, -0xFF,0xFD,0x9A,0x32,0xCC,0x7D,0x64,0x51,0x0E,0xEB,0x57,0x26,0x76,0x3A,0xE3,0x1E, -0x22,0x3C,0xC2,0xA6,0x36,0xDD,0x19,0xEF,0xA7,0xFC,0x12,0xF3,0x26,0xC0,0x59,0x31, -0x85,0x4C,0x9C,0xD8,0xCF,0xDF,0xA4,0xCC,0xCC,0x29,0x93,0xFF,0x94,0x6D,0x76,0x5C, -0x13,0x08,0x97,0xF2,0xED,0xA5,0x0B,0x4D,0xDD,0xE8,0xC9,0x68,0x0E,0x66,0xD3,0x00, -0x0E,0x33,0x12,0x5B,0xBC,0x95,0xE5,0x32,0x90,0xA8,0xB3,0xC6,0x6C,0x83,0xAD,0x77, -0xEE,0x8B,0x7E,0x7E,0xB1,0xA9,0xAB,0xD3,0xE1,0xF1,0xB6,0xC0,0xB1,0xEA,0x88,0xC0, -0xE7,0xD3,0x90,0xE9,0x28,0x92,0x94,0x7B,0x68,0x7B,0x97,0x2A,0x0A,0x67,0x2D,0x85, -0x02,0x38,0x10,0xE4,0x03,0x61,0xD4,0xDA,0x25,0x36,0xC7,0x08,0x58,0x2D,0xA1,0xA7, -0x51,0xAF,0x30,0x0A,0x49,0xF5,0xA6,0x69,0x87,0x07,0x2D,0x44,0x46,0x76,0x8E,0x2A, -0xE5,0x9A,0x3B,0xD7,0x18,0xA2,0xFC,0x9C,0x38,0x10,0xCC,0xC6,0x3B,0xD2,0xB5,0x17, -0x3A,0x6F,0xFD,0xAE,0x25,0xBD,0xF5,0x72,0x59,0x64,0xB1,0x74,0x2A,0x38,0x5F,0x18, -0x4C,0xDF,0xCF,0x71,0x04,0x5A,0x36,0xD4,0xBF,0x2F,0x99,0x9C,0xE8,0xD9,0xBA,0xB1, -0x95,0xE6,0x02,0x4B,0x21,0xA1,0x5B,0xD5,0xC1,0x4F,0x8F,0xAE,0x69,0x6D,0x53,0xDB, -0x01,0x93,0xB5,0x5C,0x1E,0x18,0xDD,0x64,0x5A,0xCA,0x18,0x28,0x3E,0x63,0x04,0x11, -0xFD,0x1C,0x8D,0x00,0x0F,0xB8,0x37,0xDF,0x67,0x8A,0x9D,0x66,0xA9,0x02,0x6A,0x91, -0xFF,0x13,0xCA,0x2F,0x5D,0x83,0xBC,0x87,0x93,0x6C,0xDC,0x24,0x51,0x16,0x04,0x25, -0x66,0xFA,0xB3,0xD9,0xC2,0xBA,0x29,0xBE,0x9A,0x48,0x38,0x82,0x99,0xF4,0xBF,0x3B, -0x4A,0x31,0x19,0xF9,0xBF,0x8E,0x21,0x33,0x14,0xCA,0x4F,0x54,0x5F,0xFB,0xCE,0xFB, -0x8F,0x71,0x7F,0xFD,0x5E,0x19,0xA0,0x0F,0x4B,0x91,0xB8,0xC4,0x54,0xBC,0x06,0xB0, -0x45,0x8F,0x26,0x91,0xA2,0x8E,0xFE,0xA9, -}; - - -/* subject:/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -/* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ - - -const unsigned char Baltimore_CyberTrust_Root_certificate[891]={ -0x30,0x82,0x03,0x77,0x30,0x82,0x02,0x5F,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x02, -0x00,0x00,0xB9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, -0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, -0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, -0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, -0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, -0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, -0x17,0x0D,0x30,0x30,0x30,0x35,0x31,0x32,0x31,0x38,0x34,0x36,0x30,0x30,0x5A,0x17, -0x0D,0x32,0x35,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,0x30,0x30,0x5A,0x30,0x5A, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x45,0x31,0x12,0x30, -0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72, -0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A,0x43,0x79,0x62,0x65, -0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13, -0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43,0x79,0x62,0x65,0x72, -0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D, -0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, -0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xA3,0x04,0xBB,0x22,0xAB, -0x98,0x3D,0x57,0xE8,0x26,0x72,0x9A,0xB5,0x79,0xD4,0x29,0xE2,0xE1,0xE8,0x95,0x80, -0xB1,0xB0,0xE3,0x5B,0x8E,0x2B,0x29,0x9A,0x64,0xDF,0xA1,0x5D,0xED,0xB0,0x09,0x05, -0x6D,0xDB,0x28,0x2E,0xCE,0x62,0xA2,0x62,0xFE,0xB4,0x88,0xDA,0x12,0xEB,0x38,0xEB, -0x21,0x9D,0xC0,0x41,0x2B,0x01,0x52,0x7B,0x88,0x77,0xD3,0x1C,0x8F,0xC7,0xBA,0xB9, -0x88,0xB5,0x6A,0x09,0xE7,0x73,0xE8,0x11,0x40,0xA7,0xD1,0xCC,0xCA,0x62,0x8D,0x2D, -0xE5,0x8F,0x0B,0xA6,0x50,0xD2,0xA8,0x50,0xC3,0x28,0xEA,0xF5,0xAB,0x25,0x87,0x8A, -0x9A,0x96,0x1C,0xA9,0x67,0xB8,0x3F,0x0C,0xD5,0xF7,0xF9,0x52,0x13,0x2F,0xC2,0x1B, -0xD5,0x70,0x70,0xF0,0x8F,0xC0,0x12,0xCA,0x06,0xCB,0x9A,0xE1,0xD9,0xCA,0x33,0x7A, -0x77,0xD6,0xF8,0xEC,0xB9,0xF1,0x68,0x44,0x42,0x48,0x13,0xD2,0xC0,0xC2,0xA4,0xAE, -0x5E,0x60,0xFE,0xB6,0xA6,0x05,0xFC,0xB4,0xDD,0x07,0x59,0x02,0xD4,0x59,0x18,0x98, -0x63,0xF5,0xA5,0x63,0xE0,0x90,0x0C,0x7D,0x5D,0xB2,0x06,0x7A,0xF3,0x85,0xEA,0xEB, -0xD4,0x03,0xAE,0x5E,0x84,0x3E,0x5F,0xFF,0x15,0xED,0x69,0xBC,0xF9,0x39,0x36,0x72, -0x75,0xCF,0x77,0x52,0x4D,0xF3,0xC9,0x90,0x2C,0xB9,0x3D,0xE5,0xC9,0x23,0x53,0x3F, -0x1F,0x24,0x98,0x21,0x5C,0x07,0x99,0x29,0xBD,0xC6,0x3A,0xEC,0xE7,0x6E,0x86,0x3A, -0x6B,0x97,0x74,0x63,0x33,0xBD,0x68,0x18,0x31,0xF0,0x78,0x8D,0x76,0xBF,0xFC,0x9E, -0x8E,0x5D,0x2A,0x86,0xA7,0x4D,0x90,0xDC,0x27,0x1A,0x39,0x02,0x03,0x01,0x00,0x01, -0xA3,0x45,0x30,0x43,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xE5, -0x9D,0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54,0x36,0x86,0x7B,0x3A,0xB5, -0x04,0x4D,0xF0,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30, -0x06,0x01,0x01,0xFF,0x02,0x01,0x03,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, -0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x85,0x0C,0x5D,0x8E,0xE4, -0x6F,0x51,0x68,0x42,0x05,0xA0,0xDD,0xBB,0x4F,0x27,0x25,0x84,0x03,0xBD,0xF7,0x64, -0xFD,0x2D,0xD7,0x30,0xE3,0xA4,0x10,0x17,0xEB,0xDA,0x29,0x29,0xB6,0x79,0x3F,0x76, -0xF6,0x19,0x13,0x23,0xB8,0x10,0x0A,0xF9,0x58,0xA4,0xD4,0x61,0x70,0xBD,0x04,0x61, -0x6A,0x12,0x8A,0x17,0xD5,0x0A,0xBD,0xC5,0xBC,0x30,0x7C,0xD6,0xE9,0x0C,0x25,0x8D, -0x86,0x40,0x4F,0xEC,0xCC,0xA3,0x7E,0x38,0xC6,0x37,0x11,0x4F,0xED,0xDD,0x68,0x31, -0x8E,0x4C,0xD2,0xB3,0x01,0x74,0xEE,0xBE,0x75,0x5E,0x07,0x48,0x1A,0x7F,0x70,0xFF, -0x16,0x5C,0x84,0xC0,0x79,0x85,0xB8,0x05,0xFD,0x7F,0xBE,0x65,0x11,0xA3,0x0F,0xC0, -0x02,0xB4,0xF8,0x52,0x37,0x39,0x04,0xD5,0xA9,0x31,0x7A,0x18,0xBF,0xA0,0x2A,0xF4, -0x12,0x99,0xF7,0xA3,0x45,0x82,0xE3,0x3C,0x5E,0xF5,0x9D,0x9E,0xB5,0xC8,0x9E,0x7C, -0x2E,0xC8,0xA4,0x9E,0x4E,0x08,0x14,0x4B,0x6D,0xFD,0x70,0x6D,0x6B,0x1A,0x63,0xBD, -0x64,0xE6,0x1F,0xB7,0xCE,0xF0,0xF2,0x9F,0x2E,0xBB,0x1B,0xB7,0xF2,0x50,0x88,0x73, -0x92,0xC2,0xE2,0xE3,0x16,0x8D,0x9A,0x32,0x02,0xAB,0x8E,0x18,0xDD,0xE9,0x10,0x11, -0xEE,0x7E,0x35,0xAB,0x90,0xAF,0x3E,0x30,0x94,0x7A,0xD0,0x33,0x3D,0xA7,0x65,0x0F, -0xF5,0xFC,0x8E,0x9E,0x62,0xCF,0x47,0x44,0x2C,0x01,0x5D,0xBB,0x1D,0xB5,0x32,0xD2, -0x47,0xD2,0x38,0x2E,0xD0,0xFE,0x81,0xDC,0x32,0x6A,0x1E,0xB5,0xEE,0x3C,0xD5,0xFC, -0xE7,0x81,0x1D,0x19,0xC3,0x24,0x42,0xEA,0x63,0x39,0xA9, -}; - - -/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services */ -/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services */ - - -const unsigned char Comodo_AAA_Services_root_certificate[1078]={ -0x30,0x82,0x04,0x32,0x30,0x82,0x03,0x1A,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x7B,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, -0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, -0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, -0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, -0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, -0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, -0x04,0x03,0x0C,0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, -0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x1E,0x17,0x0D, -0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32, -0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x7B,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, -0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, -0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, -0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, -0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43,0x41,0x20,0x4C, -0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C, -0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65, -0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, -0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBE,0x40,0x9D,0xF4,0x6E,0xE1, -0xEA,0x76,0x87,0x1C,0x4D,0x45,0x44,0x8E,0xBE,0x46,0xC8,0x83,0x06,0x9D,0xC1,0x2A, -0xFE,0x18,0x1F,0x8E,0xE4,0x02,0xFA,0xF3,0xAB,0x5D,0x50,0x8A,0x16,0x31,0x0B,0x9A, -0x06,0xD0,0xC5,0x70,0x22,0xCD,0x49,0x2D,0x54,0x63,0xCC,0xB6,0x6E,0x68,0x46,0x0B, -0x53,0xEA,0xCB,0x4C,0x24,0xC0,0xBC,0x72,0x4E,0xEA,0xF1,0x15,0xAE,0xF4,0x54,0x9A, -0x12,0x0A,0xC3,0x7A,0xB2,0x33,0x60,0xE2,0xDA,0x89,0x55,0xF3,0x22,0x58,0xF3,0xDE, -0xDC,0xCF,0xEF,0x83,0x86,0xA2,0x8C,0x94,0x4F,0x9F,0x68,0xF2,0x98,0x90,0x46,0x84, -0x27,0xC7,0x76,0xBF,0xE3,0xCC,0x35,0x2C,0x8B,0x5E,0x07,0x64,0x65,0x82,0xC0,0x48, -0xB0,0xA8,0x91,0xF9,0x61,0x9F,0x76,0x20,0x50,0xA8,0x91,0xC7,0x66,0xB5,0xEB,0x78, -0x62,0x03,0x56,0xF0,0x8A,0x1A,0x13,0xEA,0x31,0xA3,0x1E,0xA0,0x99,0xFD,0x38,0xF6, -0xF6,0x27,0x32,0x58,0x6F,0x07,0xF5,0x6B,0xB8,0xFB,0x14,0x2B,0xAF,0xB7,0xAA,0xCC, -0xD6,0x63,0x5F,0x73,0x8C,0xDA,0x05,0x99,0xA8,0x38,0xA8,0xCB,0x17,0x78,0x36,0x51, -0xAC,0xE9,0x9E,0xF4,0x78,0x3A,0x8D,0xCF,0x0F,0xD9,0x42,0xE2,0x98,0x0C,0xAB,0x2F, -0x9F,0x0E,0x01,0xDE,0xEF,0x9F,0x99,0x49,0xF1,0x2D,0xDF,0xAC,0x74,0x4D,0x1B,0x98, -0xB5,0x47,0xC5,0xE5,0x29,0xD1,0xF9,0x90,0x18,0xC7,0x62,0x9C,0xBE,0x83,0xC7,0x26, -0x7B,0x3E,0x8A,0x25,0xC7,0xC0,0xDD,0x9D,0xE6,0x35,0x68,0x10,0x20,0x9D,0x8F,0xD8, -0xDE,0xD2,0xC3,0x84,0x9C,0x0D,0x5E,0xE8,0x2F,0xC9,0x02,0x03,0x01,0x00,0x01,0xA3, -0x81,0xC0,0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, -0xA0,0x11,0x0A,0x23,0x3E,0x96,0xF1,0x07,0xEC,0xE2,0xAF,0x29,0xEF,0x82,0xA5,0x7F, -0xD0,0x30,0xA4,0xB4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, -0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, -0x30,0x03,0x01,0x01,0xFF,0x30,0x7B,0x06,0x03,0x55,0x1D,0x1F,0x04,0x74,0x30,0x72, -0x30,0x38,0xA0,0x36,0xA0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63, -0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F, -0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65, -0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30,0x36,0xA0,0x34,0xA0,0x32, -0x86,0x30,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D, -0x6F,0x64,0x6F,0x2E,0x6E,0x65,0x74,0x2F,0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63, -0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05, -0x00,0x03,0x82,0x01,0x01,0x00,0x08,0x56,0xFC,0x02,0xF0,0x9B,0xE8,0xFF,0xA4,0xFA, -0xD6,0x7B,0xC6,0x44,0x80,0xCE,0x4F,0xC4,0xC5,0xF6,0x00,0x58,0xCC,0xA6,0xB6,0xBC, -0x14,0x49,0x68,0x04,0x76,0xE8,0xE6,0xEE,0x5D,0xEC,0x02,0x0F,0x60,0xD6,0x8D,0x50, -0x18,0x4F,0x26,0x4E,0x01,0xE3,0xE6,0xB0,0xA5,0xEE,0xBF,0xBC,0x74,0x54,0x41,0xBF, -0xFD,0xFC,0x12,0xB8,0xC7,0x4F,0x5A,0xF4,0x89,0x60,0x05,0x7F,0x60,0xB7,0x05,0x4A, -0xF3,0xF6,0xF1,0xC2,0xBF,0xC4,0xB9,0x74,0x86,0xB6,0x2D,0x7D,0x6B,0xCC,0xD2,0xF3, -0x46,0xDD,0x2F,0xC6,0xE0,0x6A,0xC3,0xC3,0x34,0x03,0x2C,0x7D,0x96,0xDD,0x5A,0xC2, -0x0E,0xA7,0x0A,0x99,0xC1,0x05,0x8B,0xAB,0x0C,0x2F,0xF3,0x5C,0x3A,0xCF,0x6C,0x37, -0x55,0x09,0x87,0xDE,0x53,0x40,0x6C,0x58,0xEF,0xFC,0xB6,0xAB,0x65,0x6E,0x04,0xF6, -0x1B,0xDC,0x3C,0xE0,0x5A,0x15,0xC6,0x9E,0xD9,0xF1,0x59,0x48,0x30,0x21,0x65,0x03, -0x6C,0xEC,0xE9,0x21,0x73,0xEC,0x9B,0x03,0xA1,0xE0,0x37,0xAD,0xA0,0x15,0x18,0x8F, -0xFA,0xBA,0x02,0xCE,0xA7,0x2C,0xA9,0x10,0x13,0x2C,0xD4,0xE5,0x08,0x26,0xAB,0x22, -0x97,0x60,0xF8,0x90,0x5E,0x74,0xD4,0xA2,0x9A,0x53,0xBD,0xF2,0xA9,0x68,0xE0,0xA2, -0x6E,0xC2,0xD7,0x6C,0xB1,0xA3,0x0F,0x9E,0xBF,0xEB,0x68,0xE7,0x56,0xF2,0xAE,0xF2, -0xE3,0x2B,0x38,0x3A,0x09,0x81,0xB5,0x6B,0x85,0xD7,0xBE,0x2D,0xED,0x3F,0x1A,0xB7, -0xB2,0x63,0xE2,0xF5,0x62,0x2C,0x82,0xD4,0x6A,0x00,0x41,0x50,0xF1,0x39,0x83,0x9F, -0x95,0xE9,0x36,0x96,0x98,0x6E, -}; - - -/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Certification Authority */ -/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Certification Authority */ - - -const unsigned char COMODO_Certification_Authority_certificate[1057]={ -0x30,0x82,0x04,0x1D,0x30,0x82,0x03,0x05,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4E, -0x81,0x2D,0x8A,0x82,0x65,0xE0,0x0B,0x02,0xEE,0x3E,0x35,0x02,0x46,0xE5,0x3D,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, -0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, -0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, -0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, -0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, -0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, -0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30,0x25,0x06,0x03,0x55, -0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x30, -0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, -0x39,0x5A,0x30,0x81,0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, -0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65, -0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31, -0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72, -0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F, -0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30, -0x25,0x06,0x03,0x55,0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, -0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, -0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, -0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD0,0x40,0x8B,0x8B,0x72,0xE3,0x91,0x1B,0xF7, -0x51,0xC1,0x1B,0x54,0x04,0x98,0xD3,0xA9,0xBF,0xC1,0xE6,0x8A,0x5D,0x3B,0x87,0xFB, -0xBB,0x88,0xCE,0x0D,0xE3,0x2F,0x3F,0x06,0x96,0xF0,0xA2,0x29,0x50,0x99,0xAE,0xDB, -0x3B,0xA1,0x57,0xB0,0x74,0x51,0x71,0xCD,0xED,0x42,0x91,0x4D,0x41,0xFE,0xA9,0xC8, -0xD8,0x6A,0x86,0x77,0x44,0xBB,0x59,0x66,0x97,0x50,0x5E,0xB4,0xD4,0x2C,0x70,0x44, -0xCF,0xDA,0x37,0x95,0x42,0x69,0x3C,0x30,0xC4,0x71,0xB3,0x52,0xF0,0x21,0x4D,0xA1, -0xD8,0xBA,0x39,0x7C,0x1C,0x9E,0xA3,0x24,0x9D,0xF2,0x83,0x16,0x98,0xAA,0x16,0x7C, -0x43,0x9B,0x15,0x5B,0xB7,0xAE,0x34,0x91,0xFE,0xD4,0x62,0x26,0x18,0x46,0x9A,0x3F, -0xEB,0xC1,0xF9,0xF1,0x90,0x57,0xEB,0xAC,0x7A,0x0D,0x8B,0xDB,0x72,0x30,0x6A,0x66, -0xD5,0xE0,0x46,0xA3,0x70,0xDC,0x68,0xD9,0xFF,0x04,0x48,0x89,0x77,0xDE,0xB5,0xE9, -0xFB,0x67,0x6D,0x41,0xE9,0xBC,0x39,0xBD,0x32,0xD9,0x62,0x02,0xF1,0xB1,0xA8,0x3D, -0x6E,0x37,0x9C,0xE2,0x2F,0xE2,0xD3,0xA2,0x26,0x8B,0xC6,0xB8,0x55,0x43,0x88,0xE1, -0x23,0x3E,0xA5,0xD2,0x24,0x39,0x6A,0x47,0xAB,0x00,0xD4,0xA1,0xB3,0xA9,0x25,0xFE, -0x0D,0x3F,0xA7,0x1D,0xBA,0xD3,0x51,0xC1,0x0B,0xA4,0xDA,0xAC,0x38,0xEF,0x55,0x50, -0x24,0x05,0x65,0x46,0x93,0x34,0x4F,0x2D,0x8D,0xAD,0xC6,0xD4,0x21,0x19,0xD2,0x8E, -0xCA,0x05,0x61,0x71,0x07,0x73,0x47,0xE5,0x8A,0x19,0x12,0xBD,0x04,0x4D,0xCE,0x4E, -0x9C,0xA5,0x48,0xAC,0xBB,0x26,0xF7,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x8E,0x30, -0x81,0x8B,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x0B,0x58,0xE5, -0x8B,0xC6,0x4C,0x15,0x37,0xA4,0x40,0xA9,0x30,0xA9,0x21,0xBE,0x47,0x36,0x5A,0x56, -0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, -0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, -0x01,0xFF,0x30,0x49,0x06,0x03,0x55,0x1D,0x1F,0x04,0x42,0x30,0x40,0x30,0x3E,0xA0, -0x3C,0xA0,0x3A,0x86,0x38,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E, -0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D, -0x4F,0x44,0x4F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E, -0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, -0x00,0x3E,0x98,0x9E,0x9B,0xF6,0x1B,0xE9,0xD7,0x39,0xB7,0x78,0xAE,0x1D,0x72,0x18, -0x49,0xD3,0x87,0xE4,0x43,0x82,0xEB,0x3F,0xC9,0xAA,0xF5,0xA8,0xB5,0xEF,0x55,0x7C, -0x21,0x52,0x65,0xF9,0xD5,0x0D,0xE1,0x6C,0xF4,0x3E,0x8C,0x93,0x73,0x91,0x2E,0x02, -0xC4,0x4E,0x07,0x71,0x6F,0xC0,0x8F,0x38,0x61,0x08,0xA8,0x1E,0x81,0x0A,0xC0,0x2F, -0x20,0x2F,0x41,0x8B,0x91,0xDC,0x48,0x45,0xBC,0xF1,0xC6,0xDE,0xBA,0x76,0x6B,0x33, -0xC8,0x00,0x2D,0x31,0x46,0x4C,0xED,0xE7,0x9D,0xCF,0x88,0x94,0xFF,0x33,0xC0,0x56, -0xE8,0x24,0x86,0x26,0xB8,0xD8,0x38,0x38,0xDF,0x2A,0x6B,0xDD,0x12,0xCC,0xC7,0x3F, -0x47,0x17,0x4C,0xA2,0xC2,0x06,0x96,0x09,0xD6,0xDB,0xFE,0x3F,0x3C,0x46,0x41,0xDF, -0x58,0xE2,0x56,0x0F,0x3C,0x3B,0xC1,0x1C,0x93,0x35,0xD9,0x38,0x52,0xAC,0xEE,0xC8, -0xEC,0x2E,0x30,0x4E,0x94,0x35,0xB4,0x24,0x1F,0x4B,0x78,0x69,0xDA,0xF2,0x02,0x38, -0xCC,0x95,0x52,0x93,0xF0,0x70,0x25,0x59,0x9C,0x20,0x67,0xC4,0xEE,0xF9,0x8B,0x57, -0x61,0xF4,0x92,0x76,0x7D,0x3F,0x84,0x8D,0x55,0xB7,0xE8,0xE5,0xAC,0xD5,0xF1,0xF5, -0x19,0x56,0xA6,0x5A,0xFB,0x90,0x1C,0xAF,0x93,0xEB,0xE5,0x1C,0xD4,0x67,0x97,0x5D, -0x04,0x0E,0xBE,0x0B,0x83,0xA6,0x17,0x83,0xB9,0x30,0x12,0xA0,0xC5,0x33,0x15,0x05, -0xB9,0x0D,0xFB,0xC7,0x05,0x76,0xE3,0xD8,0x4A,0x8D,0xFC,0x34,0x17,0xA3,0xC6,0x21, -0x28,0xBE,0x30,0x45,0x31,0x1E,0xC7,0x78,0xBE,0x58,0x61,0x38,0xAC,0x3B,0xE2,0x01, -0x65, -}; - - -/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Certification Authority */ -/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Certification Authority */ - - -const unsigned char COMODO_ECC_Certification_Authority_certificate[653]={ -0x30,0x82,0x02,0x89,0x30,0x82,0x02,0x0F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x1F, -0x47,0xAF,0xAA,0x62,0x00,0x70,0x50,0x54,0x4C,0x01,0x9E,0x9B,0x63,0x99,0x2A,0x30, -0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x85,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, -0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, -0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, -0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, -0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C, -0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13, -0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74, -0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x38,0x30,0x33,0x30,0x36,0x30,0x30,0x30, -0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32,0x33,0x35,0x39, -0x35,0x39,0x5A,0x30,0x81,0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72, -0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72, -0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F, -0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D, -0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B, -0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20, -0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, -0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x76,0x30,0x10,0x06, -0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03, -0x62,0x00,0x04,0x03,0x47,0x7B,0x2F,0x75,0xC9,0x82,0x15,0x85,0xFB,0x75,0xE4,0x91, -0x16,0xD4,0xAB,0x62,0x99,0xF5,0x3E,0x52,0x0B,0x06,0xCE,0x41,0x00,0x7F,0x97,0xE1, -0x0A,0x24,0x3C,0x1D,0x01,0x04,0xEE,0x3D,0xD2,0x8D,0x09,0x97,0x0C,0xE0,0x75,0xE4, -0xFA,0xFB,0x77,0x8A,0x2A,0xF5,0x03,0x60,0x4B,0x36,0x8B,0x16,0x23,0x16,0xAD,0x09, -0x71,0xF4,0x4A,0xF4,0x28,0x50,0xB4,0xFE,0x88,0x1C,0x6E,0x3F,0x6C,0x2F,0x2F,0x09, -0x59,0x5B,0xA5,0x5B,0x0B,0x33,0x99,0xE2,0xC3,0x3D,0x89,0xF9,0x6A,0x2C,0xEF,0xB2, -0xD3,0x06,0xE9,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, -0x04,0x14,0x75,0x71,0xA7,0x19,0x48,0x19,0xBC,0x9D,0x9D,0xEA,0x41,0x47,0xDF,0x94, -0xC4,0x48,0x77,0x99,0xD3,0x79,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, -0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, -0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, -0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31,0x00,0xEF,0x03,0x5B,0x7A,0xAC, -0xB7,0x78,0x0A,0x72,0xB7,0x88,0xDF,0xFF,0xB5,0x46,0x14,0x09,0x0A,0xFA,0xA0,0xE6, -0x7D,0x08,0xC6,0x1A,0x87,0xBD,0x18,0xA8,0x73,0xBD,0x26,0xCA,0x60,0x0C,0x9D,0xCE, -0x99,0x9F,0xCF,0x5C,0x0F,0x30,0xE1,0xBE,0x14,0x31,0xEA,0x02,0x30,0x14,0xF4,0x93, -0x3C,0x49,0xA7,0x33,0x7A,0x90,0x46,0x47,0xB3,0x63,0x7D,0x13,0x9B,0x4E,0xB7,0x6F, -0x18,0x37,0x80,0x53,0xFE,0xDD,0x20,0xE0,0x35,0x9A,0x36,0xD1,0xC7,0x01,0xB9,0xE6, -0xDC,0xDD,0xF3,0xFF,0x1D,0x2C,0x3A,0x16,0x57,0xD9,0x92,0x39,0xD6, -}; - - -/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Secure Certificate Services */ -/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Secure Certificate Services */ - - -const unsigned char Comodo_Secure_Services_root_certificate[1091]={ -0x30,0x82,0x04,0x3F,0x30,0x82,0x03,0x27,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, -0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, -0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, -0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, -0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, -0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x24,0x30,0x22,0x06,0x03,0x55, -0x04,0x03,0x0C,0x1B,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30, -0x1E,0x17,0x0D,0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A, -0x17,0x0D,0x32,0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30, -0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, -0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, -0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, -0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, -0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, -0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x24,0x30,0x22,0x06,0x03,0x55, -0x04,0x03,0x0C,0x1B,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30, -0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01, -0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00, -0xC0,0x71,0x33,0x82,0x8A,0xD0,0x70,0xEB,0x73,0x87,0x82,0x40,0xD5,0x1D,0xE4,0xCB, -0xC9,0x0E,0x42,0x90,0xF9,0xDE,0x34,0xB9,0xA1,0xBA,0x11,0xF4,0x25,0x85,0xF3,0xCC, -0x72,0x6D,0xF2,0x7B,0x97,0x6B,0xB3,0x07,0xF1,0x77,0x24,0x91,0x5F,0x25,0x8F,0xF6, -0x74,0x3D,0xE4,0x80,0xC2,0xF8,0x3C,0x0D,0xF3,0xBF,0x40,0xEA,0xF7,0xC8,0x52,0xD1, -0x72,0x6F,0xEF,0xC8,0xAB,0x41,0xB8,0x6E,0x2E,0x17,0x2A,0x95,0x69,0x0C,0xCD,0xD2, -0x1E,0x94,0x7B,0x2D,0x94,0x1D,0xAA,0x75,0xD7,0xB3,0x98,0xCB,0xAC,0xBC,0x64,0x53, -0x40,0xBC,0x8F,0xAC,0xAC,0x36,0xCB,0x5C,0xAD,0xBB,0xDD,0xE0,0x94,0x17,0xEC,0xD1, -0x5C,0xD0,0xBF,0xEF,0xA5,0x95,0xC9,0x90,0xC5,0xB0,0xAC,0xFB,0x1B,0x43,0xDF,0x7A, -0x08,0x5D,0xB7,0xB8,0xF2,0x40,0x1B,0x2B,0x27,0x9E,0x50,0xCE,0x5E,0x65,0x82,0x88, -0x8C,0x5E,0xD3,0x4E,0x0C,0x7A,0xEA,0x08,0x91,0xB6,0x36,0xAA,0x2B,0x42,0xFB,0xEA, -0xC2,0xA3,0x39,0xE5,0xDB,0x26,0x38,0xAD,0x8B,0x0A,0xEE,0x19,0x63,0xC7,0x1C,0x24, -0xDF,0x03,0x78,0xDA,0xE6,0xEA,0xC1,0x47,0x1A,0x0B,0x0B,0x46,0x09,0xDD,0x02,0xFC, -0xDE,0xCB,0x87,0x5F,0xD7,0x30,0x63,0x68,0xA1,0xAE,0xDC,0x32,0xA1,0xBA,0xBE,0xFE, -0x44,0xAB,0x68,0xB6,0xA5,0x17,0x15,0xFD,0xBD,0xD5,0xA7,0xA7,0x9A,0xE4,0x44,0x33, -0xE9,0x88,0x8E,0xFC,0xED,0x51,0xEB,0x93,0x71,0x4E,0xAD,0x01,0xE7,0x44,0x8E,0xAB, -0x2D,0xCB,0xA8,0xFE,0x01,0x49,0x48,0xF0,0xC0,0xDD,0xC7,0x68,0xD8,0x92,0xFE,0x3D, -0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xC7,0x30,0x81,0xC4,0x30,0x1D,0x06,0x03,0x55, -0x1D,0x0E,0x04,0x16,0x04,0x14,0x3C,0xD8,0x93,0x88,0xC2,0xC0,0x82,0x09,0xCC,0x01, -0x99,0x06,0x93,0x20,0xE9,0x9E,0x70,0x09,0x63,0x4F,0x30,0x0E,0x06,0x03,0x55,0x1D, -0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D, -0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x81,0x06,0x03, -0x55,0x1D,0x1F,0x04,0x7A,0x30,0x78,0x30,0x3B,0xA0,0x39,0xA0,0x37,0x86,0x35,0x68, -0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F, -0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x53,0x65,0x63,0x75,0x72,0x65,0x43,0x65,0x72, -0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, -0x2E,0x63,0x72,0x6C,0x30,0x39,0xA0,0x37,0xA0,0x35,0x86,0x33,0x68,0x74,0x74,0x70, -0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x6E,0x65, -0x74,0x2F,0x53,0x65,0x63,0x75,0x72,0x65,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, -0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, -0x01,0x01,0x00,0x87,0x01,0x6D,0x23,0x1D,0x7E,0x5B,0x17,0x7D,0xC1,0x61,0x32,0xCF, -0x8F,0xE7,0xF3,0x8A,0x94,0x59,0x66,0xE0,0x9E,0x28,0xA8,0x5E,0xD3,0xB7,0xF4,0x34, -0xE6,0xAA,0x39,0xB2,0x97,0x16,0xC5,0x82,0x6F,0x32,0xA4,0xE9,0x8C,0xE7,0xAF,0xFD, -0xEF,0xC2,0xE8,0xB9,0x4B,0xAA,0xA3,0xF4,0xE6,0xDA,0x8D,0x65,0x21,0xFB,0xBA,0x80, -0xEB,0x26,0x28,0x85,0x1A,0xFE,0x39,0x8C,0xDE,0x5B,0x04,0x04,0xB4,0x54,0xF9,0xA3, -0x67,0x9E,0x41,0xFA,0x09,0x52,0xCC,0x05,0x48,0xA8,0xC9,0x3F,0x21,0x04,0x1E,0xCE, -0x48,0x6B,0xFC,0x85,0xE8,0xC2,0x7B,0xAF,0x7F,0xB7,0xCC,0xF8,0x5F,0x3A,0xFD,0x35, -0xC6,0x0D,0xEF,0x97,0xDC,0x4C,0xAB,0x11,0xE1,0x6B,0xCB,0x31,0xD1,0x6C,0xFB,0x48, -0x80,0xAB,0xDC,0x9C,0x37,0xB8,0x21,0x14,0x4B,0x0D,0x71,0x3D,0xEC,0x83,0x33,0x6E, -0xD1,0x6E,0x32,0x16,0xEC,0x98,0xC7,0x16,0x8B,0x59,0xA6,0x34,0xAB,0x05,0x57,0x2D, -0x93,0xF7,0xAA,0x13,0xCB,0xD2,0x13,0xE2,0xB7,0x2E,0x3B,0xCD,0x6B,0x50,0x17,0x09, -0x68,0x3E,0xB5,0x26,0x57,0xEE,0xB6,0xE0,0xB6,0xDD,0xB9,0x29,0x80,0x79,0x7D,0x8F, -0xA3,0xF0,0xA4,0x28,0xA4,0x15,0xC4,0x85,0xF4,0x27,0xD4,0x6B,0xBF,0xE5,0x5C,0xE4, -0x65,0x02,0x76,0x54,0xB4,0xE3,0x37,0x66,0x24,0xD3,0x19,0x61,0xC8,0x52,0x10,0xE5, -0x8B,0x37,0x9A,0xB9,0xA9,0xF9,0x1D,0xBF,0xEA,0x99,0x92,0x61,0x96,0xFF,0x01,0xCD, -0xA1,0x5F,0x0D,0xBC,0x71,0xBC,0x0E,0xAC,0x0B,0x1D,0x47,0x45,0x1D,0xC1,0xEC,0x7C, -0xEC,0xFD,0x29, -}; - - -/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Trusted Certificate Services */ -/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Trusted Certificate Services */ - - -const unsigned char Comodo_Trusted_Services_root_certificate[1095]={ -0x30,0x82,0x04,0x43,0x30,0x82,0x03,0x2B,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x7F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, -0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, -0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, -0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, -0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, -0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x25,0x30,0x23,0x06,0x03,0x55, -0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x43,0x65,0x72,0x74, -0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, -0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30, -0x5A,0x17,0x0D,0x32,0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A, -0x30,0x7F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31, -0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65, -0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E, -0x06,0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A, -0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20, -0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x25,0x30,0x23,0x06,0x03, -0x55,0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x43,0x65,0x72, -0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65, -0x73,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, -0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01, -0x01,0x00,0xDF,0x71,0x6F,0x36,0x58,0x53,0x5A,0xF2,0x36,0x54,0x57,0x80,0xC4,0x74, -0x08,0x20,0xED,0x18,0x7F,0x2A,0x1D,0xE6,0x35,0x9A,0x1E,0x25,0xAC,0x9C,0xE5,0x96, -0x7E,0x72,0x52,0xA0,0x15,0x42,0xDB,0x59,0xDD,0x64,0x7A,0x1A,0xD0,0xB8,0x7B,0xDD, -0x39,0x15,0xBC,0x55,0x48,0xC4,0xED,0x3A,0x00,0xEA,0x31,0x11,0xBA,0xF2,0x71,0x74, -0x1A,0x67,0xB8,0xCF,0x33,0xCC,0xA8,0x31,0xAF,0xA3,0xE3,0xD7,0x7F,0xBF,0x33,0x2D, -0x4C,0x6A,0x3C,0xEC,0x8B,0xC3,0x92,0xD2,0x53,0x77,0x24,0x74,0x9C,0x07,0x6E,0x70, -0xFC,0xBD,0x0B,0x5B,0x76,0xBA,0x5F,0xF2,0xFF,0xD7,0x37,0x4B,0x4A,0x60,0x78,0xF7, -0xF0,0xFA,0xCA,0x70,0xB4,0xEA,0x59,0xAA,0xA3,0xCE,0x48,0x2F,0xA9,0xC3,0xB2,0x0B, -0x7E,0x17,0x72,0x16,0x0C,0xA6,0x07,0x0C,0x1B,0x38,0xCF,0xC9,0x62,0xB7,0x3F,0xA0, -0x93,0xA5,0x87,0x41,0xF2,0xB7,0x70,0x40,0x77,0xD8,0xBE,0x14,0x7C,0xE3,0xA8,0xC0, -0x7A,0x8E,0xE9,0x63,0x6A,0xD1,0x0F,0x9A,0xC6,0xD2,0xF4,0x8B,0x3A,0x14,0x04,0x56, -0xD4,0xED,0xB8,0xCC,0x6E,0xF5,0xFB,0xE2,0x2C,0x58,0xBD,0x7F,0x4F,0x6B,0x2B,0xF7, -0x60,0x24,0x58,0x24,0xCE,0x26,0xEF,0x34,0x91,0x3A,0xD5,0xE3,0x81,0xD0,0xB2,0xF0, -0x04,0x02,0xD7,0x5B,0xB7,0x3E,0x92,0xAC,0x6B,0x12,0x8A,0xF9,0xE4,0x05,0xB0,0x3B, -0x91,0x49,0x5C,0xB2,0xEB,0x53,0xEA,0xF8,0x9F,0x47,0x86,0xEE,0xBF,0x95,0xC0,0xC0, -0x06,0x9F,0xD2,0x5B,0x5E,0x11,0x1B,0xF4,0xC7,0x04,0x35,0x29,0xD2,0x55,0x5C,0xE4, -0xED,0xEB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xC9,0x30,0x81,0xC6,0x30,0x1D,0x06, -0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC5,0x7B,0x58,0xBD,0xED,0xDA,0x25,0x69, -0xD2,0xF7,0x59,0x16,0xA8,0xB3,0x32,0xC0,0x7B,0x27,0x5B,0xF4,0x30,0x0E,0x06,0x03, -0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03, -0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x83, -0x06,0x03,0x55,0x1D,0x1F,0x04,0x7C,0x30,0x7A,0x30,0x3C,0xA0,0x3A,0xA0,0x38,0x86, -0x36,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F, -0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x54,0x72,0x75,0x73,0x74,0x65,0x64, -0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69, -0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30,0x3A,0xA0,0x38,0xA0,0x36,0x86,0x34,0x68, -0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F, -0x2E,0x6E,0x65,0x74,0x2F,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x43,0x65,0x72,0x74, -0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E, -0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xC8,0x93,0x81,0x3B,0x89,0xB4,0xAF,0xB8,0x84, -0x12,0x4C,0x8D,0xD2,0xF0,0xDB,0x70,0xBA,0x57,0x86,0x15,0x34,0x10,0xB9,0x2F,0x7F, -0x1E,0xB0,0xA8,0x89,0x60,0xA1,0x8A,0xC2,0x77,0x0C,0x50,0x4A,0x9B,0x00,0x8B,0xD8, -0x8B,0xF4,0x41,0xE2,0xD0,0x83,0x8A,0x4A,0x1C,0x14,0x06,0xB0,0xA3,0x68,0x05,0x70, -0x31,0x30,0xA7,0x53,0x9B,0x0E,0xE9,0x4A,0xA0,0x58,0x69,0x67,0x0E,0xAE,0x9D,0xF6, -0xA5,0x2C,0x41,0xBF,0x3C,0x06,0x6B,0xE4,0x59,0xCC,0x6D,0x10,0xF1,0x96,0x6F,0x1F, -0xDF,0xF4,0x04,0x02,0xA4,0x9F,0x45,0x3E,0xC8,0xD8,0xFA,0x36,0x46,0x44,0x50,0x3F, -0x82,0x97,0x91,0x1F,0x28,0xDB,0x18,0x11,0x8C,0x2A,0xE4,0x65,0x83,0x57,0x12,0x12, -0x8C,0x17,0x3F,0x94,0x36,0xFE,0x5D,0xB0,0xC0,0x04,0x77,0x13,0xB8,0xF4,0x15,0xD5, -0x3F,0x38,0xCC,0x94,0x3A,0x55,0xD0,0xAC,0x98,0xF5,0xBA,0x00,0x5F,0xE0,0x86,0x19, -0x81,0x78,0x2F,0x28,0xC0,0x7E,0xD3,0xCC,0x42,0x0A,0xF5,0xAE,0x50,0xA0,0xD1,0x3E, -0xC6,0xA1,0x71,0xEC,0x3F,0xA0,0x20,0x8C,0x66,0x3A,0x89,0xB4,0x8E,0xD4,0xD8,0xB1, -0x4D,0x25,0x47,0xEE,0x2F,0x88,0xC8,0xB5,0xE1,0x05,0x45,0xC0,0xBE,0x14,0x71,0xDE, -0x7A,0xFD,0x8E,0x7B,0x7D,0x4D,0x08,0x96,0xA5,0x12,0x73,0xF0,0x2D,0xCA,0x37,0x27, -0x74,0x12,0x27,0x4C,0xCB,0xB6,0x97,0xE9,0xD9,0xAE,0x08,0x6D,0x5A,0x39,0x40,0xDD, -0x05,0x47,0x75,0x6A,0x5A,0x21,0xB3,0xA3,0x18,0xCF,0x4E,0xF7,0x2E,0x57,0xB7,0x98, -0x70,0x5E,0xC8,0xC4,0x78,0xB0,0x62, -}; - - -/* subject:/O=Cybertrust, Inc/CN=Cybertrust Global Root */ -/* issuer :/O=Cybertrust, Inc/CN=Cybertrust Global Root */ - - -const unsigned char Cybertrust_Global_Root_certificate[933]={ -0x30,0x82,0x03,0xA1,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, -0x00,0x00,0x00,0x00,0x01,0x0F,0x85,0xAA,0x2D,0x48,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x3B,0x31,0x18,0x30,0x16,0x06, -0x03,0x55,0x04,0x0A,0x13,0x0F,0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74, -0x2C,0x20,0x49,0x6E,0x63,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16, -0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61, -0x6C,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x31,0x35, -0x30,0x38,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x31,0x31,0x32,0x31,0x35,0x30, -0x38,0x30,0x30,0x30,0x30,0x5A,0x30,0x3B,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04, -0x0A,0x13,0x0F,0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49, -0x6E,0x63,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x43,0x79,0x62, -0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52, -0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02, -0x82,0x01,0x01,0x00,0xF8,0xC8,0xBC,0xBD,0x14,0x50,0x66,0x13,0xFF,0xF0,0xD3,0x79, -0xEC,0x23,0xF2,0xB7,0x1A,0xC7,0x8E,0x85,0xF1,0x12,0x73,0xA6,0x19,0xAA,0x10,0xDB, -0x9C,0xA2,0x65,0x74,0x5A,0x77,0x3E,0x51,0x7D,0x56,0xF6,0xDC,0x23,0xB6,0xD4,0xED, -0x5F,0x58,0xB1,0x37,0x4D,0xD5,0x49,0x0E,0x6E,0xF5,0x6A,0x87,0xD6,0xD2,0x8C,0xD2, -0x27,0xC6,0xE2,0xFF,0x36,0x9F,0x98,0x65,0xA0,0x13,0x4E,0xC6,0x2A,0x64,0x9B,0xD5, -0x90,0x12,0xCF,0x14,0x06,0xF4,0x3B,0xE3,0xD4,0x28,0xBE,0xE8,0x0E,0xF8,0xAB,0x4E, -0x48,0x94,0x6D,0x8E,0x95,0x31,0x10,0x5C,0xED,0xA2,0x2D,0xBD,0xD5,0x3A,0x6D,0xB2, -0x1C,0xBB,0x60,0xC0,0x46,0x4B,0x01,0xF5,0x49,0xAE,0x7E,0x46,0x8A,0xD0,0x74,0x8D, -0xA1,0x0C,0x02,0xCE,0xEE,0xFC,0xE7,0x8F,0xB8,0x6B,0x66,0xF3,0x7F,0x44,0x00,0xBF, -0x66,0x25,0x14,0x2B,0xDD,0x10,0x30,0x1D,0x07,0x96,0x3F,0x4D,0xF6,0x6B,0xB8,0x8F, -0xB7,0x7B,0x0C,0xA5,0x38,0xEB,0xDE,0x47,0xDB,0xD5,0x5D,0x39,0xFC,0x88,0xA7,0xF3, -0xD7,0x2A,0x74,0xF1,0xE8,0x5A,0xA2,0x3B,0x9F,0x50,0xBA,0xA6,0x8C,0x45,0x35,0xC2, -0x50,0x65,0x95,0xDC,0x63,0x82,0xEF,0xDD,0xBF,0x77,0x4D,0x9C,0x62,0xC9,0x63,0x73, -0x16,0xD0,0x29,0x0F,0x49,0xA9,0x48,0xF0,0xB3,0xAA,0xB7,0x6C,0xC5,0xA7,0x30,0x39, -0x40,0x5D,0xAE,0xC4,0xE2,0x5D,0x26,0x53,0xF0,0xCE,0x1C,0x23,0x08,0x61,0xA8,0x94, -0x19,0xBA,0x04,0x62,0x40,0xEC,0x1F,0x38,0x70,0x77,0x12,0x06,0x71,0xA7,0x30,0x18, -0x5D,0x25,0x27,0xA5,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xA5,0x30,0x81,0xA2,0x30, -0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30, -0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, -0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB6,0x08,0x7B,0x0D,0x7A, -0xCC,0xAC,0x20,0x4C,0x86,0x56,0x32,0x5E,0xCF,0xAB,0x6E,0x85,0x2D,0x70,0x57,0x30, -0x3F,0x06,0x03,0x55,0x1D,0x1F,0x04,0x38,0x30,0x36,0x30,0x34,0xA0,0x32,0xA0,0x30, -0x86,0x2E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x32,0x2E,0x70,0x75, -0x62,0x6C,0x69,0x63,0x2D,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x63, -0x72,0x6C,0x2F,0x63,0x74,0x2F,0x63,0x74,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C, -0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xB6,0x08,0x7B, -0x0D,0x7A,0xCC,0xAC,0x20,0x4C,0x86,0x56,0x32,0x5E,0xCF,0xAB,0x6E,0x85,0x2D,0x70, -0x57,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, -0x03,0x82,0x01,0x01,0x00,0x56,0xEF,0x0A,0x23,0xA0,0x54,0x4E,0x95,0x97,0xC9,0xF8, -0x89,0xDA,0x45,0xC1,0xD4,0xA3,0x00,0x25,0xF4,0x1F,0x13,0xAB,0xB7,0xA3,0x85,0x58, -0x69,0xC2,0x30,0xAD,0xD8,0x15,0x8A,0x2D,0xE3,0xC9,0xCD,0x81,0x5A,0xF8,0x73,0x23, -0x5A,0xA7,0x7C,0x05,0xF3,0xFD,0x22,0x3B,0x0E,0xD1,0x06,0xC4,0xDB,0x36,0x4C,0x73, -0x04,0x8E,0xE5,0xB0,0x22,0xE4,0xC5,0xF3,0x2E,0xA5,0xD9,0x23,0xE3,0xB8,0x4E,0x4A, -0x20,0xA7,0x6E,0x02,0x24,0x9F,0x22,0x60,0x67,0x7B,0x8B,0x1D,0x72,0x09,0xC5,0x31, -0x5C,0xE9,0x79,0x9F,0x80,0x47,0x3D,0xAD,0xA1,0x0B,0x07,0x14,0x3D,0x47,0xFF,0x03, -0x69,0x1A,0x0C,0x0B,0x44,0xE7,0x63,0x25,0xA7,0x7F,0xB2,0xC9,0xB8,0x76,0x84,0xED, -0x23,0xF6,0x7D,0x07,0xAB,0x45,0x7E,0xD3,0xDF,0xB3,0xBF,0xE9,0x8A,0xB6,0xCD,0xA8, -0xA2,0x67,0x2B,0x52,0xD5,0xB7,0x65,0xF0,0x39,0x4C,0x63,0xA0,0x91,0x79,0x93,0x52, -0x0F,0x54,0xDD,0x83,0xBB,0x9F,0xD1,0x8F,0xA7,0x53,0x73,0xC3,0xCB,0xFF,0x30,0xEC, -0x7C,0x04,0xB8,0xD8,0x44,0x1F,0x93,0x5F,0x71,0x09,0x22,0xB7,0x6E,0x3E,0xEA,0x1C, -0x03,0x4E,0x9D,0x1A,0x20,0x61,0xFB,0x81,0x37,0xEC,0x5E,0xFC,0x0A,0x45,0xAB,0xD7, -0xE7,0x17,0x55,0xD0,0xA0,0xEA,0x60,0x9B,0xA6,0xF6,0xE3,0x8C,0x5B,0x29,0xC2,0x06, -0x60,0x14,0x9D,0x2D,0x97,0x4C,0xA9,0x93,0x15,0x9D,0x61,0xC4,0x01,0x5F,0x48,0xD6, -0x58,0xBD,0x56,0x31,0x12,0x4E,0x11,0xC8,0x21,0xE0,0xB3,0x11,0x91,0x65,0xDB,0xB4, -0xA6,0x88,0x38,0xCE,0x55, -}; - - -/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA */ -/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA */ - - -const unsigned char DigiCert_Assured_ID_Root_CA_certificate[955]={ -0x30,0x82,0x03,0xB7,0x30,0x82,0x02,0x9F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0C, -0xE7,0xE0,0xE5,0x17,0xD8,0x46,0xFE,0x8F,0xE5,0x60,0xFC,0x1B,0xF0,0x30,0x39,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x65, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, -0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, -0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, -0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, -0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65, -0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F, -0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30, -0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30, -0x30,0x30,0x30,0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, -0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44, -0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06, -0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65, -0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13, -0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65, -0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, -0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAD,0x0E,0x15, -0xCE,0xE4,0x43,0x80,0x5C,0xB1,0x87,0xF3,0xB7,0x60,0xF9,0x71,0x12,0xA5,0xAE,0xDC, -0x26,0x94,0x88,0xAA,0xF4,0xCE,0xF5,0x20,0x39,0x28,0x58,0x60,0x0C,0xF8,0x80,0xDA, -0xA9,0x15,0x95,0x32,0x61,0x3C,0xB5,0xB1,0x28,0x84,0x8A,0x8A,0xDC,0x9F,0x0A,0x0C, -0x83,0x17,0x7A,0x8F,0x90,0xAC,0x8A,0xE7,0x79,0x53,0x5C,0x31,0x84,0x2A,0xF6,0x0F, -0x98,0x32,0x36,0x76,0xCC,0xDE,0xDD,0x3C,0xA8,0xA2,0xEF,0x6A,0xFB,0x21,0xF2,0x52, -0x61,0xDF,0x9F,0x20,0xD7,0x1F,0xE2,0xB1,0xD9,0xFE,0x18,0x64,0xD2,0x12,0x5B,0x5F, -0xF9,0x58,0x18,0x35,0xBC,0x47,0xCD,0xA1,0x36,0xF9,0x6B,0x7F,0xD4,0xB0,0x38,0x3E, -0xC1,0x1B,0xC3,0x8C,0x33,0xD9,0xD8,0x2F,0x18,0xFE,0x28,0x0F,0xB3,0xA7,0x83,0xD6, -0xC3,0x6E,0x44,0xC0,0x61,0x35,0x96,0x16,0xFE,0x59,0x9C,0x8B,0x76,0x6D,0xD7,0xF1, -0xA2,0x4B,0x0D,0x2B,0xFF,0x0B,0x72,0xDA,0x9E,0x60,0xD0,0x8E,0x90,0x35,0xC6,0x78, -0x55,0x87,0x20,0xA1,0xCF,0xE5,0x6D,0x0A,0xC8,0x49,0x7C,0x31,0x98,0x33,0x6C,0x22, -0xE9,0x87,0xD0,0x32,0x5A,0xA2,0xBA,0x13,0x82,0x11,0xED,0x39,0x17,0x9D,0x99,0x3A, -0x72,0xA1,0xE6,0xFA,0xA4,0xD9,0xD5,0x17,0x31,0x75,0xAE,0x85,0x7D,0x22,0xAE,0x3F, -0x01,0x46,0x86,0xF6,0x28,0x79,0xC8,0xB1,0xDA,0xE4,0x57,0x17,0xC4,0x7E,0x1C,0x0E, -0xB0,0xB4,0x92,0xA6,0x56,0xB3,0xBD,0xB2,0x97,0xED,0xAA,0xA7,0xF0,0xB7,0xC5,0xA8, -0x3F,0x95,0x16,0xD0,0xFF,0xA1,0x96,0xEB,0x08,0x5F,0x18,0x77,0x4F,0x02,0x03,0x01, -0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, -0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, -0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, -0x04,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7,0xA7, -0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, -0x16,0x80,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7, -0xA7,0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xA2,0x0E,0xBC,0xDF,0xE2, -0xED,0xF0,0xE3,0x72,0x73,0x7A,0x64,0x94,0xBF,0xF7,0x72,0x66,0xD8,0x32,0xE4,0x42, -0x75,0x62,0xAE,0x87,0xEB,0xF2,0xD5,0xD9,0xDE,0x56,0xB3,0x9F,0xCC,0xCE,0x14,0x28, -0xB9,0x0D,0x97,0x60,0x5C,0x12,0x4C,0x58,0xE4,0xD3,0x3D,0x83,0x49,0x45,0x58,0x97, -0x35,0x69,0x1A,0xA8,0x47,0xEA,0x56,0xC6,0x79,0xAB,0x12,0xD8,0x67,0x81,0x84,0xDF, -0x7F,0x09,0x3C,0x94,0xE6,0xB8,0x26,0x2C,0x20,0xBD,0x3D,0xB3,0x28,0x89,0xF7,0x5F, -0xFF,0x22,0xE2,0x97,0x84,0x1F,0xE9,0x65,0xEF,0x87,0xE0,0xDF,0xC1,0x67,0x49,0xB3, -0x5D,0xEB,0xB2,0x09,0x2A,0xEB,0x26,0xED,0x78,0xBE,0x7D,0x3F,0x2B,0xF3,0xB7,0x26, -0x35,0x6D,0x5F,0x89,0x01,0xB6,0x49,0x5B,0x9F,0x01,0x05,0x9B,0xAB,0x3D,0x25,0xC1, -0xCC,0xB6,0x7F,0xC2,0xF1,0x6F,0x86,0xC6,0xFA,0x64,0x68,0xEB,0x81,0x2D,0x94,0xEB, -0x42,0xB7,0xFA,0x8C,0x1E,0xDD,0x62,0xF1,0xBE,0x50,0x67,0xB7,0x6C,0xBD,0xF3,0xF1, -0x1F,0x6B,0x0C,0x36,0x07,0x16,0x7F,0x37,0x7C,0xA9,0x5B,0x6D,0x7A,0xF1,0x12,0x46, -0x60,0x83,0xD7,0x27,0x04,0xBE,0x4B,0xCE,0x97,0xBE,0xC3,0x67,0x2A,0x68,0x11,0xDF, -0x80,0xE7,0x0C,0x33,0x66,0xBF,0x13,0x0D,0x14,0x6E,0xF3,0x7F,0x1F,0x63,0x10,0x1E, -0xFA,0x8D,0x1B,0x25,0x6D,0x6C,0x8F,0xA5,0xB7,0x61,0x01,0xB1,0xD2,0xA3,0x26,0xA1, -0x10,0x71,0x9D,0xAD,0xE2,0xC3,0xF9,0xC3,0x99,0x51,0xB7,0x2B,0x07,0x08,0xCE,0x2E, -0xE6,0x50,0xB2,0xA7,0xFA,0x0A,0x45,0x2F,0xA2,0xF0,0xF2, -}; - - -/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */ -/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */ - - -const unsigned char DigiCert_Global_Root_CA_certificate[947]={ -0x30,0x82,0x03,0xAF,0x30,0x82,0x02,0x97,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x08, -0x3B,0xE0,0x56,0x90,0x42,0x46,0xB1,0xA1,0x75,0x6A,0xC9,0x59,0x91,0xC7,0x4A,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x61, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, -0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, -0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, -0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, -0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, -0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, -0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30, -0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30, -0x5A,0x30,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, -0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43, -0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B, -0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63, -0x6F,0x6D,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67, -0x69,0x43,0x65,0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F, -0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, -0x02,0x82,0x01,0x01,0x00,0xE2,0x3B,0xE1,0x11,0x72,0xDE,0xA8,0xA4,0xD3,0xA3,0x57, -0xAA,0x50,0xA2,0x8F,0x0B,0x77,0x90,0xC9,0xA2,0xA5,0xEE,0x12,0xCE,0x96,0x5B,0x01, -0x09,0x20,0xCC,0x01,0x93,0xA7,0x4E,0x30,0xB7,0x53,0xF7,0x43,0xC4,0x69,0x00,0x57, -0x9D,0xE2,0x8D,0x22,0xDD,0x87,0x06,0x40,0x00,0x81,0x09,0xCE,0xCE,0x1B,0x83,0xBF, -0xDF,0xCD,0x3B,0x71,0x46,0xE2,0xD6,0x66,0xC7,0x05,0xB3,0x76,0x27,0x16,0x8F,0x7B, -0x9E,0x1E,0x95,0x7D,0xEE,0xB7,0x48,0xA3,0x08,0xDA,0xD6,0xAF,0x7A,0x0C,0x39,0x06, -0x65,0x7F,0x4A,0x5D,0x1F,0xBC,0x17,0xF8,0xAB,0xBE,0xEE,0x28,0xD7,0x74,0x7F,0x7A, -0x78,0x99,0x59,0x85,0x68,0x6E,0x5C,0x23,0x32,0x4B,0xBF,0x4E,0xC0,0xE8,0x5A,0x6D, -0xE3,0x70,0xBF,0x77,0x10,0xBF,0xFC,0x01,0xF6,0x85,0xD9,0xA8,0x44,0x10,0x58,0x32, -0xA9,0x75,0x18,0xD5,0xD1,0xA2,0xBE,0x47,0xE2,0x27,0x6A,0xF4,0x9A,0x33,0xF8,0x49, -0x08,0x60,0x8B,0xD4,0x5F,0xB4,0x3A,0x84,0xBF,0xA1,0xAA,0x4A,0x4C,0x7D,0x3E,0xCF, -0x4F,0x5F,0x6C,0x76,0x5E,0xA0,0x4B,0x37,0x91,0x9E,0xDC,0x22,0xE6,0x6D,0xCE,0x14, -0x1A,0x8E,0x6A,0xCB,0xFE,0xCD,0xB3,0x14,0x64,0x17,0xC7,0x5B,0x29,0x9E,0x32,0xBF, -0xF2,0xEE,0xFA,0xD3,0x0B,0x42,0xD4,0xAB,0xB7,0x41,0x32,0xDA,0x0C,0xD4,0xEF,0xF8, -0x81,0xD5,0xBB,0x8D,0x58,0x3F,0xB5,0x1B,0xE8,0x49,0x28,0xA2,0x70,0xDA,0x31,0x04, -0xDD,0xF7,0xB2,0x16,0xF2,0x4C,0x0A,0x4E,0x07,0xA8,0xED,0x4A,0x3D,0x5E,0xB5,0x7F, -0xA3,0x90,0xC3,0xAF,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E, -0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F, -0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, -0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x03,0xDE,0x50,0x35,0x56,0xD1, -0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30,0x1F, -0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x03,0xDE,0x50,0x35,0x56, -0xD1,0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, -0x01,0x01,0x00,0xCB,0x9C,0x37,0xAA,0x48,0x13,0x12,0x0A,0xFA,0xDD,0x44,0x9C,0x4F, -0x52,0xB0,0xF4,0xDF,0xAE,0x04,0xF5,0x79,0x79,0x08,0xA3,0x24,0x18,0xFC,0x4B,0x2B, -0x84,0xC0,0x2D,0xB9,0xD5,0xC7,0xFE,0xF4,0xC1,0x1F,0x58,0xCB,0xB8,0x6D,0x9C,0x7A, -0x74,0xE7,0x98,0x29,0xAB,0x11,0xB5,0xE3,0x70,0xA0,0xA1,0xCD,0x4C,0x88,0x99,0x93, -0x8C,0x91,0x70,0xE2,0xAB,0x0F,0x1C,0xBE,0x93,0xA9,0xFF,0x63,0xD5,0xE4,0x07,0x60, -0xD3,0xA3,0xBF,0x9D,0x5B,0x09,0xF1,0xD5,0x8E,0xE3,0x53,0xF4,0x8E,0x63,0xFA,0x3F, -0xA7,0xDB,0xB4,0x66,0xDF,0x62,0x66,0xD6,0xD1,0x6E,0x41,0x8D,0xF2,0x2D,0xB5,0xEA, -0x77,0x4A,0x9F,0x9D,0x58,0xE2,0x2B,0x59,0xC0,0x40,0x23,0xED,0x2D,0x28,0x82,0x45, -0x3E,0x79,0x54,0x92,0x26,0x98,0xE0,0x80,0x48,0xA8,0x37,0xEF,0xF0,0xD6,0x79,0x60, -0x16,0xDE,0xAC,0xE8,0x0E,0xCD,0x6E,0xAC,0x44,0x17,0x38,0x2F,0x49,0xDA,0xE1,0x45, -0x3E,0x2A,0xB9,0x36,0x53,0xCF,0x3A,0x50,0x06,0xF7,0x2E,0xE8,0xC4,0x57,0x49,0x6C, -0x61,0x21,0x18,0xD5,0x04,0xAD,0x78,0x3C,0x2C,0x3A,0x80,0x6B,0xA7,0xEB,0xAF,0x15, -0x14,0xE9,0xD8,0x89,0xC1,0xB9,0x38,0x6C,0xE2,0x91,0x6C,0x8A,0xFF,0x64,0xB9,0x77, -0x25,0x57,0x30,0xC0,0x1B,0x24,0xA3,0xE1,0xDC,0xE9,0xDF,0x47,0x7C,0xB5,0xB4,0x24, -0x08,0x05,0x30,0xEC,0x2D,0xBD,0x0B,0xBF,0x45,0xBF,0x50,0xB9,0xA9,0xF3,0xEB,0x98, -0x01,0x12,0xAD,0xC8,0x88,0xC6,0x98,0x34,0x5F,0x8D,0x0A,0x3C,0xC6,0xE9,0xD5,0x95, -0x95,0x6D,0xDE, -}; - - -/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */ -/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */ - - -const unsigned char DigiCert_High_Assurance_EV_Root_CA_certificate[969]={ -0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x02, -0xAC,0x5C,0x26,0x6A,0x0B,0x40,0x9B,0x8F,0x0B,0x79,0xF2,0xAE,0x46,0x25,0x77,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x6C, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, -0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, -0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, -0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, -0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65, -0x72,0x74,0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63, -0x65,0x20,0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D, -0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33, -0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x6C,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06, -0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49, -0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77, -0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x2B,0x30, -0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, -0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,0x65,0x20, -0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D, -0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, -0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC6,0xCC,0xE5,0x73,0xE6, -0xFB,0xD4,0xBB,0xE5,0x2D,0x2D,0x32,0xA6,0xDF,0xE5,0x81,0x3F,0xC9,0xCD,0x25,0x49, -0xB6,0x71,0x2A,0xC3,0xD5,0x94,0x34,0x67,0xA2,0x0A,0x1C,0xB0,0x5F,0x69,0xA6,0x40, -0xB1,0xC4,0xB7,0xB2,0x8F,0xD0,0x98,0xA4,0xA9,0x41,0x59,0x3A,0xD3,0xDC,0x94,0xD6, -0x3C,0xDB,0x74,0x38,0xA4,0x4A,0xCC,0x4D,0x25,0x82,0xF7,0x4A,0xA5,0x53,0x12,0x38, -0xEE,0xF3,0x49,0x6D,0x71,0x91,0x7E,0x63,0xB6,0xAB,0xA6,0x5F,0xC3,0xA4,0x84,0xF8, -0x4F,0x62,0x51,0xBE,0xF8,0xC5,0xEC,0xDB,0x38,0x92,0xE3,0x06,0xE5,0x08,0x91,0x0C, -0xC4,0x28,0x41,0x55,0xFB,0xCB,0x5A,0x89,0x15,0x7E,0x71,0xE8,0x35,0xBF,0x4D,0x72, -0x09,0x3D,0xBE,0x3A,0x38,0x50,0x5B,0x77,0x31,0x1B,0x8D,0xB3,0xC7,0x24,0x45,0x9A, -0xA7,0xAC,0x6D,0x00,0x14,0x5A,0x04,0xB7,0xBA,0x13,0xEB,0x51,0x0A,0x98,0x41,0x41, -0x22,0x4E,0x65,0x61,0x87,0x81,0x41,0x50,0xA6,0x79,0x5C,0x89,0xDE,0x19,0x4A,0x57, -0xD5,0x2E,0xE6,0x5D,0x1C,0x53,0x2C,0x7E,0x98,0xCD,0x1A,0x06,0x16,0xA4,0x68,0x73, -0xD0,0x34,0x04,0x13,0x5C,0xA1,0x71,0xD3,0x5A,0x7C,0x55,0xDB,0x5E,0x64,0xE1,0x37, -0x87,0x30,0x56,0x04,0xE5,0x11,0xB4,0x29,0x80,0x12,0xF1,0x79,0x39,0x88,0xA2,0x02, -0x11,0x7C,0x27,0x66,0xB7,0x88,0xB7,0x78,0xF2,0xCA,0x0A,0xA8,0x38,0xAB,0x0A,0x64, -0xC2,0xBF,0x66,0x5D,0x95,0x84,0xC1,0xA1,0x25,0x1E,0x87,0x5D,0x1A,0x50,0x0B,0x20, -0x12,0xCC,0x41,0xBB,0x6E,0x0B,0x51,0x38,0xB8,0x4B,0xCB,0x02,0x03,0x01,0x00,0x01, -0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, -0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, -0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, -0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02,0xEF, -0x63,0x64,0x2B,0xC3,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80, -0x14,0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02, -0xEF,0x63,0x64,0x2B,0xC3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, -0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x1C,0x1A,0x06,0x97,0xDC,0xD7,0x9C, -0x9F,0x3C,0x88,0x66,0x06,0x08,0x57,0x21,0xDB,0x21,0x47,0xF8,0x2A,0x67,0xAA,0xBF, -0x18,0x32,0x76,0x40,0x10,0x57,0xC1,0x8A,0xF3,0x7A,0xD9,0x11,0x65,0x8E,0x35,0xFA, -0x9E,0xFC,0x45,0xB5,0x9E,0xD9,0x4C,0x31,0x4B,0xB8,0x91,0xE8,0x43,0x2C,0x8E,0xB3, -0x78,0xCE,0xDB,0xE3,0x53,0x79,0x71,0xD6,0xE5,0x21,0x94,0x01,0xDA,0x55,0x87,0x9A, -0x24,0x64,0xF6,0x8A,0x66,0xCC,0xDE,0x9C,0x37,0xCD,0xA8,0x34,0xB1,0x69,0x9B,0x23, -0xC8,0x9E,0x78,0x22,0x2B,0x70,0x43,0xE3,0x55,0x47,0x31,0x61,0x19,0xEF,0x58,0xC5, -0x85,0x2F,0x4E,0x30,0xF6,0xA0,0x31,0x16,0x23,0xC8,0xE7,0xE2,0x65,0x16,0x33,0xCB, -0xBF,0x1A,0x1B,0xA0,0x3D,0xF8,0xCA,0x5E,0x8B,0x31,0x8B,0x60,0x08,0x89,0x2D,0x0C, -0x06,0x5C,0x52,0xB7,0xC4,0xF9,0x0A,0x98,0xD1,0x15,0x5F,0x9F,0x12,0xBE,0x7C,0x36, -0x63,0x38,0xBD,0x44,0xA4,0x7F,0xE4,0x26,0x2B,0x0A,0xC4,0x97,0x69,0x0D,0xE9,0x8C, -0xE2,0xC0,0x10,0x57,0xB8,0xC8,0x76,0x12,0x91,0x55,0xF2,0x48,0x69,0xD8,0xBC,0x2A, -0x02,0x5B,0x0F,0x44,0xD4,0x20,0x31,0xDB,0xF4,0xBA,0x70,0x26,0x5D,0x90,0x60,0x9E, -0xBC,0x4B,0x17,0x09,0x2F,0xB4,0xCB,0x1E,0x43,0x68,0xC9,0x07,0x27,0xC1,0xD2,0x5C, -0xF7,0xEA,0x21,0xB9,0x68,0x12,0x9C,0x3C,0x9C,0xBF,0x9E,0xFC,0x80,0x5C,0x9B,0x63, -0xCD,0xEC,0x47,0xAA,0x25,0x27,0x67,0xA0,0x37,0xF3,0x00,0x82,0x7D,0x54,0xD7,0xA9, -0xF8,0xE9,0x2E,0x13,0xA3,0x77,0xE8,0x1F,0x4A, -}; - - -/* subject:/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048) */ -/* issuer :/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048) */ - - -const unsigned char Entrust_net_Premium_2048_Secure_Server_CA_certificate[1120]={ -0x30,0x82,0x04,0x5C,0x30,0x82,0x03,0x44,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x38, -0x63,0xB9,0x66,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x30,0x81,0xB4,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B, -0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x40,0x30,0x3E,0x06, -0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73, -0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x5F,0x32,0x30,0x34,0x38,0x20,0x69, -0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28, -0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30, -0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39, -0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D, -0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03,0x13,0x2A,0x45, -0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31, -0x32,0x32,0x34,0x31,0x37,0x35,0x30,0x35,0x31,0x5A,0x17,0x0D,0x31,0x39,0x31,0x32, -0x32,0x34,0x31,0x38,0x32,0x30,0x35,0x31,0x5A,0x30,0x81,0xB4,0x31,0x14,0x30,0x12, -0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, -0x65,0x74,0x31,0x40,0x30,0x3E,0x06,0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77, -0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53, -0x5F,0x32,0x30,0x34,0x38,0x20,0x69,0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79, -0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69, -0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28, -0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E, -0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06, -0x03,0x55,0x04,0x03,0x13,0x2A,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65, -0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, -0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29, -0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01, -0x00,0xAD,0x4D,0x4B,0xA9,0x12,0x86,0xB2,0xEA,0xA3,0x20,0x07,0x15,0x16,0x64,0x2A, -0x2B,0x4B,0xD1,0xBF,0x0B,0x4A,0x4D,0x8E,0xED,0x80,0x76,0xA5,0x67,0xB7,0x78,0x40, -0xC0,0x73,0x42,0xC8,0x68,0xC0,0xDB,0x53,0x2B,0xDD,0x5E,0xB8,0x76,0x98,0x35,0x93, -0x8B,0x1A,0x9D,0x7C,0x13,0x3A,0x0E,0x1F,0x5B,0xB7,0x1E,0xCF,0xE5,0x24,0x14,0x1E, -0xB1,0x81,0xA9,0x8D,0x7D,0xB8,0xCC,0x6B,0x4B,0x03,0xF1,0x02,0x0C,0xDC,0xAB,0xA5, -0x40,0x24,0x00,0x7F,0x74,0x94,0xA1,0x9D,0x08,0x29,0xB3,0x88,0x0B,0xF5,0x87,0x77, -0x9D,0x55,0xCD,0xE4,0xC3,0x7E,0xD7,0x6A,0x64,0xAB,0x85,0x14,0x86,0x95,0x5B,0x97, -0x32,0x50,0x6F,0x3D,0xC8,0xBA,0x66,0x0C,0xE3,0xFC,0xBD,0xB8,0x49,0xC1,0x76,0x89, -0x49,0x19,0xFD,0xC0,0xA8,0xBD,0x89,0xA3,0x67,0x2F,0xC6,0x9F,0xBC,0x71,0x19,0x60, -0xB8,0x2D,0xE9,0x2C,0xC9,0x90,0x76,0x66,0x7B,0x94,0xE2,0xAF,0x78,0xD6,0x65,0x53, -0x5D,0x3C,0xD6,0x9C,0xB2,0xCF,0x29,0x03,0xF9,0x2F,0xA4,0x50,0xB2,0xD4,0x48,0xCE, -0x05,0x32,0x55,0x8A,0xFD,0xB2,0x64,0x4C,0x0E,0xE4,0x98,0x07,0x75,0xDB,0x7F,0xDF, -0xB9,0x08,0x55,0x60,0x85,0x30,0x29,0xF9,0x7B,0x48,0xA4,0x69,0x86,0xE3,0x35,0x3F, -0x1E,0x86,0x5D,0x7A,0x7A,0x15,0xBD,0xEF,0x00,0x8E,0x15,0x22,0x54,0x17,0x00,0x90, -0x26,0x93,0xBC,0x0E,0x49,0x68,0x91,0xBF,0xF8,0x47,0xD3,0x9D,0x95,0x42,0xC1,0x0E, -0x4D,0xDF,0x6F,0x26,0xCF,0xC3,0x18,0x21,0x62,0x66,0x43,0x70,0xD6,0xD5,0xC0,0x07, -0xE1,0x02,0x03,0x01,0x00,0x01,0xA3,0x74,0x30,0x72,0x30,0x11,0x06,0x09,0x60,0x86, -0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x1F,0x06, -0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x55,0xE4,0x81,0xD1,0x11,0x80, -0xBE,0xD8,0x89,0xB9,0x08,0xA3,0x31,0xF9,0xA1,0x24,0x09,0x16,0xB9,0x70,0x30,0x1D, -0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x55,0xE4,0x81,0xD1,0x11,0x80,0xBE, -0xD8,0x89,0xB9,0x08,0xA3,0x31,0xF9,0xA1,0x24,0x09,0x16,0xB9,0x70,0x30,0x1D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04,0x10,0x30,0x0E,0x1B,0x08, -0x56,0x35,0x2E,0x30,0x3A,0x34,0x2E,0x30,0x03,0x02,0x04,0x90,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, -0x59,0x47,0xAC,0x21,0x84,0x8A,0x17,0xC9,0x9C,0x89,0x53,0x1E,0xBA,0x80,0x85,0x1A, -0xC6,0x3C,0x4E,0x3E,0xB1,0x9C,0xB6,0x7C,0xC6,0x92,0x5D,0x18,0x64,0x02,0xE3,0xD3, -0x06,0x08,0x11,0x61,0x7C,0x63,0xE3,0x2B,0x9D,0x31,0x03,0x70,0x76,0xD2,0xA3,0x28, -0xA0,0xF4,0xBB,0x9A,0x63,0x73,0xED,0x6D,0xE5,0x2A,0xDB,0xED,0x14,0xA9,0x2B,0xC6, -0x36,0x11,0xD0,0x2B,0xEB,0x07,0x8B,0xA5,0xDA,0x9E,0x5C,0x19,0x9D,0x56,0x12,0xF5, -0x54,0x29,0xC8,0x05,0xED,0xB2,0x12,0x2A,0x8D,0xF4,0x03,0x1B,0xFF,0xE7,0x92,0x10, -0x87,0xB0,0x3A,0xB5,0xC3,0x9D,0x05,0x37,0x12,0xA3,0xC7,0xF4,0x15,0xB9,0xD5,0xA4, -0x39,0x16,0x9B,0x53,0x3A,0x23,0x91,0xF1,0xA8,0x82,0xA2,0x6A,0x88,0x68,0xC1,0x79, -0x02,0x22,0xBC,0xAA,0xA6,0xD6,0xAE,0xDF,0xB0,0x14,0x5F,0xB8,0x87,0xD0,0xDD,0x7C, -0x7F,0x7B,0xFF,0xAF,0x1C,0xCF,0xE6,0xDB,0x07,0xAD,0x5E,0xDB,0x85,0x9D,0xD0,0x2B, -0x0D,0x33,0xDB,0x04,0xD1,0xE6,0x49,0x40,0x13,0x2B,0x76,0xFB,0x3E,0xE9,0x9C,0x89, -0x0F,0x15,0xCE,0x18,0xB0,0x85,0x78,0x21,0x4F,0x6B,0x4F,0x0E,0xFA,0x36,0x67,0xCD, -0x07,0xF2,0xFF,0x08,0xD0,0xE2,0xDE,0xD9,0xBF,0x2A,0xAF,0xB8,0x87,0x86,0x21,0x3C, -0x04,0xCA,0xB7,0x94,0x68,0x7F,0xCF,0x3C,0xE9,0x98,0xD7,0x38,0xFF,0xEC,0xC0,0xD9, -0x50,0xF0,0x2E,0x4B,0x58,0xAE,0x46,0x6F,0xD0,0x2E,0xC3,0x60,0xDA,0x72,0x55,0x72, -0xBD,0x4C,0x45,0x9E,0x61,0xBA,0xBF,0x84,0x81,0x92,0x03,0xD1,0xD2,0x69,0x7C,0xC5, -}; - - -/* subject:/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority */ -/* issuer :/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority */ - - -const unsigned char Entrust_net_Secure_Server_CA_certificate[1244]={ -0x30,0x82,0x04,0xD8,0x30,0x82,0x04,0x41,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x37, -0x4A,0xD2,0x43,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x30,0x81,0xC3,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, -0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x45,0x6E,0x74, -0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x3B,0x30,0x39,0x06,0x03,0x55,0x04, -0x0B,0x13,0x32,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, -0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62, -0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C, -0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C, -0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, -0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x3A,0x30,0x38, -0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, -0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72, -0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, -0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x35, -0x32,0x35,0x31,0x36,0x30,0x39,0x34,0x30,0x5A,0x17,0x0D,0x31,0x39,0x30,0x35,0x32, -0x35,0x31,0x36,0x33,0x39,0x34,0x30,0x5A,0x30,0x81,0xC3,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, -0x0A,0x13,0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x3B, -0x30,0x39,0x06,0x03,0x55,0x04,0x0B,0x13,0x32,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74, -0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x6E,0x63, -0x6F,0x72,0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69, -0x6D,0x69,0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06, -0x03,0x55,0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45, -0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74, -0x65,0x64,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6E,0x74, -0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20, -0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, -0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x81, -0x9D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, -0x03,0x81,0x8B,0x00,0x30,0x81,0x87,0x02,0x81,0x81,0x00,0xCD,0x28,0x83,0x34,0x54, -0x1B,0x89,0xF3,0x0F,0xAF,0x37,0x91,0x31,0xFF,0xAF,0x31,0x60,0xC9,0xA8,0xE8,0xB2, -0x10,0x68,0xED,0x9F,0xE7,0x93,0x36,0xF1,0x0A,0x64,0xBB,0x47,0xF5,0x04,0x17,0x3F, -0x23,0x47,0x4D,0xC5,0x27,0x19,0x81,0x26,0x0C,0x54,0x72,0x0D,0x88,0x2D,0xD9,0x1F, -0x9A,0x12,0x9F,0xBC,0xB3,0x71,0xD3,0x80,0x19,0x3F,0x47,0x66,0x7B,0x8C,0x35,0x28, -0xD2,0xB9,0x0A,0xDF,0x24,0xDA,0x9C,0xD6,0x50,0x79,0x81,0x7A,0x5A,0xD3,0x37,0xF7, -0xC2,0x4A,0xD8,0x29,0x92,0x26,0x64,0xD1,0xE4,0x98,0x6C,0x3A,0x00,0x8A,0xF5,0x34, -0x9B,0x65,0xF8,0xED,0xE3,0x10,0xFF,0xFD,0xB8,0x49,0x58,0xDC,0xA0,0xDE,0x82,0x39, -0x6B,0x81,0xB1,0x16,0x19,0x61,0xB9,0x54,0xB6,0xE6,0x43,0x02,0x01,0x03,0xA3,0x82, -0x01,0xD7,0x30,0x82,0x01,0xD3,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xF8, -0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x82,0x01,0x19,0x06,0x03,0x55, -0x1D,0x1F,0x04,0x82,0x01,0x10,0x30,0x82,0x01,0x0C,0x30,0x81,0xDE,0xA0,0x81,0xDB, -0xA0,0x81,0xD8,0xA4,0x81,0xD5,0x30,0x81,0xD2,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, -0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13, -0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x3B,0x30,0x39, -0x06,0x03,0x55,0x04,0x0B,0x13,0x32,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75, -0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x6E,0x63,0x6F,0x72, -0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69, -0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55, -0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74, -0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64, -0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6E,0x74,0x72,0x75, -0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65, -0x72,0x76,0x65,0x72,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, -0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x0D,0x30,0x0B, -0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4C,0x31,0x30,0x29,0xA0,0x27,0xA0, -0x25,0x86,0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x65,0x6E, -0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x52,0x4C,0x2F,0x6E,0x65, -0x74,0x31,0x2E,0x63,0x72,0x6C,0x30,0x2B,0x06,0x03,0x55,0x1D,0x10,0x04,0x24,0x30, -0x22,0x80,0x0F,0x31,0x39,0x39,0x39,0x30,0x35,0x32,0x35,0x31,0x36,0x30,0x39,0x34, -0x30,0x5A,0x81,0x0F,0x32,0x30,0x31,0x39,0x30,0x35,0x32,0x35,0x31,0x36,0x30,0x39, -0x34,0x30,0x5A,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06, -0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xF0,0x17,0x62, -0x13,0x55,0x3D,0xB3,0xFF,0x0A,0x00,0x6B,0xFB,0x50,0x84,0x97,0xF3,0xED,0x62,0xD0, -0x1A,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xF0,0x17,0x62,0x13, -0x55,0x3D,0xB3,0xFF,0x0A,0x00,0x6B,0xFB,0x50,0x84,0x97,0xF3,0xED,0x62,0xD0,0x1A, -0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x19, -0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04,0x0C,0x30,0x0A,0x1B, -0x04,0x56,0x34,0x2E,0x30,0x03,0x02,0x04,0x90,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, -0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x90,0xDC,0x30,0x02, -0xFA,0x64,0x74,0xC2,0xA7,0x0A,0xA5,0x7C,0x21,0x8D,0x34,0x17,0xA8,0xFB,0x47,0x0E, -0xFF,0x25,0x7C,0x8D,0x13,0x0A,0xFB,0xE4,0x98,0xB5,0xEF,0x8C,0xF8,0xC5,0x10,0x0D, -0xF7,0x92,0xBE,0xF1,0xC3,0xD5,0xD5,0x95,0x6A,0x04,0xBB,0x2C,0xCE,0x26,0x36,0x65, -0xC8,0x31,0xC6,0xE7,0xEE,0x3F,0xE3,0x57,0x75,0x84,0x7A,0x11,0xEF,0x46,0x4F,0x18, -0xF4,0xD3,0x98,0xBB,0xA8,0x87,0x32,0xBA,0x72,0xF6,0x3C,0xE2,0x3D,0x9F,0xD7,0x1D, -0xD9,0xC3,0x60,0x43,0x8C,0x58,0x0E,0x22,0x96,0x2F,0x62,0xA3,0x2C,0x1F,0xBA,0xAD, -0x05,0xEF,0xAB,0x32,0x78,0x87,0xA0,0x54,0x73,0x19,0xB5,0x5C,0x05,0xF9,0x52,0x3E, -0x6D,0x2D,0x45,0x0B,0xF7,0x0A,0x93,0xEA,0xED,0x06,0xF9,0xB2, -}; - - -/* subject:/C=US/O=Entrust, Inc./OU=www.entrust.net/CPS is incorporated by reference/OU=(c) 2006 Entrust, Inc./CN=Entrust Root Certification Authority */ -/* issuer :/C=US/O=Entrust, Inc./OU=www.entrust.net/CPS is incorporated by reference/OU=(c) 2006 Entrust, Inc./CN=Entrust Root Certification Authority */ - - -const unsigned char Entrust_Root_Certification_Authority_certificate[1173]={ -0x30,0x82,0x04,0x91,0x30,0x82,0x03,0x79,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x45, -0x6B,0x50,0x54,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, -0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74, -0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03, -0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74, -0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69,0x6E,0x63,0x6F, -0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x65, -0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16, -0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, -0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x03,0x13, -0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65, -0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68, -0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x32,0x37,0x32, -0x30,0x32,0x33,0x34,0x32,0x5A,0x17,0x0D,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30, -0x35,0x33,0x34,0x32,0x5A,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, -0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D, -0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30, -0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72, -0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69, -0x6E,0x63,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72, -0x65,0x66,0x65,0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04, -0x0B,0x13,0x16,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72, -0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55, -0x04,0x03,0x13,0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74, -0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, -0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00, -0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB6,0x95,0xB6,0x43,0x42,0xFA,0xC6, -0x6D,0x2A,0x6F,0x48,0xDF,0x94,0x4C,0x39,0x57,0x05,0xEE,0xC3,0x79,0x11,0x41,0x68, -0x36,0xED,0xEC,0xFE,0x9A,0x01,0x8F,0xA1,0x38,0x28,0xFC,0xF7,0x10,0x46,0x66,0x2E, -0x4D,0x1E,0x1A,0xB1,0x1A,0x4E,0xC6,0xD1,0xC0,0x95,0x88,0xB0,0xC9,0xFF,0x31,0x8B, -0x33,0x03,0xDB,0xB7,0x83,0x7B,0x3E,0x20,0x84,0x5E,0xED,0xB2,0x56,0x28,0xA7,0xF8, -0xE0,0xB9,0x40,0x71,0x37,0xC5,0xCB,0x47,0x0E,0x97,0x2A,0x68,0xC0,0x22,0x95,0x62, -0x15,0xDB,0x47,0xD9,0xF5,0xD0,0x2B,0xFF,0x82,0x4B,0xC9,0xAD,0x3E,0xDE,0x4C,0xDB, -0x90,0x80,0x50,0x3F,0x09,0x8A,0x84,0x00,0xEC,0x30,0x0A,0x3D,0x18,0xCD,0xFB,0xFD, -0x2A,0x59,0x9A,0x23,0x95,0x17,0x2C,0x45,0x9E,0x1F,0x6E,0x43,0x79,0x6D,0x0C,0x5C, -0x98,0xFE,0x48,0xA7,0xC5,0x23,0x47,0x5C,0x5E,0xFD,0x6E,0xE7,0x1E,0xB4,0xF6,0x68, -0x45,0xD1,0x86,0x83,0x5B,0xA2,0x8A,0x8D,0xB1,0xE3,0x29,0x80,0xFE,0x25,0x71,0x88, -0xAD,0xBE,0xBC,0x8F,0xAC,0x52,0x96,0x4B,0xAA,0x51,0x8D,0xE4,0x13,0x31,0x19,0xE8, -0x4E,0x4D,0x9F,0xDB,0xAC,0xB3,0x6A,0xD5,0xBC,0x39,0x54,0x71,0xCA,0x7A,0x7A,0x7F, -0x90,0xDD,0x7D,0x1D,0x80,0xD9,0x81,0xBB,0x59,0x26,0xC2,0x11,0xFE,0xE6,0x93,0xE2, -0xF7,0x80,0xE4,0x65,0xFB,0x34,0x37,0x0E,0x29,0x80,0x70,0x4D,0xAF,0x38,0x86,0x2E, -0x9E,0x7F,0x57,0xAF,0x9E,0x17,0xAE,0xEB,0x1C,0xCB,0x28,0x21,0x5F,0xB6,0x1C,0xD8, -0xE7,0xA2,0x04,0x22,0xF9,0xD3,0xDA,0xD8,0xCB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81, -0xB0,0x30,0x81,0xAD,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, -0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, -0x30,0x03,0x01,0x01,0xFF,0x30,0x2B,0x06,0x03,0x55,0x1D,0x10,0x04,0x24,0x30,0x22, -0x80,0x0F,0x32,0x30,0x30,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x32,0x33,0x34,0x32, -0x5A,0x81,0x0F,0x32,0x30,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x35,0x33,0x34, -0x32,0x5A,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x68, -0x90,0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB, -0x84,0xBD,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x68,0x90, -0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB,0x84, -0xBD,0x6D,0x30,0x1D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04, -0x10,0x30,0x0E,0x1B,0x08,0x56,0x37,0x2E,0x31,0x3A,0x34,0x2E,0x30,0x03,0x02,0x04, -0x90,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, -0x03,0x82,0x01,0x01,0x00,0x93,0xD4,0x30,0xB0,0xD7,0x03,0x20,0x2A,0xD0,0xF9,0x63, -0xE8,0x91,0x0C,0x05,0x20,0xA9,0x5F,0x19,0xCA,0x7B,0x72,0x4E,0xD4,0xB1,0xDB,0xD0, -0x96,0xFB,0x54,0x5A,0x19,0x2C,0x0C,0x08,0xF7,0xB2,0xBC,0x85,0xA8,0x9D,0x7F,0x6D, -0x3B,0x52,0xB3,0x2A,0xDB,0xE7,0xD4,0x84,0x8C,0x63,0xF6,0x0F,0xCB,0x26,0x01,0x91, -0x50,0x6C,0xF4,0x5F,0x14,0xE2,0x93,0x74,0xC0,0x13,0x9E,0x30,0x3A,0x50,0xE3,0xB4, -0x60,0xC5,0x1C,0xF0,0x22,0x44,0x8D,0x71,0x47,0xAC,0xC8,0x1A,0xC9,0xE9,0x9B,0x9A, -0x00,0x60,0x13,0xFF,0x70,0x7E,0x5F,0x11,0x4D,0x49,0x1B,0xB3,0x15,0x52,0x7B,0xC9, -0x54,0xDA,0xBF,0x9D,0x95,0xAF,0x6B,0x9A,0xD8,0x9E,0xE9,0xF1,0xE4,0x43,0x8D,0xE2, -0x11,0x44,0x3A,0xBF,0xAF,0xBD,0x83,0x42,0x73,0x52,0x8B,0xAA,0xBB,0xA7,0x29,0xCF, -0xF5,0x64,0x1C,0x0A,0x4D,0xD1,0xBC,0xAA,0xAC,0x9F,0x2A,0xD0,0xFF,0x7F,0x7F,0xDA, -0x7D,0xEA,0xB1,0xED,0x30,0x25,0xC1,0x84,0xDA,0x34,0xD2,0x5B,0x78,0x83,0x56,0xEC, -0x9C,0x36,0xC3,0x26,0xE2,0x11,0xF6,0x67,0x49,0x1D,0x92,0xAB,0x8C,0xFB,0xEB,0xFF, -0x7A,0xEE,0x85,0x4A,0xA7,0x50,0x80,0xF0,0xA7,0x5C,0x4A,0x94,0x2E,0x5F,0x05,0x99, -0x3C,0x52,0x41,0xE0,0xCD,0xB4,0x63,0xCF,0x01,0x43,0xBA,0x9C,0x83,0xDC,0x8F,0x60, -0x3B,0xF3,0x5A,0xB4,0xB4,0x7B,0xAE,0xDA,0x0B,0x90,0x38,0x75,0xEF,0x81,0x1D,0x66, -0xD2,0xF7,0x57,0x70,0x36,0xB3,0xBF,0xFC,0x28,0xAF,0x71,0x25,0x85,0x5B,0x13,0xFE, -0x1E,0x7F,0x5A,0xB4,0x3C, -}; - - -/* subject:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority */ -/* issuer :/C=US/O=Equifax/OU=Equifax Secure Certificate Authority */ - - -const unsigned char Equifax_Secure_CA_certificate[804]={ -0x30,0x82,0x03,0x20,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x35, -0xDE,0xF4,0xCF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, -0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69, -0x66,0x61,0x78,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71, -0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72, -0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x38,0x32,0x32,0x31,0x36,0x34,0x31, -0x35,0x31,0x5A,0x17,0x0D,0x31,0x38,0x30,0x38,0x32,0x32,0x31,0x36,0x34,0x31,0x35, -0x31,0x5A,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, -0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69, -0x66,0x61,0x78,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71, -0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72, -0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, -0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xC1, -0x5D,0xB1,0x58,0x67,0x08,0x62,0xEE,0xA0,0x9A,0x2D,0x1F,0x08,0x6D,0x91,0x14,0x68, -0x98,0x0A,0x1E,0xFE,0xDA,0x04,0x6F,0x13,0x84,0x62,0x21,0xC3,0xD1,0x7C,0xCE,0x9F, -0x05,0xE0,0xB8,0x01,0xF0,0x4E,0x34,0xEC,0xE2,0x8A,0x95,0x04,0x64,0xAC,0xF1,0x6B, -0x53,0x5F,0x05,0xB3,0xCB,0x67,0x80,0xBF,0x42,0x02,0x8E,0xFE,0xDD,0x01,0x09,0xEC, -0xE1,0x00,0x14,0x4F,0xFC,0xFB,0xF0,0x0C,0xDD,0x43,0xBA,0x5B,0x2B,0xE1,0x1F,0x80, -0x70,0x99,0x15,0x57,0x93,0x16,0xF1,0x0F,0x97,0x6A,0xB7,0xC2,0x68,0x23,0x1C,0xCC, -0x4D,0x59,0x30,0xAC,0x51,0x1E,0x3B,0xAF,0x2B,0xD6,0xEE,0x63,0x45,0x7B,0xC5,0xD9, -0x5F,0x50,0xD2,0xE3,0x50,0x0F,0x3A,0x88,0xE7,0xBF,0x14,0xFD,0xE0,0xC7,0xB9,0x02, -0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x09,0x30,0x82,0x01,0x05,0x30,0x70,0x06,0x03, -0x55,0x1D,0x1F,0x04,0x69,0x30,0x67,0x30,0x65,0xA0,0x63,0xA0,0x61,0xA4,0x5F,0x30, -0x5D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x10, -0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69,0x66,0x61,0x78, -0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71,0x75,0x69,0x66, -0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66, -0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31, -0x0D,0x30,0x0B,0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4C,0x31,0x30,0x1A, -0x06,0x03,0x55,0x1D,0x10,0x04,0x13,0x30,0x11,0x81,0x0F,0x32,0x30,0x31,0x38,0x30, -0x38,0x32,0x32,0x31,0x36,0x34,0x31,0x35,0x31,0x5A,0x30,0x0B,0x06,0x03,0x55,0x1D, -0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, -0x30,0x16,0x80,0x14,0x48,0xE6,0x68,0xF9,0x2B,0xD2,0xB2,0x95,0xD7,0x47,0xD8,0x23, -0x20,0x10,0x4F,0x33,0x98,0x90,0x9F,0xD4,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, -0x16,0x04,0x14,0x48,0xE6,0x68,0xF9,0x2B,0xD2,0xB2,0x95,0xD7,0x47,0xD8,0x23,0x20, -0x10,0x4F,0x33,0x98,0x90,0x9F,0xD4,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05, -0x30,0x03,0x01,0x01,0xFF,0x30,0x1A,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07, -0x41,0x00,0x04,0x0D,0x30,0x0B,0x1B,0x05,0x56,0x33,0x2E,0x30,0x63,0x03,0x02,0x06, -0xC0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, -0x03,0x81,0x81,0x00,0x58,0xCE,0x29,0xEA,0xFC,0xF7,0xDE,0xB5,0xCE,0x02,0xB9,0x17, -0xB5,0x85,0xD1,0xB9,0xE3,0xE0,0x95,0xCC,0x25,0x31,0x0D,0x00,0xA6,0x92,0x6E,0x7F, -0xB6,0x92,0x63,0x9E,0x50,0x95,0xD1,0x9A,0x6F,0xE4,0x11,0xDE,0x63,0x85,0x6E,0x98, -0xEE,0xA8,0xFF,0x5A,0xC8,0xD3,0x55,0xB2,0x66,0x71,0x57,0xDE,0xC0,0x21,0xEB,0x3D, -0x2A,0xA7,0x23,0x49,0x01,0x04,0x86,0x42,0x7B,0xFC,0xEE,0x7F,0xA2,0x16,0x52,0xB5, -0x67,0x67,0xD3,0x40,0xDB,0x3B,0x26,0x58,0xB2,0x28,0x77,0x3D,0xAE,0x14,0x77,0x61, -0xD6,0xFA,0x2A,0x66,0x27,0xA0,0x0D,0xFA,0xA7,0x73,0x5C,0xEA,0x70,0xF1,0x94,0x21, -0x65,0x44,0x5F,0xFA,0xFC,0xEF,0x29,0x68,0xA9,0xA2,0x87,0x79,0xEF,0x79,0xEF,0x4F, -0xAC,0x07,0x77,0x38, -}; - - -/* subject:/C=US/O=Equifax Secure Inc./CN=Equifax Secure eBusiness CA-1 */ -/* issuer :/C=US/O=Equifax Secure Inc./CN=Equifax Secure eBusiness CA-1 */ - - -const unsigned char Equifax_Secure_eBusiness_CA_1_certificate[646]={ -0x30,0x82,0x02,0x82,0x30,0x82,0x01,0xEB,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x04, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, -0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, -0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78, -0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x26,0x30,0x24, -0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53, -0x65,0x63,0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20, -0x43,0x41,0x2D,0x31,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36,0x32,0x31,0x30,0x34, -0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30,0x30,0x36,0x32,0x31,0x30,0x34,0x30, -0x30,0x30,0x30,0x5A,0x30,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x45,0x71, -0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x49,0x6E,0x63, -0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x45,0x71,0x75,0x69, -0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69, -0x6E,0x65,0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30, -0x81,0x89,0x02,0x81,0x81,0x00,0xCE,0x2F,0x19,0xBC,0x17,0xB7,0x77,0xDE,0x93,0xA9, -0x5F,0x5A,0x0D,0x17,0x4F,0x34,0x1A,0x0C,0x98,0xF4,0x22,0xD9,0x59,0xD4,0xC4,0x68, -0x46,0xF0,0xB4,0x35,0xC5,0x85,0x03,0x20,0xC6,0xAF,0x45,0xA5,0x21,0x51,0x45,0x41, -0xEB,0x16,0x58,0x36,0x32,0x6F,0xE2,0x50,0x62,0x64,0xF9,0xFD,0x51,0x9C,0xAA,0x24, -0xD9,0xF4,0x9D,0x83,0x2A,0x87,0x0A,0x21,0xD3,0x12,0x38,0x34,0x6C,0x8D,0x00,0x6E, -0x5A,0xA0,0xD9,0x42,0xEE,0x1A,0x21,0x95,0xF9,0x52,0x4C,0x55,0x5A,0xC5,0x0F,0x38, -0x4F,0x46,0xFA,0x6D,0xF8,0x2E,0x35,0xD6,0x1D,0x7C,0xEB,0xE2,0xF0,0xB0,0x75,0x80, -0xC8,0xA9,0x13,0xAC,0xBE,0x88,0xEF,0x3A,0x6E,0xAB,0x5F,0x2A,0x38,0x62,0x02,0xB0, -0x12,0x7B,0xFE,0x8F,0xA6,0x03,0x02,0x03,0x01,0x00,0x01,0xA3,0x66,0x30,0x64,0x30, -0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02, -0x00,0x07,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03, -0x01,0x01,0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, -0x4A,0x78,0x32,0x52,0x11,0xDB,0x59,0x16,0x36,0x5E,0xDF,0xC1,0x14,0x36,0x40,0x6A, -0x47,0x7C,0x4C,0xA1,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4A, -0x78,0x32,0x52,0x11,0xDB,0x59,0x16,0x36,0x5E,0xDF,0xC1,0x14,0x36,0x40,0x6A,0x47, -0x7C,0x4C,0xA1,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04, -0x05,0x00,0x03,0x81,0x81,0x00,0x75,0x5B,0xA8,0x9B,0x03,0x11,0xE6,0xE9,0x56,0x4C, -0xCD,0xF9,0xA9,0x4C,0xC0,0x0D,0x9A,0xF3,0xCC,0x65,0x69,0xE6,0x25,0x76,0xCC,0x59, -0xB7,0xD6,0x54,0xC3,0x1D,0xCD,0x99,0xAC,0x19,0xDD,0xB4,0x85,0xD5,0xE0,0x3D,0xFC, -0x62,0x20,0xA7,0x84,0x4B,0x58,0x65,0xF1,0xE2,0xF9,0x95,0x21,0x3F,0xF5,0xD4,0x7E, -0x58,0x1E,0x47,0x87,0x54,0x3E,0x58,0xA1,0xB5,0xB5,0xF8,0x2A,0xEF,0x71,0xE7,0xBC, -0xC3,0xF6,0xB1,0x49,0x46,0xE2,0xD7,0xA0,0x6B,0xE5,0x56,0x7A,0x9A,0x27,0x98,0x7C, -0x46,0x62,0x14,0xE7,0xC9,0xFC,0x6E,0x03,0x12,0x79,0x80,0x38,0x1D,0x48,0x82,0x8D, -0xFC,0x17,0xFE,0x2A,0x96,0x2B,0xB5,0x62,0xA6,0xA6,0x3D,0xBD,0x7F,0x92,0x59,0xCD, -0x5A,0x2A,0x82,0xB2,0x37,0x79, -}; - - -/* subject:/C=US/O=Equifax Secure/OU=Equifax Secure eBusiness CA-2 */ -/* issuer :/C=US/O=Equifax Secure/OU=Equifax Secure eBusiness CA-2 */ - - -const unsigned char Equifax_Secure_eBusiness_CA_2_certificate[804]={ -0x30,0x82,0x03,0x20,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x37, -0x70,0xCF,0xB5,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, -0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x45,0x71,0x75,0x69, -0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x31,0x26,0x30,0x24,0x06,0x03, -0x55,0x04,0x0B,0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63, -0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41, -0x2D,0x32,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36,0x32,0x33,0x31,0x32,0x31,0x34, -0x34,0x35,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32,0x33,0x31,0x32,0x31,0x34,0x34, -0x35,0x5A,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, -0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x45,0x71,0x75,0x69, -0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x31,0x26,0x30,0x24,0x06,0x03, -0x55,0x04,0x0B,0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63, -0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41, -0x2D,0x32,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, -0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xE4, -0x39,0x39,0x93,0x1E,0x52,0x06,0x1B,0x28,0x36,0xF8,0xB2,0xA3,0x29,0xC5,0xED,0x8E, -0xB2,0x11,0xBD,0xFE,0xEB,0xE7,0xB4,0x74,0xC2,0x8F,0xFF,0x05,0xE7,0xD9,0x9D,0x06, -0xBF,0x12,0xC8,0x3F,0x0E,0xF2,0xD6,0xD1,0x24,0xB2,0x11,0xDE,0xD1,0x73,0x09,0x8A, -0xD4,0xB1,0x2C,0x98,0x09,0x0D,0x1E,0x50,0x46,0xB2,0x83,0xA6,0x45,0x8D,0x62,0x68, -0xBB,0x85,0x1B,0x20,0x70,0x32,0xAA,0x40,0xCD,0xA6,0x96,0x5F,0xC4,0x71,0x37,0x3F, -0x04,0xF3,0xB7,0x41,0x24,0x39,0x07,0x1A,0x1E,0x2E,0x61,0x58,0xA0,0x12,0x0B,0xE5, -0xA5,0xDF,0xC5,0xAB,0xEA,0x37,0x71,0xCC,0x1C,0xC8,0x37,0x3A,0xB9,0x97,0x52,0xA7, -0xAC,0xC5,0x6A,0x24,0x94,0x4E,0x9C,0x7B,0xCF,0xC0,0x6A,0xD6,0xDF,0x21,0xBD,0x02, -0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x09,0x30,0x82,0x01,0x05,0x30,0x70,0x06,0x03, -0x55,0x1D,0x1F,0x04,0x69,0x30,0x67,0x30,0x65,0xA0,0x63,0xA0,0x61,0xA4,0x5F,0x30, -0x5D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, -0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x45,0x71,0x75,0x69,0x66,0x61,0x78, -0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, -0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65, -0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41,0x2D,0x32,0x31, -0x0D,0x30,0x0B,0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4C,0x31,0x30,0x1A, -0x06,0x03,0x55,0x1D,0x10,0x04,0x13,0x30,0x11,0x81,0x0F,0x32,0x30,0x31,0x39,0x30, -0x36,0x32,0x33,0x31,0x32,0x31,0x34,0x34,0x35,0x5A,0x30,0x0B,0x06,0x03,0x55,0x1D, -0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, -0x30,0x16,0x80,0x14,0x50,0x9E,0x0B,0xEA,0xAF,0x5E,0xB9,0x20,0x48,0xA6,0x50,0x6A, -0xCB,0xFD,0xD8,0x20,0x7A,0xA7,0x82,0x76,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, -0x16,0x04,0x14,0x50,0x9E,0x0B,0xEA,0xAF,0x5E,0xB9,0x20,0x48,0xA6,0x50,0x6A,0xCB, -0xFD,0xD8,0x20,0x7A,0xA7,0x82,0x76,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05, -0x30,0x03,0x01,0x01,0xFF,0x30,0x1A,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07, -0x41,0x00,0x04,0x0D,0x30,0x0B,0x1B,0x05,0x56,0x33,0x2E,0x30,0x63,0x03,0x02,0x06, -0xC0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, -0x03,0x81,0x81,0x00,0x0C,0x86,0x82,0xAD,0xE8,0x4E,0x1A,0xF5,0x8E,0x89,0x27,0xE2, -0x35,0x58,0x3D,0x29,0xB4,0x07,0x8F,0x36,0x50,0x95,0xBF,0x6E,0xC1,0x9E,0xEB,0xC4, -0x90,0xB2,0x85,0xA8,0xBB,0xB7,0x42,0xE0,0x0F,0x07,0x39,0xDF,0xFB,0x9E,0x90,0xB2, -0xD1,0xC1,0x3E,0x53,0x9F,0x03,0x44,0xB0,0x7E,0x4B,0xF4,0x6F,0xE4,0x7C,0x1F,0xE7, -0xE2,0xB1,0xE4,0xB8,0x9A,0xEF,0xC3,0xBD,0xCE,0xDE,0x0B,0x32,0x34,0xD9,0xDE,0x28, -0xED,0x33,0x6B,0xC4,0xD4,0xD7,0x3D,0x12,0x58,0xAB,0x7D,0x09,0x2D,0xCB,0x70,0xF5, -0x13,0x8A,0x94,0xA1,0x27,0xA4,0xD6,0x70,0xC5,0x6D,0x94,0xB5,0xC9,0x7D,0x9D,0xA0, -0xD2,0xC6,0x08,0x49,0xD9,0x66,0x9B,0xA6,0xD3,0xF4,0x0B,0xDC,0xC5,0x26,0x57,0xE1, -0x91,0x30,0xEA,0xCD, -}; - - -/* subject:/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1 */ -/* issuer :/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1 */ - - -const unsigned char Equifax_Secure_Global_eBusiness_CA_certificate[660]={ -0x30,0x82,0x02,0x90,0x30,0x82,0x01,0xF9,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, -0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, -0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78, -0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B, -0x06,0x03,0x55,0x04,0x03,0x13,0x24,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53, -0x65,0x63,0x75,0x72,0x65,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x65,0x42,0x75, -0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x1E,0x17,0x0D,0x39, -0x39,0x30,0x36,0x32,0x31,0x30,0x34,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30, -0x30,0x36,0x32,0x31,0x30,0x34,0x30,0x30,0x30,0x30,0x5A,0x30,0x5A,0x31,0x0B,0x30, -0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03, -0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63, -0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04, -0x03,0x13,0x24,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72, -0x65,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65, -0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89, -0x02,0x81,0x81,0x00,0xBA,0xE7,0x17,0x90,0x02,0x65,0xB1,0x34,0x55,0x3C,0x49,0xC2, -0x51,0xD5,0xDF,0xA7,0xD1,0x37,0x8F,0xD1,0xE7,0x81,0x73,0x41,0x52,0x60,0x9B,0x9D, -0xA1,0x17,0x26,0x78,0xAD,0xC7,0xB1,0xE8,0x26,0x94,0x32,0xB5,0xDE,0x33,0x8D,0x3A, -0x2F,0xDB,0xF2,0x9A,0x7A,0x5A,0x73,0x98,0xA3,0x5C,0xE9,0xFB,0x8A,0x73,0x1B,0x5C, -0xE7,0xC3,0xBF,0x80,0x6C,0xCD,0xA9,0xF4,0xD6,0x2B,0xC0,0xF7,0xF9,0x99,0xAA,0x63, -0xA2,0xB1,0x47,0x02,0x0F,0xD4,0xE4,0x51,0x3A,0x12,0x3C,0x6C,0x8A,0x5A,0x54,0x84, -0x70,0xDB,0xC1,0xC5,0x90,0xCF,0x72,0x45,0xCB,0xA8,0x59,0xC0,0xCD,0x33,0x9D,0x3F, -0xA3,0x96,0xEB,0x85,0x33,0x21,0x1C,0x3E,0x1E,0x3E,0x60,0x6E,0x76,0x9C,0x67,0x85, -0xC5,0xC8,0xC3,0x61,0x02,0x03,0x01,0x00,0x01,0xA3,0x66,0x30,0x64,0x30,0x11,0x06, -0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07, -0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01, -0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xBE,0xA8, -0xA0,0x74,0x72,0x50,0x6B,0x44,0xB7,0xC9,0x23,0xD8,0xFB,0xA8,0xFF,0xB3,0x57,0x6B, -0x68,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBE,0xA8,0xA0, -0x74,0x72,0x50,0x6B,0x44,0xB7,0xC9,0x23,0xD8,0xFB,0xA8,0xFF,0xB3,0x57,0x6B,0x68, -0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00, -0x03,0x81,0x81,0x00,0x30,0xE2,0x01,0x51,0xAA,0xC7,0xEA,0x5F,0xDA,0xB9,0xD0,0x65, -0x0F,0x30,0xD6,0x3E,0xDA,0x0D,0x14,0x49,0x6E,0x91,0x93,0x27,0x14,0x31,0xEF,0xC4, -0xF7,0x2D,0x45,0xF8,0xEC,0xC7,0xBF,0xA2,0x41,0x0D,0x23,0xB4,0x92,0xF9,0x19,0x00, -0x67,0xBD,0x01,0xAF,0xCD,0xE0,0x71,0xFC,0x5A,0xCF,0x64,0xC4,0xE0,0x96,0x98,0xD0, -0xA3,0x40,0xE2,0x01,0x8A,0xEF,0x27,0x07,0xF1,0x65,0x01,0x8A,0x44,0x2D,0x06,0x65, -0x75,0x52,0xC0,0x86,0x10,0x20,0x21,0x5F,0x6C,0x6B,0x0F,0x6C,0xAE,0x09,0x1C,0xAF, -0xF2,0xA2,0x18,0x34,0xC4,0x75,0xA4,0x73,0x1C,0xF1,0x8D,0xDC,0xEF,0xAD,0xF9,0xB3, -0x76,0xB4,0x92,0xBF,0xDC,0x95,0x10,0x1E,0xBE,0xCB,0xC8,0x3B,0x5A,0x84,0x60,0x19, -0x56,0x94,0xA9,0x55, -}; - - -/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ -/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ - - -const unsigned char GeoTrust_Global_CA_certificate[856]={ -0x30,0x82,0x03,0x54,0x30,0x82,0x02,0x3C,0xA0,0x03,0x02,0x01,0x02,0x02,0x03,0x02, -0x34,0x56,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05, -0x00,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, -0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72, -0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04, -0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62, -0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x32,0x30,0x35,0x32,0x31,0x30, -0x34,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x32,0x30,0x35,0x32,0x31,0x30,0x34, -0x30,0x30,0x30,0x30,0x5A,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, -0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47, -0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19, -0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, -0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, -0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDA,0xCC,0x18,0x63,0x30,0xFD, -0xF4,0x17,0x23,0x1A,0x56,0x7E,0x5B,0xDF,0x3C,0x6C,0x38,0xE4,0x71,0xB7,0x78,0x91, -0xD4,0xBC,0xA1,0xD8,0x4C,0xF8,0xA8,0x43,0xB6,0x03,0xE9,0x4D,0x21,0x07,0x08,0x88, -0xDA,0x58,0x2F,0x66,0x39,0x29,0xBD,0x05,0x78,0x8B,0x9D,0x38,0xE8,0x05,0xB7,0x6A, -0x7E,0x71,0xA4,0xE6,0xC4,0x60,0xA6,0xB0,0xEF,0x80,0xE4,0x89,0x28,0x0F,0x9E,0x25, -0xD6,0xED,0x83,0xF3,0xAD,0xA6,0x91,0xC7,0x98,0xC9,0x42,0x18,0x35,0x14,0x9D,0xAD, -0x98,0x46,0x92,0x2E,0x4F,0xCA,0xF1,0x87,0x43,0xC1,0x16,0x95,0x57,0x2D,0x50,0xEF, -0x89,0x2D,0x80,0x7A,0x57,0xAD,0xF2,0xEE,0x5F,0x6B,0xD2,0x00,0x8D,0xB9,0x14,0xF8, -0x14,0x15,0x35,0xD9,0xC0,0x46,0xA3,0x7B,0x72,0xC8,0x91,0xBF,0xC9,0x55,0x2B,0xCD, -0xD0,0x97,0x3E,0x9C,0x26,0x64,0xCC,0xDF,0xCE,0x83,0x19,0x71,0xCA,0x4E,0xE6,0xD4, -0xD5,0x7B,0xA9,0x19,0xCD,0x55,0xDE,0xC8,0xEC,0xD2,0x5E,0x38,0x53,0xE5,0x5C,0x4F, -0x8C,0x2D,0xFE,0x50,0x23,0x36,0xFC,0x66,0xE6,0xCB,0x8E,0xA4,0x39,0x19,0x00,0xB7, -0x95,0x02,0x39,0x91,0x0B,0x0E,0xFE,0x38,0x2E,0xD1,0x1D,0x05,0x9A,0xF6,0x4D,0x3E, -0x6F,0x0F,0x07,0x1D,0xAF,0x2C,0x1E,0x8F,0x60,0x39,0xE2,0xFA,0x36,0x53,0x13,0x39, -0xD4,0x5E,0x26,0x2B,0xDB,0x3D,0xA8,0x14,0xBD,0x32,0xEB,0x18,0x03,0x28,0x52,0x04, -0x71,0xE5,0xAB,0x33,0x3D,0xE1,0x38,0xBB,0x07,0x36,0x84,0x62,0x9C,0x79,0xEA,0x16, -0x30,0xF4,0x5F,0xC0,0x2B,0xE8,0x71,0x6B,0xE4,0xF9,0x02,0x03,0x01,0x00,0x01,0xA3, -0x53,0x30,0x51,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, -0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC0, -0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,0x7D,0xAA,0x7D,0x65,0xB8, -0xCA,0xCC,0x4E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, -0xC0,0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,0x7D,0xAA,0x7D,0x65, -0xB8,0xCA,0xCC,0x4E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x35,0xE3,0x29,0x6A,0xE5,0x2F,0x5D,0x54, -0x8E,0x29,0x50,0x94,0x9F,0x99,0x1A,0x14,0xE4,0x8F,0x78,0x2A,0x62,0x94,0xA2,0x27, -0x67,0x9E,0xD0,0xCF,0x1A,0x5E,0x47,0xE9,0xC1,0xB2,0xA4,0xCF,0xDD,0x41,0x1A,0x05, -0x4E,0x9B,0x4B,0xEE,0x4A,0x6F,0x55,0x52,0xB3,0x24,0xA1,0x37,0x0A,0xEB,0x64,0x76, -0x2A,0x2E,0x2C,0xF3,0xFD,0x3B,0x75,0x90,0xBF,0xFA,0x71,0xD8,0xC7,0x3D,0x37,0xD2, -0xB5,0x05,0x95,0x62,0xB9,0xA6,0xDE,0x89,0x3D,0x36,0x7B,0x38,0x77,0x48,0x97,0xAC, -0xA6,0x20,0x8F,0x2E,0xA6,0xC9,0x0C,0xC2,0xB2,0x99,0x45,0x00,0xC7,0xCE,0x11,0x51, -0x22,0x22,0xE0,0xA5,0xEA,0xB6,0x15,0x48,0x09,0x64,0xEA,0x5E,0x4F,0x74,0xF7,0x05, -0x3E,0xC7,0x8A,0x52,0x0C,0xDB,0x15,0xB4,0xBD,0x6D,0x9B,0xE5,0xC6,0xB1,0x54,0x68, -0xA9,0xE3,0x69,0x90,0xB6,0x9A,0xA5,0x0F,0xB8,0xB9,0x3F,0x20,0x7D,0xAE,0x4A,0xB5, -0xB8,0x9C,0xE4,0x1D,0xB6,0xAB,0xE6,0x94,0xA5,0xC1,0xC7,0x83,0xAD,0xDB,0xF5,0x27, -0x87,0x0E,0x04,0x6C,0xD5,0xFF,0xDD,0xA0,0x5D,0xED,0x87,0x52,0xB7,0x2B,0x15,0x02, -0xAE,0x39,0xA6,0x6A,0x74,0xE9,0xDA,0xC4,0xE7,0xBC,0x4D,0x34,0x1E,0xA9,0x5C,0x4D, -0x33,0x5F,0x92,0x09,0x2F,0x88,0x66,0x5D,0x77,0x97,0xC7,0x1D,0x76,0x13,0xA9,0xD5, -0xE5,0xF1,0x16,0x09,0x11,0x35,0xD5,0xAC,0xDB,0x24,0x71,0x70,0x2C,0x98,0x56,0x0B, -0xD9,0x17,0xB4,0xD1,0xE3,0x51,0x2B,0x5E,0x75,0xE8,0xD5,0xD0,0xDC,0x4F,0x34,0xED, -0xC2,0x05,0x66,0x80,0xA1,0xCB,0xE6,0x33, -}; - - -/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 */ -/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 */ - - -const unsigned char GeoTrust_Global_CA_2_certificate[874]={ -0x30,0x82,0x03,0x66,0x30,0x82,0x02,0x4E,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, -0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, -0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x03,0x13, -0x14,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C, -0x20,0x43,0x41,0x20,0x32,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x33,0x30,0x34,0x30, -0x35,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x31,0x39,0x30,0x33,0x30,0x34,0x30,0x35, -0x30,0x30,0x30,0x30,0x5A,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, -0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47, -0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B, -0x06,0x03,0x55,0x04,0x03,0x13,0x14,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, -0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x41,0x20,0x32,0x30,0x82,0x01,0x22,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, -0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xEF,0x3C,0x4D,0x40, -0x3D,0x10,0xDF,0x3B,0x53,0x00,0xE1,0x67,0xFE,0x94,0x60,0x15,0x3E,0x85,0x88,0xF1, -0x89,0x0D,0x90,0xC8,0x28,0x23,0x99,0x05,0xE8,0x2B,0x20,0x9D,0xC6,0xF3,0x60,0x46, -0xD8,0xC1,0xB2,0xD5,0x8C,0x31,0xD9,0xDC,0x20,0x79,0x24,0x81,0xBF,0x35,0x32,0xFC, -0x63,0x69,0xDB,0xB1,0x2A,0x6B,0xEE,0x21,0x58,0xF2,0x08,0xE9,0x78,0xCB,0x6F,0xCB, -0xFC,0x16,0x52,0xC8,0x91,0xC4,0xFF,0x3D,0x73,0xDE,0xB1,0x3E,0xA7,0xC2,0x7D,0x66, -0xC1,0xF5,0x7E,0x52,0x24,0x1A,0xE2,0xD5,0x67,0x91,0xD0,0x82,0x10,0xD7,0x78,0x4B, -0x4F,0x2B,0x42,0x39,0xBD,0x64,0x2D,0x40,0xA0,0xB0,0x10,0xD3,0x38,0x48,0x46,0x88, -0xA1,0x0C,0xBB,0x3A,0x33,0x2A,0x62,0x98,0xFB,0x00,0x9D,0x13,0x59,0x7F,0x6F,0x3B, -0x72,0xAA,0xEE,0xA6,0x0F,0x86,0xF9,0x05,0x61,0xEA,0x67,0x7F,0x0C,0x37,0x96,0x8B, -0xE6,0x69,0x16,0x47,0x11,0xC2,0x27,0x59,0x03,0xB3,0xA6,0x60,0xC2,0x21,0x40,0x56, -0xFA,0xA0,0xC7,0x7D,0x3A,0x13,0xE3,0xEC,0x57,0xC7,0xB3,0xD6,0xAE,0x9D,0x89,0x80, -0xF7,0x01,0xE7,0x2C,0xF6,0x96,0x2B,0x13,0x0D,0x79,0x2C,0xD9,0xC0,0xE4,0x86,0x7B, -0x4B,0x8C,0x0C,0x72,0x82,0x8A,0xFB,0x17,0xCD,0x00,0x6C,0x3A,0x13,0x3C,0xB0,0x84, -0x87,0x4B,0x16,0x7A,0x29,0xB2,0x4F,0xDB,0x1D,0xD4,0x0B,0xF3,0x66,0x37,0xBD,0xD8, -0xF6,0x57,0xBB,0x5E,0x24,0x7A,0xB8,0x3C,0x8B,0xB9,0xFA,0x92,0x1A,0x1A,0x84,0x9E, -0xD8,0x74,0x8F,0xAA,0x1B,0x7F,0x5E,0xF4,0xFE,0x45,0x22,0x21,0x02,0x03,0x01,0x00, -0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, -0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, -0x14,0x71,0x38,0x36,0xF2,0x02,0x31,0x53,0x47,0x2B,0x6E,0xBA,0x65,0x46,0xA9,0x10, -0x15,0x58,0x20,0x05,0x09,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16, -0x80,0x14,0x71,0x38,0x36,0xF2,0x02,0x31,0x53,0x47,0x2B,0x6E,0xBA,0x65,0x46,0xA9, -0x10,0x15,0x58,0x20,0x05,0x09,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, -0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x03,0xF7,0xB5,0x2B,0xAB,0x5D, -0x10,0xFC,0x7B,0xB2,0xB2,0x5E,0xAC,0x9B,0x0E,0x7E,0x53,0x78,0x59,0x3E,0x42,0x04, -0xFE,0x75,0xA3,0xAD,0xAC,0x81,0x4E,0xD7,0x02,0x8B,0x5E,0xC4,0x2D,0xC8,0x52,0x76, -0xC7,0x2C,0x1F,0xFC,0x81,0x32,0x98,0xD1,0x4B,0xC6,0x92,0x93,0x33,0x35,0x31,0x2F, -0xFC,0xD8,0x1D,0x44,0xDD,0xE0,0x81,0x7F,0x9D,0xE9,0x8B,0xE1,0x64,0x91,0x62,0x0B, -0x39,0x08,0x8C,0xAC,0x74,0x9D,0x59,0xD9,0x7A,0x59,0x52,0x97,0x11,0xB9,0x16,0x7B, -0x6F,0x45,0xD3,0x96,0xD9,0x31,0x7D,0x02,0x36,0x0F,0x9C,0x3B,0x6E,0xCF,0x2C,0x0D, -0x03,0x46,0x45,0xEB,0xA0,0xF4,0x7F,0x48,0x44,0xC6,0x08,0x40,0xCC,0xDE,0x1B,0x70, -0xB5,0x29,0xAD,0xBA,0x8B,0x3B,0x34,0x65,0x75,0x1B,0x71,0x21,0x1D,0x2C,0x14,0x0A, -0xB0,0x96,0x95,0xB8,0xD6,0xEA,0xF2,0x65,0xFB,0x29,0xBA,0x4F,0xEA,0x91,0x93,0x74, -0x69,0xB6,0xF2,0xFF,0xE1,0x1A,0xD0,0x0C,0xD1,0x76,0x85,0xCB,0x8A,0x25,0xBD,0x97, -0x5E,0x2C,0x6F,0x15,0x99,0x26,0xE7,0xB6,0x29,0xFF,0x22,0xEC,0xC9,0x02,0xC7,0x56, -0x00,0xCD,0x49,0xB9,0xB3,0x6C,0x7B,0x53,0x04,0x1A,0xE2,0xA8,0xC9,0xAA,0x12,0x05, -0x23,0xC2,0xCE,0xE7,0xBB,0x04,0x02,0xCC,0xC0,0x47,0xA2,0xE4,0xC4,0x29,0x2F,0x5B, -0x45,0x57,0x89,0x51,0xEE,0x3C,0xEB,0x52,0x08,0xFF,0x07,0x35,0x1E,0x9F,0x35,0x6A, -0x47,0x4A,0x56,0x98,0xD1,0x5A,0x85,0x1F,0x8C,0xF5,0x22,0xBF,0xAB,0xCE,0x83,0xF3, -0xE2,0x22,0x29,0xAE,0x7D,0x83,0x40,0xA8,0xBA,0x6C, -}; - - -/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Primary Certification Authority */ -/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Primary Certification Authority */ - - -const unsigned char GeoTrust_Primary_Certification_Authority_certificate[896]={ -0x30,0x82,0x03,0x7C,0x30,0x82,0x02,0x64,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x18, -0xAC,0xB5,0x6A,0xFD,0x69,0xB6,0x15,0x3A,0x63,0x6C,0xAF,0xDA,0xFA,0xC4,0xA1,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x58, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30, -0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74, -0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28, -0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79, -0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, -0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31, -0x32,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31, -0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x58,0x31,0x0B,0x30,0x09,0x06,0x03, -0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A, -0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31, -0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28,0x47,0x65,0x6F,0x54,0x72,0x75, -0x73,0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, -0x01,0x01,0x00,0xBE,0xB8,0x15,0x7B,0xFF,0xD4,0x7C,0x7D,0x67,0xAD,0x83,0x64,0x7B, -0xC8,0x42,0x53,0x2D,0xDF,0xF6,0x84,0x08,0x20,0x61,0xD6,0x01,0x59,0x6A,0x9C,0x44, -0x11,0xAF,0xEF,0x76,0xFD,0x95,0x7E,0xCE,0x61,0x30,0xBB,0x7A,0x83,0x5F,0x02,0xBD, -0x01,0x66,0xCA,0xEE,0x15,0x8D,0x6F,0xA1,0x30,0x9C,0xBD,0xA1,0x85,0x9E,0x94,0x3A, -0xF3,0x56,0x88,0x00,0x31,0xCF,0xD8,0xEE,0x6A,0x96,0x02,0xD9,0xED,0x03,0x8C,0xFB, -0x75,0x6D,0xE7,0xEA,0xB8,0x55,0x16,0x05,0x16,0x9A,0xF4,0xE0,0x5E,0xB1,0x88,0xC0, -0x64,0x85,0x5C,0x15,0x4D,0x88,0xC7,0xB7,0xBA,0xE0,0x75,0xE9,0xAD,0x05,0x3D,0x9D, -0xC7,0x89,0x48,0xE0,0xBB,0x28,0xC8,0x03,0xE1,0x30,0x93,0x64,0x5E,0x52,0xC0,0x59, -0x70,0x22,0x35,0x57,0x88,0x8A,0xF1,0x95,0x0A,0x83,0xD7,0xBC,0x31,0x73,0x01,0x34, -0xED,0xEF,0x46,0x71,0xE0,0x6B,0x02,0xA8,0x35,0x72,0x6B,0x97,0x9B,0x66,0xE0,0xCB, -0x1C,0x79,0x5F,0xD8,0x1A,0x04,0x68,0x1E,0x47,0x02,0xE6,0x9D,0x60,0xE2,0x36,0x97, -0x01,0xDF,0xCE,0x35,0x92,0xDF,0xBE,0x67,0xC7,0x6D,0x77,0x59,0x3B,0x8F,0x9D,0xD6, -0x90,0x15,0x94,0xBC,0x42,0x34,0x10,0xC1,0x39,0xF9,0xB1,0x27,0x3E,0x7E,0xD6,0x8A, -0x75,0xC5,0xB2,0xAF,0x96,0xD3,0xA2,0xDE,0x9B,0xE4,0x98,0xBE,0x7D,0xE1,0xE9,0x81, -0xAD,0xB6,0x6F,0xFC,0xD7,0x0E,0xDA,0xE0,0x34,0xB0,0x0D,0x1A,0x77,0xE7,0xE3,0x08, -0x98,0xEF,0x58,0xFA,0x9C,0x84,0xB7,0x36,0xAF,0xC2,0xDF,0xAC,0xD2,0xF4,0x10,0x06, -0x70,0x71,0x35,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03, -0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06, -0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06, -0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x2C,0xD5,0x50,0x41,0x97,0x15,0x8B,0xF0, -0x8F,0x36,0x61,0x5B,0x4A,0xFB,0x6B,0xD9,0x99,0xC9,0x33,0x92,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, -0x5A,0x70,0x7F,0x2C,0xDD,0xB7,0x34,0x4F,0xF5,0x86,0x51,0xA9,0x26,0xBE,0x4B,0xB8, -0xAA,0xF1,0x71,0x0D,0xDC,0x61,0xC7,0xA0,0xEA,0x34,0x1E,0x7A,0x77,0x0F,0x04,0x35, -0xE8,0x27,0x8F,0x6C,0x90,0xBF,0x91,0x16,0x24,0x46,0x3E,0x4A,0x4E,0xCE,0x2B,0x16, -0xD5,0x0B,0x52,0x1D,0xFC,0x1F,0x67,0xA2,0x02,0x45,0x31,0x4F,0xCE,0xF3,0xFA,0x03, -0xA7,0x79,0x9D,0x53,0x6A,0xD9,0xDA,0x63,0x3A,0xF8,0x80,0xD7,0xD3,0x99,0xE1,0xA5, -0xE1,0xBE,0xD4,0x55,0x71,0x98,0x35,0x3A,0xBE,0x93,0xEA,0xAE,0xAD,0x42,0xB2,0x90, -0x6F,0xE0,0xFC,0x21,0x4D,0x35,0x63,0x33,0x89,0x49,0xD6,0x9B,0x4E,0xCA,0xC7,0xE7, -0x4E,0x09,0x00,0xF7,0xDA,0xC7,0xEF,0x99,0x62,0x99,0x77,0xB6,0x95,0x22,0x5E,0x8A, -0xA0,0xAB,0xF4,0xB8,0x78,0x98,0xCA,0x38,0x19,0x99,0xC9,0x72,0x9E,0x78,0xCD,0x4B, -0xAC,0xAF,0x19,0xA0,0x73,0x12,0x2D,0xFC,0xC2,0x41,0xBA,0x81,0x91,0xDA,0x16,0x5A, -0x31,0xB7,0xF9,0xB4,0x71,0x80,0x12,0x48,0x99,0x72,0x73,0x5A,0x59,0x53,0xC1,0x63, -0x52,0x33,0xED,0xA7,0xC9,0xD2,0x39,0x02,0x70,0xFA,0xE0,0xB1,0x42,0x66,0x29,0xAA, -0x9B,0x51,0xED,0x30,0x54,0x22,0x14,0x5F,0xD9,0xAB,0x1D,0xC1,0xE4,0x94,0xF0,0xF8, -0xF5,0x2B,0xF7,0xEA,0xCA,0x78,0x46,0xD6,0xB8,0x91,0xFD,0xA6,0x0D,0x2B,0x1A,0x14, -0x01,0x3E,0x80,0xF0,0x42,0xA0,0x95,0x07,0x5E,0x6D,0xCD,0xCC,0x4B,0xA4,0x45,0x8D, -0xAB,0x12,0xE8,0xB3,0xDE,0x5A,0xE5,0xA0,0x7C,0xE8,0x0F,0x22,0x1D,0x5A,0xE9,0x59, -}; - - -/* subject:/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ -/* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ - - -const unsigned char GeoTrust_Primary_Certification_Authority___G2_certificate[690]={ -0x30,0x82,0x02,0xAE,0x30,0x82,0x02,0x35,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x3C, -0xB2,0xF4,0x48,0x0A,0x00,0xE2,0xFE,0xEB,0x24,0x3B,0x5E,0x60,0x3E,0xC3,0x6B,0x30, -0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x98,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06, -0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49, -0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63, -0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, -0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F, -0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x36, -0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, -0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66, -0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, -0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31,0x30,0x35, -0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, -0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x98,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, -0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13, -0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39, -0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x30, -0x37,0x20,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x20, -0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64, -0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x36,0x30,0x34,0x06,0x03,0x55, -0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x69, -0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, -0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47, -0x32,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, -0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x15,0xB1,0xE8,0xFD,0x03,0x15,0x43, -0xE5,0xAC,0xEB,0x87,0x37,0x11,0x62,0xEF,0xD2,0x83,0x36,0x52,0x7D,0x45,0x57,0x0B, -0x4A,0x8D,0x7B,0x54,0x3B,0x3A,0x6E,0x5F,0x15,0x02,0xC0,0x50,0xA6,0xCF,0x25,0x2F, -0x7D,0xCA,0x48,0xB8,0xC7,0x50,0x63,0x1C,0x2A,0x21,0x08,0x7C,0x9A,0x36,0xD8,0x0B, -0xFE,0xD1,0x26,0xC5,0x58,0x31,0x30,0x28,0x25,0xF3,0x5D,0x5D,0xA3,0xB8,0xB6,0xA5, -0xB4,0x92,0xED,0x6C,0x2C,0x9F,0xEB,0xDD,0x43,0x89,0xA2,0x3C,0x4B,0x48,0x91,0x1D, -0x50,0xEC,0x26,0xDF,0xD6,0x60,0x2E,0xBD,0x21,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, -0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, -0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D, -0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x15,0x5F,0x35,0x57,0x51,0x55,0xFB, -0x25,0xB2,0xAD,0x03,0x69,0xFC,0x01,0xA3,0xFA,0xBE,0x11,0x55,0xD5,0x30,0x0A,0x06, -0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30, -0x64,0x96,0x59,0xA6,0xE8,0x09,0xDE,0x8B,0xBA,0xFA,0x5A,0x88,0x88,0xF0,0x1F,0x91, -0xD3,0x46,0xA8,0xF2,0x4A,0x4C,0x02,0x63,0xFB,0x6C,0x5F,0x38,0xDB,0x2E,0x41,0x93, -0xA9,0x0E,0xE6,0x9D,0xDC,0x31,0x1C,0xB2,0xA0,0xA7,0x18,0x1C,0x79,0xE1,0xC7,0x36, -0x02,0x30,0x3A,0x56,0xAF,0x9A,0x74,0x6C,0xF6,0xFB,0x83,0xE0,0x33,0xD3,0x08,0x5F, -0xA1,0x9C,0xC2,0x5B,0x9F,0x46,0xD6,0xB6,0xCB,0x91,0x06,0x63,0xA2,0x06,0xE7,0x33, -0xAC,0x3E,0xA8,0x81,0x12,0xD0,0xCB,0xBA,0xD0,0x92,0x0B,0xB6,0x9E,0x96,0xAA,0x04, -0x0F,0x8A, -}; - - /* subject:/C=US/O=GeoTrust Inc./OU=(c) 2008 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G3 */ /* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2008 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G3 */ @@ -2194,101 +1298,6 @@ }; -/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA */ -/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA */ - - -const unsigned char GeoTrust_Universal_CA_certificate[1388]={ -0x30,0x82,0x05,0x68,0x30,0x82,0x03,0x50,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, -0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, -0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x13, -0x15,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x55,0x6E,0x69,0x76,0x65,0x72, -0x73,0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x33,0x30,0x34, -0x30,0x35,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x30,0x33,0x30,0x34,0x30, -0x35,0x30,0x30,0x30,0x30,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, -0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D, -0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1E,0x30, -0x1C,0x06,0x03,0x55,0x04,0x03,0x13,0x15,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74, -0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x30,0x82,0x02, -0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, -0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xA6,0x15, -0x55,0xA0,0xA3,0xC6,0xE0,0x1F,0x8C,0x9D,0x21,0x50,0xD7,0xC1,0xBE,0x2B,0x5B,0xB5, -0xA4,0x9E,0xA1,0xD9,0x72,0x58,0xBD,0x00,0x1B,0x4C,0xBF,0x61,0xC9,0x14,0x1D,0x45, -0x82,0xAB,0xC6,0x1D,0x80,0xD6,0x3D,0xEB,0x10,0x9C,0x3A,0xAF,0x6D,0x24,0xF8,0xBC, -0x71,0x01,0x9E,0x06,0xF5,0x7C,0x5F,0x1E,0xC1,0x0E,0x55,0xCA,0x83,0x9A,0x59,0x30, -0xAE,0x19,0xCB,0x30,0x48,0x95,0xED,0x22,0x37,0x8D,0xF4,0x4A,0x9A,0x72,0x66,0x3E, -0xAD,0x95,0xC0,0xE0,0x16,0x00,0xE0,0x10,0x1F,0x2B,0x31,0x0E,0xD7,0x94,0x54,0xD3, -0x42,0x33,0xA0,0x34,0x1D,0x1E,0x45,0x76,0xDD,0x4F,0xCA,0x18,0x37,0xEC,0x85,0x15, -0x7A,0x19,0x08,0xFC,0xD5,0xC7,0x9C,0xF0,0xF2,0xA9,0x2E,0x10,0xA9,0x92,0xE6,0x3D, -0x58,0x3D,0xA9,0x16,0x68,0x3C,0x2F,0x75,0x21,0x18,0x7F,0x28,0x77,0xA5,0xE1,0x61, -0x17,0xB7,0xA6,0xE9,0xF8,0x1E,0x99,0xDB,0x73,0x6E,0xF4,0x0A,0xA2,0x21,0x6C,0xEE, -0xDA,0xAA,0x85,0x92,0x66,0xAF,0xF6,0x7A,0x6B,0x82,0xDA,0xBA,0x22,0x08,0x35,0x0F, -0xCF,0x42,0xF1,0x35,0xFA,0x6A,0xEE,0x7E,0x2B,0x25,0xCC,0x3A,0x11,0xE4,0x6D,0xAF, -0x73,0xB2,0x76,0x1D,0xAD,0xD0,0xB2,0x78,0x67,0x1A,0xA4,0x39,0x1C,0x51,0x0B,0x67, -0x56,0x83,0xFD,0x38,0x5D,0x0D,0xCE,0xDD,0xF0,0xBB,0x2B,0x96,0x1F,0xDE,0x7B,0x32, -0x52,0xFD,0x1D,0xBB,0xB5,0x06,0xA1,0xB2,0x21,0x5E,0xA5,0xD6,0x95,0x68,0x7F,0xF0, -0x99,0x9E,0xDC,0x45,0x08,0x3E,0xE7,0xD2,0x09,0x0D,0x35,0x94,0xDD,0x80,0x4E,0x53, -0x97,0xD7,0xB5,0x09,0x44,0x20,0x64,0x16,0x17,0x03,0x02,0x4C,0x53,0x0D,0x68,0xDE, -0xD5,0xAA,0x72,0x4D,0x93,0x6D,0x82,0x0E,0xDB,0x9C,0xBD,0xCF,0xB4,0xF3,0x5C,0x5D, -0x54,0x7A,0x69,0x09,0x96,0xD6,0xDB,0x11,0xC1,0x8D,0x75,0xA8,0xB4,0xCF,0x39,0xC8, -0xCE,0x3C,0xBC,0x24,0x7C,0xE6,0x62,0xCA,0xE1,0xBD,0x7D,0xA7,0xBD,0x57,0x65,0x0B, -0xE4,0xFE,0x25,0xED,0xB6,0x69,0x10,0xDC,0x28,0x1A,0x46,0xBD,0x01,0x1D,0xD0,0x97, -0xB5,0xE1,0x98,0x3B,0xC0,0x37,0x64,0xD6,0x3D,0x94,0xEE,0x0B,0xE1,0xF5,0x28,0xAE, -0x0B,0x56,0xBF,0x71,0x8B,0x23,0x29,0x41,0x8E,0x86,0xC5,0x4B,0x52,0x7B,0xD8,0x71, -0xAB,0x1F,0x8A,0x15,0xA6,0x3B,0x83,0x5A,0xD7,0x58,0x01,0x51,0xC6,0x4C,0x41,0xD9, -0x7F,0xD8,0x41,0x67,0x72,0xA2,0x28,0xDF,0x60,0x83,0xA9,0x9E,0xC8,0x7B,0xFC,0x53, -0x73,0x72,0x59,0xF5,0x93,0x7A,0x17,0x76,0x0E,0xCE,0xF7,0xE5,0x5C,0xD9,0x0B,0x55, -0x34,0xA2,0xAA,0x5B,0xB5,0x6A,0x54,0xE7,0x13,0xCA,0x57,0xEC,0x97,0x6D,0xF4,0x5E, -0x06,0x2F,0x45,0x8B,0x58,0xD4,0x23,0x16,0x92,0xE4,0x16,0x6E,0x28,0x63,0x59,0x30, -0xDF,0x50,0x01,0x9C,0x63,0x89,0x1A,0x9F,0xDB,0x17,0x94,0x82,0x70,0x37,0xC3,0x24, -0x9E,0x9A,0x47,0xD6,0x5A,0xCA,0x4E,0xA8,0x69,0x89,0x72,0x1F,0x91,0x6C,0xDB,0x7E, -0x9E,0x1B,0xAD,0xC7,0x1F,0x73,0xDD,0x2C,0x4F,0x19,0x65,0xFD,0x7F,0x93,0x40,0x10, -0x2E,0xD2,0xF0,0xED,0x3C,0x9E,0x2E,0x28,0x3E,0x69,0x26,0x33,0xC5,0x7B,0x02,0x03, -0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, -0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, -0x16,0x04,0x14,0xDA,0xBB,0x2E,0xAA,0xB0,0x0C,0xB8,0x88,0x26,0x51,0x74,0x5C,0x6D, -0x03,0xD3,0xC0,0xD8,0x8F,0x7A,0xD6,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, -0x30,0x16,0x80,0x14,0xDA,0xBB,0x2E,0xAA,0xB0,0x0C,0xB8,0x88,0x26,0x51,0x74,0x5C, -0x6D,0x03,0xD3,0xC0,0xD8,0x8F,0x7A,0xD6,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01, -0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x31,0x78,0xE6,0xC7, -0xB5,0xDF,0xB8,0x94,0x40,0xC9,0x71,0xC4,0xA8,0x35,0xEC,0x46,0x1D,0xC2,0x85,0xF3, -0x28,0x58,0x86,0xB0,0x0B,0xFC,0x8E,0xB2,0x39,0x8F,0x44,0x55,0xAB,0x64,0x84,0x5C, -0x69,0xA9,0xD0,0x9A,0x38,0x3C,0xFA,0xE5,0x1F,0x35,0xE5,0x44,0xE3,0x80,0x79,0x94, -0x68,0xA4,0xBB,0xC4,0x9F,0x3D,0xE1,0x34,0xCD,0x30,0x46,0x8B,0x54,0x2B,0x95,0xA5, -0xEF,0xF7,0x3F,0x99,0x84,0xFD,0x35,0xE6,0xCF,0x31,0xC6,0xDC,0x6A,0xBF,0xA7,0xD7, -0x23,0x08,0xE1,0x98,0x5E,0xC3,0x5A,0x08,0x76,0xA9,0xA6,0xAF,0x77,0x2F,0xB7,0x60, -0xBD,0x44,0x46,0x6A,0xEF,0x97,0xFF,0x73,0x95,0xC1,0x8E,0xE8,0x93,0xFB,0xFD,0x31, -0xB7,0xEC,0x57,0x11,0x11,0x45,0x9B,0x30,0xF1,0x1A,0x88,0x39,0xC1,0x4F,0x3C,0xA7, -0x00,0xD5,0xC7,0xFC,0xAB,0x6D,0x80,0x22,0x70,0xA5,0x0C,0xE0,0x5D,0x04,0x29,0x02, -0xFB,0xCB,0xA0,0x91,0xD1,0x7C,0xD6,0xC3,0x7E,0x50,0xD5,0x9D,0x58,0xBE,0x41,0x38, -0xEB,0xB9,0x75,0x3C,0x15,0xD9,0x9B,0xC9,0x4A,0x83,0x59,0xC0,0xDA,0x53,0xFD,0x33, -0xBB,0x36,0x18,0x9B,0x85,0x0F,0x15,0xDD,0xEE,0x2D,0xAC,0x76,0x93,0xB9,0xD9,0x01, -0x8D,0x48,0x10,0xA8,0xFB,0xF5,0x38,0x86,0xF1,0xDB,0x0A,0xC6,0xBD,0x84,0xA3,0x23, -0x41,0xDE,0xD6,0x77,0x6F,0x85,0xD4,0x85,0x1C,0x50,0xE0,0xAE,0x51,0x8A,0xBA,0x8D, -0x3E,0x76,0xE2,0xB9,0xCA,0x27,0xF2,0x5F,0x9F,0xEF,0x6E,0x59,0x0D,0x06,0xD8,0x2B, -0x17,0xA4,0xD2,0x7C,0x6B,0xBB,0x5F,0x14,0x1A,0x48,0x8F,0x1A,0x4C,0xE7,0xB3,0x47, -0x1C,0x8E,0x4C,0x45,0x2B,0x20,0xEE,0x48,0xDF,0xE7,0xDD,0x09,0x8E,0x18,0xA8,0xDA, -0x40,0x8D,0x92,0x26,0x11,0x53,0x61,0x73,0x5D,0xEB,0xBD,0xE7,0xC4,0x4D,0x29,0x37, -0x61,0xEB,0xAC,0x39,0x2D,0x67,0x2E,0x16,0xD6,0xF5,0x00,0x83,0x85,0xA1,0xCC,0x7F, -0x76,0xC4,0x7D,0xE4,0xB7,0x4B,0x66,0xEF,0x03,0x45,0x60,0x69,0xB6,0x0C,0x52,0x96, -0x92,0x84,0x5E,0xA6,0xA3,0xB5,0xA4,0x3E,0x2B,0xD9,0xCC,0xD8,0x1B,0x47,0xAA,0xF2, -0x44,0xDA,0x4F,0xF9,0x03,0xE8,0xF0,0x14,0xCB,0x3F,0xF3,0x83,0xDE,0xD0,0xC1,0x54, -0xE3,0xB7,0xE8,0x0A,0x37,0x4D,0x8B,0x20,0x59,0x03,0x30,0x19,0xA1,0x2C,0xC8,0xBD, -0x11,0x1F,0xDF,0xAE,0xC9,0x4A,0xC5,0xF3,0x27,0x66,0x66,0x86,0xAC,0x68,0x91,0xFF, -0xD9,0xE6,0x53,0x1C,0x0F,0x8B,0x5C,0x69,0x65,0x0A,0x26,0xC8,0x1E,0x34,0xC3,0x5D, -0x51,0x7B,0xD7,0xA9,0x9C,0x06,0xA1,0x36,0xDD,0xD5,0x89,0x94,0xBC,0xD9,0xE4,0x2D, -0x0C,0x5E,0x09,0x6C,0x08,0x97,0x7C,0xA3,0x3D,0x7C,0x93,0xFF,0x3F,0xA1,0x14,0xA7, -0xCF,0xB5,0x5D,0xEB,0xDB,0xDB,0x1C,0xC4,0x76,0xDF,0x88,0xB9,0xBD,0x45,0x05,0x95, -0x1B,0xAE,0xFC,0x46,0x6A,0x4C,0xAF,0x48,0xE3,0xCE,0xAE,0x0F,0xD2,0x7E,0xEB,0xE6, -0x6C,0x9C,0x4F,0x81,0x6A,0x7A,0x64,0xAC,0xBB,0x3E,0xD5,0xE7,0xCB,0x76,0x2E,0xC5, -0xA7,0x48,0xC1,0x5C,0x90,0x0F,0xCB,0xC8,0x3F,0xFA,0xE6,0x32,0xE1,0x8D,0x1B,0x6F, -0xA4,0xE6,0x8E,0xD8,0xF9,0x29,0x48,0x8A,0xCE,0x73,0xFE,0x2C, -}; - - /* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA 2 */ /* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA 2 */ @@ -2384,67 +1393,67 @@ }; -/* subject:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ -/* issuer :/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ +/* subject:/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ +/* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -const unsigned char GlobalSign_Root_CA_certificate[889]={ -0x30,0x82,0x03,0x75,0x30,0x82,0x02,0x5D,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, -0x00,0x00,0x00,0x00,0x01,0x15,0x4B,0x5A,0xC3,0x94,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, -0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76, -0x2D,0x73,0x61,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F, -0x6F,0x74,0x20,0x43,0x41,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, -0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20, -0x43,0x41,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x39,0x30,0x31,0x31,0x32,0x30,0x30, -0x30,0x30,0x5A,0x17,0x0D,0x32,0x38,0x30,0x31,0x32,0x38,0x31,0x32,0x30,0x30,0x30, -0x30,0x5A,0x30,0x57,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, -0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62, -0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76,0x2D,0x73,0x61,0x31,0x10,0x30,0x0E, -0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x1B, -0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, -0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, -0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDA,0x0E,0xE6,0x99, -0x8D,0xCE,0xA3,0xE3,0x4F,0x8A,0x7E,0xFB,0xF1,0x8B,0x83,0x25,0x6B,0xEA,0x48,0x1F, -0xF1,0x2A,0xB0,0xB9,0x95,0x11,0x04,0xBD,0xF0,0x63,0xD1,0xE2,0x67,0x66,0xCF,0x1C, -0xDD,0xCF,0x1B,0x48,0x2B,0xEE,0x8D,0x89,0x8E,0x9A,0xAF,0x29,0x80,0x65,0xAB,0xE9, -0xC7,0x2D,0x12,0xCB,0xAB,0x1C,0x4C,0x70,0x07,0xA1,0x3D,0x0A,0x30,0xCD,0x15,0x8D, -0x4F,0xF8,0xDD,0xD4,0x8C,0x50,0x15,0x1C,0xEF,0x50,0xEE,0xC4,0x2E,0xF7,0xFC,0xE9, -0x52,0xF2,0x91,0x7D,0xE0,0x6D,0xD5,0x35,0x30,0x8E,0x5E,0x43,0x73,0xF2,0x41,0xE9, -0xD5,0x6A,0xE3,0xB2,0x89,0x3A,0x56,0x39,0x38,0x6F,0x06,0x3C,0x88,0x69,0x5B,0x2A, -0x4D,0xC5,0xA7,0x54,0xB8,0x6C,0x89,0xCC,0x9B,0xF9,0x3C,0xCA,0xE5,0xFD,0x89,0xF5, -0x12,0x3C,0x92,0x78,0x96,0xD6,0xDC,0x74,0x6E,0x93,0x44,0x61,0xD1,0x8D,0xC7,0x46, -0xB2,0x75,0x0E,0x86,0xE8,0x19,0x8A,0xD5,0x6D,0x6C,0xD5,0x78,0x16,0x95,0xA2,0xE9, -0xC8,0x0A,0x38,0xEB,0xF2,0x24,0x13,0x4F,0x73,0x54,0x93,0x13,0x85,0x3A,0x1B,0xBC, -0x1E,0x34,0xB5,0x8B,0x05,0x8C,0xB9,0x77,0x8B,0xB1,0xDB,0x1F,0x20,0x91,0xAB,0x09, -0x53,0x6E,0x90,0xCE,0x7B,0x37,0x74,0xB9,0x70,0x47,0x91,0x22,0x51,0x63,0x16,0x79, -0xAE,0xB1,0xAE,0x41,0x26,0x08,0xC8,0x19,0x2B,0xD1,0x46,0xAA,0x48,0xD6,0x64,0x2A, -0xD7,0x83,0x34,0xFF,0x2C,0x2A,0xC1,0x6C,0x19,0x43,0x4A,0x07,0x85,0xE7,0xD3,0x7C, -0xF6,0x21,0x68,0xEF,0xEA,0xF2,0x52,0x9F,0x7F,0x93,0x90,0xCF,0x02,0x03,0x01,0x00, -0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04, -0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, -0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, -0x14,0x60,0x7B,0x66,0x1A,0x45,0x0D,0x97,0xCA,0x89,0x50,0x2F,0x7D,0x04,0xCD,0x34, -0xA8,0xFF,0xFC,0xFD,0x4B,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, -0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xD6,0x73,0xE7,0x7C,0x4F,0x76,0xD0, -0x8D,0xBF,0xEC,0xBA,0xA2,0xBE,0x34,0xC5,0x28,0x32,0xB5,0x7C,0xFC,0x6C,0x9C,0x2C, -0x2B,0xBD,0x09,0x9E,0x53,0xBF,0x6B,0x5E,0xAA,0x11,0x48,0xB6,0xE5,0x08,0xA3,0xB3, -0xCA,0x3D,0x61,0x4D,0xD3,0x46,0x09,0xB3,0x3E,0xC3,0xA0,0xE3,0x63,0x55,0x1B,0xF2, -0xBA,0xEF,0xAD,0x39,0xE1,0x43,0xB9,0x38,0xA3,0xE6,0x2F,0x8A,0x26,0x3B,0xEF,0xA0, -0x50,0x56,0xF9,0xC6,0x0A,0xFD,0x38,0xCD,0xC4,0x0B,0x70,0x51,0x94,0x97,0x98,0x04, -0xDF,0xC3,0x5F,0x94,0xD5,0x15,0xC9,0x14,0x41,0x9C,0xC4,0x5D,0x75,0x64,0x15,0x0D, -0xFF,0x55,0x30,0xEC,0x86,0x8F,0xFF,0x0D,0xEF,0x2C,0xB9,0x63,0x46,0xF6,0xAA,0xFC, -0xDF,0xBC,0x69,0xFD,0x2E,0x12,0x48,0x64,0x9A,0xE0,0x95,0xF0,0xA6,0xEF,0x29,0x8F, -0x01,0xB1,0x15,0xB5,0x0C,0x1D,0xA5,0xFE,0x69,0x2C,0x69,0x24,0x78,0x1E,0xB3,0xA7, -0x1C,0x71,0x62,0xEE,0xCA,0xC8,0x97,0xAC,0x17,0x5D,0x8A,0xC2,0xF8,0x47,0x86,0x6E, -0x2A,0xC4,0x56,0x31,0x95,0xD0,0x67,0x89,0x85,0x2B,0xF9,0x6C,0xA6,0x5D,0x46,0x9D, -0x0C,0xAA,0x82,0xE4,0x99,0x51,0xDD,0x70,0xB7,0xDB,0x56,0x3D,0x61,0xE4,0x6A,0xE1, -0x5C,0xD6,0xF6,0xFE,0x3D,0xDE,0x41,0xCC,0x07,0xAE,0x63,0x52,0xBF,0x53,0x53,0xF4, -0x2B,0xE9,0xC7,0xFD,0xB6,0xF7,0x82,0x5F,0x85,0xD2,0x41,0x18,0xDB,0x81,0xB3,0x04, -0x1C,0xC5,0x1F,0xA4,0x80,0x6F,0x15,0x20,0xC9,0xDE,0x0C,0x88,0x0A,0x1D,0xD6,0x66, -0x55,0xE2,0xFC,0x48,0xC9,0x29,0x26,0x69,0xE0, +const unsigned char Baltimore_CyberTrust_Root_certificate[891]={ +0x30,0x82,0x03,0x77,0x30,0x82,0x02,0x5F,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x02, +0x00,0x00,0xB9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, +0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, +0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, +0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, +0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, +0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, +0x17,0x0D,0x30,0x30,0x30,0x35,0x31,0x32,0x31,0x38,0x34,0x36,0x30,0x30,0x5A,0x17, +0x0D,0x32,0x35,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,0x30,0x30,0x5A,0x30,0x5A, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x45,0x31,0x12,0x30, +0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72, +0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A,0x43,0x79,0x62,0x65, +0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13, +0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43,0x79,0x62,0x65,0x72, +0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xA3,0x04,0xBB,0x22,0xAB, +0x98,0x3D,0x57,0xE8,0x26,0x72,0x9A,0xB5,0x79,0xD4,0x29,0xE2,0xE1,0xE8,0x95,0x80, +0xB1,0xB0,0xE3,0x5B,0x8E,0x2B,0x29,0x9A,0x64,0xDF,0xA1,0x5D,0xED,0xB0,0x09,0x05, +0x6D,0xDB,0x28,0x2E,0xCE,0x62,0xA2,0x62,0xFE,0xB4,0x88,0xDA,0x12,0xEB,0x38,0xEB, +0x21,0x9D,0xC0,0x41,0x2B,0x01,0x52,0x7B,0x88,0x77,0xD3,0x1C,0x8F,0xC7,0xBA,0xB9, +0x88,0xB5,0x6A,0x09,0xE7,0x73,0xE8,0x11,0x40,0xA7,0xD1,0xCC,0xCA,0x62,0x8D,0x2D, +0xE5,0x8F,0x0B,0xA6,0x50,0xD2,0xA8,0x50,0xC3,0x28,0xEA,0xF5,0xAB,0x25,0x87,0x8A, +0x9A,0x96,0x1C,0xA9,0x67,0xB8,0x3F,0x0C,0xD5,0xF7,0xF9,0x52,0x13,0x2F,0xC2,0x1B, +0xD5,0x70,0x70,0xF0,0x8F,0xC0,0x12,0xCA,0x06,0xCB,0x9A,0xE1,0xD9,0xCA,0x33,0x7A, +0x77,0xD6,0xF8,0xEC,0xB9,0xF1,0x68,0x44,0x42,0x48,0x13,0xD2,0xC0,0xC2,0xA4,0xAE, +0x5E,0x60,0xFE,0xB6,0xA6,0x05,0xFC,0xB4,0xDD,0x07,0x59,0x02,0xD4,0x59,0x18,0x98, +0x63,0xF5,0xA5,0x63,0xE0,0x90,0x0C,0x7D,0x5D,0xB2,0x06,0x7A,0xF3,0x85,0xEA,0xEB, +0xD4,0x03,0xAE,0x5E,0x84,0x3E,0x5F,0xFF,0x15,0xED,0x69,0xBC,0xF9,0x39,0x36,0x72, +0x75,0xCF,0x77,0x52,0x4D,0xF3,0xC9,0x90,0x2C,0xB9,0x3D,0xE5,0xC9,0x23,0x53,0x3F, +0x1F,0x24,0x98,0x21,0x5C,0x07,0x99,0x29,0xBD,0xC6,0x3A,0xEC,0xE7,0x6E,0x86,0x3A, +0x6B,0x97,0x74,0x63,0x33,0xBD,0x68,0x18,0x31,0xF0,0x78,0x8D,0x76,0xBF,0xFC,0x9E, +0x8E,0x5D,0x2A,0x86,0xA7,0x4D,0x90,0xDC,0x27,0x1A,0x39,0x02,0x03,0x01,0x00,0x01, +0xA3,0x45,0x30,0x43,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xE5, +0x9D,0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54,0x36,0x86,0x7B,0x3A,0xB5, +0x04,0x4D,0xF0,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30, +0x06,0x01,0x01,0xFF,0x02,0x01,0x03,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x85,0x0C,0x5D,0x8E,0xE4, +0x6F,0x51,0x68,0x42,0x05,0xA0,0xDD,0xBB,0x4F,0x27,0x25,0x84,0x03,0xBD,0xF7,0x64, +0xFD,0x2D,0xD7,0x30,0xE3,0xA4,0x10,0x17,0xEB,0xDA,0x29,0x29,0xB6,0x79,0x3F,0x76, +0xF6,0x19,0x13,0x23,0xB8,0x10,0x0A,0xF9,0x58,0xA4,0xD4,0x61,0x70,0xBD,0x04,0x61, +0x6A,0x12,0x8A,0x17,0xD5,0x0A,0xBD,0xC5,0xBC,0x30,0x7C,0xD6,0xE9,0x0C,0x25,0x8D, +0x86,0x40,0x4F,0xEC,0xCC,0xA3,0x7E,0x38,0xC6,0x37,0x11,0x4F,0xED,0xDD,0x68,0x31, +0x8E,0x4C,0xD2,0xB3,0x01,0x74,0xEE,0xBE,0x75,0x5E,0x07,0x48,0x1A,0x7F,0x70,0xFF, +0x16,0x5C,0x84,0xC0,0x79,0x85,0xB8,0x05,0xFD,0x7F,0xBE,0x65,0x11,0xA3,0x0F,0xC0, +0x02,0xB4,0xF8,0x52,0x37,0x39,0x04,0xD5,0xA9,0x31,0x7A,0x18,0xBF,0xA0,0x2A,0xF4, +0x12,0x99,0xF7,0xA3,0x45,0x82,0xE3,0x3C,0x5E,0xF5,0x9D,0x9E,0xB5,0xC8,0x9E,0x7C, +0x2E,0xC8,0xA4,0x9E,0x4E,0x08,0x14,0x4B,0x6D,0xFD,0x70,0x6D,0x6B,0x1A,0x63,0xBD, +0x64,0xE6,0x1F,0xB7,0xCE,0xF0,0xF2,0x9F,0x2E,0xBB,0x1B,0xB7,0xF2,0x50,0x88,0x73, +0x92,0xC2,0xE2,0xE3,0x16,0x8D,0x9A,0x32,0x02,0xAB,0x8E,0x18,0xDD,0xE9,0x10,0x11, +0xEE,0x7E,0x35,0xAB,0x90,0xAF,0x3E,0x30,0x94,0x7A,0xD0,0x33,0x3D,0xA7,0x65,0x0F, +0xF5,0xFC,0x8E,0x9E,0x62,0xCF,0x47,0x44,0x2C,0x01,0x5D,0xBB,0x1D,0xB5,0x32,0xD2, +0x47,0xD2,0x38,0x2E,0xD0,0xFE,0x81,0xDC,0x32,0x6A,0x1E,0xB5,0xEE,0x3C,0xD5,0xFC, +0xE7,0x81,0x1D,0x19,0xC3,0x24,0x42,0xEA,0x63,0x39,0xA9, }; @@ -2579,1249 +1588,140 @@ }; -/* subject:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority */ -/* issuer :/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority */ +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Networking */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Networking */ -const unsigned char Go_Daddy_Class_2_CA_certificate[1028]={ -0x30,0x82,0x04,0x00,0x30,0x82,0x02,0xE8,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21, -0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20, -0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63, -0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44, -0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72, -0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, -0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x36,0x32,0x39,0x31,0x37, -0x30,0x36,0x32,0x30,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36,0x32,0x39,0x31,0x37,0x30, -0x36,0x32,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68, -0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70, -0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13, -0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, -0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, -0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D, -0x00,0x30,0x82,0x01,0x08,0x02,0x82,0x01,0x01,0x00,0xDE,0x9D,0xD7,0xEA,0x57,0x18, -0x49,0xA1,0x5B,0xEB,0xD7,0x5F,0x48,0x86,0xEA,0xBE,0xDD,0xFF,0xE4,0xEF,0x67,0x1C, -0xF4,0x65,0x68,0xB3,0x57,0x71,0xA0,0x5E,0x77,0xBB,0xED,0x9B,0x49,0xE9,0x70,0x80, -0x3D,0x56,0x18,0x63,0x08,0x6F,0xDA,0xF2,0xCC,0xD0,0x3F,0x7F,0x02,0x54,0x22,0x54, -0x10,0xD8,0xB2,0x81,0xD4,0xC0,0x75,0x3D,0x4B,0x7F,0xC7,0x77,0xC3,0x3E,0x78,0xAB, -0x1A,0x03,0xB5,0x20,0x6B,0x2F,0x6A,0x2B,0xB1,0xC5,0x88,0x7E,0xC4,0xBB,0x1E,0xB0, -0xC1,0xD8,0x45,0x27,0x6F,0xAA,0x37,0x58,0xF7,0x87,0x26,0xD7,0xD8,0x2D,0xF6,0xA9, -0x17,0xB7,0x1F,0x72,0x36,0x4E,0xA6,0x17,0x3F,0x65,0x98,0x92,0xDB,0x2A,0x6E,0x5D, -0xA2,0xFE,0x88,0xE0,0x0B,0xDE,0x7F,0xE5,0x8D,0x15,0xE1,0xEB,0xCB,0x3A,0xD5,0xE2, -0x12,0xA2,0x13,0x2D,0xD8,0x8E,0xAF,0x5F,0x12,0x3D,0xA0,0x08,0x05,0x08,0xB6,0x5C, -0xA5,0x65,0x38,0x04,0x45,0x99,0x1E,0xA3,0x60,0x60,0x74,0xC5,0x41,0xA5,0x72,0x62, -0x1B,0x62,0xC5,0x1F,0x6F,0x5F,0x1A,0x42,0xBE,0x02,0x51,0x65,0xA8,0xAE,0x23,0x18, -0x6A,0xFC,0x78,0x03,0xA9,0x4D,0x7F,0x80,0xC3,0xFA,0xAB,0x5A,0xFC,0xA1,0x40,0xA4, -0xCA,0x19,0x16,0xFE,0xB2,0xC8,0xEF,0x5E,0x73,0x0D,0xEE,0x77,0xBD,0x9A,0xF6,0x79, -0x98,0xBC,0xB1,0x07,0x67,0xA2,0x15,0x0D,0xDD,0xA0,0x58,0xC6,0x44,0x7B,0x0A,0x3E, -0x62,0x28,0x5F,0xBA,0x41,0x07,0x53,0x58,0xCF,0x11,0x7E,0x38,0x74,0xC5,0xF8,0xFF, -0xB5,0x69,0x90,0x8F,0x84,0x74,0xEA,0x97,0x1B,0xAF,0x02,0x01,0x03,0xA3,0x81,0xC0, -0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xD2,0xC4, -0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1,0xFE,0xDD,0xA8,0x6A, -0xD4,0xE3,0x30,0x81,0x8D,0x06,0x03,0x55,0x1D,0x23,0x04,0x81,0x85,0x30,0x81,0x82, -0x80,0x14,0xD2,0xC4,0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1, -0xFE,0xDD,0xA8,0x6A,0xD4,0xE3,0xA1,0x67,0xA4,0x65,0x30,0x63,0x31,0x0B,0x30,0x09, -0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, -0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79, -0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F, -0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20, -0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, -0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82, -0x01,0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, -0x82,0x01,0x01,0x00,0x32,0x4B,0xF3,0xB2,0xCA,0x3E,0x91,0xFC,0x12,0xC6,0xA1,0x07, -0x8C,0x8E,0x77,0xA0,0x33,0x06,0x14,0x5C,0x90,0x1E,0x18,0xF7,0x08,0xA6,0x3D,0x0A, -0x19,0xF9,0x87,0x80,0x11,0x6E,0x69,0xE4,0x96,0x17,0x30,0xFF,0x34,0x91,0x63,0x72, -0x38,0xEE,0xCC,0x1C,0x01,0xA3,0x1D,0x94,0x28,0xA4,0x31,0xF6,0x7A,0xC4,0x54,0xD7, -0xF6,0xE5,0x31,0x58,0x03,0xA2,0xCC,0xCE,0x62,0xDB,0x94,0x45,0x73,0xB5,0xBF,0x45, -0xC9,0x24,0xB5,0xD5,0x82,0x02,0xAD,0x23,0x79,0x69,0x8D,0xB8,0xB6,0x4D,0xCE,0xCF, -0x4C,0xCA,0x33,0x23,0xE8,0x1C,0x88,0xAA,0x9D,0x8B,0x41,0x6E,0x16,0xC9,0x20,0xE5, -0x89,0x9E,0xCD,0x3B,0xDA,0x70,0xF7,0x7E,0x99,0x26,0x20,0x14,0x54,0x25,0xAB,0x6E, -0x73,0x85,0xE6,0x9B,0x21,0x9D,0x0A,0x6C,0x82,0x0E,0xA8,0xF8,0xC2,0x0C,0xFA,0x10, -0x1E,0x6C,0x96,0xEF,0x87,0x0D,0xC4,0x0F,0x61,0x8B,0xAD,0xEE,0x83,0x2B,0x95,0xF8, -0x8E,0x92,0x84,0x72,0x39,0xEB,0x20,0xEA,0x83,0xED,0x83,0xCD,0x97,0x6E,0x08,0xBC, -0xEB,0x4E,0x26,0xB6,0x73,0x2B,0xE4,0xD3,0xF6,0x4C,0xFE,0x26,0x71,0xE2,0x61,0x11, -0x74,0x4A,0xFF,0x57,0x1A,0x87,0x0F,0x75,0x48,0x2E,0xCF,0x51,0x69,0x17,0xA0,0x02, -0x12,0x61,0x95,0xD5,0xD1,0x40,0xB2,0x10,0x4C,0xEE,0xC4,0xAC,0x10,0x43,0xA6,0xA5, -0x9E,0x0A,0xD5,0x95,0x62,0x9A,0x0D,0xCF,0x88,0x82,0xC5,0x32,0x0C,0xE4,0x2B,0x9F, -0x45,0xE6,0x0D,0x9F,0x28,0x9C,0xB1,0xB9,0x2A,0x5A,0x57,0xAD,0x37,0x0F,0xAF,0x1D, -0x7F,0xDB,0xBD,0x9F, -}; - - -/* subject:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2 */ -/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2 */ - - -const unsigned char Go_Daddy_Root_Certificate_Authority___G2_certificate[969]={ -0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, -0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, -0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, -0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, -0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13, -0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63,0x6F,0x6D,0x2C,0x20,0x49,0x6E, -0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28,0x47,0x6F,0x20, -0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, -0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30, -0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33, -0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, -0x06,0x13,0x02,0x55,0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07, -0x41,0x72,0x69,0x7A,0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07, -0x13,0x0A,0x53,0x63,0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18, -0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63, -0x6F,0x6D,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04, -0x03,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74, -0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74, -0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, -0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBF,0x71,0x62,0x08, -0xF1,0xFA,0x59,0x34,0xF7,0x1B,0xC9,0x18,0xA3,0xF7,0x80,0x49,0x58,0xE9,0x22,0x83, -0x13,0xA6,0xC5,0x20,0x43,0x01,0x3B,0x84,0xF1,0xE6,0x85,0x49,0x9F,0x27,0xEA,0xF6, -0x84,0x1B,0x4E,0xA0,0xB4,0xDB,0x70,0x98,0xC7,0x32,0x01,0xB1,0x05,0x3E,0x07,0x4E, -0xEE,0xF4,0xFA,0x4F,0x2F,0x59,0x30,0x22,0xE7,0xAB,0x19,0x56,0x6B,0xE2,0x80,0x07, -0xFC,0xF3,0x16,0x75,0x80,0x39,0x51,0x7B,0xE5,0xF9,0x35,0xB6,0x74,0x4E,0xA9,0x8D, -0x82,0x13,0xE4,0xB6,0x3F,0xA9,0x03,0x83,0xFA,0xA2,0xBE,0x8A,0x15,0x6A,0x7F,0xDE, -0x0B,0xC3,0xB6,0x19,0x14,0x05,0xCA,0xEA,0xC3,0xA8,0x04,0x94,0x3B,0x46,0x7C,0x32, -0x0D,0xF3,0x00,0x66,0x22,0xC8,0x8D,0x69,0x6D,0x36,0x8C,0x11,0x18,0xB7,0xD3,0xB2, -0x1C,0x60,0xB4,0x38,0xFA,0x02,0x8C,0xCE,0xD3,0xDD,0x46,0x07,0xDE,0x0A,0x3E,0xEB, -0x5D,0x7C,0xC8,0x7C,0xFB,0xB0,0x2B,0x53,0xA4,0x92,0x62,0x69,0x51,0x25,0x05,0x61, -0x1A,0x44,0x81,0x8C,0x2C,0xA9,0x43,0x96,0x23,0xDF,0xAC,0x3A,0x81,0x9A,0x0E,0x29, -0xC5,0x1C,0xA9,0xE9,0x5D,0x1E,0xB6,0x9E,0x9E,0x30,0x0A,0x39,0xCE,0xF1,0x88,0x80, -0xFB,0x4B,0x5D,0xCC,0x32,0xEC,0x85,0x62,0x43,0x25,0x34,0x02,0x56,0x27,0x01,0x91, -0xB4,0x3B,0x70,0x2A,0x3F,0x6E,0xB1,0xE8,0x9C,0x88,0x01,0x7D,0x9F,0xD4,0xF9,0xDB, -0x53,0x6D,0x60,0x9D,0xBF,0x2C,0xE7,0x58,0xAB,0xB8,0x5F,0x46,0xFC,0xCE,0xC4,0x1B, -0x03,0x3C,0x09,0xEB,0x49,0x31,0x5C,0x69,0x46,0xB3,0xE0,0x47,0x02,0x03,0x01,0x00, -0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, -0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, -0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, -0x14,0x3A,0x9A,0x85,0x07,0x10,0x67,0x28,0xB6,0xEF,0xF6,0xBD,0x05,0x41,0x6E,0x20, -0xC1,0x94,0xDA,0x0F,0xDE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, -0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x99,0xDB,0x5D,0x79,0xD5,0xF9,0x97, -0x59,0x67,0x03,0x61,0xF1,0x7E,0x3B,0x06,0x31,0x75,0x2D,0xA1,0x20,0x8E,0x4F,0x65, -0x87,0xB4,0xF7,0xA6,0x9C,0xBC,0xD8,0xE9,0x2F,0xD0,0xDB,0x5A,0xEE,0xCF,0x74,0x8C, -0x73,0xB4,0x38,0x42,0xDA,0x05,0x7B,0xF8,0x02,0x75,0xB8,0xFD,0xA5,0xB1,0xD7,0xAE, -0xF6,0xD7,0xDE,0x13,0xCB,0x53,0x10,0x7E,0x8A,0x46,0xD1,0x97,0xFA,0xB7,0x2E,0x2B, -0x11,0xAB,0x90,0xB0,0x27,0x80,0xF9,0xE8,0x9F,0x5A,0xE9,0x37,0x9F,0xAB,0xE4,0xDF, -0x6C,0xB3,0x85,0x17,0x9D,0x3D,0xD9,0x24,0x4F,0x79,0x91,0x35,0xD6,0x5F,0x04,0xEB, -0x80,0x83,0xAB,0x9A,0x02,0x2D,0xB5,0x10,0xF4,0xD8,0x90,0xC7,0x04,0x73,0x40,0xED, -0x72,0x25,0xA0,0xA9,0x9F,0xEC,0x9E,0xAB,0x68,0x12,0x99,0x57,0xC6,0x8F,0x12,0x3A, -0x09,0xA4,0xBD,0x44,0xFD,0x06,0x15,0x37,0xC1,0x9B,0xE4,0x32,0xA3,0xED,0x38,0xE8, -0xD8,0x64,0xF3,0x2C,0x7E,0x14,0xFC,0x02,0xEA,0x9F,0xCD,0xFF,0x07,0x68,0x17,0xDB, -0x22,0x90,0x38,0x2D,0x7A,0x8D,0xD1,0x54,0xF1,0x69,0xE3,0x5F,0x33,0xCA,0x7A,0x3D, -0x7B,0x0A,0xE3,0xCA,0x7F,0x5F,0x39,0xE5,0xE2,0x75,0xBA,0xC5,0x76,0x18,0x33,0xCE, -0x2C,0xF0,0x2F,0x4C,0xAD,0xF7,0xB1,0xE7,0xCE,0x4F,0xA8,0xC4,0x9B,0x4A,0x54,0x06, -0xC5,0x7F,0x7D,0xD5,0x08,0x0F,0xE2,0x1C,0xFE,0x7E,0x17,0xB8,0xAC,0x5E,0xF6,0xD4, -0x16,0xB2,0x43,0x09,0x0C,0x4D,0xF6,0xA7,0x6B,0xB4,0x99,0x84,0x65,0xCA,0x7A,0x88, -0xE2,0xE2,0x44,0xBE,0x5C,0xF7,0xEA,0x1C,0xF5, -}; - - -/* subject:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root */ -/* issuer :/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root */ - - -const unsigned char GTE_CyberTrust_Global_Root_certificate[606]={ -0x30,0x82,0x02,0x5A,0x30,0x82,0x01,0xC3,0x02,0x02,0x01,0xA5,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30,0x75,0x31,0x0B,0x30, -0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x18,0x30,0x16,0x06,0x03, -0x55,0x04,0x0A,0x13,0x0F,0x47,0x54,0x45,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61, -0x74,0x69,0x6F,0x6E,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x0B,0x13,0x1E,0x47, -0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x6F, -0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x23,0x30, -0x21,0x06,0x03,0x55,0x04,0x03,0x13,0x1A,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65, -0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F, -0x6F,0x74,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x38,0x31,0x33,0x30,0x30,0x32,0x39, -0x30,0x30,0x5A,0x17,0x0D,0x31,0x38,0x30,0x38,0x31,0x33,0x32,0x33,0x35,0x39,0x30, -0x30,0x5A,0x30,0x75,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, -0x53,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,0x0A,0x13,0x0F,0x47,0x54,0x45,0x20, -0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x27,0x30,0x25,0x06, -0x03,0x55,0x04,0x0B,0x13,0x1E,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54, -0x72,0x75,0x73,0x74,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x2C,0x20, -0x49,0x6E,0x63,0x2E,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x13,0x1A,0x47, -0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C, -0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09, -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30, -0x81,0x89,0x02,0x81,0x81,0x00,0x95,0x0F,0xA0,0xB6,0xF0,0x50,0x9C,0xE8,0x7A,0xC7, -0x88,0xCD,0xDD,0x17,0x0E,0x2E,0xB0,0x94,0xD0,0x1B,0x3D,0x0E,0xF6,0x94,0xC0,0x8A, -0x94,0xC7,0x06,0xC8,0x90,0x97,0xC8,0xB8,0x64,0x1A,0x7A,0x7E,0x6C,0x3C,0x53,0xE1, -0x37,0x28,0x73,0x60,0x7F,0xB2,0x97,0x53,0x07,0x9F,0x53,0xF9,0x6D,0x58,0x94,0xD2, -0xAF,0x8D,0x6D,0x88,0x67,0x80,0xE6,0xED,0xB2,0x95,0xCF,0x72,0x31,0xCA,0xA5,0x1C, -0x72,0xBA,0x5C,0x02,0xE7,0x64,0x42,0xE7,0xF9,0xA9,0x2C,0xD6,0x3A,0x0D,0xAC,0x8D, -0x42,0xAA,0x24,0x01,0x39,0xE6,0x9C,0x3F,0x01,0x85,0x57,0x0D,0x58,0x87,0x45,0xF8, -0xD3,0x85,0xAA,0x93,0x69,0x26,0x85,0x70,0x48,0x80,0x3F,0x12,0x15,0xC7,0x79,0xB4, -0x1F,0x05,0x2F,0x3B,0x62,0x99,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A, -0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x03,0x81,0x81,0x00,0x6D,0xEB, -0x1B,0x09,0xE9,0x5E,0xD9,0x51,0xDB,0x67,0x22,0x61,0xA4,0x2A,0x3C,0x48,0x77,0xE3, -0xA0,0x7C,0xA6,0xDE,0x73,0xA2,0x14,0x03,0x85,0x3D,0xFB,0xAB,0x0E,0x30,0xC5,0x83, -0x16,0x33,0x81,0x13,0x08,0x9E,0x7B,0x34,0x4E,0xDF,0x40,0xC8,0x74,0xD7,0xB9,0x7D, -0xDC,0xF4,0x76,0x55,0x7D,0x9B,0x63,0x54,0x18,0xE9,0xF0,0xEA,0xF3,0x5C,0xB1,0xD9, -0x8B,0x42,0x1E,0xB9,0xC0,0x95,0x4E,0xBA,0xFA,0xD5,0xE2,0x7C,0xF5,0x68,0x61,0xBF, -0x8E,0xEC,0x05,0x97,0x5F,0x5B,0xB0,0xD7,0xA3,0x85,0x34,0xC4,0x24,0xA7,0x0D,0x0F, -0x95,0x93,0xEF,0xCB,0x94,0xD8,0x9E,0x1F,0x9D,0x5C,0x85,0x6D,0xC7,0xAA,0xAE,0x4F, -0x1F,0x22,0xB5,0xCD,0x95,0xAD,0xBA,0xA7,0xCC,0xF9,0xAB,0x0B,0x7A,0x7F, -}; - - -/* subject:/C=US/O=Network Solutions L.L.C./CN=Network Solutions Certificate Authority */ -/* issuer :/C=US/O=Network Solutions L.L.C./CN=Network Solutions Certificate Authority */ - - -const unsigned char Network_Solutions_Certificate_Authority_certificate[1002]={ -0x30,0x82,0x03,0xE6,0x30,0x82,0x02,0xCE,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x57, -0xCB,0x33,0x6F,0xC2,0x5C,0x16,0xE6,0x47,0x16,0x17,0xE3,0x90,0x31,0x68,0xE0,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x62, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21,0x30, -0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x20, -0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x20,0x4C,0x2E,0x4C,0x2E,0x43,0x2E, -0x31,0x30,0x30,0x2E,0x06,0x03,0x55,0x04,0x03,0x13,0x27,0x4E,0x65,0x74,0x77,0x6F, -0x72,0x6B,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x20,0x43,0x65,0x72, -0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x30, -0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, -0x39,0x5A,0x30,0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, -0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x4E,0x65,0x74,0x77, -0x6F,0x72,0x6B,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x20,0x4C,0x2E, -0x4C,0x2E,0x43,0x2E,0x31,0x30,0x30,0x2E,0x06,0x03,0x55,0x04,0x03,0x13,0x27,0x4E, -0x65,0x74,0x77,0x6F,0x72,0x6B,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73, -0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74, -0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, -0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xE4,0xBC,0x7E,0x92,0x30,0x6D,0xC6,0xD8,0x8E, -0x2B,0x0B,0xBC,0x46,0xCE,0xE0,0x27,0x96,0xDE,0xDE,0xF9,0xFA,0x12,0xD3,0x3C,0x33, -0x73,0xB3,0x04,0x2F,0xBC,0x71,0x8C,0xE5,0x9F,0xB6,0x22,0x60,0x3E,0x5F,0x5D,0xCE, -0x09,0xFF,0x82,0x0C,0x1B,0x9A,0x51,0x50,0x1A,0x26,0x89,0xDD,0xD5,0x61,0x5D,0x19, -0xDC,0x12,0x0F,0x2D,0x0A,0xA2,0x43,0x5D,0x17,0xD0,0x34,0x92,0x20,0xEA,0x73,0xCF, -0x38,0x2C,0x06,0x26,0x09,0x7A,0x72,0xF7,0xFA,0x50,0x32,0xF8,0xC2,0x93,0xD3,0x69, -0xA2,0x23,0xCE,0x41,0xB1,0xCC,0xE4,0xD5,0x1F,0x36,0xD1,0x8A,0x3A,0xF8,0x8C,0x63, -0xE2,0x14,0x59,0x69,0xED,0x0D,0xD3,0x7F,0x6B,0xE8,0xB8,0x03,0xE5,0x4F,0x6A,0xE5, -0x98,0x63,0x69,0x48,0x05,0xBE,0x2E,0xFF,0x33,0xB6,0xE9,0x97,0x59,0x69,0xF8,0x67, -0x19,0xAE,0x93,0x61,0x96,0x44,0x15,0xD3,0x72,0xB0,0x3F,0xBC,0x6A,0x7D,0xEC,0x48, -0x7F,0x8D,0xC3,0xAB,0xAA,0x71,0x2B,0x53,0x69,0x41,0x53,0x34,0xB5,0xB0,0xB9,0xC5, -0x06,0x0A,0xC4,0xB0,0x45,0xF5,0x41,0x5D,0x6E,0x89,0x45,0x7B,0x3D,0x3B,0x26,0x8C, -0x74,0xC2,0xE5,0xD2,0xD1,0x7D,0xB2,0x11,0xD4,0xFB,0x58,0x32,0x22,0x9A,0x80,0xC9, -0xDC,0xFD,0x0C,0xE9,0x7F,0x5E,0x03,0x97,0xCE,0x3B,0x00,0x14,0x87,0x27,0x70,0x38, -0xA9,0x8E,0x6E,0xB3,0x27,0x76,0x98,0x51,0xE0,0x05,0xE3,0x21,0xAB,0x1A,0xD5,0x85, -0x22,0x3C,0x29,0xB5,0x9A,0x16,0xC5,0x80,0xA8,0xF4,0xBB,0x6B,0x30,0x8F,0x2F,0x46, -0x02,0xA2,0xB1,0x0C,0x22,0xE0,0xD3,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x97,0x30, -0x81,0x94,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x21,0x30,0xC9, -0xFB,0x00,0xD7,0x4E,0x98,0xDA,0x87,0xAA,0x2A,0xD0,0xA7,0x2E,0xB1,0x40,0x31,0xA7, -0x4C,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, -0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, -0x01,0xFF,0x30,0x52,0x06,0x03,0x55,0x1D,0x1F,0x04,0x4B,0x30,0x49,0x30,0x47,0xA0, -0x45,0xA0,0x43,0x86,0x41,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E, -0x6E,0x65,0x74,0x73,0x6F,0x6C,0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x4E,0x65, -0x74,0x77,0x6F,0x72,0x6B,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x43,0x65, -0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xBB,0xAE,0x4B,0xE7,0xB7,0x57, -0xEB,0x7F,0xAA,0x2D,0xB7,0x73,0x47,0x85,0x6A,0xC1,0xE4,0xA5,0x1D,0xE4,0xE7,0x3C, -0xE9,0xF4,0x59,0x65,0x77,0xB5,0x7A,0x5B,0x5A,0x8D,0x25,0x36,0xE0,0x7A,0x97,0x2E, -0x38,0xC0,0x57,0x60,0x83,0x98,0x06,0x83,0x9F,0xB9,0x76,0x7A,0x6E,0x50,0xE0,0xBA, -0x88,0x2C,0xFC,0x45,0xCC,0x18,0xB0,0x99,0x95,0x51,0x0E,0xEC,0x1D,0xB8,0x88,0xFF, -0x87,0x50,0x1C,0x82,0xC2,0xE3,0xE0,0x32,0x80,0xBF,0xA0,0x0B,0x47,0xC8,0xC3,0x31, -0xEF,0x99,0x67,0x32,0x80,0x4F,0x17,0x21,0x79,0x0C,0x69,0x5C,0xDE,0x5E,0x34,0xAE, -0x02,0xB5,0x26,0xEA,0x50,0xDF,0x7F,0x18,0x65,0x2C,0xC9,0xF2,0x63,0xE1,0xA9,0x07, -0xFE,0x7C,0x71,0x1F,0x6B,0x33,0x24,0x6A,0x1E,0x05,0xF7,0x05,0x68,0xC0,0x6A,0x12, -0xCB,0x2E,0x5E,0x61,0xCB,0xAE,0x28,0xD3,0x7E,0xC2,0xB4,0x66,0x91,0x26,0x5F,0x3C, -0x2E,0x24,0x5F,0xCB,0x58,0x0F,0xEB,0x28,0xEC,0xAF,0x11,0x96,0xF3,0xDC,0x7B,0x6F, -0xC0,0xA7,0x88,0xF2,0x53,0x77,0xB3,0x60,0x5E,0xAE,0xAE,0x28,0xDA,0x35,0x2C,0x6F, -0x34,0x45,0xD3,0x26,0xE1,0xDE,0xEC,0x5B,0x4F,0x27,0x6B,0x16,0x7C,0xBD,0x44,0x04, -0x18,0x82,0xB3,0x89,0x79,0x17,0x10,0x71,0x3D,0x7A,0xA2,0x16,0x4E,0xF5,0x01,0xCD, -0xA4,0x6C,0x65,0x68,0xA1,0x49,0x76,0x5C,0x43,0xC9,0xD8,0xBC,0x36,0x67,0x6C,0xA5, -0x94,0xB5,0xD4,0xCC,0xB9,0xBD,0x6A,0x35,0x56,0x21,0xDE,0xD8,0xC3,0xEB,0xFB,0xCB, -0xA4,0x60,0x4C,0xB0,0x55,0xA0,0xA0,0x7B,0x57,0xB2, -}; - - -/* subject:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 3 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ -/* issuer :/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 3 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ - - -const unsigned char RSA_Root_Certificate_1_certificate[747]={ -0x30,0x82,0x02,0xE7,0x30,0x82,0x02,0x50,0x02,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A, -0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xBB,0x31,0x24,0x30, -0x22,0x06,0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74, -0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77, -0x6F,0x72,0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61, -0x6C,0x69,0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33, -0x06,0x03,0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20, -0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56, -0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74, -0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72, -0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69, -0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36, -0x32,0x36,0x30,0x30,0x32,0x32,0x33,0x33,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32, -0x36,0x30,0x30,0x32,0x32,0x33,0x33,0x5A,0x30,0x81,0xBB,0x31,0x24,0x30,0x22,0x06, -0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x56, -0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, -0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61,0x6C,0x69, -0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33,0x06,0x03, -0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x43,0x6C, -0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56,0x61,0x6C, -0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, -0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74,0x74,0x70, -0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72,0x74,0x2E, -0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69,0x63,0x65, -0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, -0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02, -0x81,0x81,0x00,0xE3,0x98,0x51,0x96,0x1C,0xE8,0xD5,0xB1,0x06,0x81,0x6A,0x57,0xC3, -0x72,0x75,0x93,0xAB,0xCF,0x9E,0xA6,0xFC,0xF3,0x16,0x52,0xD6,0x2D,0x4D,0x9F,0x35, -0x44,0xA8,0x2E,0x04,0x4D,0x07,0x49,0x8A,0x38,0x29,0xF5,0x77,0x37,0xE7,0xB7,0xAB, -0x5D,0xDF,0x36,0x71,0x14,0x99,0x8F,0xDC,0xC2,0x92,0xF1,0xE7,0x60,0x92,0x97,0xEC, -0xD8,0x48,0xDC,0xBF,0xC1,0x02,0x20,0xC6,0x24,0xA4,0x28,0x4C,0x30,0x5A,0x76,0x6D, -0xB1,0x5C,0xF3,0xDD,0xDE,0x9E,0x10,0x71,0xA1,0x88,0xC7,0x5B,0x9B,0x41,0x6D,0xCA, -0xB0,0xB8,0x8E,0x15,0xEE,0xAD,0x33,0x2B,0xCF,0x47,0x04,0x5C,0x75,0x71,0x0A,0x98, -0x24,0x98,0x29,0xA7,0x49,0x59,0xA5,0xDD,0xF8,0xB7,0x43,0x62,0x61,0xF3,0xD3,0xE2, -0xD0,0x55,0x3F,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x56,0xBB,0x02,0x58,0x84, -0x67,0x08,0x2C,0xDF,0x1F,0xDB,0x7B,0x49,0x33,0xF5,0xD3,0x67,0x9D,0xF4,0xB4,0x0A, -0x10,0xB3,0xC9,0xC5,0x2C,0xE2,0x92,0x6A,0x71,0x78,0x27,0xF2,0x70,0x83,0x42,0xD3, -0x3E,0xCF,0xA9,0x54,0xF4,0xF1,0xD8,0x92,0x16,0x8C,0xD1,0x04,0xCB,0x4B,0xAB,0xC9, -0x9F,0x45,0xAE,0x3C,0x8A,0xA9,0xB0,0x71,0x33,0x5D,0xC8,0xC5,0x57,0xDF,0xAF,0xA8, -0x35,0xB3,0x7F,0x89,0x87,0xE9,0xE8,0x25,0x92,0xB8,0x7F,0x85,0x7A,0xAE,0xD6,0xBC, -0x1E,0x37,0x58,0x2A,0x67,0xC9,0x91,0xCF,0x2A,0x81,0x3E,0xED,0xC6,0x39,0xDF,0xC0, -0x3E,0x19,0x9C,0x19,0xCC,0x13,0x4D,0x82,0x41,0xB5,0x8C,0xDE,0xE0,0x3D,0x60,0x08, -0x20,0x0F,0x45,0x7E,0x6B,0xA2,0x7F,0xA3,0x8C,0x15,0xEE, -}; - - -/* subject:/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority */ -/* issuer :/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority */ - - -const unsigned char Starfield_Class_2_CA_certificate[1043]={ -0x30,0x82,0x04,0x0F,0x30,0x82,0x02,0xF7,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, -0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25, -0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65, -0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C, -0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29, -0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, -0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, -0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30, -0x36,0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36, -0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, -0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, -0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, -0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, -0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74, -0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D,0x00,0x30,0x82,0x01,0x08,0x02, -0x82,0x01,0x01,0x00,0xB7,0x32,0xC8,0xFE,0xE9,0x71,0xA6,0x04,0x85,0xAD,0x0C,0x11, -0x64,0xDF,0xCE,0x4D,0xEF,0xC8,0x03,0x18,0x87,0x3F,0xA1,0xAB,0xFB,0x3C,0xA6,0x9F, -0xF0,0xC3,0xA1,0xDA,0xD4,0xD8,0x6E,0x2B,0x53,0x90,0xFB,0x24,0xA4,0x3E,0x84,0xF0, -0x9E,0xE8,0x5F,0xEC,0xE5,0x27,0x44,0xF5,0x28,0xA6,0x3F,0x7B,0xDE,0xE0,0x2A,0xF0, -0xC8,0xAF,0x53,0x2F,0x9E,0xCA,0x05,0x01,0x93,0x1E,0x8F,0x66,0x1C,0x39,0xA7,0x4D, -0xFA,0x5A,0xB6,0x73,0x04,0x25,0x66,0xEB,0x77,0x7F,0xE7,0x59,0xC6,0x4A,0x99,0x25, -0x14,0x54,0xEB,0x26,0xC7,0xF3,0x7F,0x19,0xD5,0x30,0x70,0x8F,0xAF,0xB0,0x46,0x2A, -0xFF,0xAD,0xEB,0x29,0xED,0xD7,0x9F,0xAA,0x04,0x87,0xA3,0xD4,0xF9,0x89,0xA5,0x34, -0x5F,0xDB,0x43,0x91,0x82,0x36,0xD9,0x66,0x3C,0xB1,0xB8,0xB9,0x82,0xFD,0x9C,0x3A, -0x3E,0x10,0xC8,0x3B,0xEF,0x06,0x65,0x66,0x7A,0x9B,0x19,0x18,0x3D,0xFF,0x71,0x51, -0x3C,0x30,0x2E,0x5F,0xBE,0x3D,0x77,0x73,0xB2,0x5D,0x06,0x6C,0xC3,0x23,0x56,0x9A, -0x2B,0x85,0x26,0x92,0x1C,0xA7,0x02,0xB3,0xE4,0x3F,0x0D,0xAF,0x08,0x79,0x82,0xB8, -0x36,0x3D,0xEA,0x9C,0xD3,0x35,0xB3,0xBC,0x69,0xCA,0xF5,0xCC,0x9D,0xE8,0xFD,0x64, -0x8D,0x17,0x80,0x33,0x6E,0x5E,0x4A,0x5D,0x99,0xC9,0x1E,0x87,0xB4,0x9D,0x1A,0xC0, -0xD5,0x6E,0x13,0x35,0x23,0x5E,0xDF,0x9B,0x5F,0x3D,0xEF,0xD6,0xF7,0x76,0xC2,0xEA, -0x3E,0xBB,0x78,0x0D,0x1C,0x42,0x67,0x6B,0x04,0xD8,0xF8,0xD6,0xDA,0x6F,0x8B,0xF2, -0x44,0xA0,0x01,0xAB,0x02,0x01,0x03,0xA3,0x81,0xC5,0x30,0x81,0xC2,0x30,0x1D,0x06, -0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBF,0x5F,0xB7,0xD1,0xCE,0xDD,0x1F,0x86, -0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7,0x30,0x81,0x92,0x06, -0x03,0x55,0x1D,0x23,0x04,0x81,0x8A,0x30,0x81,0x87,0x80,0x14,0xBF,0x5F,0xB7,0xD1, -0xCE,0xDD,0x1F,0x86,0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7, -0xA1,0x6C,0xA4,0x6A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74, -0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F, -0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03, -0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43, -0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, -0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82,0x01, -0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, -0x01,0x01,0x00,0x05,0x9D,0x3F,0x88,0x9D,0xD1,0xC9,0x1A,0x55,0xA1,0xAC,0x69,0xF3, -0xF3,0x59,0xDA,0x9B,0x01,0x87,0x1A,0x4F,0x57,0xA9,0xA1,0x79,0x09,0x2A,0xDB,0xF7, -0x2F,0xB2,0x1E,0xCC,0xC7,0x5E,0x6A,0xD8,0x83,0x87,0xA1,0x97,0xEF,0x49,0x35,0x3E, -0x77,0x06,0x41,0x58,0x62,0xBF,0x8E,0x58,0xB8,0x0A,0x67,0x3F,0xEC,0xB3,0xDD,0x21, -0x66,0x1F,0xC9,0x54,0xFA,0x72,0xCC,0x3D,0x4C,0x40,0xD8,0x81,0xAF,0x77,0x9E,0x83, -0x7A,0xBB,0xA2,0xC7,0xF5,0x34,0x17,0x8E,0xD9,0x11,0x40,0xF4,0xFC,0x2C,0x2A,0x4D, -0x15,0x7F,0xA7,0x62,0x5D,0x2E,0x25,0xD3,0x00,0x0B,0x20,0x1A,0x1D,0x68,0xF9,0x17, -0xB8,0xF4,0xBD,0x8B,0xED,0x28,0x59,0xDD,0x4D,0x16,0x8B,0x17,0x83,0xC8,0xB2,0x65, -0xC7,0x2D,0x7A,0xA5,0xAA,0xBC,0x53,0x86,0x6D,0xDD,0x57,0xA4,0xCA,0xF8,0x20,0x41, -0x0B,0x68,0xF0,0xF4,0xFB,0x74,0xBE,0x56,0x5D,0x7A,0x79,0xF5,0xF9,0x1D,0x85,0xE3, -0x2D,0x95,0xBE,0xF5,0x71,0x90,0x43,0xCC,0x8D,0x1F,0x9A,0x00,0x0A,0x87,0x29,0xE9, -0x55,0x22,0x58,0x00,0x23,0xEA,0xE3,0x12,0x43,0x29,0x5B,0x47,0x08,0xDD,0x8C,0x41, -0x6A,0x65,0x06,0xA8,0xE5,0x21,0xAA,0x41,0xB4,0x95,0x21,0x95,0xB9,0x7D,0xD1,0x34, -0xAB,0x13,0xD6,0xAD,0xBC,0xDC,0xE2,0x3D,0x39,0xCD,0xBD,0x3E,0x75,0x70,0xA1,0x18, -0x59,0x03,0xC9,0x22,0xB4,0x8F,0x9C,0xD5,0x5E,0x2A,0xD7,0xA5,0xB6,0xD4,0x0A,0x6D, -0xF8,0xB7,0x40,0x11,0x46,0x9A,0x1F,0x79,0x0E,0x62,0xBF,0x0F,0x97,0xEC,0xE0,0x2F, -0x1F,0x17,0x94, -}; - - -/* subject:/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Root Certificate Authority - G2 */ -/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Root Certificate Authority - G2 */ - - -const unsigned char Starfield_Root_Certificate_Authority___G2_certificate[993]={ -0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, -0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, -0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, -0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, -0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13, -0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E, -0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30, -0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C, -0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, -0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47, -0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30, -0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39, -0x5A,0x30,0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, -0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A, -0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63, -0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, -0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, -0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, -0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, -0x65,0x6C,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69, -0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D, -0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02, -0x82,0x01,0x01,0x00,0xBD,0xED,0xC1,0x03,0xFC,0xF6,0x8F,0xFC,0x02,0xB1,0x6F,0x5B, -0x9F,0x48,0xD9,0x9D,0x79,0xE2,0xA2,0xB7,0x03,0x61,0x56,0x18,0xC3,0x47,0xB6,0xD7, -0xCA,0x3D,0x35,0x2E,0x89,0x43,0xF7,0xA1,0x69,0x9B,0xDE,0x8A,0x1A,0xFD,0x13,0x20, -0x9C,0xB4,0x49,0x77,0x32,0x29,0x56,0xFD,0xB9,0xEC,0x8C,0xDD,0x22,0xFA,0x72,0xDC, -0x27,0x61,0x97,0xEE,0xF6,0x5A,0x84,0xEC,0x6E,0x19,0xB9,0x89,0x2C,0xDC,0x84,0x5B, -0xD5,0x74,0xFB,0x6B,0x5F,0xC5,0x89,0xA5,0x10,0x52,0x89,0x46,0x55,0xF4,0xB8,0x75, -0x1C,0xE6,0x7F,0xE4,0x54,0xAE,0x4B,0xF8,0x55,0x72,0x57,0x02,0x19,0xF8,0x17,0x71, -0x59,0xEB,0x1E,0x28,0x07,0x74,0xC5,0x9D,0x48,0xBE,0x6C,0xB4,0xF4,0xA4,0xB0,0xF3, -0x64,0x37,0x79,0x92,0xC0,0xEC,0x46,0x5E,0x7F,0xE1,0x6D,0x53,0x4C,0x62,0xAF,0xCD, -0x1F,0x0B,0x63,0xBB,0x3A,0x9D,0xFB,0xFC,0x79,0x00,0x98,0x61,0x74,0xCF,0x26,0x82, -0x40,0x63,0xF3,0xB2,0x72,0x6A,0x19,0x0D,0x99,0xCA,0xD4,0x0E,0x75,0xCC,0x37,0xFB, -0x8B,0x89,0xC1,0x59,0xF1,0x62,0x7F,0x5F,0xB3,0x5F,0x65,0x30,0xF8,0xA7,0xB7,0x4D, -0x76,0x5A,0x1E,0x76,0x5E,0x34,0xC0,0xE8,0x96,0x56,0x99,0x8A,0xB3,0xF0,0x7F,0xA4, -0xCD,0xBD,0xDC,0x32,0x31,0x7C,0x91,0xCF,0xE0,0x5F,0x11,0xF8,0x6B,0xAA,0x49,0x5C, -0xD1,0x99,0x94,0xD1,0xA2,0xE3,0x63,0x5B,0x09,0x76,0xB5,0x56,0x62,0xE1,0x4B,0x74, -0x1D,0x96,0xD4,0x26,0xD4,0x08,0x04,0x59,0xD0,0x98,0x0E,0x0E,0xE6,0xDE,0xFC,0xC3, -0xEC,0x1F,0x90,0xF1,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, -0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, -0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D, -0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7C,0x0C,0x32,0x1F,0xA7,0xD9,0x30, -0x7F,0xC4,0x7D,0x68,0xA3,0x62,0xA8,0xA1,0xCE,0xAB,0x07,0x5B,0x27,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01, -0x00,0x11,0x59,0xFA,0x25,0x4F,0x03,0x6F,0x94,0x99,0x3B,0x9A,0x1F,0x82,0x85,0x39, -0xD4,0x76,0x05,0x94,0x5E,0xE1,0x28,0x93,0x6D,0x62,0x5D,0x09,0xC2,0xA0,0xA8,0xD4, -0xB0,0x75,0x38,0xF1,0x34,0x6A,0x9D,0xE4,0x9F,0x8A,0x86,0x26,0x51,0xE6,0x2C,0xD1, -0xC6,0x2D,0x6E,0x95,0x20,0x4A,0x92,0x01,0xEC,0xB8,0x8A,0x67,0x7B,0x31,0xE2,0x67, -0x2E,0x8C,0x95,0x03,0x26,0x2E,0x43,0x9D,0x4A,0x31,0xF6,0x0E,0xB5,0x0C,0xBB,0xB7, -0xE2,0x37,0x7F,0x22,0xBA,0x00,0xA3,0x0E,0x7B,0x52,0xFB,0x6B,0xBB,0x3B,0xC4,0xD3, -0x79,0x51,0x4E,0xCD,0x90,0xF4,0x67,0x07,0x19,0xC8,0x3C,0x46,0x7A,0x0D,0x01,0x7D, -0xC5,0x58,0xE7,0x6D,0xE6,0x85,0x30,0x17,0x9A,0x24,0xC4,0x10,0xE0,0x04,0xF7,0xE0, -0xF2,0x7F,0xD4,0xAA,0x0A,0xFF,0x42,0x1D,0x37,0xED,0x94,0xE5,0x64,0x59,0x12,0x20, -0x77,0x38,0xD3,0x32,0x3E,0x38,0x81,0x75,0x96,0x73,0xFA,0x68,0x8F,0xB1,0xCB,0xCE, -0x1F,0xC5,0xEC,0xFA,0x9C,0x7E,0xCF,0x7E,0xB1,0xF1,0x07,0x2D,0xB6,0xFC,0xBF,0xCA, -0xA4,0xBF,0xD0,0x97,0x05,0x4A,0xBC,0xEA,0x18,0x28,0x02,0x90,0xBD,0x54,0x78,0x09, -0x21,0x71,0xD3,0xD1,0x7D,0x1D,0xD9,0x16,0xB0,0xA9,0x61,0x3D,0xD0,0x0A,0x00,0x22, -0xFC,0xC7,0x7B,0xCB,0x09,0x64,0x45,0x0B,0x3B,0x40,0x81,0xF7,0x7D,0x7C,0x32,0xF5, -0x98,0xCA,0x58,0x8E,0x7D,0x2A,0xEE,0x90,0x59,0x73,0x64,0xF9,0x36,0x74,0x5E,0x25, -0xA1,0xF5,0x66,0x05,0x2E,0x7F,0x39,0x15,0xA9,0x2A,0xFB,0x50,0x8B,0x8E,0x85,0x69, -0xF4, -}; - - -/* subject:/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Services Root Certificate Authority - G2 */ -/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Services Root Certificate Authority - G2 */ - - -const unsigned char Starfield_Services_Root_Certificate_Authority___G2_certificate[1011]={ -0x30,0x82,0x03,0xEF,0x30,0x82,0x02,0xD7,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, -0x81,0x98,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, -0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, -0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, -0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13, -0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E, -0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x3B,0x30, -0x39,0x06,0x03,0x55,0x04,0x03,0x13,0x32,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C, -0x64,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x20, -0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68, -0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39, -0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31, -0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x98,0x31,0x0B,0x30, -0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x10,0x30,0x0E,0x06,0x03, -0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E,0x61,0x31,0x13,0x30,0x11, -0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74,0x74,0x73,0x64,0x61,0x6C, -0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74,0x61,0x72, -0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69, -0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x3B,0x30,0x39,0x06,0x03,0x55,0x04, -0x03,0x13,0x32,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x53,0x65,0x72, -0x76,0x69,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, -0x20,0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, -0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01, -0x0A,0x02,0x82,0x01,0x01,0x00,0xD5,0x0C,0x3A,0xC4,0x2A,0xF9,0x4E,0xE2,0xF5,0xBE, -0x19,0x97,0x5F,0x8E,0x88,0x53,0xB1,0x1F,0x3F,0xCB,0xCF,0x9F,0x20,0x13,0x6D,0x29, -0x3A,0xC8,0x0F,0x7D,0x3C,0xF7,0x6B,0x76,0x38,0x63,0xD9,0x36,0x60,0xA8,0x9B,0x5E, -0x5C,0x00,0x80,0xB2,0x2F,0x59,0x7F,0xF6,0x87,0xF9,0x25,0x43,0x86,0xE7,0x69,0x1B, -0x52,0x9A,0x90,0xE1,0x71,0xE3,0xD8,0x2D,0x0D,0x4E,0x6F,0xF6,0xC8,0x49,0xD9,0xB6, -0xF3,0x1A,0x56,0xAE,0x2B,0xB6,0x74,0x14,0xEB,0xCF,0xFB,0x26,0xE3,0x1A,0xBA,0x1D, -0x96,0x2E,0x6A,0x3B,0x58,0x94,0x89,0x47,0x56,0xFF,0x25,0xA0,0x93,0x70,0x53,0x83, -0xDA,0x84,0x74,0x14,0xC3,0x67,0x9E,0x04,0x68,0x3A,0xDF,0x8E,0x40,0x5A,0x1D,0x4A, -0x4E,0xCF,0x43,0x91,0x3B,0xE7,0x56,0xD6,0x00,0x70,0xCB,0x52,0xEE,0x7B,0x7D,0xAE, -0x3A,0xE7,0xBC,0x31,0xF9,0x45,0xF6,0xC2,0x60,0xCF,0x13,0x59,0x02,0x2B,0x80,0xCC, -0x34,0x47,0xDF,0xB9,0xDE,0x90,0x65,0x6D,0x02,0xCF,0x2C,0x91,0xA6,0xA6,0xE7,0xDE, -0x85,0x18,0x49,0x7C,0x66,0x4E,0xA3,0x3A,0x6D,0xA9,0xB5,0xEE,0x34,0x2E,0xBA,0x0D, -0x03,0xB8,0x33,0xDF,0x47,0xEB,0xB1,0x6B,0x8D,0x25,0xD9,0x9B,0xCE,0x81,0xD1,0x45, -0x46,0x32,0x96,0x70,0x87,0xDE,0x02,0x0E,0x49,0x43,0x85,0xB6,0x6C,0x73,0xBB,0x64, -0xEA,0x61,0x41,0xAC,0xC9,0xD4,0x54,0xDF,0x87,0x2F,0xC7,0x22,0xB2,0x26,0xCC,0x9F, -0x59,0x54,0x68,0x9F,0xFC,0xBE,0x2A,0x2F,0xC4,0x55,0x1C,0x75,0x40,0x60,0x17,0x85, -0x02,0x55,0x39,0x8B,0x7F,0x05,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30, -0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, -0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06, -0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9C,0x5F,0x00,0xDF,0xAA, -0x01,0xD7,0x30,0x2B,0x38,0x88,0xA2,0xB8,0x6D,0x4A,0x9C,0xF2,0x11,0x91,0x83,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82, -0x01,0x01,0x00,0x4B,0x36,0xA6,0x84,0x77,0x69,0xDD,0x3B,0x19,0x9F,0x67,0x23,0x08, -0x6F,0x0E,0x61,0xC9,0xFD,0x84,0xDC,0x5F,0xD8,0x36,0x81,0xCD,0xD8,0x1B,0x41,0x2D, -0x9F,0x60,0xDD,0xC7,0x1A,0x68,0xD9,0xD1,0x6E,0x86,0xE1,0x88,0x23,0xCF,0x13,0xDE, -0x43,0xCF,0xE2,0x34,0xB3,0x04,0x9D,0x1F,0x29,0xD5,0xBF,0xF8,0x5E,0xC8,0xD5,0xC1, -0xBD,0xEE,0x92,0x6F,0x32,0x74,0xF2,0x91,0x82,0x2F,0xBD,0x82,0x42,0x7A,0xAD,0x2A, -0xB7,0x20,0x7D,0x4D,0xBC,0x7A,0x55,0x12,0xC2,0x15,0xEA,0xBD,0xF7,0x6A,0x95,0x2E, -0x6C,0x74,0x9F,0xCF,0x1C,0xB4,0xF2,0xC5,0x01,0xA3,0x85,0xD0,0x72,0x3E,0xAD,0x73, -0xAB,0x0B,0x9B,0x75,0x0C,0x6D,0x45,0xB7,0x8E,0x94,0xAC,0x96,0x37,0xB5,0xA0,0xD0, -0x8F,0x15,0x47,0x0E,0xE3,0xE8,0x83,0xDD,0x8F,0xFD,0xEF,0x41,0x01,0x77,0xCC,0x27, -0xA9,0x62,0x85,0x33,0xF2,0x37,0x08,0xEF,0x71,0xCF,0x77,0x06,0xDE,0xC8,0x19,0x1D, -0x88,0x40,0xCF,0x7D,0x46,0x1D,0xFF,0x1E,0xC7,0xE1,0xCE,0xFF,0x23,0xDB,0xC6,0xFA, -0x8D,0x55,0x4E,0xA9,0x02,0xE7,0x47,0x11,0x46,0x3E,0xF4,0xFD,0xBD,0x7B,0x29,0x26, -0xBB,0xA9,0x61,0x62,0x37,0x28,0xB6,0x2D,0x2A,0xF6,0x10,0x86,0x64,0xC9,0x70,0xA7, -0xD2,0xAD,0xB7,0x29,0x70,0x79,0xEA,0x3C,0xDA,0x63,0x25,0x9F,0xFD,0x68,0xB7,0x30, -0xEC,0x70,0xFB,0x75,0x8A,0xB7,0x6D,0x60,0x67,0xB2,0x1E,0xC8,0xB9,0xE9,0xD8,0xA8, -0x6F,0x02,0x8B,0x67,0x0D,0x4D,0x26,0x57,0x71,0xDA,0x20,0xFC,0xC1,0x4A,0x50,0x8D, -0xB1,0x28,0xBA, -}; - - -/* subject:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority */ -/* issuer :/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority */ - - -const unsigned char StartCom_Certification_Authority_certificate[1931]={ -0x30,0x82,0x07,0x87,0x30,0x82,0x05,0x6F,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x2D, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, -0x7D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x4C,0x31,0x16, -0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74,0x61,0x72,0x74,0x43,0x6F, -0x6D,0x20,0x4C,0x74,0x64,0x2E,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x0B,0x13, -0x22,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x44,0x69,0x67,0x69,0x74,0x61,0x6C,0x20, -0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x69,0x67,0x6E, -0x69,0x6E,0x67,0x31,0x29,0x30,0x27,0x06,0x03,0x55,0x04,0x03,0x13,0x20,0x53,0x74, -0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, -0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E, -0x17,0x0D,0x30,0x36,0x30,0x39,0x31,0x37,0x31,0x39,0x34,0x36,0x33,0x37,0x5A,0x17, -0x0D,0x33,0x36,0x30,0x39,0x31,0x37,0x31,0x39,0x34,0x36,0x33,0x36,0x5A,0x30,0x7D, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x4C,0x31,0x16,0x30, -0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D, -0x20,0x4C,0x74,0x64,0x2E,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x0B,0x13,0x22, -0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x44,0x69,0x67,0x69,0x74,0x61,0x6C,0x20,0x43, -0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x69,0x67,0x6E,0x69, -0x6E,0x67,0x31,0x29,0x30,0x27,0x06,0x03,0x55,0x04,0x03,0x13,0x20,0x53,0x74,0x61, -0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74, -0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x02, -0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, -0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xC1,0x88, -0xDB,0x09,0xBC,0x6C,0x46,0x7C,0x78,0x9F,0x95,0x7B,0xB5,0x33,0x90,0xF2,0x72,0x62, -0xD6,0xC1,0x36,0x20,0x22,0x24,0x5E,0xCE,0xE9,0x77,0xF2,0x43,0x0A,0xA2,0x06,0x64, -0xA4,0xCC,0x8E,0x36,0xF8,0x38,0xE6,0x23,0xF0,0x6E,0x6D,0xB1,0x3C,0xDD,0x72,0xA3, -0x85,0x1C,0xA1,0xD3,0x3D,0xB4,0x33,0x2B,0xD3,0x2F,0xAF,0xFE,0xEA,0xB0,0x41,0x59, -0x67,0xB6,0xC4,0x06,0x7D,0x0A,0x9E,0x74,0x85,0xD6,0x79,0x4C,0x80,0x37,0x7A,0xDF, -0x39,0x05,0x52,0x59,0xF7,0xF4,0x1B,0x46,0x43,0xA4,0xD2,0x85,0x85,0xD2,0xC3,0x71, -0xF3,0x75,0x62,0x34,0xBA,0x2C,0x8A,0x7F,0x1E,0x8F,0xEE,0xED,0x34,0xD0,0x11,0xC7, -0x96,0xCD,0x52,0x3D,0xBA,0x33,0xD6,0xDD,0x4D,0xDE,0x0B,0x3B,0x4A,0x4B,0x9F,0xC2, -0x26,0x2F,0xFA,0xB5,0x16,0x1C,0x72,0x35,0x77,0xCA,0x3C,0x5D,0xE6,0xCA,0xE1,0x26, -0x8B,0x1A,0x36,0x76,0x5C,0x01,0xDB,0x74,0x14,0x25,0xFE,0xED,0xB5,0xA0,0x88,0x0F, -0xDD,0x78,0xCA,0x2D,0x1F,0x07,0x97,0x30,0x01,0x2D,0x72,0x79,0xFA,0x46,0xD6,0x13, -0x2A,0xA8,0xB9,0xA6,0xAB,0x83,0x49,0x1D,0xE5,0xF2,0xEF,0xDD,0xE4,0x01,0x8E,0x18, -0x0A,0x8F,0x63,0x53,0x16,0x85,0x62,0xA9,0x0E,0x19,0x3A,0xCC,0xB5,0x66,0xA6,0xC2, -0x6B,0x74,0x07,0xE4,0x2B,0xE1,0x76,0x3E,0xB4,0x6D,0xD8,0xF6,0x44,0xE1,0x73,0x62, -0x1F,0x3B,0xC4,0xBE,0xA0,0x53,0x56,0x25,0x6C,0x51,0x09,0xF7,0xAA,0xAB,0xCA,0xBF, -0x76,0xFD,0x6D,0x9B,0xF3,0x9D,0xDB,0xBF,0x3D,0x66,0xBC,0x0C,0x56,0xAA,0xAF,0x98, -0x48,0x95,0x3A,0x4B,0xDF,0xA7,0x58,0x50,0xD9,0x38,0x75,0xA9,0x5B,0xEA,0x43,0x0C, -0x02,0xFF,0x99,0xEB,0xE8,0x6C,0x4D,0x70,0x5B,0x29,0x65,0x9C,0xDD,0xAA,0x5D,0xCC, -0xAF,0x01,0x31,0xEC,0x0C,0xEB,0xD2,0x8D,0xE8,0xEA,0x9C,0x7B,0xE6,0x6E,0xF7,0x27, -0x66,0x0C,0x1A,0x48,0xD7,0x6E,0x42,0xE3,0x3F,0xDE,0x21,0x3E,0x7B,0xE1,0x0D,0x70, -0xFB,0x63,0xAA,0xA8,0x6C,0x1A,0x54,0xB4,0x5C,0x25,0x7A,0xC9,0xA2,0xC9,0x8B,0x16, -0xA6,0xBB,0x2C,0x7E,0x17,0x5E,0x05,0x4D,0x58,0x6E,0x12,0x1D,0x01,0xEE,0x12,0x10, -0x0D,0xC6,0x32,0x7F,0x18,0xFF,0xFC,0xF4,0xFA,0xCD,0x6E,0x91,0xE8,0x36,0x49,0xBE, -0x1A,0x48,0x69,0x8B,0xC2,0x96,0x4D,0x1A,0x12,0xB2,0x69,0x17,0xC1,0x0A,0x90,0xD6, -0xFA,0x79,0x22,0x48,0xBF,0xBA,0x7B,0x69,0xF8,0x70,0xC7,0xFA,0x7A,0x37,0xD8,0xD8, -0x0D,0xD2,0x76,0x4F,0x57,0xFF,0x90,0xB7,0xE3,0x91,0xD2,0xDD,0xEF,0xC2,0x60,0xB7, -0x67,0x3A,0xDD,0xFE,0xAA,0x9C,0xF0,0xD4,0x8B,0x7F,0x72,0x22,0xCE,0xC6,0x9F,0x97, -0xB6,0xF8,0xAF,0x8A,0xA0,0x10,0xA8,0xD9,0xFB,0x18,0xC6,0xB6,0xB5,0x5C,0x52,0x3C, -0x89,0xB6,0x19,0x2A,0x73,0x01,0x0A,0x0F,0x03,0xB3,0x12,0x60,0xF2,0x7A,0x2F,0x81, -0xDB,0xA3,0x6E,0xFF,0x26,0x30,0x97,0xF5,0x8B,0xDD,0x89,0x57,0xB6,0xAD,0x3D,0xB3, -0xAF,0x2B,0xC5,0xB7,0x76,0x02,0xF0,0xA5,0xD6,0x2B,0x9A,0x86,0x14,0x2A,0x72,0xF6, -0xE3,0x33,0x8C,0x5D,0x09,0x4B,0x13,0xDF,0xBB,0x8C,0x74,0x13,0x52,0x4B,0x02,0x03, -0x01,0x00,0x01,0xA3,0x82,0x02,0x10,0x30,0x82,0x02,0x0C,0x30,0x0F,0x06,0x03,0x55, -0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, -0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03, -0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4E,0x0B,0xEF,0x1A,0xA4,0x40,0x5B,0xA5,0x17, -0x69,0x87,0x30,0xCA,0x34,0x68,0x43,0xD0,0x41,0xAE,0xF2,0x30,0x1F,0x06,0x03,0x55, -0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x4E,0x0B,0xEF,0x1A,0xA4,0x40,0x5B,0xA5, -0x17,0x69,0x87,0x30,0xCA,0x34,0x68,0x43,0xD0,0x41,0xAE,0xF2,0x30,0x82,0x01,0x5A, -0x06,0x03,0x55,0x1D,0x20,0x04,0x82,0x01,0x51,0x30,0x82,0x01,0x4D,0x30,0x82,0x01, -0x49,0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0x81,0xB5,0x37,0x01,0x01,0x01,0x30,0x82, -0x01,0x38,0x30,0x2E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x22, -0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x73,0x74,0x61,0x72,0x74, -0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x70,0x6F,0x6C,0x69,0x63,0x79,0x2E,0x70, -0x64,0x66,0x30,0x34,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x28, -0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x73,0x74,0x61,0x72,0x74, -0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x69,0x6E,0x74,0x65,0x72,0x6D,0x65,0x64, -0x69,0x61,0x74,0x65,0x2E,0x70,0x64,0x66,0x30,0x81,0xCF,0x06,0x08,0x2B,0x06,0x01, -0x05,0x05,0x07,0x02,0x02,0x30,0x81,0xC2,0x30,0x27,0x16,0x20,0x53,0x74,0x61,0x72, -0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69,0x61,0x6C,0x20,0x28,0x53,0x74, -0x61,0x72,0x74,0x43,0x6F,0x6D,0x29,0x20,0x4C,0x74,0x64,0x2E,0x30,0x03,0x02,0x01, -0x01,0x1A,0x81,0x96,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x20,0x4C,0x69,0x61,0x62, -0x69,0x6C,0x69,0x74,0x79,0x2C,0x20,0x72,0x65,0x61,0x64,0x20,0x74,0x68,0x65,0x20, -0x73,0x65,0x63,0x74,0x69,0x6F,0x6E,0x20,0x2A,0x4C,0x65,0x67,0x61,0x6C,0x20,0x4C, -0x69,0x6D,0x69,0x74,0x61,0x74,0x69,0x6F,0x6E,0x73,0x2A,0x20,0x6F,0x66,0x20,0x74, -0x68,0x65,0x20,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74, -0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x61,0x76,0x61,0x69,0x6C, -0x61,0x62,0x6C,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77, -0x77,0x77,0x2E,0x73,0x74,0x61,0x72,0x74,0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F, -0x70,0x6F,0x6C,0x69,0x63,0x79,0x2E,0x70,0x64,0x66,0x30,0x11,0x06,0x09,0x60,0x86, -0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x38,0x06, -0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0D,0x04,0x2B,0x16,0x29,0x53,0x74, -0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x46,0x72,0x65,0x65,0x20,0x53,0x53,0x4C,0x20, -0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75, -0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x8E,0x8F,0xE7,0xDC,0x94, -0x79,0x7C,0xF1,0x85,0x7F,0x9F,0x49,0x6F,0x6B,0xCA,0x5D,0xFB,0x8C,0xFE,0x04,0xC5, -0xC1,0x62,0xD1,0x7D,0x42,0x8A,0xBC,0x53,0xB7,0x94,0x03,0x66,0x30,0x3F,0xB1,0xE7, -0x0A,0xA7,0x50,0x20,0x55,0x25,0x7F,0x76,0x7A,0x14,0x0D,0xEB,0x04,0x0E,0x40,0xE6, -0x3E,0xD8,0x88,0xAB,0x07,0x27,0x83,0xA9,0x75,0xA6,0x37,0x73,0xC7,0xFD,0x4B,0xD2, -0x4D,0xAD,0x17,0x40,0xC8,0x46,0xBE,0x3B,0x7F,0x51,0xFC,0xC3,0xB6,0x05,0x31,0xDC, -0xCD,0x85,0x22,0x4E,0x71,0xB7,0xF2,0x71,0x5E,0xB0,0x1A,0xC6,0xBA,0x93,0x8B,0x78, -0x92,0x4A,0x85,0xF8,0x78,0x0F,0x83,0xFE,0x2F,0xAD,0x2C,0xF7,0xE4,0xA4,0xBB,0x2D, -0xD0,0xE7,0x0D,0x3A,0xB8,0x3E,0xCE,0xF6,0x78,0xF6,0xAE,0x47,0x24,0xCA,0xA3,0x35, -0x36,0xCE,0xC7,0xC6,0x87,0x98,0xDA,0xEC,0xFB,0xE9,0xB2,0xCE,0x27,0x9B,0x88,0xC3, -0x04,0xA1,0xF6,0x0B,0x59,0x68,0xAF,0xC9,0xDB,0x10,0x0F,0x4D,0xF6,0x64,0x63,0x5C, -0xA5,0x12,0x6F,0x92,0xB2,0x93,0x94,0xC7,0x88,0x17,0x0E,0x93,0xB6,0x7E,0x62,0x8B, -0x90,0x7F,0xAB,0x4E,0x9F,0xFC,0xE3,0x75,0x14,0x4F,0x2A,0x32,0xDF,0x5B,0x0D,0xE0, -0xF5,0x7B,0x93,0x0D,0xAB,0xA1,0xCF,0x87,0xE1,0xA5,0x04,0x45,0xE8,0x3C,0x12,0xA5, -0x09,0xC5,0xB0,0xD1,0xB7,0x53,0xF3,0x60,0x14,0xBA,0x85,0x69,0x6A,0x21,0x7C,0x1F, -0x75,0x61,0x17,0x20,0x17,0x7B,0x6C,0x3B,0x41,0x29,0x5C,0xE1,0xAC,0x5A,0xD1,0xCD, -0x8C,0x9B,0xEB,0x60,0x1D,0x19,0xEC,0xF7,0xE5,0xB0,0xDA,0xF9,0x79,0x18,0xA5,0x45, -0x3F,0x49,0x43,0x57,0xD2,0xDD,0x24,0xD5,0x2C,0xA3,0xFD,0x91,0x8D,0x27,0xB5,0xE5, -0xEB,0x14,0x06,0x9A,0x4C,0x7B,0x21,0xBB,0x3A,0xAD,0x30,0x06,0x18,0xC0,0xD8,0xC1, -0x6B,0x2C,0x7F,0x59,0x5C,0x5D,0x91,0xB1,0x70,0x22,0x57,0xEB,0x8A,0x6B,0x48,0x4A, -0xD5,0x0F,0x29,0xEC,0xC6,0x40,0xC0,0x2F,0x88,0x4C,0x68,0x01,0x17,0x77,0xF4,0x24, -0x19,0x4F,0xBD,0xFA,0xE1,0xB2,0x20,0x21,0x4B,0xDD,0x1A,0xD8,0x29,0x7D,0xAA,0xB8, -0xDE,0x54,0xEC,0x21,0x55,0x80,0x6C,0x1E,0xF5,0x30,0xC8,0xA3,0x10,0xE5,0xB2,0xE6, -0x2A,0x14,0x31,0xC3,0x85,0x2D,0x8C,0x98,0xB1,0x86,0x5A,0x4F,0x89,0x59,0x2D,0xB9, -0xC7,0xF7,0x1C,0xC8,0x8A,0x7F,0xC0,0x9D,0x05,0x4A,0xE6,0x42,0x4F,0x62,0xA3,0x6D, -0x29,0xA4,0x1F,0x85,0xAB,0xDB,0xE5,0x81,0xC8,0xAD,0x2A,0x3D,0x4C,0x5D,0x5B,0x84, -0x26,0x71,0xC4,0x85,0x5E,0x71,0x24,0xCA,0xA5,0x1B,0x6C,0xD8,0x61,0xD3,0x1A,0xE0, -0x54,0xDB,0xCE,0xBA,0xA9,0x32,0xB5,0x22,0xF6,0x73,0x41,0x09,0x5D,0xB8,0x17,0x5D, -0x0E,0x0F,0x99,0x90,0xD6,0x47,0xDA,0x6F,0x0A,0x3A,0x62,0x28,0x14,0x67,0x82,0xD9, -0xF1,0xD0,0x80,0x59,0x9B,0xCB,0x31,0xD8,0x9B,0x0F,0x8C,0x77,0x4E,0xB5,0x68,0x8A, -0xF2,0x6C,0xF6,0x24,0x0E,0x2D,0x6C,0x70,0xC5,0x73,0xD1,0xDE,0x14,0xD0,0x71,0x8F, -0xB6,0xD3,0x7B,0x02,0xF6,0xE3,0xB8,0xD4,0x09,0x6E,0x6B,0x9E,0x75,0x84,0x39,0xE6, -0x7F,0x25,0xA5,0xF2,0x48,0x00,0xC0,0xA4,0x01,0xDA,0x3F, -}; - - -/* subject:/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2 */ -/* issuer :/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2 */ - - -const unsigned char StartCom_Certification_Authority_G2_certificate[1383]={ -0x30,0x82,0x05,0x63,0x30,0x82,0x03,0x4B,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x3B, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, -0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x4C,0x31,0x16, -0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74,0x61,0x72,0x74,0x43,0x6F, -0x6D,0x20,0x4C,0x74,0x64,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x03,0x13, -0x23,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74,0x69,0x66, -0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, -0x79,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30,0x31,0x30,0x31,0x30,0x31, -0x30,0x30,0x30,0x31,0x5A,0x17,0x0D,0x33,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35, -0x39,0x30,0x31,0x5A,0x30,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x49,0x4C,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74, -0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x4C,0x74,0x64,0x2E,0x31,0x2C,0x30,0x2A,0x06, -0x03,0x55,0x04,0x03,0x13,0x23,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43, -0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, -0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x47,0x32,0x30,0x82,0x02,0x22,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F, -0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xB6,0x89,0x36,0x5B,0x07,0xB7, -0x20,0x36,0xBD,0x82,0xBB,0xE1,0x16,0x20,0x03,0x95,0x7A,0xAF,0x0E,0xA3,0x55,0xC9, -0x25,0x99,0x4A,0xC5,0xD0,0x56,0x41,0x87,0x90,0x4D,0x21,0x60,0xA4,0x14,0x87,0x3B, -0xCD,0xFD,0xB2,0x3E,0xB4,0x67,0x03,0x6A,0xED,0xE1,0x0F,0x4B,0xC0,0x91,0x85,0x70, -0x45,0xE0,0x42,0x9E,0xDE,0x29,0x23,0xD4,0x01,0x0D,0xA0,0x10,0x79,0xB8,0xDB,0x03, -0xBD,0xF3,0xA9,0x2F,0xD1,0xC6,0xE0,0x0F,0xCB,0x9E,0x8A,0x14,0x0A,0xB8,0xBD,0xF6, -0x56,0x62,0xF1,0xC5,0x72,0xB6,0x32,0x25,0xD9,0xB2,0xF3,0xBD,0x65,0xC5,0x0D,0x2C, -0x6E,0xD5,0x92,0x6F,0x18,0x8B,0x00,0x41,0x14,0x82,0x6F,0x40,0x20,0x26,0x7A,0x28, -0x0F,0xF5,0x1E,0x7F,0x27,0xF7,0x94,0xB1,0x37,0x3D,0xB7,0xC7,0x91,0xF7,0xE2,0x01, -0xEC,0xFD,0x94,0x89,0xE1,0xCC,0x6E,0xD3,0x36,0xD6,0x0A,0x19,0x79,0xAE,0xD7,0x34, -0x82,0x65,0xFF,0x7C,0x42,0xBB,0xB6,0xDD,0x0B,0xA6,0x34,0xAF,0x4B,0x60,0xFE,0x7F, -0x43,0x49,0x06,0x8B,0x8C,0x43,0xB8,0x56,0xF2,0xD9,0x7F,0x21,0x43,0x17,0xEA,0xA7, -0x48,0x95,0x01,0x75,0x75,0xEA,0x2B,0xA5,0x43,0x95,0xEA,0x15,0x84,0x9D,0x08,0x8D, -0x26,0x6E,0x55,0x9B,0xAB,0xDC,0xD2,0x39,0xD2,0x31,0x1D,0x60,0xE2,0xAC,0xCC,0x56, -0x45,0x24,0xF5,0x1C,0x54,0xAB,0xEE,0x86,0xDD,0x96,0x32,0x85,0xF8,0x4C,0x4F,0xE8, -0x95,0x76,0xB6,0x05,0xDD,0x36,0x23,0x67,0xBC,0xFF,0x15,0xE2,0xCA,0x3B,0xE6,0xA6, -0xEC,0x3B,0xEC,0x26,0x11,0x34,0x48,0x8D,0xF6,0x80,0x2B,0x1A,0x23,0x02,0xEB,0x8A, -0x1C,0x3A,0x76,0x2A,0x7B,0x56,0x16,0x1C,0x72,0x2A,0xB3,0xAA,0xE3,0x60,0xA5,0x00, -0x9F,0x04,0x9B,0xE2,0x6F,0x1E,0x14,0x58,0x5B,0xA5,0x6C,0x8B,0x58,0x3C,0xC3,0xBA, -0x4E,0x3A,0x5C,0xF7,0xE1,0x96,0x2B,0x3E,0xEF,0x07,0xBC,0xA4,0xE5,0x5D,0xCC,0x4D, -0x9F,0x0D,0xE1,0xDC,0xAA,0xBB,0xE1,0x6E,0x1A,0xEC,0x8F,0xE1,0xB6,0x4C,0x4D,0x79, -0x72,0x5D,0x17,0x35,0x0B,0x1D,0xD7,0xC1,0x47,0xDA,0x96,0x24,0xE0,0xD0,0x72,0xA8, -0x5A,0x5F,0x66,0x2D,0x10,0xDC,0x2F,0x2A,0x13,0xAE,0x26,0xFE,0x0A,0x1C,0x19,0xCC, -0xD0,0x3E,0x0B,0x9C,0xC8,0x09,0x2E,0xF9,0x5B,0x96,0x7A,0x47,0x9C,0xE9,0x7A,0xF3, -0x05,0x50,0x74,0x95,0x73,0x9E,0x30,0x09,0xF3,0x97,0x82,0x5E,0xE6,0x8F,0x39,0x08, -0x1E,0x59,0xE5,0x35,0x14,0x42,0x13,0xFF,0x00,0x9C,0xF7,0xBE,0xAA,0x50,0xCF,0xE2, -0x51,0x48,0xD7,0xB8,0x6F,0xAF,0xF8,0x4E,0x7E,0x33,0x98,0x92,0x14,0x62,0x3A,0x75, -0x63,0xCF,0x7B,0xFA,0xDE,0x82,0x3B,0xA9,0xBB,0x39,0xE2,0xC4,0xBD,0x2C,0x00,0x0E, -0xC8,0x17,0xAC,0x13,0xEF,0x4D,0x25,0x8E,0xD8,0xB3,0x90,0x2F,0xA9,0xDA,0x29,0x7D, -0x1D,0xAF,0x74,0x3A,0xB2,0x27,0xC0,0xC1,0x1E,0x3E,0x75,0xA3,0x16,0xA9,0xAF,0x7A, -0x22,0x5D,0x9F,0x13,0x1A,0xCF,0xA7,0xA0,0xEB,0xE3,0x86,0x0A,0xD3,0xFD,0xE6,0x96, -0x95,0xD7,0x23,0xC8,0x37,0xDD,0xC4,0x7C,0xAA,0x36,0xAC,0x98,0x1A,0x12,0xB1,0xE0, -0x4E,0xE8,0xB1,0x3B,0xF5,0xD6,0x6F,0xF1,0x30,0xD7,0x02,0x03,0x01,0x00,0x01,0xA3, -0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, -0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, -0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4B, -0xC5,0xB4,0x40,0x6B,0xAD,0x1C,0xB3,0xA5,0x1C,0x65,0x6E,0x46,0x36,0x89,0x87,0x05, -0x0C,0x0E,0xB6,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B, -0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x73,0x57,0x3F,0x2C,0xD5,0x95,0x32,0x7E,0x37, -0xDB,0x96,0x92,0xEB,0x19,0x5E,0x7E,0x53,0xE7,0x41,0xEC,0x11,0xB6,0x47,0xEF,0xB5, -0xDE,0xED,0x74,0x5C,0xC5,0xF1,0x8E,0x49,0xE0,0xFC,0x6E,0x99,0x13,0xCD,0x9F,0x8A, -0xDA,0xCD,0x3A,0x0A,0xD8,0x3A,0x5A,0x09,0x3F,0x5F,0x34,0xD0,0x2F,0x03,0xD2,0x66, -0x1D,0x1A,0xBD,0x9C,0x90,0x37,0xC8,0x0C,0x8E,0x07,0x5A,0x94,0x45,0x46,0x2A,0xE6, -0xBE,0x7A,0xDA,0xA1,0xA9,0xA4,0x69,0x12,0x92,0xB0,0x7D,0x36,0xD4,0x44,0x87,0xD7, -0x51,0xF1,0x29,0x63,0xD6,0x75,0xCD,0x16,0xE4,0x27,0x89,0x1D,0xF8,0xC2,0x32,0x48, -0xFD,0xDB,0x99,0xD0,0x8F,0x5F,0x54,0x74,0xCC,0xAC,0x67,0x34,0x11,0x62,0xD9,0x0C, -0x0A,0x37,0x87,0xD1,0xA3,0x17,0x48,0x8E,0xD2,0x17,0x1D,0xF6,0xD7,0xFD,0xDB,0x65, -0xEB,0xFD,0xA8,0xD4,0xF5,0xD6,0x4F,0xA4,0x5B,0x75,0xE8,0xC5,0xD2,0x60,0xB2,0xDB, -0x09,0x7E,0x25,0x8B,0x7B,0xBA,0x52,0x92,0x9E,0x3E,0xE8,0xC5,0x77,0xA1,0x3C,0xE0, -0x4A,0x73,0x6B,0x61,0xCF,0x86,0xDC,0x43,0xFF,0xFF,0x21,0xFE,0x23,0x5D,0x24,0x4A, -0xF5,0xD3,0x6D,0x0F,0x62,0x04,0x05,0x57,0x82,0xDA,0x6E,0xA4,0x33,0x25,0x79,0x4B, -0x2E,0x54,0x19,0x8B,0xCC,0x2C,0x3D,0x30,0xE9,0xD1,0x06,0xFF,0xE8,0x32,0x46,0xBE, -0xB5,0x33,0x76,0x77,0xA8,0x01,0x5D,0x96,0xC1,0xC1,0xD5,0xBE,0xAE,0x25,0xC0,0xC9, -0x1E,0x0A,0x09,0x20,0x88,0xA1,0x0E,0xC9,0xF3,0x6F,0x4D,0x82,0x54,0x00,0x20,0xA7, -0xD2,0x8F,0xE4,0x39,0x54,0x17,0x2E,0x8D,0x1E,0xB8,0x1B,0xBB,0x1B,0xBD,0x9A,0x4E, -0x3B,0x10,0x34,0xDC,0x9C,0x88,0x53,0xEF,0xA2,0x31,0x5B,0x58,0x4F,0x91,0x62,0xC8, -0xC2,0x9A,0x9A,0xCD,0x15,0x5D,0x38,0xA9,0xD6,0xBE,0xF8,0x13,0xB5,0x9F,0x12,0x69, -0xF2,0x50,0x62,0xAC,0xFB,0x17,0x37,0xF4,0xEE,0xB8,0x75,0x67,0x60,0x10,0xFB,0x83, -0x50,0xF9,0x44,0xB5,0x75,0x9C,0x40,0x17,0xB2,0xFE,0xFD,0x79,0x5D,0x6E,0x58,0x58, -0x5F,0x30,0xFC,0x00,0xAE,0xAF,0x33,0xC1,0x0E,0x4E,0x6C,0xBA,0xA7,0xA6,0xA1,0x7F, -0x32,0xDB,0x38,0xE0,0xB1,0x72,0x17,0x0A,0x2B,0x91,0xEC,0x6A,0x63,0x26,0xED,0x89, -0xD4,0x78,0xCC,0x74,0x1E,0x05,0xF8,0x6B,0xFE,0x8C,0x6A,0x76,0x39,0x29,0xAE,0x65, -0x23,0x12,0x95,0x08,0x22,0x1C,0x97,0xCE,0x5B,0x06,0xEE,0x0C,0xE2,0xBB,0xBC,0x1F, -0x44,0x93,0xF6,0xD8,0x38,0x45,0x05,0x21,0xED,0xE4,0xAD,0xAB,0x12,0xB6,0x03,0xA4, -0x42,0x2E,0x2D,0xC4,0x09,0x3A,0x03,0x67,0x69,0x84,0x9A,0xE1,0x59,0x90,0x8A,0x28, -0x85,0xD5,0x5D,0x74,0xB1,0xD1,0x0E,0x20,0x58,0x9B,0x13,0xA5,0xB0,0x63,0xA6,0xED, -0x7B,0x47,0xFD,0x45,0x55,0x30,0xA4,0xEE,0x9A,0xD4,0xE6,0xE2,0x87,0xEF,0x98,0xC9, -0x32,0x82,0x11,0x29,0x22,0xBC,0x00,0x0A,0x31,0x5E,0x2D,0x0F,0xC0,0x8E,0xE9,0x6B, -0xB2,0x8F,0x2E,0x06,0xD8,0xD1,0x91,0xC7,0xC6,0x12,0xF4,0x4C,0xFD,0x30,0x17,0xC3, -0xC1,0xDA,0x38,0x5B,0xE3,0xA9,0xEA,0xE6,0xA1,0xBA,0x79,0xEF,0x73,0xD8,0xB6,0x53, -0x57,0x2D,0xF6,0xD0,0xE1,0xD7,0x48, -}; - - -/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 2 CA/CN=TC TrustCenter Class 2 CA II */ -/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 2 CA/CN=TC TrustCenter Class 2 CA II */ - - -const unsigned char TC_TrustCenter_Class_2_CA_II_certificate[1198]={ -0x30,0x82,0x04,0xAA,0x30,0x82,0x03,0x92,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x2E, -0x6A,0x00,0x01,0x00,0x02,0x1F,0xD7,0x52,0x21,0x2C,0x11,0x5C,0x3B,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x76,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, -0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, -0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55, -0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, -0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x41,0x31,0x25,0x30, -0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74, -0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43, -0x41,0x20,0x49,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x31,0x31,0x32,0x31,0x34, -0x33,0x38,0x34,0x33,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31,0x32,0x32,0x35, -0x39,0x35,0x39,0x5A,0x30,0x76,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43, -0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62, -0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54, -0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73, -0x20,0x32,0x20,0x43,0x41,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C, -0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43, -0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x41,0x20,0x49,0x49,0x30,0x82,0x01,0x22, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, -0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAB,0x80,0x87, -0x9B,0x8E,0xF0,0xC3,0x7C,0x87,0xD7,0xE8,0x24,0x82,0x11,0xB3,0x3C,0xDD,0x43,0x62, -0xEE,0xF8,0xC3,0x45,0xDA,0xE8,0xE1,0xA0,0x5F,0xD1,0x2A,0xB2,0xEA,0x93,0x68,0xDF, -0xB4,0xC8,0xD6,0x43,0xE9,0xC4,0x75,0x59,0x7F,0xFC,0xE1,0x1D,0xF8,0x31,0x70,0x23, -0x1B,0x88,0x9E,0x27,0xB9,0x7B,0xFD,0x3A,0xD2,0xC9,0xA9,0xE9,0x14,0x2F,0x90,0xBE, -0x03,0x52,0xC1,0x49,0xCD,0xF6,0xFD,0xE4,0x08,0x66,0x0B,0x57,0x8A,0xA2,0x42,0xA0, -0xB8,0xD5,0x7F,0x69,0x5C,0x90,0x32,0xB2,0x97,0x0D,0xCA,0x4A,0xDC,0x46,0x3E,0x02, -0x55,0x89,0x53,0xE3,0x1A,0x5A,0xCB,0x36,0xC6,0x07,0x56,0xF7,0x8C,0xCF,0x11,0xF4, -0x4C,0xBB,0x30,0x70,0x04,0x95,0xA5,0xF6,0x39,0x8C,0xFD,0x73,0x81,0x08,0x7D,0x89, -0x5E,0x32,0x1E,0x22,0xA9,0x22,0x45,0x4B,0xB0,0x66,0x2E,0x30,0xCC,0x9F,0x65,0xFD, -0xFC,0xCB,0x81,0xA9,0xF1,0xE0,0x3B,0xAF,0xA3,0x86,0xD1,0x89,0xEA,0xC4,0x45,0x79, -0x50,0x5D,0xAE,0xE9,0x21,0x74,0x92,0x4D,0x8B,0x59,0x82,0x8F,0x94,0xE3,0xE9,0x4A, -0xF1,0xE7,0x49,0xB0,0x14,0xE3,0xF5,0x62,0xCB,0xD5,0x72,0xBD,0x1F,0xB9,0xD2,0x9F, -0xA0,0xCD,0xA8,0xFA,0x01,0xC8,0xD9,0x0D,0xDF,0xDA,0xFC,0x47,0x9D,0xB3,0xC8,0x54, -0xDF,0x49,0x4A,0xF1,0x21,0xA9,0xFE,0x18,0x4E,0xEE,0x48,0xD4,0x19,0xBB,0xEF,0x7D, -0xE4,0xE2,0x9D,0xCB,0x5B,0xB6,0x6E,0xFF,0xE3,0xCD,0x5A,0xE7,0x74,0x82,0x05,0xBA, -0x80,0x25,0x38,0xCB,0xE4,0x69,0x9E,0xAF,0x41,0xAA,0x1A,0x84,0xF5,0x02,0x03,0x01, -0x00,0x01,0xA3,0x82,0x01,0x34,0x30,0x82,0x01,0x30,0x30,0x0F,0x06,0x03,0x55,0x1D, -0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, -0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55, -0x1D,0x0E,0x04,0x16,0x04,0x14,0xE3,0xAB,0x54,0x4C,0x80,0xA1,0xDB,0x56,0x43,0xB7, -0x91,0x4A,0xCB,0xF3,0x82,0x7A,0x13,0x5C,0x08,0xAB,0x30,0x81,0xED,0x06,0x03,0x55, -0x1D,0x1F,0x04,0x81,0xE5,0x30,0x81,0xE2,0x30,0x81,0xDF,0xA0,0x81,0xDC,0xA0,0x81, -0xD9,0x86,0x35,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72, -0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x72,0x6C, -0x2F,0x76,0x32,0x2F,0x74,0x63,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x32,0x5F,0x63, -0x61,0x5F,0x49,0x49,0x2E,0x63,0x72,0x6C,0x86,0x81,0x9F,0x6C,0x64,0x61,0x70,0x3A, -0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65, -0x72,0x2E,0x64,0x65,0x2F,0x43,0x4E,0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75, -0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x25,0x32,0x30,0x43,0x6C,0x61,0x73,0x73, -0x25,0x32,0x30,0x32,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x49,0x49,0x2C,0x4F, -0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65, -0x72,0x25,0x32,0x30,0x47,0x6D,0x62,0x48,0x2C,0x4F,0x55,0x3D,0x72,0x6F,0x6F,0x74, -0x63,0x65,0x72,0x74,0x73,0x2C,0x44,0x43,0x3D,0x74,0x72,0x75,0x73,0x74,0x63,0x65, -0x6E,0x74,0x65,0x72,0x2C,0x44,0x43,0x3D,0x64,0x65,0x3F,0x63,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x65,0x52,0x65,0x76,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E, -0x4C,0x69,0x73,0x74,0x3F,0x62,0x61,0x73,0x65,0x3F,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x8C,0xD7, -0xDF,0x7E,0xEE,0x1B,0x80,0x10,0xB3,0x83,0xF5,0xDB,0x11,0xEA,0x6B,0x4B,0xA8,0x92, -0x18,0xD9,0xF7,0x07,0x39,0xF5,0x2C,0xBE,0x06,0x75,0x7A,0x68,0x53,0x15,0x1C,0xEA, -0x4A,0xED,0x5E,0xFC,0x23,0xB2,0x13,0xA0,0xD3,0x09,0xFF,0xF6,0xF6,0x2E,0x6B,0x41, -0x71,0x79,0xCD,0xE2,0x6D,0xFD,0xAE,0x59,0x6B,0x85,0x1D,0xB8,0x4E,0x22,0x9A,0xED, -0x66,0x39,0x6E,0x4B,0x94,0xE6,0x55,0xFC,0x0B,0x1B,0x8B,0x77,0xC1,0x53,0x13,0x66, -0x89,0xD9,0x28,0xD6,0x8B,0xF3,0x45,0x4A,0x63,0xB7,0xFD,0x7B,0x0B,0x61,0x5D,0xB8, -0x6D,0xBE,0xC3,0xDC,0x5B,0x79,0xD2,0xED,0x86,0xE5,0xA2,0x4D,0xBE,0x5E,0x74,0x7C, -0x6A,0xED,0x16,0x38,0x1F,0x7F,0x58,0x81,0x5A,0x1A,0xEB,0x32,0x88,0x2D,0xB2,0xF3, -0x39,0x77,0x80,0xAF,0x5E,0xB6,0x61,0x75,0x29,0xDB,0x23,0x4D,0x88,0xCA,0x50,0x28, -0xCB,0x85,0xD2,0xD3,0x10,0xA2,0x59,0x6E,0xD3,0x93,0x54,0x00,0x7A,0xA2,0x46,0x95, -0x86,0x05,0x9C,0xA9,0x19,0x98,0xE5,0x31,0x72,0x0C,0x00,0xE2,0x67,0xD9,0x40,0xE0, -0x24,0x33,0x7B,0x6F,0x2C,0xB9,0x5C,0xAB,0x65,0x9D,0x2C,0xAC,0x76,0xEA,0x35,0x99, -0xF5,0x97,0xB9,0x0F,0x24,0xEC,0xC7,0x76,0x21,0x28,0x65,0xAE,0x57,0xE8,0x07,0x88, -0x75,0x4A,0x56,0xA0,0xD2,0x05,0x3A,0xA4,0xE6,0x8D,0x92,0x88,0x2C,0xF3,0xF2,0xE1, -0xC1,0xC6,0x61,0xDB,0x41,0xC5,0xC7,0x9B,0xF7,0x0E,0x1A,0x51,0x45,0xC2,0x61,0x6B, -0xDC,0x64,0x27,0x17,0x8C,0x5A,0xB7,0xDA,0x74,0x28,0xCD,0x97,0xE4,0xBD, -}; - - -/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 3 CA/CN=TC TrustCenter Class 3 CA II */ -/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 3 CA/CN=TC TrustCenter Class 3 CA II */ - - -const unsigned char TC_TrustCenter_Class_3_CA_II_certificate[1198]={ -0x30,0x82,0x04,0xAA,0x30,0x82,0x03,0x92,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x4A, -0x47,0x00,0x01,0x00,0x02,0xE5,0xA0,0x5D,0xD6,0x3F,0x00,0x51,0xBF,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x76,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, -0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, -0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55, -0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, -0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x41,0x31,0x25,0x30, -0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74, -0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x43, -0x41,0x20,0x49,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x31,0x31,0x32,0x31,0x34, -0x34,0x31,0x35,0x37,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31,0x32,0x32,0x35, -0x39,0x35,0x39,0x5A,0x30,0x76,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43, -0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62, -0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54, -0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73, -0x20,0x33,0x20,0x43,0x41,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C, -0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43, -0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x41,0x20,0x49,0x49,0x30,0x82,0x01,0x22, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, -0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB4,0xE0,0xBB, -0x51,0xBB,0x39,0x5C,0x8B,0x04,0xC5,0x4C,0x79,0x1C,0x23,0x86,0x31,0x10,0x63,0x43, -0x55,0x27,0x3F,0xC6,0x45,0xC7,0xA4,0x3D,0xEC,0x09,0x0D,0x1A,0x1E,0x20,0xC2,0x56, -0x1E,0xDE,0x1B,0x37,0x07,0x30,0x22,0x2F,0x6F,0xF1,0x06,0xF1,0xAB,0xAD,0xD6,0xC8, -0xAB,0x61,0xA3,0x2F,0x43,0xC4,0xB0,0xB2,0x2D,0xFC,0xC3,0x96,0x69,0x7B,0x7E,0x8A, -0xE4,0xCC,0xC0,0x39,0x12,0x90,0x42,0x60,0xC9,0xCC,0x35,0x68,0xEE,0xDA,0x5F,0x90, -0x56,0x5F,0xCD,0x1C,0x4D,0x5B,0x58,0x49,0xEB,0x0E,0x01,0x4F,0x64,0xFA,0x2C,0x3C, -0x89,0x58,0xD8,0x2F,0x2E,0xE2,0xB0,0x68,0xE9,0x22,0x3B,0x75,0x89,0xD6,0x44,0x1A, -0x65,0xF2,0x1B,0x97,0x26,0x1D,0x28,0x6D,0xAC,0xE8,0xBD,0x59,0x1D,0x2B,0x24,0xF6, -0xD6,0x84,0x03,0x66,0x88,0x24,0x00,0x78,0x60,0xF1,0xF8,0xAB,0xFE,0x02,0xB2,0x6B, -0xFB,0x22,0xFB,0x35,0xE6,0x16,0xD1,0xAD,0xF6,0x2E,0x12,0xE4,0xFA,0x35,0x6A,0xE5, -0x19,0xB9,0x5D,0xDB,0x3B,0x1E,0x1A,0xFB,0xD3,0xFF,0x15,0x14,0x08,0xD8,0x09,0x6A, -0xBA,0x45,0x9D,0x14,0x79,0x60,0x7D,0xAF,0x40,0x8A,0x07,0x73,0xB3,0x93,0x96,0xD3, -0x74,0x34,0x8D,0x3A,0x37,0x29,0xDE,0x5C,0xEC,0xF5,0xEE,0x2E,0x31,0xC2,0x20,0xDC, -0xBE,0xF1,0x4F,0x7F,0x23,0x52,0xD9,0x5B,0xE2,0x64,0xD9,0x9C,0xAA,0x07,0x08,0xB5, -0x45,0xBD,0xD1,0xD0,0x31,0xC1,0xAB,0x54,0x9F,0xA9,0xD2,0xC3,0x62,0x60,0x03,0xF1, -0xBB,0x39,0x4A,0x92,0x4A,0x3D,0x0A,0xB9,0x9D,0xC5,0xA0,0xFE,0x37,0x02,0x03,0x01, -0x00,0x01,0xA3,0x82,0x01,0x34,0x30,0x82,0x01,0x30,0x30,0x0F,0x06,0x03,0x55,0x1D, -0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, -0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55, -0x1D,0x0E,0x04,0x16,0x04,0x14,0xD4,0xA2,0xFC,0x9F,0xB3,0xC3,0xD8,0x03,0xD3,0x57, -0x5C,0x07,0xA4,0xD0,0x24,0xA7,0xC0,0xF2,0x00,0xD4,0x30,0x81,0xED,0x06,0x03,0x55, -0x1D,0x1F,0x04,0x81,0xE5,0x30,0x81,0xE2,0x30,0x81,0xDF,0xA0,0x81,0xDC,0xA0,0x81, -0xD9,0x86,0x35,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72, -0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x72,0x6C, -0x2F,0x76,0x32,0x2F,0x74,0x63,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x33,0x5F,0x63, -0x61,0x5F,0x49,0x49,0x2E,0x63,0x72,0x6C,0x86,0x81,0x9F,0x6C,0x64,0x61,0x70,0x3A, -0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65, -0x72,0x2E,0x64,0x65,0x2F,0x43,0x4E,0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75, -0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x25,0x32,0x30,0x43,0x6C,0x61,0x73,0x73, -0x25,0x32,0x30,0x33,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x49,0x49,0x2C,0x4F, -0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65, -0x72,0x25,0x32,0x30,0x47,0x6D,0x62,0x48,0x2C,0x4F,0x55,0x3D,0x72,0x6F,0x6F,0x74, -0x63,0x65,0x72,0x74,0x73,0x2C,0x44,0x43,0x3D,0x74,0x72,0x75,0x73,0x74,0x63,0x65, -0x6E,0x74,0x65,0x72,0x2C,0x44,0x43,0x3D,0x64,0x65,0x3F,0x63,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x65,0x52,0x65,0x76,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E, -0x4C,0x69,0x73,0x74,0x3F,0x62,0x61,0x73,0x65,0x3F,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x36,0x60, -0xE4,0x70,0xF7,0x06,0x20,0x43,0xD9,0x23,0x1A,0x42,0xF2,0xF8,0xA3,0xB2,0xB9,0x4D, -0x8A,0xB4,0xF3,0xC2,0x9A,0x55,0x31,0x7C,0xC4,0x3B,0x67,0x9A,0xB4,0xDF,0x4D,0x0E, -0x8A,0x93,0x4A,0x17,0x8B,0x1B,0x8D,0xCA,0x89,0xE1,0xCF,0x3A,0x1E,0xAC,0x1D,0xF1, -0x9C,0x32,0xB4,0x8E,0x59,0x76,0xA2,0x41,0x85,0x25,0x37,0xA0,0x13,0xD0,0xF5,0x7C, -0x4E,0xD5,0xEA,0x96,0xE2,0x6E,0x72,0xC1,0xBB,0x2A,0xFE,0x6C,0x6E,0xF8,0x91,0x98, -0x46,0xFC,0xC9,0x1B,0x57,0x5B,0xEA,0xC8,0x1A,0x3B,0x3F,0xB0,0x51,0x98,0x3C,0x07, -0xDA,0x2C,0x59,0x01,0xDA,0x8B,0x44,0xE8,0xE1,0x74,0xFD,0xA7,0x68,0xDD,0x54,0xBA, -0x83,0x46,0xEC,0xC8,0x46,0xB5,0xF8,0xAF,0x97,0xC0,0x3B,0x09,0x1C,0x8F,0xCE,0x72, -0x96,0x3D,0x33,0x56,0x70,0xBC,0x96,0xCB,0xD8,0xD5,0x7D,0x20,0x9A,0x83,0x9F,0x1A, -0xDC,0x39,0xF1,0xC5,0x72,0xA3,0x11,0x03,0xFD,0x3B,0x42,0x52,0x29,0xDB,0xE8,0x01, -0xF7,0x9B,0x5E,0x8C,0xD6,0x8D,0x86,0x4E,0x19,0xFA,0xBC,0x1C,0xBE,0xC5,0x21,0xA5, -0x87,0x9E,0x78,0x2E,0x36,0xDB,0x09,0x71,0xA3,0x72,0x34,0xF8,0x6C,0xE3,0x06,0x09, -0xF2,0x5E,0x56,0xA5,0xD3,0xDD,0x98,0xFA,0xD4,0xE6,0x06,0xF4,0xF0,0xB6,0x20,0x63, -0x4B,0xEA,0x29,0xBD,0xAA,0x82,0x66,0x1E,0xFB,0x81,0xAA,0xA7,0x37,0xAD,0x13,0x18, -0xE6,0x92,0xC3,0x81,0xC1,0x33,0xBB,0x88,0x1E,0xA1,0xE7,0xE2,0xB4,0xBD,0x31,0x6C, -0x0E,0x51,0x3D,0x6F,0xFB,0x96,0x56,0x80,0xE2,0x36,0x17,0xD1,0xDC,0xE4, -}; - - -/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA I */ -/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA I */ - - -const unsigned char TC_TrustCenter_Universal_CA_I_certificate[993]={ -0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x1D, -0xA2,0x00,0x01,0x00,0x02,0xEC,0xB7,0x60,0x80,0x78,0x8D,0xB6,0x06,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x79,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, -0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, -0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55, -0x04,0x0B,0x13,0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, -0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31, -0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75, -0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73, -0x61,0x6C,0x20,0x43,0x41,0x20,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x33,0x32, -0x32,0x31,0x35,0x35,0x34,0x32,0x38,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31, -0x32,0x32,0x35,0x39,0x35,0x39,0x5A,0x30,0x79,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, -0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13, -0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20, -0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x54, -0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E, -0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,0x26,0x30,0x24,0x06,0x03, -0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E, -0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41, -0x20,0x49,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +const unsigned char AffirmTrust_Networking_certificate[848]={ +0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x7C, +0x4F,0x04,0x39,0x1C,0xD4,0x99,0x2D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, +0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69,0x6E,0x67,0x30,0x1E,0x17,0x0D, +0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x17,0x0D,0x33, +0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x30,0x44,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, +0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69, +0x6E,0x67,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, 0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, -0x01,0x01,0x00,0xA4,0x77,0x23,0x96,0x44,0xAF,0x90,0xF4,0x31,0xA7,0x10,0xF4,0x26, -0x87,0x9C,0xF3,0x38,0xD9,0x0F,0x5E,0xDE,0xCF,0x41,0xE8,0x31,0xAD,0xC6,0x74,0x91, -0x24,0x96,0x78,0x1E,0x09,0xA0,0x9B,0x9A,0x95,0x4A,0x4A,0xF5,0x62,0x7C,0x02,0xA8, -0xCA,0xAC,0xFB,0x5A,0x04,0x76,0x39,0xDE,0x5F,0xF1,0xF9,0xB3,0xBF,0xF3,0x03,0x58, -0x55,0xD2,0xAA,0xB7,0xE3,0x04,0x22,0xD1,0xF8,0x94,0xDA,0x22,0x08,0x00,0x8D,0xD3, -0x7C,0x26,0x5D,0xCC,0x77,0x79,0xE7,0x2C,0x78,0x39,0xA8,0x26,0x73,0x0E,0xA2,0x5D, -0x25,0x69,0x85,0x4F,0x55,0x0E,0x9A,0xEF,0xC6,0xB9,0x44,0xE1,0x57,0x3D,0xDF,0x1F, -0x54,0x22,0xE5,0x6F,0x65,0xAA,0x33,0x84,0x3A,0xF3,0xCE,0x7A,0xBE,0x55,0x97,0xAE, -0x8D,0x12,0x0F,0x14,0x33,0xE2,0x50,0x70,0xC3,0x49,0x87,0x13,0xBC,0x51,0xDE,0xD7, -0x98,0x12,0x5A,0xEF,0x3A,0x83,0x33,0x92,0x06,0x75,0x8B,0x92,0x7C,0x12,0x68,0x7B, -0x70,0x6A,0x0F,0xB5,0x9B,0xB6,0x77,0x5B,0x48,0x59,0x9D,0xE4,0xEF,0x5A,0xAD,0xF3, -0xC1,0x9E,0xD4,0xD7,0x45,0x4E,0xCA,0x56,0x34,0x21,0xBC,0x3E,0x17,0x5B,0x6F,0x77, -0x0C,0x48,0x01,0x43,0x29,0xB0,0xDD,0x3F,0x96,0x6E,0xE6,0x95,0xAA,0x0C,0xC0,0x20, -0xB6,0xFD,0x3E,0x36,0x27,0x9C,0xE3,0x5C,0xCF,0x4E,0x81,0xDC,0x19,0xBB,0x91,0x90, -0x7D,0xEC,0xE6,0x97,0x04,0x1E,0x93,0xCC,0x22,0x49,0xD7,0x97,0x86,0xB6,0x13,0x0A, -0x3C,0x43,0x23,0x77,0x7E,0xF0,0xDC,0xE6,0xCD,0x24,0x1F,0x3B,0x83,0x9B,0x34,0x3A, -0x83,0x34,0xE3,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x1F,0x06,0x03, -0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE, -0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0F,0x06, -0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, -0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D, -0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE, -0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, -0x00,0x28,0xD2,0xE0,0x86,0xD5,0xE6,0xF8,0x7B,0xF0,0x97,0xDC,0x22,0x6B,0x3B,0x95, -0x14,0x56,0x0F,0x11,0x30,0xA5,0x9A,0x4F,0x3A,0xB0,0x3A,0xE0,0x06,0xCB,0x65,0xF5, -0xED,0xC6,0x97,0x27,0xFE,0x25,0xF2,0x57,0xE6,0x5E,0x95,0x8C,0x3E,0x64,0x60,0x15, -0x5A,0x7F,0x2F,0x0D,0x01,0xC5,0xB1,0x60,0xFD,0x45,0x35,0xCF,0xF0,0xB2,0xBF,0x06, -0xD9,0xEF,0x5A,0xBE,0xB3,0x62,0x21,0xB4,0xD7,0xAB,0x35,0x7C,0x53,0x3E,0xA6,0x27, -0xF1,0xA1,0x2D,0xDA,0x1A,0x23,0x9D,0xCC,0xDD,0xEC,0x3C,0x2D,0x9E,0x27,0x34,0x5D, -0x0F,0xC2,0x36,0x79,0xBC,0xC9,0x4A,0x62,0x2D,0xED,0x6B,0xD9,0x7D,0x41,0x43,0x7C, -0xB6,0xAA,0xCA,0xED,0x61,0xB1,0x37,0x82,0x15,0x09,0x1A,0x8A,0x16,0x30,0xD8,0xEC, -0xC9,0xD6,0x47,0x72,0x78,0x4B,0x10,0x46,0x14,0x8E,0x5F,0x0E,0xAF,0xEC,0xC7,0x2F, -0xAB,0x10,0xD7,0xB6,0xF1,0x6E,0xEC,0x86,0xB2,0xC2,0xE8,0x0D,0x92,0x73,0xDC,0xA2, -0xF4,0x0F,0x3A,0xBF,0x61,0x23,0x10,0x89,0x9C,0x48,0x40,0x6E,0x70,0x00,0xB3,0xD3, -0xBA,0x37,0x44,0x58,0x11,0x7A,0x02,0x6A,0x88,0xF0,0x37,0x34,0xF0,0x19,0xE9,0xAC, -0xD4,0x65,0x73,0xF6,0x69,0x8C,0x64,0x94,0x3A,0x79,0x85,0x29,0xB0,0x16,0x2B,0x0C, -0x82,0x3F,0x06,0x9C,0xC7,0xFD,0x10,0x2B,0x9E,0x0F,0x2C,0xB6,0x9E,0xE3,0x15,0xBF, -0xD9,0x36,0x1C,0xBA,0x25,0x1A,0x52,0x3D,0x1A,0xEC,0x22,0x0C,0x1C,0xE0,0xA4,0xA2, -0x3D,0xF0,0xE8,0x39,0xCF,0x81,0xC0,0x7B,0xED,0x5D,0x1F,0x6F,0xC5,0xD0,0x0B,0xD7, -0x98, +0x01,0x01,0x00,0xB4,0x84,0xCC,0x33,0x17,0x2E,0x6B,0x94,0x6C,0x6B,0x61,0x52,0xA0, +0xEB,0xA3,0xCF,0x79,0x94,0x4C,0xE5,0x94,0x80,0x99,0xCB,0x55,0x64,0x44,0x65,0x8F, +0x67,0x64,0xE2,0x06,0xE3,0x5C,0x37,0x49,0xF6,0x2F,0x9B,0x84,0x84,0x1E,0x2D,0xF2, +0x60,0x9D,0x30,0x4E,0xCC,0x84,0x85,0xE2,0x2C,0xCF,0x1E,0x9E,0xFE,0x36,0xAB,0x33, +0x77,0x35,0x44,0xD8,0x35,0x96,0x1A,0x3D,0x36,0xE8,0x7A,0x0E,0xD8,0xD5,0x47,0xA1, +0x6A,0x69,0x8B,0xD9,0xFC,0xBB,0x3A,0xAE,0x79,0x5A,0xD5,0xF4,0xD6,0x71,0xBB,0x9A, +0x90,0x23,0x6B,0x9A,0xB7,0x88,0x74,0x87,0x0C,0x1E,0x5F,0xB9,0x9E,0x2D,0xFA,0xAB, +0x53,0x2B,0xDC,0xBB,0x76,0x3E,0x93,0x4C,0x08,0x08,0x8C,0x1E,0xA2,0x23,0x1C,0xD4, +0x6A,0xAD,0x22,0xBA,0x99,0x01,0x2E,0x6D,0x65,0xCB,0xBE,0x24,0x66,0x55,0x24,0x4B, +0x40,0x44,0xB1,0x1B,0xD7,0xE1,0xC2,0x85,0xC0,0xDE,0x10,0x3F,0x3D,0xED,0xB8,0xFC, +0xF1,0xF1,0x23,0x53,0xDC,0xBF,0x65,0x97,0x6F,0xD9,0xF9,0x40,0x71,0x8D,0x7D,0xBD, +0x95,0xD4,0xCE,0xBE,0xA0,0x5E,0x27,0x23,0xDE,0xFD,0xA6,0xD0,0x26,0x0E,0x00,0x29, +0xEB,0x3C,0x46,0xF0,0x3D,0x60,0xBF,0x3F,0x50,0xD2,0xDC,0x26,0x41,0x51,0x9E,0x14, +0x37,0x42,0x04,0xA3,0x70,0x57,0xA8,0x1B,0x87,0xED,0x2D,0xFA,0x7B,0xEE,0x8C,0x0A, +0xE3,0xA9,0x66,0x89,0x19,0xCB,0x41,0xF9,0xDD,0x44,0x36,0x61,0xCF,0xE2,0x77,0x46, +0xC8,0x7D,0xF6,0xF4,0x92,0x81,0x36,0xFD,0xDB,0x34,0xF1,0x72,0x7E,0xF3,0x0C,0x16, +0xBD,0xB4,0x15,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x07,0x1F,0xD2,0xE7,0x9C,0xDA,0xC2,0x6E,0xA2, +0x40,0xB4,0xB0,0x7A,0x50,0x10,0x50,0x74,0xC4,0xC8,0xBD,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x89,0x57,0xB2,0x16,0x7A,0xA8,0xC2,0xFD,0xD6,0xD9,0x9B,0x9B,0x34,0xC2,0x9C,0xB4, +0x32,0x14,0x4D,0xA7,0xA4,0xDF,0xEC,0xBE,0xA7,0xBE,0xF8,0x43,0xDB,0x91,0x37,0xCE, +0xB4,0x32,0x2E,0x50,0x55,0x1A,0x35,0x4E,0x76,0x43,0x71,0x20,0xEF,0x93,0x77,0x4E, +0x15,0x70,0x2E,0x87,0xC3,0xC1,0x1D,0x6D,0xDC,0xCB,0xB5,0x27,0xD4,0x2C,0x56,0xD1, +0x52,0x53,0x3A,0x44,0xD2,0x73,0xC8,0xC4,0x1B,0x05,0x65,0x5A,0x62,0x92,0x9C,0xEE, +0x41,0x8D,0x31,0xDB,0xE7,0x34,0xEA,0x59,0x21,0xD5,0x01,0x7A,0xD7,0x64,0xB8,0x64, +0x39,0xCD,0xC9,0xED,0xAF,0xED,0x4B,0x03,0x48,0xA7,0xA0,0x99,0x01,0x80,0xDC,0x65, +0xA3,0x36,0xAE,0x65,0x59,0x48,0x4F,0x82,0x4B,0xC8,0x65,0xF1,0x57,0x1D,0xE5,0x59, +0x2E,0x0A,0x3F,0x6C,0xD8,0xD1,0xF5,0xE5,0x09,0xB4,0x6C,0x54,0x00,0x0A,0xE0,0x15, +0x4D,0x87,0x75,0x6D,0xB7,0x58,0x96,0x5A,0xDD,0x6D,0xD2,0x00,0xA0,0xF4,0x9B,0x48, +0xBE,0xC3,0x37,0xA4,0xBA,0x36,0xE0,0x7C,0x87,0x85,0x97,0x1A,0x15,0xA2,0xDE,0x2E, +0xA2,0x5B,0xBD,0xAF,0x18,0xF9,0x90,0x50,0xCD,0x70,0x59,0xF8,0x27,0x67,0x47,0xCB, +0xC7,0xA0,0x07,0x3A,0x7D,0xD1,0x2C,0x5D,0x6C,0x19,0x3A,0x66,0xB5,0x7D,0xFD,0x91, +0x6F,0x82,0xB1,0xBE,0x08,0x93,0xDB,0x14,0x47,0xF1,0xA2,0x37,0xC7,0x45,0x9E,0x3C, +0xC7,0x77,0xAF,0x64,0xA8,0x93,0xDF,0xF6,0x69,0x83,0x82,0x60,0xF2,0x49,0x42,0x34, +0xED,0x5A,0x00,0x54,0x85,0x1C,0x16,0x36,0x92,0x0C,0x5C,0xFA,0xA6,0xAD,0xBF,0xDB, }; -/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA III */ -/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA III */ +/* subject:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */ +/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */ -const unsigned char TC_TrustCenter_Universal_CA_III_certificate[997]={ -0x30,0x82,0x03,0xE1,0x30,0x82,0x02,0xC9,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x63, -0x25,0x00,0x01,0x00,0x02,0x14,0x8D,0x33,0x15,0x02,0xE4,0x6C,0xF4,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x7B,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, -0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, -0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55, -0x04,0x0B,0x13,0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, -0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31, -0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x03,0x13,0x1F,0x54,0x43,0x20,0x54,0x72,0x75, -0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73, -0x61,0x6C,0x20,0x43,0x41,0x20,0x49,0x49,0x49,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30, -0x39,0x30,0x39,0x30,0x38,0x31,0x35,0x32,0x37,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32, -0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x7B,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04, -0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65, -0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13, -0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20, -0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,0x28,0x30,0x26, -0x06,0x03,0x55,0x04,0x03,0x13,0x1F,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43, -0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20, -0x43,0x41,0x20,0x49,0x49,0x49,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, -0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC2,0xDA,0x9C,0x62,0xB0,0xB9,0x71,0x12,0xB0, -0x0B,0xC8,0x1A,0x57,0xB2,0xAE,0x83,0x14,0x99,0xB3,0x34,0x4B,0x9B,0x90,0xA2,0xC5, -0xE7,0xE7,0x2F,0x02,0xA0,0x4D,0x2D,0xA4,0xFA,0x85,0xDA,0x9B,0x25,0x85,0x2D,0x40, -0x28,0x20,0x6D,0xEA,0xE0,0xBD,0xB1,0x48,0x83,0x22,0x29,0x44,0x9F,0x4E,0x83,0xEE, -0x35,0x51,0x13,0x73,0x74,0xD5,0xBC,0xF2,0x30,0x66,0x94,0x53,0xC0,0x40,0x36,0x2F, -0x0C,0x84,0x65,0xCE,0x0F,0x6E,0xC2,0x58,0x93,0xE8,0x2C,0x0B,0x3A,0xE9,0xC1,0x8E, -0xFB,0xF2,0x6B,0xCA,0x3C,0xE2,0x9C,0x4E,0x8E,0xE4,0xF9,0x7D,0xD3,0x27,0x9F,0x1B, -0xD5,0x67,0x78,0x87,0x2D,0x7F,0x0B,0x47,0xB3,0xC7,0xE8,0xC9,0x48,0x7C,0xAF,0x2F, -0xCC,0x0A,0xD9,0x41,0xEF,0x9F,0xFE,0x9A,0xE1,0xB2,0xAE,0xF9,0x53,0xB5,0xE5,0xE9, -0x46,0x9F,0x60,0xE3,0xDF,0x8D,0xD3,0x7F,0xFB,0x96,0x7E,0xB3,0xB5,0x72,0xF8,0x4B, -0xAD,0x08,0x79,0xCD,0x69,0x89,0x40,0x27,0xF5,0x2A,0xC1,0xAD,0x43,0xEC,0xA4,0x53, -0xC8,0x61,0xB6,0xF7,0xD2,0x79,0x2A,0x67,0x18,0x76,0x48,0x6D,0x5B,0x25,0x01,0xD1, -0x26,0xC5,0xB7,0x57,0x69,0x23,0x15,0x5B,0x61,0x8A,0xAD,0xF0,0x1B,0x2D,0xD9,0xAF, -0x5C,0xF1,0x26,0x90,0x69,0xA9,0xD5,0x0C,0x40,0xF5,0x33,0x80,0x43,0x8F,0x9C,0xA3, -0x76,0x2A,0x45,0xB4,0xAF,0xBF,0x7F,0x3E,0x87,0x3F,0x76,0xC5,0xCD,0x2A,0xDE,0x20, -0xC5,0x16,0x58,0xCB,0xF9,0x1B,0xF5,0x0F,0xCB,0x0D,0x11,0x52,0x64,0xB8,0xD2,0x76, -0x62,0x77,0x83,0xF1,0x58,0x9F,0xFF,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61, -0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x56,0xE7,0xE1, -0x5B,0x25,0x43,0x80,0xE0,0xF6,0x8C,0xE1,0x71,0xBC,0x8E,0xE5,0x80,0x2F,0xC4,0x48, -0xE2,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, -0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02, -0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x56,0xE7,0xE1, -0x5B,0x25,0x43,0x80,0xE0,0xF6,0x8C,0xE1,0x71,0xBC,0x8E,0xE5,0x80,0x2F,0xC4,0x48, -0xE2,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, -0x03,0x82,0x01,0x01,0x00,0x83,0xC7,0xAF,0xEA,0x7F,0x4D,0x0A,0x3C,0x39,0xB1,0x68, -0xBE,0x7B,0x6D,0x89,0x2E,0xE9,0xB3,0x09,0xE7,0x18,0x57,0x8D,0x85,0x9A,0x17,0xF3, -0x76,0x42,0x50,0x13,0x0F,0xC7,0x90,0x6F,0x33,0xAD,0xC5,0x49,0x60,0x2B,0x6C,0x49, -0x58,0x19,0xD4,0xE2,0xBE,0xB7,0xBF,0xAB,0x49,0xBC,0x94,0xC8,0xAB,0xBE,0x28,0x6C, -0x16,0x68,0xE0,0xC8,0x97,0x46,0x20,0xA0,0x68,0x67,0x60,0x88,0x39,0x20,0x51,0xD8, -0x68,0x01,0x11,0xCE,0xA7,0xF6,0x11,0x07,0xF6,0xEC,0xEC,0xAC,0x1A,0x1F,0xB2,0x66, -0x6E,0x56,0x67,0x60,0x7A,0x74,0x5E,0xC0,0x6D,0x97,0x36,0xAE,0xB5,0x0D,0x5D,0x66, -0x73,0xC0,0x25,0x32,0x45,0xD8,0x4A,0x06,0x07,0x8F,0xC4,0xB7,0x07,0xB1,0x4D,0x06, -0x0D,0xE1,0xA5,0xEB,0xF4,0x75,0xCA,0xBA,0x9C,0xD0,0xBD,0xB3,0xD3,0x32,0x24,0x4C, -0xEE,0x7E,0xE2,0x76,0x04,0x4B,0x49,0x53,0xD8,0xF2,0xE9,0x54,0x33,0xFC,0xE5,0x71, -0x1F,0x3D,0x14,0x5C,0x96,0x4B,0xF1,0x3A,0xF2,0x00,0xBB,0x6C,0xB4,0xFA,0x96,0x55, -0x08,0x88,0x09,0xC1,0xCC,0x91,0x19,0x29,0xB0,0x20,0x2D,0xFF,0xCB,0x38,0xA4,0x40, -0xE1,0x17,0xBE,0x79,0x61,0x80,0xFF,0x07,0x03,0x86,0x4C,0x4E,0x7B,0x06,0x9F,0x11, -0x86,0x8D,0x89,0xEE,0x27,0xC4,0xDB,0xE2,0xBC,0x19,0x8E,0x0B,0xC3,0xC3,0x13,0xC7, -0x2D,0x03,0x63,0x3B,0xD3,0xE8,0xE4,0xA2,0x2A,0xC2,0x82,0x08,0x94,0x16,0x54,0xF0, -0xEF,0x1F,0x27,0x90,0x25,0xB8,0x0D,0x0E,0x28,0x1B,0x47,0x77,0x47,0xBD,0x1C,0xA8, -0x25,0xF1,0x94,0xB4,0x66, -}; - - -/* subject:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com */ -/* issuer :/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com */ - - -const unsigned char Thawte_Premium_Server_CA_certificate[811]={ -0x30,0x82,0x03,0x27,0x30,0x82,0x02,0x90,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, -0x81,0xCE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5A,0x41,0x31, -0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13,0x0C,0x57,0x65,0x73,0x74,0x65,0x72, -0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13, -0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77,0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03, -0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,0x6F,0x6E,0x73, -0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63,0x31,0x28,0x30,0x26,0x06,0x03,0x55, -0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, -0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73, -0x69,0x6F,0x6E,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x54,0x68, -0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x53,0x65,0x72, -0x76,0x65,0x72,0x20,0x43,0x41,0x31,0x28,0x30,0x26,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x09,0x01,0x16,0x19,0x70,0x72,0x65,0x6D,0x69,0x75,0x6D,0x2D,0x73, -0x65,0x72,0x76,0x65,0x72,0x40,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F,0x6D, -0x30,0x1E,0x17,0x0D,0x39,0x36,0x30,0x38,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30, -0x5A,0x17,0x0D,0x32,0x30,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A, -0x30,0x81,0xCE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5A,0x41, -0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13,0x0C,0x57,0x65,0x73,0x74,0x65, -0x72,0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07, -0x13,0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77,0x6E,0x31,0x1D,0x30,0x1B,0x06, -0x03,0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,0x6F,0x6E, -0x73,0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63,0x31,0x28,0x30,0x26,0x06,0x03, -0x55,0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, -0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69, -0x73,0x69,0x6F,0x6E,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x54, -0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x53,0x65, -0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x31,0x28,0x30,0x26,0x06,0x09,0x2A,0x86,0x48, -0x86,0xF7,0x0D,0x01,0x09,0x01,0x16,0x19,0x70,0x72,0x65,0x6D,0x69,0x75,0x6D,0x2D, -0x73,0x65,0x72,0x76,0x65,0x72,0x40,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F, -0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xD2,0x36, -0x36,0x6A,0x8B,0xD7,0xC2,0x5B,0x9E,0xDA,0x81,0x41,0x62,0x8F,0x38,0xEE,0x49,0x04, -0x55,0xD6,0xD0,0xEF,0x1C,0x1B,0x95,0x16,0x47,0xEF,0x18,0x48,0x35,0x3A,0x52,0xF4, -0x2B,0x6A,0x06,0x8F,0x3B,0x2F,0xEA,0x56,0xE3,0xAF,0x86,0x8D,0x9E,0x17,0xF7,0x9E, -0xB4,0x65,0x75,0x02,0x4D,0xEF,0xCB,0x09,0xA2,0x21,0x51,0xD8,0x9B,0xD0,0x67,0xD0, -0xBA,0x0D,0x92,0x06,0x14,0x73,0xD4,0x93,0xCB,0x97,0x2A,0x00,0x9C,0x5C,0x4E,0x0C, -0xBC,0xFA,0x15,0x52,0xFC,0xF2,0x44,0x6E,0xDA,0x11,0x4A,0x6E,0x08,0x9F,0x2F,0x2D, -0xE3,0xF9,0xAA,0x3A,0x86,0x73,0xB6,0x46,0x53,0x58,0xC8,0x89,0x05,0xBD,0x83,0x11, -0xB8,0x73,0x3F,0xAA,0x07,0x8D,0xF4,0x42,0x4D,0xE7,0x40,0x9D,0x1C,0x37,0x02,0x03, -0x01,0x00,0x01,0xA3,0x13,0x30,0x11,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, -0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x03,0x81,0x81,0x00,0x26,0x48,0x2C,0x16,0xC2, -0x58,0xFA,0xE8,0x16,0x74,0x0C,0xAA,0xAA,0x5F,0x54,0x3F,0xF2,0xD7,0xC9,0x78,0x60, -0x5E,0x5E,0x6E,0x37,0x63,0x22,0x77,0x36,0x7E,0xB2,0x17,0xC4,0x34,0xB9,0xF5,0x08, -0x85,0xFC,0xC9,0x01,0x38,0xFF,0x4D,0xBE,0xF2,0x16,0x42,0x43,0xE7,0xBB,0x5A,0x46, -0xFB,0xC1,0xC6,0x11,0x1F,0xF1,0x4A,0xB0,0x28,0x46,0xC9,0xC3,0xC4,0x42,0x7D,0xBC, -0xFA,0xAB,0x59,0x6E,0xD5,0xB7,0x51,0x88,0x11,0xE3,0xA4,0x85,0x19,0x6B,0x82,0x4C, -0xA4,0x0C,0x12,0xAD,0xE9,0xA4,0xAE,0x3F,0xF1,0xC3,0x49,0x65,0x9A,0x8C,0xC5,0xC8, -0x3E,0x25,0xB7,0x94,0x99,0xBB,0x92,0x32,0x71,0x07,0xF0,0x86,0x5E,0xED,0x50,0x27, -0xA6,0x0D,0xA6,0x23,0xF9,0xBB,0xCB,0xA6,0x07,0x14,0x42, -}; - - -/* subject:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA */ -/* issuer :/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA */ - - -const unsigned char thawte_Primary_Root_CA_certificate[1060]={ -0x30,0x82,0x04,0x20,0x30,0x82,0x03,0x08,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x34, -0x4E,0xD5,0x57,0x20,0xD5,0xED,0xEC,0x49,0xF4,0x2F,0xCE,0x37,0xDB,0x2B,0x6D,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, -0xA9,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15, -0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C, -0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F, -0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65, -0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31, -0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30, -0x30,0x36,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20, -0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64, -0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55, -0x04,0x03,0x13,0x16,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61, -0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36, -0x31,0x31,0x31,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30, -0x37,0x31,0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xA9,0x31,0x0B,0x30, -0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03, -0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63, -0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74, -0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63, -0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31,0x38,0x30,0x36,0x06, -0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x74, -0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F, -0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65, -0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16, -0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x52, -0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, -0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAC,0xA0,0xF0,0xFB,0x80,0x59,0xD4,0x9C,0xC7, -0xA4,0xCF,0x9D,0xA1,0x59,0x73,0x09,0x10,0x45,0x0C,0x0D,0x2C,0x6E,0x68,0xF1,0x6C, -0x5B,0x48,0x68,0x49,0x59,0x37,0xFC,0x0B,0x33,0x19,0xC2,0x77,0x7F,0xCC,0x10,0x2D, -0x95,0x34,0x1C,0xE6,0xEB,0x4D,0x09,0xA7,0x1C,0xD2,0xB8,0xC9,0x97,0x36,0x02,0xB7, -0x89,0xD4,0x24,0x5F,0x06,0xC0,0xCC,0x44,0x94,0x94,0x8D,0x02,0x62,0x6F,0xEB,0x5A, -0xDD,0x11,0x8D,0x28,0x9A,0x5C,0x84,0x90,0x10,0x7A,0x0D,0xBD,0x74,0x66,0x2F,0x6A, -0x38,0xA0,0xE2,0xD5,0x54,0x44,0xEB,0x1D,0x07,0x9F,0x07,0xBA,0x6F,0xEE,0xE9,0xFD, -0x4E,0x0B,0x29,0xF5,0x3E,0x84,0xA0,0x01,0xF1,0x9C,0xAB,0xF8,0x1C,0x7E,0x89,0xA4, -0xE8,0xA1,0xD8,0x71,0x65,0x0D,0xA3,0x51,0x7B,0xEE,0xBC,0xD2,0x22,0x60,0x0D,0xB9, -0x5B,0x9D,0xDF,0xBA,0xFC,0x51,0x5B,0x0B,0xAF,0x98,0xB2,0xE9,0x2E,0xE9,0x04,0xE8, -0x62,0x87,0xDE,0x2B,0xC8,0xD7,0x4E,0xC1,0x4C,0x64,0x1E,0xDD,0xCF,0x87,0x58,0xBA, -0x4A,0x4F,0xCA,0x68,0x07,0x1D,0x1C,0x9D,0x4A,0xC6,0xD5,0x2F,0x91,0xCC,0x7C,0x71, -0x72,0x1C,0xC5,0xC0,0x67,0xEB,0x32,0xFD,0xC9,0x92,0x5C,0x94,0xDA,0x85,0xC0,0x9B, -0xBF,0x53,0x7D,0x2B,0x09,0xF4,0x8C,0x9D,0x91,0x1F,0x97,0x6A,0x52,0xCB,0xDE,0x09, -0x36,0xA4,0x77,0xD8,0x7B,0x87,0x50,0x44,0xD5,0x3E,0x6E,0x29,0x69,0xFB,0x39,0x49, -0x26,0x1E,0x09,0xA5,0x80,0x7B,0x40,0x2D,0xEB,0xE8,0x27,0x85,0xC9,0xFE,0x61,0xFD, -0x7E,0xE6,0x7C,0x97,0x1D,0xD5,0x9D,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40, -0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01, -0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, -0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7B,0x5B,0x45,0xCF, -0xAF,0xCE,0xCB,0x7A,0xFD,0x31,0x92,0x1A,0x6A,0xB6,0xF3,0x46,0xEB,0x57,0x48,0x50, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, -0x82,0x01,0x01,0x00,0x79,0x11,0xC0,0x4B,0xB3,0x91,0xB6,0xFC,0xF0,0xE9,0x67,0xD4, -0x0D,0x6E,0x45,0xBE,0x55,0xE8,0x93,0xD2,0xCE,0x03,0x3F,0xED,0xDA,0x25,0xB0,0x1D, -0x57,0xCB,0x1E,0x3A,0x76,0xA0,0x4C,0xEC,0x50,0x76,0xE8,0x64,0x72,0x0C,0xA4,0xA9, -0xF1,0xB8,0x8B,0xD6,0xD6,0x87,0x84,0xBB,0x32,0xE5,0x41,0x11,0xC0,0x77,0xD9,0xB3, -0x60,0x9D,0xEB,0x1B,0xD5,0xD1,0x6E,0x44,0x44,0xA9,0xA6,0x01,0xEC,0x55,0x62,0x1D, -0x77,0xB8,0x5C,0x8E,0x48,0x49,0x7C,0x9C,0x3B,0x57,0x11,0xAC,0xAD,0x73,0x37,0x8E, -0x2F,0x78,0x5C,0x90,0x68,0x47,0xD9,0x60,0x60,0xE6,0xFC,0x07,0x3D,0x22,0x20,0x17, -0xC4,0xF7,0x16,0xE9,0xC4,0xD8,0x72,0xF9,0xC8,0x73,0x7C,0xDF,0x16,0x2F,0x15,0xA9, -0x3E,0xFD,0x6A,0x27,0xB6,0xA1,0xEB,0x5A,0xBA,0x98,0x1F,0xD5,0xE3,0x4D,0x64,0x0A, -0x9D,0x13,0xC8,0x61,0xBA,0xF5,0x39,0x1C,0x87,0xBA,0xB8,0xBD,0x7B,0x22,0x7F,0xF6, -0xFE,0xAC,0x40,0x79,0xE5,0xAC,0x10,0x6F,0x3D,0x8F,0x1B,0x79,0x76,0x8B,0xC4,0x37, -0xB3,0x21,0x18,0x84,0xE5,0x36,0x00,0xEB,0x63,0x20,0x99,0xB9,0xE9,0xFE,0x33,0x04, -0xBB,0x41,0xC8,0xC1,0x02,0xF9,0x44,0x63,0x20,0x9E,0x81,0xCE,0x42,0xD3,0xD6,0x3F, -0x2C,0x76,0xD3,0x63,0x9C,0x59,0xDD,0x8F,0xA6,0xE1,0x0E,0xA0,0x2E,0x41,0xF7,0x2E, -0x95,0x47,0xCF,0xBC,0xFD,0x33,0xF3,0xF6,0x0B,0x61,0x7E,0x7E,0x91,0x2B,0x81,0x47, -0xC2,0x27,0x30,0xEE,0xA7,0x10,0x5D,0x37,0x8F,0x5C,0x39,0x2B,0xE4,0x04,0xF0,0x7B, -0x8D,0x56,0x8C,0x68, -}; - - -/* subject:/C=US/O=thawte, Inc./OU=(c) 2007 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G2 */ -/* issuer :/C=US/O=thawte, Inc./OU=(c) 2007 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G2 */ - - -const unsigned char thawte_Primary_Root_CA___G2_certificate[652]={ -0x30,0x82,0x02,0x88,0x30,0x82,0x02,0x0D,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x35, -0xFC,0x26,0x5C,0xD9,0x84,0x4F,0xC9,0x3D,0x26,0x3D,0x57,0x9B,0xAE,0xD7,0x56,0x30, -0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x84,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06, -0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E, -0x63,0x2E,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29, -0x20,0x32,0x30,0x30,0x37,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E, -0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69, -0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x24,0x30,0x22, -0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72, -0x69,0x6D,0x61,0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20, -0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31,0x30,0x35,0x30,0x30,0x30,0x30, -0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32,0x33,0x35,0x39,0x35, -0x39,0x5A,0x30,0x81,0x84,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, -0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61, -0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x38,0x30,0x36,0x06,0x03,0x55, -0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x74,0x68,0x61, -0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20, -0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F, -0x6E,0x6C,0x79,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x74,0x68, -0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x52,0x6F,0x6F, -0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x47,0x32,0x30,0x76,0x30,0x10,0x06,0x07,0x2A, -0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00, -0x04,0xA2,0xD5,0x9C,0x82,0x7B,0x95,0x9D,0xF1,0x52,0x78,0x87,0xFE,0x8A,0x16,0xBF, -0x05,0xE6,0xDF,0xA3,0x02,0x4F,0x0D,0x07,0xC6,0x00,0x51,0xBA,0x0C,0x02,0x52,0x2D, -0x22,0xA4,0x42,0x39,0xC4,0xFE,0x8F,0xEA,0xC9,0xC1,0xBE,0xD4,0x4D,0xFF,0x9F,0x7A, -0x9E,0xE2,0xB1,0x7C,0x9A,0xAD,0xA7,0x86,0x09,0x73,0x87,0xD1,0xE7,0x9A,0xE3,0x7A, -0xA5,0xAA,0x6E,0xFB,0xBA,0xB3,0x70,0xC0,0x67,0x88,0xA2,0x35,0xD4,0xA3,0x9A,0xB1, -0xFD,0xAD,0xC2,0xEF,0x31,0xFA,0xA8,0xB9,0xF3,0xFB,0x08,0xC6,0x91,0xD1,0xFB,0x29, -0x95,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, -0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, -0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, -0x14,0x9A,0xD8,0x00,0x30,0x00,0xE7,0x6B,0x7F,0x85,0x18,0xEE,0x8B,0xB6,0xCE,0x8A, -0x0C,0xF8,0x11,0xE1,0xBB,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03, -0x03,0x03,0x69,0x00,0x30,0x66,0x02,0x31,0x00,0xDD,0xF8,0xE0,0x57,0x47,0x5B,0xA7, -0xE6,0x0A,0xC3,0xBD,0xF5,0x80,0x8A,0x97,0x35,0x0D,0x1B,0x89,0x3C,0x54,0x86,0x77, -0x28,0xCA,0xA1,0xF4,0x79,0xDE,0xB5,0xE6,0x38,0xB0,0xF0,0x65,0x70,0x8C,0x7F,0x02, -0x54,0xC2,0xBF,0xFF,0xD8,0xA1,0x3E,0xD9,0xCF,0x02,0x31,0x00,0xC4,0x8D,0x94,0xFC, -0xDC,0x53,0xD2,0xDC,0x9D,0x78,0x16,0x1F,0x15,0x33,0x23,0x53,0x52,0xE3,0x5A,0x31, -0x5D,0x9D,0xCA,0xAE,0xBD,0x13,0x29,0x44,0x0D,0x27,0x5B,0xA8,0xE7,0x68,0x9C,0x12, -0xF7,0x58,0x3F,0x2E,0x72,0x02,0x57,0xA3,0x8F,0xA1,0x14,0x2E, +const unsigned char AddTrust_External_Root_certificate[1082]={ +0x30,0x82,0x04,0x36,0x30,0x82,0x03,0x1E,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73, +0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41, +0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C, +0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30,0x20, +0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20, +0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74, +0x30,0x1E,0x17,0x0D,0x30,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38, +0x5A,0x17,0x0D,0x32,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38,0x5A, +0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31, +0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75, +0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D, +0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61, +0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30, +0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74, +0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F, +0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01, +0x01,0x00,0xB7,0xF7,0x1A,0x33,0xE6,0xF2,0x00,0x04,0x2D,0x39,0xE0,0x4E,0x5B,0xED, +0x1F,0xBC,0x6C,0x0F,0xCD,0xB5,0xFA,0x23,0xB6,0xCE,0xDE,0x9B,0x11,0x33,0x97,0xA4, +0x29,0x4C,0x7D,0x93,0x9F,0xBD,0x4A,0xBC,0x93,0xED,0x03,0x1A,0xE3,0x8F,0xCF,0xE5, +0x6D,0x50,0x5A,0xD6,0x97,0x29,0x94,0x5A,0x80,0xB0,0x49,0x7A,0xDB,0x2E,0x95,0xFD, +0xB8,0xCA,0xBF,0x37,0x38,0x2D,0x1E,0x3E,0x91,0x41,0xAD,0x70,0x56,0xC7,0xF0,0x4F, +0x3F,0xE8,0x32,0x9E,0x74,0xCA,0xC8,0x90,0x54,0xE9,0xC6,0x5F,0x0F,0x78,0x9D,0x9A, +0x40,0x3C,0x0E,0xAC,0x61,0xAA,0x5E,0x14,0x8F,0x9E,0x87,0xA1,0x6A,0x50,0xDC,0xD7, +0x9A,0x4E,0xAF,0x05,0xB3,0xA6,0x71,0x94,0x9C,0x71,0xB3,0x50,0x60,0x0A,0xC7,0x13, +0x9D,0x38,0x07,0x86,0x02,0xA8,0xE9,0xA8,0x69,0x26,0x18,0x90,0xAB,0x4C,0xB0,0x4F, +0x23,0xAB,0x3A,0x4F,0x84,0xD8,0xDF,0xCE,0x9F,0xE1,0x69,0x6F,0xBB,0xD7,0x42,0xD7, +0x6B,0x44,0xE4,0xC7,0xAD,0xEE,0x6D,0x41,0x5F,0x72,0x5A,0x71,0x08,0x37,0xB3,0x79, +0x65,0xA4,0x59,0xA0,0x94,0x37,0xF7,0x00,0x2F,0x0D,0xC2,0x92,0x72,0xDA,0xD0,0x38, +0x72,0xDB,0x14,0xA8,0x45,0xC4,0x5D,0x2A,0x7D,0xB7,0xB4,0xD6,0xC4,0xEE,0xAC,0xCD, +0x13,0x44,0xB7,0xC9,0x2B,0xDD,0x43,0x00,0x25,0xFA,0x61,0xB9,0x69,0x6A,0x58,0x23, +0x11,0xB7,0xA7,0x33,0x8F,0x56,0x75,0x59,0xF5,0xCD,0x29,0xD7,0x46,0xB7,0x0A,0x2B, +0x65,0xB6,0xD3,0x42,0x6F,0x15,0xB2,0xB8,0x7B,0xFB,0xEF,0xE9,0x5D,0x53,0xD5,0x34, +0x5A,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xDC,0x30,0x81,0xD9,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4,0x26,0xF7, +0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0x30,0x0B,0x06,0x03, +0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13, +0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x99,0x06,0x03,0x55, +0x1D,0x23,0x04,0x81,0x91,0x30,0x81,0x8E,0x80,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4, +0x26,0xF7,0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0xA1,0x73, +0xA4,0x71,0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53, +0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54, +0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, +0x13,0x1D,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72, +0x6E,0x61,0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31, +0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75, +0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52, +0x6F,0x6F,0x74,0x82,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xB0,0x9B,0xE0,0x85,0x25,0xC2, +0xD6,0x23,0xE2,0x0F,0x96,0x06,0x92,0x9D,0x41,0x98,0x9C,0xD9,0x84,0x79,0x81,0xD9, +0x1E,0x5B,0x14,0x07,0x23,0x36,0x65,0x8F,0xB0,0xD8,0x77,0xBB,0xAC,0x41,0x6C,0x47, +0x60,0x83,0x51,0xB0,0xF9,0x32,0x3D,0xE7,0xFC,0xF6,0x26,0x13,0xC7,0x80,0x16,0xA5, +0xBF,0x5A,0xFC,0x87,0xCF,0x78,0x79,0x89,0x21,0x9A,0xE2,0x4C,0x07,0x0A,0x86,0x35, +0xBC,0xF2,0xDE,0x51,0xC4,0xD2,0x96,0xB7,0xDC,0x7E,0x4E,0xEE,0x70,0xFD,0x1C,0x39, +0xEB,0x0C,0x02,0x51,0x14,0x2D,0x8E,0xBD,0x16,0xE0,0xC1,0xDF,0x46,0x75,0xE7,0x24, +0xAD,0xEC,0xF4,0x42,0xB4,0x85,0x93,0x70,0x10,0x67,0xBA,0x9D,0x06,0x35,0x4A,0x18, +0xD3,0x2B,0x7A,0xCC,0x51,0x42,0xA1,0x7A,0x63,0xD1,0xE6,0xBB,0xA1,0xC5,0x2B,0xC2, +0x36,0xBE,0x13,0x0D,0xE6,0xBD,0x63,0x7E,0x79,0x7B,0xA7,0x09,0x0D,0x40,0xAB,0x6A, +0xDD,0x8F,0x8A,0xC3,0xF6,0xF6,0x8C,0x1A,0x42,0x05,0x51,0xD4,0x45,0xF5,0x9F,0xA7, +0x62,0x21,0x68,0x15,0x20,0x43,0x3C,0x99,0xE7,0x7C,0xBD,0x24,0xD8,0xA9,0x91,0x17, +0x73,0x88,0x3F,0x56,0x1B,0x31,0x38,0x18,0xB4,0x71,0x0F,0x9A,0xCD,0xC8,0x0E,0x9E, +0x8E,0x2E,0x1B,0xE1,0x8C,0x98,0x83,0xCB,0x1F,0x31,0xF1,0x44,0x4C,0xC6,0x04,0x73, +0x49,0x76,0x60,0x0F,0xC7,0xF8,0xBD,0x17,0x80,0x6B,0x2E,0xE9,0xCC,0x4C,0x0E,0x5A, +0x9A,0x79,0x0F,0x20,0x0A,0x2E,0xD5,0x9E,0x63,0x26,0x1E,0x55,0x92,0x94,0xD8,0x82, +0x17,0x5A,0x7B,0xD0,0xBC,0xC7,0x8F,0x4E,0x86,0x04, }; @@ -3900,570 +1800,208 @@ }; -/* subject:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Server CA/emailAddress=server-certs@thawte.com */ -/* issuer :/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Server CA/emailAddress=server-certs@thawte.com */ +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA */ -const unsigned char Thawte_Server_CA_certificate[791]={ -0x30,0x82,0x03,0x13,0x30,0x82,0x02,0x7C,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, -0x81,0xC4,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5A,0x41,0x31, -0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13,0x0C,0x57,0x65,0x73,0x74,0x65,0x72, -0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13, -0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77,0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03, -0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,0x6F,0x6E,0x73, -0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63,0x31,0x28,0x30,0x26,0x06,0x03,0x55, -0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, -0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73, -0x69,0x6F,0x6E,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x03,0x13,0x10,0x54,0x68, -0x61,0x77,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x31,0x26, -0x30,0x24,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x01,0x16,0x17,0x73, -0x65,0x72,0x76,0x65,0x72,0x2D,0x63,0x65,0x72,0x74,0x73,0x40,0x74,0x68,0x61,0x77, -0x74,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x36,0x30,0x38,0x30,0x31, -0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30,0x31,0x32,0x33,0x31,0x32, -0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xC4,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, -0x04,0x06,0x13,0x02,0x5A,0x41,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13, -0x0C,0x57,0x65,0x73,0x74,0x65,0x72,0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30, -0x10,0x06,0x03,0x55,0x04,0x07,0x13,0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77, -0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77, -0x74,0x65,0x20,0x43,0x6F,0x6E,0x73,0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63, -0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69, -0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65, -0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31,0x19,0x30,0x17,0x06,0x03, -0x55,0x04,0x03,0x13,0x10,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x53,0x65,0x72,0x76, -0x65,0x72,0x20,0x43,0x41,0x31,0x26,0x30,0x24,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, -0x0D,0x01,0x09,0x01,0x16,0x17,0x73,0x65,0x72,0x76,0x65,0x72,0x2D,0x63,0x65,0x72, -0x74,0x73,0x40,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F, +const unsigned char DigiCert_Assured_ID_Root_CA_certificate[955]={ +0x30,0x82,0x03,0xB7,0x30,0x82,0x02,0x9F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0C, +0xE7,0xE0,0xE5,0x17,0xD8,0x46,0xFE,0x8F,0xE5,0x60,0xFC,0x1B,0xF0,0x30,0x39,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x65, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F, +0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44, +0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06, +0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13, +0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65, +0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22, 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, -0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xD3,0xA4,0x50,0x6E,0xC8,0xFF, -0x56,0x6B,0xE6,0xCF,0x5D,0xB6,0xEA,0x0C,0x68,0x75,0x47,0xA2,0xAA,0xC2,0xDA,0x84, -0x25,0xFC,0xA8,0xF4,0x47,0x51,0xDA,0x85,0xB5,0x20,0x74,0x94,0x86,0x1E,0x0F,0x75, -0xC9,0xE9,0x08,0x61,0xF5,0x06,0x6D,0x30,0x6E,0x15,0x19,0x02,0xE9,0x52,0xC0,0x62, -0xDB,0x4D,0x99,0x9E,0xE2,0x6A,0x0C,0x44,0x38,0xCD,0xFE,0xBE,0xE3,0x64,0x09,0x70, -0xC5,0xFE,0xB1,0x6B,0x29,0xB6,0x2F,0x49,0xC8,0x3B,0xD4,0x27,0x04,0x25,0x10,0x97, -0x2F,0xE7,0x90,0x6D,0xC0,0x28,0x42,0x99,0xD7,0x4C,0x43,0xDE,0xC3,0xF5,0x21,0x6D, -0x54,0x9F,0x5D,0xC3,0x58,0xE1,0xC0,0xE4,0xD9,0x5B,0xB0,0xB8,0xDC,0xB4,0x7B,0xDF, -0x36,0x3A,0xC2,0xB5,0x66,0x22,0x12,0xD6,0x87,0x0D,0x02,0x03,0x01,0x00,0x01,0xA3, -0x13,0x30,0x11,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, -0x03,0x01,0x01,0xFF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x04,0x05,0x00,0x03,0x81,0x81,0x00,0x07,0xFA,0x4C,0x69,0x5C,0xFB,0x95,0xCC,0x46, -0xEE,0x85,0x83,0x4D,0x21,0x30,0x8E,0xCA,0xD9,0xA8,0x6F,0x49,0x1A,0xE6,0xDA,0x51, -0xE3,0x60,0x70,0x6C,0x84,0x61,0x11,0xA1,0x1A,0xC8,0x48,0x3E,0x59,0x43,0x7D,0x4F, -0x95,0x3D,0xA1,0x8B,0xB7,0x0B,0x62,0x98,0x7A,0x75,0x8A,0xDD,0x88,0x4E,0x4E,0x9E, -0x40,0xDB,0xA8,0xCC,0x32,0x74,0xB9,0x6F,0x0D,0xC6,0xE3,0xB3,0x44,0x0B,0xD9,0x8A, -0x6F,0x9A,0x29,0x9B,0x99,0x18,0x28,0x3B,0xD1,0xE3,0x40,0x28,0x9A,0x5A,0x3C,0xD5, -0xB5,0xE7,0x20,0x1B,0x8B,0xCA,0xA4,0xAB,0x8D,0xE9,0x51,0xD9,0xE2,0x4C,0x2C,0x59, -0xA9,0xDA,0xB9,0xB2,0x75,0x1B,0xF6,0x42,0xF2,0xEF,0xC7,0xF2,0x18,0xF9,0x89,0xBC, -0xA3,0xFF,0x8A,0x23,0x2E,0x70,0x47, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAD,0x0E,0x15, +0xCE,0xE4,0x43,0x80,0x5C,0xB1,0x87,0xF3,0xB7,0x60,0xF9,0x71,0x12,0xA5,0xAE,0xDC, +0x26,0x94,0x88,0xAA,0xF4,0xCE,0xF5,0x20,0x39,0x28,0x58,0x60,0x0C,0xF8,0x80,0xDA, +0xA9,0x15,0x95,0x32,0x61,0x3C,0xB5,0xB1,0x28,0x84,0x8A,0x8A,0xDC,0x9F,0x0A,0x0C, +0x83,0x17,0x7A,0x8F,0x90,0xAC,0x8A,0xE7,0x79,0x53,0x5C,0x31,0x84,0x2A,0xF6,0x0F, +0x98,0x32,0x36,0x76,0xCC,0xDE,0xDD,0x3C,0xA8,0xA2,0xEF,0x6A,0xFB,0x21,0xF2,0x52, +0x61,0xDF,0x9F,0x20,0xD7,0x1F,0xE2,0xB1,0xD9,0xFE,0x18,0x64,0xD2,0x12,0x5B,0x5F, +0xF9,0x58,0x18,0x35,0xBC,0x47,0xCD,0xA1,0x36,0xF9,0x6B,0x7F,0xD4,0xB0,0x38,0x3E, +0xC1,0x1B,0xC3,0x8C,0x33,0xD9,0xD8,0x2F,0x18,0xFE,0x28,0x0F,0xB3,0xA7,0x83,0xD6, +0xC3,0x6E,0x44,0xC0,0x61,0x35,0x96,0x16,0xFE,0x59,0x9C,0x8B,0x76,0x6D,0xD7,0xF1, +0xA2,0x4B,0x0D,0x2B,0xFF,0x0B,0x72,0xDA,0x9E,0x60,0xD0,0x8E,0x90,0x35,0xC6,0x78, +0x55,0x87,0x20,0xA1,0xCF,0xE5,0x6D,0x0A,0xC8,0x49,0x7C,0x31,0x98,0x33,0x6C,0x22, +0xE9,0x87,0xD0,0x32,0x5A,0xA2,0xBA,0x13,0x82,0x11,0xED,0x39,0x17,0x9D,0x99,0x3A, +0x72,0xA1,0xE6,0xFA,0xA4,0xD9,0xD5,0x17,0x31,0x75,0xAE,0x85,0x7D,0x22,0xAE,0x3F, +0x01,0x46,0x86,0xF6,0x28,0x79,0xC8,0xB1,0xDA,0xE4,0x57,0x17,0xC4,0x7E,0x1C,0x0E, +0xB0,0xB4,0x92,0xA6,0x56,0xB3,0xBD,0xB2,0x97,0xED,0xAA,0xA7,0xF0,0xB7,0xC5,0xA8, +0x3F,0x95,0x16,0xD0,0xFF,0xA1,0x96,0xEB,0x08,0x5F,0x18,0x77,0x4F,0x02,0x03,0x01, +0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7,0xA7, +0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, +0x16,0x80,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7, +0xA7,0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xA2,0x0E,0xBC,0xDF,0xE2, +0xED,0xF0,0xE3,0x72,0x73,0x7A,0x64,0x94,0xBF,0xF7,0x72,0x66,0xD8,0x32,0xE4,0x42, +0x75,0x62,0xAE,0x87,0xEB,0xF2,0xD5,0xD9,0xDE,0x56,0xB3,0x9F,0xCC,0xCE,0x14,0x28, +0xB9,0x0D,0x97,0x60,0x5C,0x12,0x4C,0x58,0xE4,0xD3,0x3D,0x83,0x49,0x45,0x58,0x97, +0x35,0x69,0x1A,0xA8,0x47,0xEA,0x56,0xC6,0x79,0xAB,0x12,0xD8,0x67,0x81,0x84,0xDF, +0x7F,0x09,0x3C,0x94,0xE6,0xB8,0x26,0x2C,0x20,0xBD,0x3D,0xB3,0x28,0x89,0xF7,0x5F, +0xFF,0x22,0xE2,0x97,0x84,0x1F,0xE9,0x65,0xEF,0x87,0xE0,0xDF,0xC1,0x67,0x49,0xB3, +0x5D,0xEB,0xB2,0x09,0x2A,0xEB,0x26,0xED,0x78,0xBE,0x7D,0x3F,0x2B,0xF3,0xB7,0x26, +0x35,0x6D,0x5F,0x89,0x01,0xB6,0x49,0x5B,0x9F,0x01,0x05,0x9B,0xAB,0x3D,0x25,0xC1, +0xCC,0xB6,0x7F,0xC2,0xF1,0x6F,0x86,0xC6,0xFA,0x64,0x68,0xEB,0x81,0x2D,0x94,0xEB, +0x42,0xB7,0xFA,0x8C,0x1E,0xDD,0x62,0xF1,0xBE,0x50,0x67,0xB7,0x6C,0xBD,0xF3,0xF1, +0x1F,0x6B,0x0C,0x36,0x07,0x16,0x7F,0x37,0x7C,0xA9,0x5B,0x6D,0x7A,0xF1,0x12,0x46, +0x60,0x83,0xD7,0x27,0x04,0xBE,0x4B,0xCE,0x97,0xBE,0xC3,0x67,0x2A,0x68,0x11,0xDF, +0x80,0xE7,0x0C,0x33,0x66,0xBF,0x13,0x0D,0x14,0x6E,0xF3,0x7F,0x1F,0x63,0x10,0x1E, +0xFA,0x8D,0x1B,0x25,0x6D,0x6C,0x8F,0xA5,0xB7,0x61,0x01,0xB1,0xD2,0xA3,0x26,0xA1, +0x10,0x71,0x9D,0xAD,0xE2,0xC3,0xF9,0xC3,0x99,0x51,0xB7,0x2B,0x07,0x08,0xCE,0x2E, +0xE6,0x50,0xB2,0xA7,0xFA,0x0A,0x45,0x2F,0xA2,0xF0,0xF2, }; -/* subject:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC */ -/* issuer :/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC */ +/* subject:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority */ +/* issuer :/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority */ -const unsigned char UTN_DATACorp_SGC_Root_CA_certificate[1122]={ -0x30,0x82,0x04,0x5E,0x30,0x82,0x03,0x46,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x44, -0xBE,0x0C,0x8B,0x50,0x00,0x21,0xB4,0x11,0xD3,0x2A,0x68,0x06,0xA9,0xAD,0x69,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, -0x93,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06, -0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20, -0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, -0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, -0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68, -0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72, -0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03, -0x13,0x12,0x55,0x54,0x4E,0x20,0x2D,0x20,0x44,0x41,0x54,0x41,0x43,0x6F,0x72,0x70, -0x20,0x53,0x47,0x43,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36,0x32,0x34,0x31,0x38, -0x35,0x37,0x32,0x31,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32,0x34,0x31,0x39,0x30, -0x36,0x33,0x30,0x5A,0x30,0x81,0x93,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, -0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55, -0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74, -0x20,0x4C,0x61,0x6B,0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03, -0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55, -0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03, -0x55,0x04,0x0B,0x13,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E, -0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1B,0x30, -0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x55,0x54,0x4E,0x20,0x2D,0x20,0x44,0x41, -0x54,0x41,0x43,0x6F,0x72,0x70,0x20,0x53,0x47,0x43,0x30,0x82,0x01,0x22,0x30,0x0D, -0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, -0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDF,0xEE,0x58,0x10,0xA2, -0x2B,0x6E,0x55,0xC4,0x8E,0xBF,0x2E,0x46,0x09,0xE7,0xE0,0x08,0x0F,0x2E,0x2B,0x7A, -0x13,0x94,0x1B,0xBD,0xF6,0xB6,0x80,0x8E,0x65,0x05,0x93,0x00,0x1E,0xBC,0xAF,0xE2, -0x0F,0x8E,0x19,0x0D,0x12,0x47,0xEC,0xAC,0xAD,0xA3,0xFA,0x2E,0x70,0xF8,0xDE,0x6E, -0xFB,0x56,0x42,0x15,0x9E,0x2E,0x5C,0xEF,0x23,0xDE,0x21,0xB9,0x05,0x76,0x27,0x19, -0x0F,0x4F,0xD6,0xC3,0x9C,0xB4,0xBE,0x94,0x19,0x63,0xF2,0xA6,0x11,0x0A,0xEB,0x53, -0x48,0x9C,0xBE,0xF2,0x29,0x3B,0x16,0xE8,0x1A,0xA0,0x4C,0xA6,0xC9,0xF4,0x18,0x59, -0x68,0xC0,0x70,0xF2,0x53,0x00,0xC0,0x5E,0x50,0x82,0xA5,0x56,0x6F,0x36,0xF9,0x4A, -0xE0,0x44,0x86,0xA0,0x4D,0x4E,0xD6,0x47,0x6E,0x49,0x4A,0xCB,0x67,0xD7,0xA6,0xC4, -0x05,0xB9,0x8E,0x1E,0xF4,0xFC,0xFF,0xCD,0xE7,0x36,0xE0,0x9C,0x05,0x6C,0xB2,0x33, -0x22,0x15,0xD0,0xB4,0xE0,0xCC,0x17,0xC0,0xB2,0xC0,0xF4,0xFE,0x32,0x3F,0x29,0x2A, -0x95,0x7B,0xD8,0xF2,0xA7,0x4E,0x0F,0x54,0x7C,0xA1,0x0D,0x80,0xB3,0x09,0x03,0xC1, -0xFF,0x5C,0xDD,0x5E,0x9A,0x3E,0xBC,0xAE,0xBC,0x47,0x8A,0x6A,0xAE,0x71,0xCA,0x1F, -0xB1,0x2A,0xB8,0x5F,0x42,0x05,0x0B,0xEC,0x46,0x30,0xD1,0x72,0x0B,0xCA,0xE9,0x56, -0x6D,0xF5,0xEF,0xDF,0x78,0xBE,0x61,0xBA,0xB2,0xA5,0xAE,0x04,0x4C,0xBC,0xA8,0xAC, -0x69,0x15,0x97,0xBD,0xEF,0xEB,0xB4,0x8C,0xBF,0x35,0xF8,0xD4,0xC3,0xD1,0x28,0x0E, -0x5C,0x3A,0x9F,0x70,0x18,0x33,0x20,0x77,0xC4,0xA2,0xAF,0x02,0x03,0x01,0x00,0x01, -0xA3,0x81,0xAB,0x30,0x81,0xA8,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03, -0x02,0x01,0xC6,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, -0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x53, -0x32,0xD1,0xB3,0xCF,0x7F,0xFA,0xE0,0xF1,0xA0,0x5D,0x85,0x4E,0x92,0xD2,0x9E,0x45, -0x1D,0xB4,0x4F,0x30,0x3D,0x06,0x03,0x55,0x1D,0x1F,0x04,0x36,0x30,0x34,0x30,0x32, -0xA0,0x30,0xA0,0x2E,0x86,0x2C,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C, -0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x55, -0x54,0x4E,0x2D,0x44,0x41,0x54,0x41,0x43,0x6F,0x72,0x70,0x53,0x47,0x43,0x2E,0x63, -0x72,0x6C,0x30,0x2A,0x06,0x03,0x55,0x1D,0x25,0x04,0x23,0x30,0x21,0x06,0x08,0x2B, -0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37, -0x0A,0x03,0x03,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,0x30,0x0D, -0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01, -0x01,0x00,0x27,0x35,0x97,0x00,0x8A,0x8B,0x28,0xBD,0xC6,0x33,0x30,0x1E,0x29,0xFC, -0xE2,0xF7,0xD5,0x98,0xD4,0x40,0xBB,0x60,0xCA,0xBF,0xAB,0x17,0x2C,0x09,0x36,0x7F, -0x50,0xFA,0x41,0xDC,0xAE,0x96,0x3A,0x0A,0x23,0x3E,0x89,0x59,0xC9,0xA3,0x07,0xED, -0x1B,0x37,0xAD,0xFC,0x7C,0xBE,0x51,0x49,0x5A,0xDE,0x3A,0x0A,0x54,0x08,0x16,0x45, -0xC2,0x99,0xB1,0x87,0xCD,0x8C,0x68,0xE0,0x69,0x03,0xE9,0xC4,0x4E,0x98,0xB2,0x3B, -0x8C,0x16,0xB3,0x0E,0xA0,0x0C,0x98,0x50,0x9B,0x93,0xA9,0x70,0x09,0xC8,0x2C,0xA3, -0x8F,0xDF,0x02,0xE4,0xE0,0x71,0x3A,0xF1,0xB4,0x23,0x72,0xA0,0xAA,0x01,0xDF,0xDF, -0x98,0x3E,0x14,0x50,0xA0,0x31,0x26,0xBD,0x28,0xE9,0x5A,0x30,0x26,0x75,0xF9,0x7B, -0x60,0x1C,0x8D,0xF3,0xCD,0x50,0x26,0x6D,0x04,0x27,0x9A,0xDF,0xD5,0x0D,0x45,0x47, -0x29,0x6B,0x2C,0xE6,0x76,0xD9,0xA9,0x29,0x7D,0x32,0xDD,0xC9,0x36,0x3C,0xBD,0xAE, -0x35,0xF1,0x11,0x9E,0x1D,0xBB,0x90,0x3F,0x12,0x47,0x4E,0x8E,0xD7,0x7E,0x0F,0x62, -0x73,0x1D,0x52,0x26,0x38,0x1C,0x18,0x49,0xFD,0x30,0x74,0x9A,0xC4,0xE5,0x22,0x2F, -0xD8,0xC0,0x8D,0xED,0x91,0x7A,0x4C,0x00,0x8F,0x72,0x7F,0x5D,0xDA,0xDD,0x1B,0x8B, -0x45,0x6B,0xE7,0xDD,0x69,0x97,0xA8,0xC5,0x56,0x4C,0x0F,0x0C,0xF6,0x9F,0x7A,0x91, -0x37,0xF6,0x97,0x82,0xE0,0xDD,0x71,0x69,0xFF,0x76,0x3F,0x60,0x4D,0x3C,0xCF,0xF7, -0x99,0xF9,0xC6,0x57,0xF4,0xC9,0x55,0x39,0x78,0xBA,0x2C,0x79,0xC9,0xA6,0x88,0x2B, -0xF4,0x08, +const unsigned char Go_Daddy_Class_2_CA_certificate[1028]={ +0x30,0x82,0x04,0x00,0x30,0x82,0x02,0xE8,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21, +0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20, +0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44, +0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x36,0x32,0x39,0x31,0x37, +0x30,0x36,0x32,0x30,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36,0x32,0x39,0x31,0x37,0x30, +0x36,0x32,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68, +0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13, +0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, +0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D, +0x00,0x30,0x82,0x01,0x08,0x02,0x82,0x01,0x01,0x00,0xDE,0x9D,0xD7,0xEA,0x57,0x18, +0x49,0xA1,0x5B,0xEB,0xD7,0x5F,0x48,0x86,0xEA,0xBE,0xDD,0xFF,0xE4,0xEF,0x67,0x1C, +0xF4,0x65,0x68,0xB3,0x57,0x71,0xA0,0x5E,0x77,0xBB,0xED,0x9B,0x49,0xE9,0x70,0x80, +0x3D,0x56,0x18,0x63,0x08,0x6F,0xDA,0xF2,0xCC,0xD0,0x3F,0x7F,0x02,0x54,0x22,0x54, +0x10,0xD8,0xB2,0x81,0xD4,0xC0,0x75,0x3D,0x4B,0x7F,0xC7,0x77,0xC3,0x3E,0x78,0xAB, +0x1A,0x03,0xB5,0x20,0x6B,0x2F,0x6A,0x2B,0xB1,0xC5,0x88,0x7E,0xC4,0xBB,0x1E,0xB0, +0xC1,0xD8,0x45,0x27,0x6F,0xAA,0x37,0x58,0xF7,0x87,0x26,0xD7,0xD8,0x2D,0xF6,0xA9, +0x17,0xB7,0x1F,0x72,0x36,0x4E,0xA6,0x17,0x3F,0x65,0x98,0x92,0xDB,0x2A,0x6E,0x5D, +0xA2,0xFE,0x88,0xE0,0x0B,0xDE,0x7F,0xE5,0x8D,0x15,0xE1,0xEB,0xCB,0x3A,0xD5,0xE2, +0x12,0xA2,0x13,0x2D,0xD8,0x8E,0xAF,0x5F,0x12,0x3D,0xA0,0x08,0x05,0x08,0xB6,0x5C, +0xA5,0x65,0x38,0x04,0x45,0x99,0x1E,0xA3,0x60,0x60,0x74,0xC5,0x41,0xA5,0x72,0x62, +0x1B,0x62,0xC5,0x1F,0x6F,0x5F,0x1A,0x42,0xBE,0x02,0x51,0x65,0xA8,0xAE,0x23,0x18, +0x6A,0xFC,0x78,0x03,0xA9,0x4D,0x7F,0x80,0xC3,0xFA,0xAB,0x5A,0xFC,0xA1,0x40,0xA4, +0xCA,0x19,0x16,0xFE,0xB2,0xC8,0xEF,0x5E,0x73,0x0D,0xEE,0x77,0xBD,0x9A,0xF6,0x79, +0x98,0xBC,0xB1,0x07,0x67,0xA2,0x15,0x0D,0xDD,0xA0,0x58,0xC6,0x44,0x7B,0x0A,0x3E, +0x62,0x28,0x5F,0xBA,0x41,0x07,0x53,0x58,0xCF,0x11,0x7E,0x38,0x74,0xC5,0xF8,0xFF, +0xB5,0x69,0x90,0x8F,0x84,0x74,0xEA,0x97,0x1B,0xAF,0x02,0x01,0x03,0xA3,0x81,0xC0, +0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xD2,0xC4, +0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1,0xFE,0xDD,0xA8,0x6A, +0xD4,0xE3,0x30,0x81,0x8D,0x06,0x03,0x55,0x1D,0x23,0x04,0x81,0x85,0x30,0x81,0x82, +0x80,0x14,0xD2,0xC4,0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1, +0xFE,0xDD,0xA8,0x6A,0xD4,0xE3,0xA1,0x67,0xA4,0x65,0x30,0x63,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, +0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79, +0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F, +0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20, +0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82, +0x01,0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, +0x82,0x01,0x01,0x00,0x32,0x4B,0xF3,0xB2,0xCA,0x3E,0x91,0xFC,0x12,0xC6,0xA1,0x07, +0x8C,0x8E,0x77,0xA0,0x33,0x06,0x14,0x5C,0x90,0x1E,0x18,0xF7,0x08,0xA6,0x3D,0x0A, +0x19,0xF9,0x87,0x80,0x11,0x6E,0x69,0xE4,0x96,0x17,0x30,0xFF,0x34,0x91,0x63,0x72, +0x38,0xEE,0xCC,0x1C,0x01,0xA3,0x1D,0x94,0x28,0xA4,0x31,0xF6,0x7A,0xC4,0x54,0xD7, +0xF6,0xE5,0x31,0x58,0x03,0xA2,0xCC,0xCE,0x62,0xDB,0x94,0x45,0x73,0xB5,0xBF,0x45, +0xC9,0x24,0xB5,0xD5,0x82,0x02,0xAD,0x23,0x79,0x69,0x8D,0xB8,0xB6,0x4D,0xCE,0xCF, +0x4C,0xCA,0x33,0x23,0xE8,0x1C,0x88,0xAA,0x9D,0x8B,0x41,0x6E,0x16,0xC9,0x20,0xE5, +0x89,0x9E,0xCD,0x3B,0xDA,0x70,0xF7,0x7E,0x99,0x26,0x20,0x14,0x54,0x25,0xAB,0x6E, +0x73,0x85,0xE6,0x9B,0x21,0x9D,0x0A,0x6C,0x82,0x0E,0xA8,0xF8,0xC2,0x0C,0xFA,0x10, +0x1E,0x6C,0x96,0xEF,0x87,0x0D,0xC4,0x0F,0x61,0x8B,0xAD,0xEE,0x83,0x2B,0x95,0xF8, +0x8E,0x92,0x84,0x72,0x39,0xEB,0x20,0xEA,0x83,0xED,0x83,0xCD,0x97,0x6E,0x08,0xBC, +0xEB,0x4E,0x26,0xB6,0x73,0x2B,0xE4,0xD3,0xF6,0x4C,0xFE,0x26,0x71,0xE2,0x61,0x11, +0x74,0x4A,0xFF,0x57,0x1A,0x87,0x0F,0x75,0x48,0x2E,0xCF,0x51,0x69,0x17,0xA0,0x02, +0x12,0x61,0x95,0xD5,0xD1,0x40,0xB2,0x10,0x4C,0xEE,0xC4,0xAC,0x10,0x43,0xA6,0xA5, +0x9E,0x0A,0xD5,0x95,0x62,0x9A,0x0D,0xCF,0x88,0x82,0xC5,0x32,0x0C,0xE4,0x2B,0x9F, +0x45,0xE6,0x0D,0x9F,0x28,0x9C,0xB1,0xB9,0x2A,0x5A,0x57,0xAD,0x37,0x0F,0xAF,0x1D, +0x7F,0xDB,0xBD,0x9F, }; -/* subject:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */ -/* issuer :/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */ +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Primary Certification Authority */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Primary Certification Authority */ -const unsigned char UTN_USERFirst_Hardware_Root_CA_certificate[1144]={ -0x30,0x82,0x04,0x74,0x30,0x82,0x03,0x5C,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x44, -0xBE,0x0C,0x8B,0x50,0x00,0x24,0xB4,0x11,0xD3,0x36,0x2A,0xFE,0x65,0x0A,0xFD,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, -0x97,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06, -0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20, -0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, -0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, -0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68, -0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72, -0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03, -0x13,0x16,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D, -0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x37, -0x30,0x39,0x31,0x38,0x31,0x30,0x34,0x32,0x5A,0x17,0x0D,0x31,0x39,0x30,0x37,0x30, -0x39,0x31,0x38,0x31,0x39,0x32,0x32,0x5A,0x30,0x81,0x97,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, -0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0E, -0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1E, -0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45, -0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21, -0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, -0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F, -0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,0x4E,0x2D, -0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61, -0x72,0x65,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, -0x01,0x01,0x00,0xB1,0xF7,0xC3,0x38,0x3F,0xB4,0xA8,0x7F,0xCF,0x39,0x82,0x51,0x67, -0xD0,0x6D,0x9F,0xD2,0xFF,0x58,0xF3,0xE7,0x9F,0x2B,0xEC,0x0D,0x89,0x54,0x99,0xB9, -0x38,0x99,0x16,0xF7,0xE0,0x21,0x79,0x48,0xC2,0xBB,0x61,0x74,0x12,0x96,0x1D,0x3C, -0x6A,0x72,0xD5,0x3C,0x10,0x67,0x3A,0x39,0xED,0x2B,0x13,0xCD,0x66,0xEB,0x95,0x09, -0x33,0xA4,0x6C,0x97,0xB1,0xE8,0xC6,0xEC,0xC1,0x75,0x79,0x9C,0x46,0x5E,0x8D,0xAB, -0xD0,0x6A,0xFD,0xB9,0x2A,0x55,0x17,0x10,0x54,0xB3,0x19,0xF0,0x9A,0xF6,0xF1,0xB1, -0x5D,0xB6,0xA7,0x6D,0xFB,0xE0,0x71,0x17,0x6B,0xA2,0x88,0xFB,0x00,0xDF,0xFE,0x1A, -0x31,0x77,0x0C,0x9A,0x01,0x7A,0xB1,0x32,0xE3,0x2B,0x01,0x07,0x38,0x6E,0xC3,0xA5, -0x5E,0x23,0xBC,0x45,0x9B,0x7B,0x50,0xC1,0xC9,0x30,0x8F,0xDB,0xE5,0x2B,0x7A,0xD3, -0x5B,0xFB,0x33,0x40,0x1E,0xA0,0xD5,0x98,0x17,0xBC,0x8B,0x87,0xC3,0x89,0xD3,0x5D, -0xA0,0x8E,0xB2,0xAA,0xAA,0xF6,0x8E,0x69,0x88,0x06,0xC5,0xFA,0x89,0x21,0xF3,0x08, -0x9D,0x69,0x2E,0x09,0x33,0x9B,0x29,0x0D,0x46,0x0F,0x8C,0xCC,0x49,0x34,0xB0,0x69, -0x51,0xBD,0xF9,0x06,0xCD,0x68,0xAD,0x66,0x4C,0xBC,0x3E,0xAC,0x61,0xBD,0x0A,0x88, -0x0E,0xC8,0xDF,0x3D,0xEE,0x7C,0x04,0x4C,0x9D,0x0A,0x5E,0x6B,0x91,0xD6,0xEE,0xC7, -0xED,0x28,0x8D,0xAB,0x4D,0x87,0x89,0x73,0xD0,0x6E,0xA4,0xD0,0x1E,0x16,0x8B,0x14, -0xE1,0x76,0x44,0x03,0x7F,0x63,0xAC,0xE4,0xCD,0x49,0x9C,0xC5,0x92,0xF4,0xAB,0x32, -0xA1,0x48,0x5B,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xB9,0x30,0x81,0xB6,0x30,0x0B, -0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0xC6,0x30,0x0F,0x06,0x03,0x55, -0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03, -0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xA1,0x72,0x5F,0x26,0x1B,0x28,0x98,0x43,0x95, -0x5D,0x07,0x37,0xD5,0x85,0x96,0x9D,0x4B,0xD2,0xC3,0x45,0x30,0x44,0x06,0x03,0x55, -0x1D,0x1F,0x04,0x3D,0x30,0x3B,0x30,0x39,0xA0,0x37,0xA0,0x35,0x86,0x33,0x68,0x74, -0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75, -0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46, -0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2E,0x63,0x72, -0x6C,0x30,0x31,0x06,0x03,0x55,0x1D,0x25,0x04,0x2A,0x30,0x28,0x06,0x08,0x2B,0x06, -0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x05, -0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x06,0x06,0x08,0x2B,0x06,0x01,0x05, -0x05,0x07,0x03,0x07,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x47,0x19,0x0F,0xDE,0x74,0xC6,0x99,0x97, -0xAF,0xFC,0xAD,0x28,0x5E,0x75,0x8E,0xEB,0x2D,0x67,0xEE,0x4E,0x7B,0x2B,0xD7,0x0C, -0xFF,0xF6,0xDE,0xCB,0x55,0xA2,0x0A,0xE1,0x4C,0x54,0x65,0x93,0x60,0x6B,0x9F,0x12, -0x9C,0xAD,0x5E,0x83,0x2C,0xEB,0x5A,0xAE,0xC0,0xE4,0x2D,0xF4,0x00,0x63,0x1D,0xB8, -0xC0,0x6C,0xF2,0xCF,0x49,0xBB,0x4D,0x93,0x6F,0x06,0xA6,0x0A,0x22,0xB2,0x49,0x62, -0x08,0x4E,0xFF,0xC8,0xC8,0x14,0xB2,0x88,0x16,0x5D,0xE7,0x01,0xE4,0x12,0x95,0xE5, -0x45,0x34,0xB3,0x8B,0x69,0xBD,0xCF,0xB4,0x85,0x8F,0x75,0x51,0x9E,0x7D,0x3A,0x38, -0x3A,0x14,0x48,0x12,0xC6,0xFB,0xA7,0x3B,0x1A,0x8D,0x0D,0x82,0x40,0x07,0xE8,0x04, -0x08,0x90,0xA1,0x89,0xCB,0x19,0x50,0xDF,0xCA,0x1C,0x01,0xBC,0x1D,0x04,0x19,0x7B, -0x10,0x76,0x97,0x3B,0xEE,0x90,0x90,0xCA,0xC4,0x0E,0x1F,0x16,0x6E,0x75,0xEF,0x33, -0xF8,0xD3,0x6F,0x5B,0x1E,0x96,0xE3,0xE0,0x74,0x77,0x74,0x7B,0x8A,0xA2,0x6E,0x2D, -0xDD,0x76,0xD6,0x39,0x30,0x82,0xF0,0xAB,0x9C,0x52,0xF2,0x2A,0xC7,0xAF,0x49,0x5E, -0x7E,0xC7,0x68,0xE5,0x82,0x81,0xC8,0x6A,0x27,0xF9,0x27,0x88,0x2A,0xD5,0x58,0x50, -0x95,0x1F,0xF0,0x3B,0x1C,0x57,0xBB,0x7D,0x14,0x39,0x62,0x2B,0x9A,0xC9,0x94,0x92, -0x2A,0xA3,0x22,0x0C,0xFF,0x89,0x26,0x7D,0x5F,0x23,0x2B,0x47,0xD7,0x15,0x1D,0xA9, -0x6A,0x9E,0x51,0x0D,0x2A,0x51,0x9E,0x81,0xF9,0xD4,0x3B,0x5E,0x70,0x12,0x7F,0x10, -0x32,0x9C,0x1E,0xBB,0x9D,0xF8,0x66,0xA8, -}; - - -/* subject:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 1 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ -/* issuer :/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 1 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ - - -const unsigned char ValiCert_Class_1_VA_certificate[747]={ -0x30,0x82,0x02,0xE7,0x30,0x82,0x02,0x50,0x02,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A, -0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xBB,0x31,0x24,0x30, -0x22,0x06,0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74, -0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77, -0x6F,0x72,0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61, -0x6C,0x69,0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33, -0x06,0x03,0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20, -0x43,0x6C,0x61,0x73,0x73,0x20,0x31,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56, -0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74, -0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72, -0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69, -0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36, -0x32,0x35,0x32,0x32,0x32,0x33,0x34,0x38,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32, -0x35,0x32,0x32,0x32,0x33,0x34,0x38,0x5A,0x30,0x81,0xBB,0x31,0x24,0x30,0x22,0x06, -0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x56, -0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, -0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61,0x6C,0x69, -0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33,0x06,0x03, -0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x43,0x6C, -0x61,0x73,0x73,0x20,0x31,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56,0x61,0x6C, -0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, -0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74,0x74,0x70, -0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72,0x74,0x2E, -0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69,0x63,0x65, -0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, -0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02, -0x81,0x81,0x00,0xD8,0x59,0x82,0x7A,0x89,0xB8,0x96,0xBA,0xA6,0x2F,0x68,0x6F,0x58, -0x2E,0xA7,0x54,0x1C,0x06,0x6E,0xF4,0xEA,0x8D,0x48,0xBC,0x31,0x94,0x17,0xF0,0xF3, -0x4E,0xBC,0xB2,0xB8,0x35,0x92,0x76,0xB0,0xD0,0xA5,0xA5,0x01,0xD7,0x00,0x03,0x12, -0x22,0x19,0x08,0xF8,0xFF,0x11,0x23,0x9B,0xCE,0x07,0xF5,0xBF,0x69,0x1A,0x26,0xFE, -0x4E,0xE9,0xD1,0x7F,0x9D,0x2C,0x40,0x1D,0x59,0x68,0x6E,0xA6,0xF8,0x58,0xB0,0x9D, -0x1A,0x8F,0xD3,0x3F,0xF1,0xDC,0x19,0x06,0x81,0xA8,0x0E,0xE0,0x3A,0xDD,0xC8,0x53, -0x45,0x09,0x06,0xE6,0x0F,0x70,0xC3,0xFA,0x40,0xA6,0x0E,0xE2,0x56,0x05,0x0F,0x18, -0x4D,0xFC,0x20,0x82,0xD1,0x73,0x55,0x74,0x8D,0x76,0x72,0xA0,0x1D,0x9D,0x1D,0xC0, -0xDD,0x3F,0x71,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x50,0x68,0x3D,0x49,0xF4, -0x2C,0x1C,0x06,0x94,0xDF,0x95,0x60,0x7F,0x96,0x7B,0x17,0xFE,0x4F,0x71,0xAD,0x64, -0xC8,0xDD,0x77,0xD2,0xEF,0x59,0x55,0xE8,0x3F,0xE8,0x8E,0x05,0x2A,0x21,0xF2,0x07, -0xD2,0xB5,0xA7,0x52,0xFE,0x9C,0xB1,0xB6,0xE2,0x5B,0x77,0x17,0x40,0xEA,0x72,0xD6, -0x23,0xCB,0x28,0x81,0x32,0xC3,0x00,0x79,0x18,0xEC,0x59,0x17,0x89,0xC9,0xC6,0x6A, -0x1E,0x71,0xC9,0xFD,0xB7,0x74,0xA5,0x25,0x45,0x69,0xC5,0x48,0xAB,0x19,0xE1,0x45, -0x8A,0x25,0x6B,0x19,0xEE,0xE5,0xBB,0x12,0xF5,0x7F,0xF7,0xA6,0x8D,0x51,0xC3,0xF0, -0x9D,0x74,0xB7,0xA9,0x3E,0xA0,0xA5,0xFF,0xB6,0x49,0x03,0x13,0xDA,0x22,0xCC,0xED, -0x71,0x82,0x2B,0x99,0xCF,0x3A,0xB7,0xF5,0x2D,0x72,0xC8, -}; - - -/* subject:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ -/* issuer :/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ - - -const unsigned char ValiCert_Class_2_VA_certificate[747]={ -0x30,0x82,0x02,0xE7,0x30,0x82,0x02,0x50,0x02,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A, -0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xBB,0x31,0x24,0x30, -0x22,0x06,0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74, -0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77, -0x6F,0x72,0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61, -0x6C,0x69,0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33, -0x06,0x03,0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20, -0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56, -0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74, -0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72, -0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69, -0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36, -0x32,0x36,0x30,0x30,0x31,0x39,0x35,0x34,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32, -0x36,0x30,0x30,0x31,0x39,0x35,0x34,0x5A,0x30,0x81,0xBB,0x31,0x24,0x30,0x22,0x06, -0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x56, -0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, -0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61,0x6C,0x69, -0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33,0x06,0x03, -0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x43,0x6C, -0x61,0x73,0x73,0x20,0x32,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56,0x61,0x6C, -0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, -0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74,0x74,0x70, -0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72,0x74,0x2E, -0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, -0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69,0x63,0x65, -0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, -0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02, -0x81,0x81,0x00,0xCE,0x3A,0x71,0xCA,0xE5,0xAB,0xC8,0x59,0x92,0x55,0xD7,0xAB,0xD8, -0x74,0x0E,0xF9,0xEE,0xD9,0xF6,0x55,0x47,0x59,0x65,0x47,0x0E,0x05,0x55,0xDC,0xEB, -0x98,0x36,0x3C,0x5C,0x53,0x5D,0xD3,0x30,0xCF,0x38,0xEC,0xBD,0x41,0x89,0xED,0x25, -0x42,0x09,0x24,0x6B,0x0A,0x5E,0xB3,0x7C,0xDD,0x52,0x2D,0x4C,0xE6,0xD4,0xD6,0x7D, -0x5A,0x59,0xA9,0x65,0xD4,0x49,0x13,0x2D,0x24,0x4D,0x1C,0x50,0x6F,0xB5,0xC1,0x85, -0x54,0x3B,0xFE,0x71,0xE4,0xD3,0x5C,0x42,0xF9,0x80,0xE0,0x91,0x1A,0x0A,0x5B,0x39, -0x36,0x67,0xF3,0x3F,0x55,0x7C,0x1B,0x3F,0xB4,0x5F,0x64,0x73,0x34,0xE3,0xB4,0x12, -0xBF,0x87,0x64,0xF8,0xDA,0x12,0xFF,0x37,0x27,0xC1,0xB3,0x43,0xBB,0xEF,0x7B,0x6E, -0x2E,0x69,0xF7,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x3B,0x7F,0x50,0x6F,0x6F, -0x50,0x94,0x99,0x49,0x62,0x38,0x38,0x1F,0x4B,0xF8,0xA5,0xC8,0x3E,0xA7,0x82,0x81, -0xF6,0x2B,0xC7,0xE8,0xC5,0xCE,0xE8,0x3A,0x10,0x82,0xCB,0x18,0x00,0x8E,0x4D,0xBD, -0xA8,0x58,0x7F,0xA1,0x79,0x00,0xB5,0xBB,0xE9,0x8D,0xAF,0x41,0xD9,0x0F,0x34,0xEE, -0x21,0x81,0x19,0xA0,0x32,0x49,0x28,0xF4,0xC4,0x8E,0x56,0xD5,0x52,0x33,0xFD,0x50, -0xD5,0x7E,0x99,0x6C,0x03,0xE4,0xC9,0x4C,0xFC,0xCB,0x6C,0xAB,0x66,0xB3,0x4A,0x21, -0x8C,0xE5,0xB5,0x0C,0x32,0x3E,0x10,0xB2,0xCC,0x6C,0xA1,0xDC,0x9A,0x98,0x4C,0x02, -0x5B,0xF3,0xCE,0xB9,0x9E,0xA5,0x72,0x0E,0x4A,0xB7,0x3F,0x3C,0xE6,0x16,0x68,0xF8, -0xBE,0xED,0x74,0x4C,0xBC,0x5B,0xD5,0x62,0x1F,0x43,0xDD, -}; - - -/* subject:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority */ -/* issuer :/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority */ - - -const unsigned char Verisign_Class_3_Public_Primary_Certification_Authority_certificate[576]={ -0x30,0x82,0x02,0x3C,0x30,0x82,0x01,0xA5,0x02,0x10,0x3C,0x91,0x31,0xCB,0x1F,0xF6, -0xD0,0x1B,0x0E,0x9A,0xB8,0xD0,0x44,0xBF,0x12,0xBE,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x5F,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04, -0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63, -0x2E,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04,0x0B,0x13,0x2E,0x43,0x6C,0x61,0x73, -0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61, -0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E, -0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x39,0x36, -0x30,0x31,0x32,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x38,0x30, -0x38,0x30,0x32,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x5F,0x31,0x0B,0x30,0x09, -0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55, -0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E, -0x63,0x2E,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04,0x0B,0x13,0x2E,0x43,0x6C,0x61, -0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D, -0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, -0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x81,0x9F,0x30,0x0D, -0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D, -0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xC9,0x5C,0x59,0x9E,0xF2,0x1B,0x8A,0x01, -0x14,0xB4,0x10,0xDF,0x04,0x40,0xDB,0xE3,0x57,0xAF,0x6A,0x45,0x40,0x8F,0x84,0x0C, -0x0B,0xD1,0x33,0xD9,0xD9,0x11,0xCF,0xEE,0x02,0x58,0x1F,0x25,0xF7,0x2A,0xA8,0x44, -0x05,0xAA,0xEC,0x03,0x1F,0x78,0x7F,0x9E,0x93,0xB9,0x9A,0x00,0xAA,0x23,0x7D,0xD6, -0xAC,0x85,0xA2,0x63,0x45,0xC7,0x72,0x27,0xCC,0xF4,0x4C,0xC6,0x75,0x71,0xD2,0x39, -0xEF,0x4F,0x42,0xF0,0x75,0xDF,0x0A,0x90,0xC6,0x8E,0x20,0x6F,0x98,0x0F,0xF8,0xAC, -0x23,0x5F,0x70,0x29,0x36,0xA4,0xC9,0x86,0xE7,0xB1,0x9A,0x20,0xCB,0x53,0xA5,0x85, -0xE7,0x3D,0xBE,0x7D,0x9A,0xFE,0x24,0x45,0x33,0xDC,0x76,0x15,0xED,0x0F,0xA2,0x71, -0x64,0x4C,0x65,0x2E,0x81,0x68,0x45,0xA7,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06, -0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00, -0x10,0x72,0x52,0xA9,0x05,0x14,0x19,0x32,0x08,0x41,0xF0,0xC5,0x6B,0x0A,0xCC,0x7E, -0x0F,0x21,0x19,0xCD,0xE4,0x67,0xDC,0x5F,0xA9,0x1B,0xE6,0xCA,0xE8,0x73,0x9D,0x22, -0xD8,0x98,0x6E,0x73,0x03,0x61,0x91,0xC5,0x7C,0xB0,0x45,0x40,0x6E,0x44,0x9D,0x8D, -0xB0,0xB1,0x96,0x74,0x61,0x2D,0x0D,0xA9,0x45,0xD2,0xA4,0x92,0x2A,0xD6,0x9A,0x75, -0x97,0x6E,0x3F,0x53,0xFD,0x45,0x99,0x60,0x1D,0xA8,0x2B,0x4C,0xF9,0x5E,0xA7,0x09, -0xD8,0x75,0x30,0xD7,0xD2,0x65,0x60,0x3D,0x67,0xD6,0x48,0x55,0x75,0x69,0x3F,0x91, -0xF5,0x48,0x0B,0x47,0x69,0x22,0x69,0x82,0x96,0xBE,0xC9,0xC8,0x38,0x86,0x4A,0x7A, -0x2C,0x73,0x19,0x48,0x69,0x4E,0x6B,0x7C,0x65,0xBF,0x0F,0xFC,0x70,0xCE,0x88,0x90, -}; - - -/* subject:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network */ -/* issuer :/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network */ - - -const unsigned char Verisign_Class_3_Public_Primary_Certification_Authority___G2_certificate[774]={ -0x30,0x82,0x03,0x02,0x30,0x82,0x02,0x6B,0x02,0x10,0x7D,0xD9,0xFE,0x07,0xCF,0xA8, -0x1E,0xB7,0x10,0x79,0x67,0xFB,0xA7,0x89,0x34,0xC6,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xC1,0x31,0x0B,0x30,0x09, -0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55, -0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E, -0x63,0x2E,0x31,0x3C,0x30,0x3A,0x06,0x03,0x55,0x04,0x0B,0x13,0x33,0x43,0x6C,0x61, -0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D, -0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, -0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32, -0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x31, -0x39,0x39,0x38,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E, -0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69, -0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D, -0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20, -0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x30,0x1E,0x17, -0x0D,0x39,0x38,0x30,0x35,0x31,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D, -0x32,0x38,0x30,0x38,0x30,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xC1, -0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30, -0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, -0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x3C,0x30,0x3A,0x06,0x03,0x55,0x04,0x0B,0x13, -0x33,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, -0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, -0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, -0x2D,0x20,0x47,0x32,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, -0x63,0x29,0x20,0x31,0x39,0x39,0x38,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, -0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, -0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, -0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, -0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, -0x6B,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, -0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xCC,0x5E, -0xD1,0x11,0x5D,0x5C,0x69,0xD0,0xAB,0xD3,0xB9,0x6A,0x4C,0x99,0x1F,0x59,0x98,0x30, -0x8E,0x16,0x85,0x20,0x46,0x6D,0x47,0x3F,0xD4,0x85,0x20,0x84,0xE1,0x6D,0xB3,0xF8, -0xA4,0xED,0x0C,0xF1,0x17,0x0F,0x3B,0xF9,0xA7,0xF9,0x25,0xD7,0xC1,0xCF,0x84,0x63, -0xF2,0x7C,0x63,0xCF,0xA2,0x47,0xF2,0xC6,0x5B,0x33,0x8E,0x64,0x40,0x04,0x68,0xC1, -0x80,0xB9,0x64,0x1C,0x45,0x77,0xC7,0xD8,0x6E,0xF5,0x95,0x29,0x3C,0x50,0xE8,0x34, -0xD7,0x78,0x1F,0xA8,0xBA,0x6D,0x43,0x91,0x95,0x8F,0x45,0x57,0x5E,0x7E,0xC5,0xFB, -0xCA,0xA4,0x04,0xEB,0xEA,0x97,0x37,0x54,0x30,0x6F,0xBB,0x01,0x47,0x32,0x33,0xCD, -0xDC,0x57,0x9B,0x64,0x69,0x61,0xF8,0x9B,0x1D,0x1C,0x89,0x4F,0x5C,0x67,0x02,0x03, -0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, -0x05,0x00,0x03,0x81,0x81,0x00,0x51,0x4D,0xCD,0xBE,0x5C,0xCB,0x98,0x19,0x9C,0x15, -0xB2,0x01,0x39,0x78,0x2E,0x4D,0x0F,0x67,0x70,0x70,0x99,0xC6,0x10,0x5A,0x94,0xA4, -0x53,0x4D,0x54,0x6D,0x2B,0xAF,0x0D,0x5D,0x40,0x8B,0x64,0xD3,0xD7,0xEE,0xDE,0x56, -0x61,0x92,0x5F,0xA6,0xC4,0x1D,0x10,0x61,0x36,0xD3,0x2C,0x27,0x3C,0xE8,0x29,0x09, -0xB9,0x11,0x64,0x74,0xCC,0xB5,0x73,0x9F,0x1C,0x48,0xA9,0xBC,0x61,0x01,0xEE,0xE2, -0x17,0xA6,0x0C,0xE3,0x40,0x08,0x3B,0x0E,0xE7,0xEB,0x44,0x73,0x2A,0x9A,0xF1,0x69, -0x92,0xEF,0x71,0x14,0xC3,0x39,0xAC,0x71,0xA7,0x91,0x09,0x6F,0xE4,0x71,0x06,0xB3, -0xBA,0x59,0x57,0x26,0x79,0x00,0xF6,0xF8,0x0D,0xA2,0x33,0x30,0x28,0xD4,0xAA,0x58, -0xA0,0x9D,0x9D,0x69,0x91,0xFD, -}; - - -/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G3 */ -/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G3 */ - - -const unsigned char Verisign_Class_3_Public_Primary_Certification_Authority___G3_certificate[1054]={ -0x30,0x82,0x04,0x1A,0x30,0x82,0x03,0x02,0x02,0x11,0x00,0x9B,0x7E,0x06,0x49,0xA3, -0x3E,0x62,0xB9,0xD5,0xEE,0x90,0x48,0x71,0x29,0xEF,0x57,0x30,0x0D,0x06,0x09,0x2A, -0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xCA,0x31,0x0B,0x30, -0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03, -0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, -0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65, -0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74, -0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, -0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, -0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, -0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, -0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53, -0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C, -0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +const unsigned char GeoTrust_Primary_Certification_Authority_certificate[896]={ +0x30,0x82,0x03,0x7C,0x30,0x82,0x02,0x64,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x18, +0xAC,0xB5,0x6A,0xFD,0x69,0xB6,0x15,0x3A,0x63,0x6C,0xAF,0xDA,0xFA,0xC4,0xA1,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x58, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30, +0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28, +0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, +0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31, +0x32,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31, +0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x58,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28,0x47,0x65,0x6F,0x54,0x72,0x75, +0x73,0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, 0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x20,0x2D,0x20,0x47,0x33,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31,0x30,0x30, -0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31,0x36, -0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06,0x03, -0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A, -0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E, -0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, -0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, -0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20, -0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, -0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72, -0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45,0x30, -0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, -0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, -0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, -0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, -0x2D,0x20,0x47,0x33,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, -0x02,0x82,0x01,0x01,0x00,0xCB,0xBA,0x9C,0x52,0xFC,0x78,0x1F,0x1A,0x1E,0x6F,0x1B, -0x37,0x73,0xBD,0xF8,0xC9,0x6B,0x94,0x12,0x30,0x4F,0xF0,0x36,0x47,0xF5,0xD0,0x91, -0x0A,0xF5,0x17,0xC8,0xA5,0x61,0xC1,0x16,0x40,0x4D,0xFB,0x8A,0x61,0x90,0xE5,0x76, -0x20,0xC1,0x11,0x06,0x7D,0xAB,0x2C,0x6E,0xA6,0xF5,0x11,0x41,0x8E,0xFA,0x2D,0xAD, -0x2A,0x61,0x59,0xA4,0x67,0x26,0x4C,0xD0,0xE8,0xBC,0x52,0x5B,0x70,0x20,0x04,0x58, -0xD1,0x7A,0xC9,0xA4,0x69,0xBC,0x83,0x17,0x64,0xAD,0x05,0x8B,0xBC,0xD0,0x58,0xCE, -0x8D,0x8C,0xF5,0xEB,0xF0,0x42,0x49,0x0B,0x9D,0x97,0x27,0x67,0x32,0x6E,0xE1,0xAE, -0x93,0x15,0x1C,0x70,0xBC,0x20,0x4D,0x2F,0x18,0xDE,0x92,0x88,0xE8,0x6C,0x85,0x57, -0x11,0x1A,0xE9,0x7E,0xE3,0x26,0x11,0x54,0xA2,0x45,0x96,0x55,0x83,0xCA,0x30,0x89, -0xE8,0xDC,0xD8,0xA3,0xED,0x2A,0x80,0x3F,0x7F,0x79,0x65,0x57,0x3E,0x15,0x20,0x66, -0x08,0x2F,0x95,0x93,0xBF,0xAA,0x47,0x2F,0xA8,0x46,0x97,0xF0,0x12,0xE2,0xFE,0xC2, -0x0A,0x2B,0x51,0xE6,0x76,0xE6,0xB7,0x46,0xB7,0xE2,0x0D,0xA6,0xCC,0xA8,0xC3,0x4C, -0x59,0x55,0x89,0xE6,0xE8,0x53,0x5C,0x1C,0xEA,0x9D,0xF0,0x62,0x16,0x0B,0xA7,0xC9, -0x5F,0x0C,0xF0,0xDE,0xC2,0x76,0xCE,0xAF,0xF7,0x6A,0xF2,0xFA,0x41,0xA6,0xA2,0x33, -0x14,0xC9,0xE5,0x7A,0x63,0xD3,0x9E,0x62,0x37,0xD5,0x85,0x65,0x9E,0x0E,0xE6,0x53, -0x24,0x74,0x1B,0x5E,0x1D,0x12,0x53,0x5B,0xC7,0x2C,0xE7,0x83,0x49,0x3B,0x15,0xAE, -0x8A,0x68,0xB9,0x57,0x97,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x11,0x14, -0x96,0xC1,0xAB,0x92,0x08,0xF7,0x3F,0x2F,0xC9,0xB2,0xFE,0xE4,0x5A,0x9F,0x64,0xDE, -0xDB,0x21,0x4F,0x86,0x99,0x34,0x76,0x36,0x57,0xDD,0xD0,0x15,0x2F,0xC5,0xAD,0x7F, -0x15,0x1F,0x37,0x62,0x73,0x3E,0xD4,0xE7,0x5F,0xCE,0x17,0x03,0xDB,0x35,0xFA,0x2B, -0xDB,0xAE,0x60,0x09,0x5F,0x1E,0x5F,0x8F,0x6E,0xBB,0x0B,0x3D,0xEA,0x5A,0x13,0x1E, -0x0C,0x60,0x6F,0xB5,0xC0,0xB5,0x23,0x22,0x2E,0x07,0x0B,0xCB,0xA9,0x74,0xCB,0x47, -0xBB,0x1D,0xC1,0xD7,0xA5,0x6B,0xCC,0x2F,0xD2,0x42,0xFD,0x49,0xDD,0xA7,0x89,0xCF, -0x53,0xBA,0xDA,0x00,0x5A,0x28,0xBF,0x82,0xDF,0xF8,0xBA,0x13,0x1D,0x50,0x86,0x82, -0xFD,0x8E,0x30,0x8F,0x29,0x46,0xB0,0x1E,0x3D,0x35,0xDA,0x38,0x62,0x16,0x18,0x4A, -0xAD,0xE6,0xB6,0x51,0x6C,0xDE,0xAF,0x62,0xEB,0x01,0xD0,0x1E,0x24,0xFE,0x7A,0x8F, -0x12,0x1A,0x12,0x68,0xB8,0xFB,0x66,0x99,0x14,0x14,0x45,0x5C,0xAE,0xE7,0xAE,0x69, -0x17,0x81,0x2B,0x5A,0x37,0xC9,0x5E,0x2A,0xF4,0xC6,0xE2,0xA1,0x5C,0x54,0x9B,0xA6, -0x54,0x00,0xCF,0xF0,0xF1,0xC1,0xC7,0x98,0x30,0x1A,0x3B,0x36,0x16,0xDB,0xA3,0x6E, -0xEA,0xFD,0xAD,0xB2,0xC2,0xDA,0xEF,0x02,0x47,0x13,0x8A,0xC0,0xF1,0xB3,0x31,0xAD, -0x4F,0x1C,0xE1,0x4F,0x9C,0xAF,0x0F,0x0C,0x9D,0xF7,0x78,0x0D,0xD8,0xF4,0x35,0x56, -0x80,0xDA,0xB7,0x6D,0x17,0x8F,0x9D,0x1E,0x81,0x64,0xE1,0xFE,0xC5,0x45,0xBA,0xAD, -0x6B,0xB9,0x0A,0x7A,0x4E,0x4F,0x4B,0x84,0xEE,0x4B,0xF1,0x7D,0xDD,0x11, -}; - - -/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2007 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G4 */ -/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2007 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G4 */ - - -const unsigned char VeriSign_Class_3_Public_Primary_Certification_Authority___G4_certificate[904]={ -0x30,0x82,0x03,0x84,0x30,0x82,0x03,0x0A,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x2F, -0x80,0xFE,0x23,0x8C,0x0E,0x22,0x0F,0x48,0x67,0x12,0x28,0x91,0x87,0xAC,0xB3,0x30, -0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0xCA,0x31,0x0B, -0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06, -0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20, -0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56, -0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65, -0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31, -0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67, -0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75, -0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C, -0x79,0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69, -0x53,0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62, -0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74, -0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x34,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31, -0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31, -0x38,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06, -0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04, -0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63, -0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69, -0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F, -0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29, -0x20,0x32,0x30,0x30,0x37,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20, -0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F, -0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45, -0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67, -0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63, -0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69, -0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, -0x20,0x2D,0x20,0x47,0x34,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D, -0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0xA7,0x56,0x7A, -0x7C,0x52,0xDA,0x64,0x9B,0x0E,0x2D,0x5C,0xD8,0x5E,0xAC,0x92,0x3D,0xFE,0x01,0xE6, -0x19,0x4A,0x3D,0x14,0x03,0x4B,0xFA,0x60,0x27,0x20,0xD9,0x83,0x89,0x69,0xFA,0x54, -0xC6,0x9A,0x18,0x5E,0x55,0x2A,0x64,0xDE,0x06,0xF6,0x8D,0x4A,0x3B,0xAD,0x10,0x3C, -0x65,0x3D,0x90,0x88,0x04,0x89,0xE0,0x30,0x61,0xB3,0xAE,0x5D,0x01,0xA7,0x7B,0xDE, -0x7C,0xB2,0xBE,0xCA,0x65,0x61,0x00,0x86,0xAE,0xDA,0x8F,0x7B,0xD0,0x89,0xAD,0x4D, -0x1D,0x59,0x9A,0x41,0xB1,0xBC,0x47,0x80,0xDC,0x9E,0x62,0xC3,0xF9,0xA3,0x81,0xB2, -0x30,0x81,0xAF,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, -0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, -0x03,0x02,0x01,0x06,0x30,0x6D,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0C, -0x04,0x61,0x30,0x5F,0xA1,0x5D,0xA0,0x5B,0x30,0x59,0x30,0x57,0x30,0x55,0x16,0x09, -0x69,0x6D,0x61,0x67,0x65,0x2F,0x67,0x69,0x66,0x30,0x21,0x30,0x1F,0x30,0x07,0x06, -0x05,0x2B,0x0E,0x03,0x02,0x1A,0x04,0x14,0x8F,0xE5,0xD3,0x1A,0x86,0xAC,0x8D,0x8E, -0x6B,0xC3,0xCF,0x80,0x6A,0xD4,0x48,0x18,0x2C,0x7B,0x19,0x2E,0x30,0x25,0x16,0x23, -0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6C,0x6F,0x67,0x6F,0x2E,0x76,0x65,0x72,0x69, -0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x76,0x73,0x6C,0x6F,0x67,0x6F,0x2E, -0x67,0x69,0x66,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB3,0x16, -0x91,0xFD,0xEE,0xA6,0x6E,0xE4,0xB5,0x2E,0x49,0x8F,0x87,0x78,0x81,0x80,0xEC,0xE5, -0xB1,0xB5,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68, -0x00,0x30,0x65,0x02,0x30,0x66,0x21,0x0C,0x18,0x26,0x60,0x5A,0x38,0x7B,0x56,0x42, -0xE0,0xA7,0xFC,0x36,0x84,0x51,0x91,0x20,0x2C,0x76,0x4D,0x43,0x3D,0xC4,0x1D,0x84, -0x23,0xD0,0xAC,0xD6,0x7C,0x35,0x06,0xCE,0xCD,0x69,0xBD,0x90,0x0D,0xDB,0x6C,0x48, -0x42,0x1D,0x0E,0xAA,0x42,0x02,0x31,0x00,0x9C,0x3D,0x48,0x39,0x23,0x39,0x58,0x1A, -0x15,0x12,0x59,0x6A,0x9E,0xEF,0xD5,0x59,0xB2,0x1D,0x52,0x2C,0x99,0x71,0xCD,0xC7, -0x29,0xDF,0x1B,0x2A,0x61,0x7B,0x71,0xD1,0xDE,0xF3,0xC0,0xE5,0x0D,0x3A,0x4A,0xAA, -0x2D,0xA7,0xD8,0x86,0x2A,0xDD,0x2E,0x10, +0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xBE,0xB8,0x15,0x7B,0xFF,0xD4,0x7C,0x7D,0x67,0xAD,0x83,0x64,0x7B, +0xC8,0x42,0x53,0x2D,0xDF,0xF6,0x84,0x08,0x20,0x61,0xD6,0x01,0x59,0x6A,0x9C,0x44, +0x11,0xAF,0xEF,0x76,0xFD,0x95,0x7E,0xCE,0x61,0x30,0xBB,0x7A,0x83,0x5F,0x02,0xBD, +0x01,0x66,0xCA,0xEE,0x15,0x8D,0x6F,0xA1,0x30,0x9C,0xBD,0xA1,0x85,0x9E,0x94,0x3A, +0xF3,0x56,0x88,0x00,0x31,0xCF,0xD8,0xEE,0x6A,0x96,0x02,0xD9,0xED,0x03,0x8C,0xFB, +0x75,0x6D,0xE7,0xEA,0xB8,0x55,0x16,0x05,0x16,0x9A,0xF4,0xE0,0x5E,0xB1,0x88,0xC0, +0x64,0x85,0x5C,0x15,0x4D,0x88,0xC7,0xB7,0xBA,0xE0,0x75,0xE9,0xAD,0x05,0x3D,0x9D, +0xC7,0x89,0x48,0xE0,0xBB,0x28,0xC8,0x03,0xE1,0x30,0x93,0x64,0x5E,0x52,0xC0,0x59, +0x70,0x22,0x35,0x57,0x88,0x8A,0xF1,0x95,0x0A,0x83,0xD7,0xBC,0x31,0x73,0x01,0x34, +0xED,0xEF,0x46,0x71,0xE0,0x6B,0x02,0xA8,0x35,0x72,0x6B,0x97,0x9B,0x66,0xE0,0xCB, +0x1C,0x79,0x5F,0xD8,0x1A,0x04,0x68,0x1E,0x47,0x02,0xE6,0x9D,0x60,0xE2,0x36,0x97, +0x01,0xDF,0xCE,0x35,0x92,0xDF,0xBE,0x67,0xC7,0x6D,0x77,0x59,0x3B,0x8F,0x9D,0xD6, +0x90,0x15,0x94,0xBC,0x42,0x34,0x10,0xC1,0x39,0xF9,0xB1,0x27,0x3E,0x7E,0xD6,0x8A, +0x75,0xC5,0xB2,0xAF,0x96,0xD3,0xA2,0xDE,0x9B,0xE4,0x98,0xBE,0x7D,0xE1,0xE9,0x81, +0xAD,0xB6,0x6F,0xFC,0xD7,0x0E,0xDA,0xE0,0x34,0xB0,0x0D,0x1A,0x77,0xE7,0xE3,0x08, +0x98,0xEF,0x58,0xFA,0x9C,0x84,0xB7,0x36,0xAF,0xC2,0xDF,0xAC,0xD2,0xF4,0x10,0x06, +0x70,0x71,0x35,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06, +0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x2C,0xD5,0x50,0x41,0x97,0x15,0x8B,0xF0, +0x8F,0x36,0x61,0x5B,0x4A,0xFB,0x6B,0xD9,0x99,0xC9,0x33,0x92,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x5A,0x70,0x7F,0x2C,0xDD,0xB7,0x34,0x4F,0xF5,0x86,0x51,0xA9,0x26,0xBE,0x4B,0xB8, +0xAA,0xF1,0x71,0x0D,0xDC,0x61,0xC7,0xA0,0xEA,0x34,0x1E,0x7A,0x77,0x0F,0x04,0x35, +0xE8,0x27,0x8F,0x6C,0x90,0xBF,0x91,0x16,0x24,0x46,0x3E,0x4A,0x4E,0xCE,0x2B,0x16, +0xD5,0x0B,0x52,0x1D,0xFC,0x1F,0x67,0xA2,0x02,0x45,0x31,0x4F,0xCE,0xF3,0xFA,0x03, +0xA7,0x79,0x9D,0x53,0x6A,0xD9,0xDA,0x63,0x3A,0xF8,0x80,0xD7,0xD3,0x99,0xE1,0xA5, +0xE1,0xBE,0xD4,0x55,0x71,0x98,0x35,0x3A,0xBE,0x93,0xEA,0xAE,0xAD,0x42,0xB2,0x90, +0x6F,0xE0,0xFC,0x21,0x4D,0x35,0x63,0x33,0x89,0x49,0xD6,0x9B,0x4E,0xCA,0xC7,0xE7, +0x4E,0x09,0x00,0xF7,0xDA,0xC7,0xEF,0x99,0x62,0x99,0x77,0xB6,0x95,0x22,0x5E,0x8A, +0xA0,0xAB,0xF4,0xB8,0x78,0x98,0xCA,0x38,0x19,0x99,0xC9,0x72,0x9E,0x78,0xCD,0x4B, +0xAC,0xAF,0x19,0xA0,0x73,0x12,0x2D,0xFC,0xC2,0x41,0xBA,0x81,0x91,0xDA,0x16,0x5A, +0x31,0xB7,0xF9,0xB4,0x71,0x80,0x12,0x48,0x99,0x72,0x73,0x5A,0x59,0x53,0xC1,0x63, +0x52,0x33,0xED,0xA7,0xC9,0xD2,0x39,0x02,0x70,0xFA,0xE0,0xB1,0x42,0x66,0x29,0xAA, +0x9B,0x51,0xED,0x30,0x54,0x22,0x14,0x5F,0xD9,0xAB,0x1D,0xC1,0xE4,0x94,0xF0,0xF8, +0xF5,0x2B,0xF7,0xEA,0xCA,0x78,0x46,0xD6,0xB8,0x91,0xFD,0xA6,0x0D,0x2B,0x1A,0x14, +0x01,0x3E,0x80,0xF0,0x42,0xA0,0x95,0x07,0x5E,0x6D,0xCD,0xCC,0x4B,0xA4,0x45,0x8D, +0xAB,0x12,0xE8,0xB3,0xDE,0x5A,0xE5,0xA0,0x7C,0xE8,0x0F,0x22,0x1D,0x5A,0xE9,0x59, }; @@ -4553,380 +2091,2176 @@ }; -/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 4 Public Primary Certification Authority - G3 */ -/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 4 Public Primary Certification Authority - G3 */ +/* subject:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority */ +/* issuer :/C=US/O=Equifax/OU=Equifax Secure Certificate Authority */ -const unsigned char Verisign_Class_4_Public_Primary_Certification_Authority___G3_certificate[1054]={ -0x30,0x82,0x04,0x1A,0x30,0x82,0x03,0x02,0x02,0x11,0x00,0xEC,0xA0,0xA7,0x8B,0x6E, -0x75,0x6A,0x01,0xCF,0xC4,0x7C,0xCC,0x2F,0x94,0x5E,0xD7,0x30,0x0D,0x06,0x09,0x2A, -0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xCA,0x31,0x0B,0x30, -0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03, -0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, -0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65, -0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74, -0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, -0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, -0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, -0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, -0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53, -0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x34,0x20,0x50,0x75,0x62,0x6C, -0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +const unsigned char Equifax_Secure_CA_certificate[804]={ +0x30,0x82,0x03,0x20,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x35, +0xDE,0xF4,0xCF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69, +0x66,0x61,0x78,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71, +0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x38,0x32,0x32,0x31,0x36,0x34,0x31, +0x35,0x31,0x5A,0x17,0x0D,0x31,0x38,0x30,0x38,0x32,0x32,0x31,0x36,0x34,0x31,0x35, +0x31,0x5A,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69, +0x66,0x61,0x78,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71, +0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xC1, +0x5D,0xB1,0x58,0x67,0x08,0x62,0xEE,0xA0,0x9A,0x2D,0x1F,0x08,0x6D,0x91,0x14,0x68, +0x98,0x0A,0x1E,0xFE,0xDA,0x04,0x6F,0x13,0x84,0x62,0x21,0xC3,0xD1,0x7C,0xCE,0x9F, +0x05,0xE0,0xB8,0x01,0xF0,0x4E,0x34,0xEC,0xE2,0x8A,0x95,0x04,0x64,0xAC,0xF1,0x6B, +0x53,0x5F,0x05,0xB3,0xCB,0x67,0x80,0xBF,0x42,0x02,0x8E,0xFE,0xDD,0x01,0x09,0xEC, +0xE1,0x00,0x14,0x4F,0xFC,0xFB,0xF0,0x0C,0xDD,0x43,0xBA,0x5B,0x2B,0xE1,0x1F,0x80, +0x70,0x99,0x15,0x57,0x93,0x16,0xF1,0x0F,0x97,0x6A,0xB7,0xC2,0x68,0x23,0x1C,0xCC, +0x4D,0x59,0x30,0xAC,0x51,0x1E,0x3B,0xAF,0x2B,0xD6,0xEE,0x63,0x45,0x7B,0xC5,0xD9, +0x5F,0x50,0xD2,0xE3,0x50,0x0F,0x3A,0x88,0xE7,0xBF,0x14,0xFD,0xE0,0xC7,0xB9,0x02, +0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x09,0x30,0x82,0x01,0x05,0x30,0x70,0x06,0x03, +0x55,0x1D,0x1F,0x04,0x69,0x30,0x67,0x30,0x65,0xA0,0x63,0xA0,0x61,0xA4,0x5F,0x30, +0x5D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x10, +0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69,0x66,0x61,0x78, +0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71,0x75,0x69,0x66, +0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66, +0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31, +0x0D,0x30,0x0B,0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4C,0x31,0x30,0x1A, +0x06,0x03,0x55,0x1D,0x10,0x04,0x13,0x30,0x11,0x81,0x0F,0x32,0x30,0x31,0x38,0x30, +0x38,0x32,0x32,0x31,0x36,0x34,0x31,0x35,0x31,0x5A,0x30,0x0B,0x06,0x03,0x55,0x1D, +0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, +0x30,0x16,0x80,0x14,0x48,0xE6,0x68,0xF9,0x2B,0xD2,0xB2,0x95,0xD7,0x47,0xD8,0x23, +0x20,0x10,0x4F,0x33,0x98,0x90,0x9F,0xD4,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0x48,0xE6,0x68,0xF9,0x2B,0xD2,0xB2,0x95,0xD7,0x47,0xD8,0x23,0x20, +0x10,0x4F,0x33,0x98,0x90,0x9F,0xD4,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x1A,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07, +0x41,0x00,0x04,0x0D,0x30,0x0B,0x1B,0x05,0x56,0x33,0x2E,0x30,0x63,0x03,0x02,0x06, +0xC0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x81,0x81,0x00,0x58,0xCE,0x29,0xEA,0xFC,0xF7,0xDE,0xB5,0xCE,0x02,0xB9,0x17, +0xB5,0x85,0xD1,0xB9,0xE3,0xE0,0x95,0xCC,0x25,0x31,0x0D,0x00,0xA6,0x92,0x6E,0x7F, +0xB6,0x92,0x63,0x9E,0x50,0x95,0xD1,0x9A,0x6F,0xE4,0x11,0xDE,0x63,0x85,0x6E,0x98, +0xEE,0xA8,0xFF,0x5A,0xC8,0xD3,0x55,0xB2,0x66,0x71,0x57,0xDE,0xC0,0x21,0xEB,0x3D, +0x2A,0xA7,0x23,0x49,0x01,0x04,0x86,0x42,0x7B,0xFC,0xEE,0x7F,0xA2,0x16,0x52,0xB5, +0x67,0x67,0xD3,0x40,0xDB,0x3B,0x26,0x58,0xB2,0x28,0x77,0x3D,0xAE,0x14,0x77,0x61, +0xD6,0xFA,0x2A,0x66,0x27,0xA0,0x0D,0xFA,0xA7,0x73,0x5C,0xEA,0x70,0xF1,0x94,0x21, +0x65,0x44,0x5F,0xFA,0xFC,0xEF,0x29,0x68,0xA9,0xA2,0x87,0x79,0xEF,0x79,0xEF,0x4F, +0xAC,0x07,0x77,0x38, +}; + + +/* subject:/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048) */ +/* issuer :/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048) */ + + +const unsigned char Entrust_net_Premium_2048_Secure_Server_CA_certificate[1120]={ +0x30,0x82,0x04,0x5C,0x30,0x82,0x03,0x44,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x38, +0x63,0xB9,0x66,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xB4,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x40,0x30,0x3E,0x06, +0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73, +0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x5F,0x32,0x30,0x34,0x38,0x20,0x69, +0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28, +0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30, +0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39, +0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D, +0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03,0x13,0x2A,0x45, +0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x43,0x65,0x72,0x74,0x69, 0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, -0x74,0x79,0x20,0x2D,0x20,0x47,0x33,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31,0x30,0x30, -0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31,0x36, -0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06,0x03, -0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A, -0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E, -0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, -0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, -0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20, -0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, -0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72, -0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45,0x30, -0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, -0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x34,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, -0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, -0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, -0x2D,0x20,0x47,0x33,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, -0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, -0x02,0x82,0x01,0x01,0x00,0xAD,0xCB,0xA5,0x11,0x69,0xC6,0x59,0xAB,0xF1,0x8F,0xB5, -0x19,0x0F,0x56,0xCE,0xCC,0xB5,0x1F,0x20,0xE4,0x9E,0x26,0x25,0x4B,0xE0,0x73,0x65, -0x89,0x59,0xDE,0xD0,0x83,0xE4,0xF5,0x0F,0xB5,0xBB,0xAD,0xF1,0x7C,0xE8,0x21,0xFC, -0xE4,0xE8,0x0C,0xEE,0x7C,0x45,0x22,0x19,0x76,0x92,0xB4,0x13,0xB7,0x20,0x5B,0x09, -0xFA,0x61,0xAE,0xA8,0xF2,0xA5,0x8D,0x85,0xC2,0x2A,0xD6,0xDE,0x66,0x36,0xD2,0x9B, -0x02,0xF4,0xA8,0x92,0x60,0x7C,0x9C,0x69,0xB4,0x8F,0x24,0x1E,0xD0,0x86,0x52,0xF6, -0x32,0x9C,0x41,0x58,0x1E,0x22,0xBD,0xCD,0x45,0x62,0x95,0x08,0x6E,0xD0,0x66,0xDD, -0x53,0xA2,0xCC,0xF0,0x10,0xDC,0x54,0x73,0x8B,0x04,0xA1,0x46,0x33,0x33,0x5C,0x17, -0x40,0xB9,0x9E,0x4D,0xD3,0xF3,0xBE,0x55,0x83,0xE8,0xB1,0x89,0x8E,0x5A,0x7C,0x9A, -0x96,0x22,0x90,0x3B,0x88,0x25,0xF2,0xD2,0x53,0x88,0x02,0x0C,0x0B,0x78,0xF2,0xE6, -0x37,0x17,0x4B,0x30,0x46,0x07,0xE4,0x80,0x6D,0xA6,0xD8,0x96,0x2E,0xE8,0x2C,0xF8, -0x11,0xB3,0x38,0x0D,0x66,0xA6,0x9B,0xEA,0xC9,0x23,0x5B,0xDB,0x8E,0xE2,0xF3,0x13, -0x8E,0x1A,0x59,0x2D,0xAA,0x02,0xF0,0xEC,0xA4,0x87,0x66,0xDC,0xC1,0x3F,0xF5,0xD8, -0xB9,0xF4,0xEC,0x82,0xC6,0xD2,0x3D,0x95,0x1D,0xE5,0xC0,0x4F,0x84,0xC9,0xD9,0xA3, -0x44,0x28,0x06,0x6A,0xD7,0x45,0xAC,0xF0,0x6B,0x6A,0xEF,0x4E,0x5F,0xF8,0x11,0x82, -0x1E,0x38,0x63,0x34,0x66,0x50,0xD4,0x3E,0x93,0x73,0xFA,0x30,0xC3,0x66,0xAD,0xFF, -0x93,0x2D,0x97,0xEF,0x03,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86, -0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x8F,0xFA, -0x25,0x6B,0x4F,0x5B,0xE4,0xA4,0x4E,0x27,0x55,0xAB,0x22,0x15,0x59,0x3C,0xCA,0xB5, -0x0A,0xD4,0x4A,0xDB,0xAB,0xDD,0xA1,0x5F,0x53,0xC5,0xA0,0x57,0x39,0xC2,0xCE,0x47, -0x2B,0xBE,0x3A,0xC8,0x56,0xBF,0xC2,0xD9,0x27,0x10,0x3A,0xB1,0x05,0x3C,0xC0,0x77, -0x31,0xBB,0x3A,0xD3,0x05,0x7B,0x6D,0x9A,0x1C,0x30,0x8C,0x80,0xCB,0x93,0x93,0x2A, -0x83,0xAB,0x05,0x51,0x82,0x02,0x00,0x11,0x67,0x6B,0xF3,0x88,0x61,0x47,0x5F,0x03, -0x93,0xD5,0x5B,0x0D,0xE0,0xF1,0xD4,0xA1,0x32,0x35,0x85,0xB2,0x3A,0xDB,0xB0,0x82, -0xAB,0xD1,0xCB,0x0A,0xBC,0x4F,0x8C,0x5B,0xC5,0x4B,0x00,0x3B,0x1F,0x2A,0x82,0xA6, -0x7E,0x36,0x85,0xDC,0x7E,0x3C,0x67,0x00,0xB5,0xE4,0x3B,0x52,0xE0,0xA8,0xEB,0x5D, -0x15,0xF9,0xC6,0x6D,0xF0,0xAD,0x1D,0x0E,0x85,0xB7,0xA9,0x9A,0x73,0x14,0x5A,0x5B, -0x8F,0x41,0x28,0xC0,0xD5,0xE8,0x2D,0x4D,0xA4,0x5E,0xCD,0xAA,0xD9,0xED,0xCE,0xDC, -0xD8,0xD5,0x3C,0x42,0x1D,0x17,0xC1,0x12,0x5D,0x45,0x38,0xC3,0x38,0xF3,0xFC,0x85, -0x2E,0x83,0x46,0x48,0xB2,0xD7,0x20,0x5F,0x92,0x36,0x8F,0xE7,0x79,0x0F,0x98,0x5E, -0x99,0xE8,0xF0,0xD0,0xA4,0xBB,0xF5,0x53,0xBD,0x2A,0xCE,0x59,0xB0,0xAF,0x6E,0x7F, -0x6C,0xBB,0xD2,0x1E,0x00,0xB0,0x21,0xED,0xF8,0x41,0x62,0x82,0xB9,0xD8,0xB2,0xC4, -0xBB,0x46,0x50,0xF3,0x31,0xC5,0x8F,0x01,0xA8,0x74,0xEB,0xF5,0x78,0x27,0xDA,0xE7, -0xF7,0x66,0x43,0xF3,0x9E,0x83,0x3E,0x20,0xAA,0xC3,0x35,0x60,0x91,0xCE, +0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31, +0x32,0x32,0x34,0x31,0x37,0x35,0x30,0x35,0x31,0x5A,0x17,0x0D,0x31,0x39,0x31,0x32, +0x32,0x34,0x31,0x38,0x32,0x30,0x35,0x31,0x5A,0x30,0x81,0xB4,0x31,0x14,0x30,0x12, +0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, +0x65,0x74,0x31,0x40,0x30,0x3E,0x06,0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77, +0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53, +0x5F,0x32,0x30,0x34,0x38,0x20,0x69,0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79, +0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69, +0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E, +0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06, +0x03,0x55,0x04,0x03,0x13,0x2A,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65, +0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29, +0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01, +0x00,0xAD,0x4D,0x4B,0xA9,0x12,0x86,0xB2,0xEA,0xA3,0x20,0x07,0x15,0x16,0x64,0x2A, +0x2B,0x4B,0xD1,0xBF,0x0B,0x4A,0x4D,0x8E,0xED,0x80,0x76,0xA5,0x67,0xB7,0x78,0x40, +0xC0,0x73,0x42,0xC8,0x68,0xC0,0xDB,0x53,0x2B,0xDD,0x5E,0xB8,0x76,0x98,0x35,0x93, +0x8B,0x1A,0x9D,0x7C,0x13,0x3A,0x0E,0x1F,0x5B,0xB7,0x1E,0xCF,0xE5,0x24,0x14,0x1E, +0xB1,0x81,0xA9,0x8D,0x7D,0xB8,0xCC,0x6B,0x4B,0x03,0xF1,0x02,0x0C,0xDC,0xAB,0xA5, +0x40,0x24,0x00,0x7F,0x74,0x94,0xA1,0x9D,0x08,0x29,0xB3,0x88,0x0B,0xF5,0x87,0x77, +0x9D,0x55,0xCD,0xE4,0xC3,0x7E,0xD7,0x6A,0x64,0xAB,0x85,0x14,0x86,0x95,0x5B,0x97, +0x32,0x50,0x6F,0x3D,0xC8,0xBA,0x66,0x0C,0xE3,0xFC,0xBD,0xB8,0x49,0xC1,0x76,0x89, +0x49,0x19,0xFD,0xC0,0xA8,0xBD,0x89,0xA3,0x67,0x2F,0xC6,0x9F,0xBC,0x71,0x19,0x60, +0xB8,0x2D,0xE9,0x2C,0xC9,0x90,0x76,0x66,0x7B,0x94,0xE2,0xAF,0x78,0xD6,0x65,0x53, +0x5D,0x3C,0xD6,0x9C,0xB2,0xCF,0x29,0x03,0xF9,0x2F,0xA4,0x50,0xB2,0xD4,0x48,0xCE, +0x05,0x32,0x55,0x8A,0xFD,0xB2,0x64,0x4C,0x0E,0xE4,0x98,0x07,0x75,0xDB,0x7F,0xDF, +0xB9,0x08,0x55,0x60,0x85,0x30,0x29,0xF9,0x7B,0x48,0xA4,0x69,0x86,0xE3,0x35,0x3F, +0x1E,0x86,0x5D,0x7A,0x7A,0x15,0xBD,0xEF,0x00,0x8E,0x15,0x22,0x54,0x17,0x00,0x90, +0x26,0x93,0xBC,0x0E,0x49,0x68,0x91,0xBF,0xF8,0x47,0xD3,0x9D,0x95,0x42,0xC1,0x0E, +0x4D,0xDF,0x6F,0x26,0xCF,0xC3,0x18,0x21,0x62,0x66,0x43,0x70,0xD6,0xD5,0xC0,0x07, +0xE1,0x02,0x03,0x01,0x00,0x01,0xA3,0x74,0x30,0x72,0x30,0x11,0x06,0x09,0x60,0x86, +0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x1F,0x06, +0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x55,0xE4,0x81,0xD1,0x11,0x80, +0xBE,0xD8,0x89,0xB9,0x08,0xA3,0x31,0xF9,0xA1,0x24,0x09,0x16,0xB9,0x70,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x55,0xE4,0x81,0xD1,0x11,0x80,0xBE, +0xD8,0x89,0xB9,0x08,0xA3,0x31,0xF9,0xA1,0x24,0x09,0x16,0xB9,0x70,0x30,0x1D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04,0x10,0x30,0x0E,0x1B,0x08, +0x56,0x35,0x2E,0x30,0x3A,0x34,0x2E,0x30,0x03,0x02,0x04,0x90,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x59,0x47,0xAC,0x21,0x84,0x8A,0x17,0xC9,0x9C,0x89,0x53,0x1E,0xBA,0x80,0x85,0x1A, +0xC6,0x3C,0x4E,0x3E,0xB1,0x9C,0xB6,0x7C,0xC6,0x92,0x5D,0x18,0x64,0x02,0xE3,0xD3, +0x06,0x08,0x11,0x61,0x7C,0x63,0xE3,0x2B,0x9D,0x31,0x03,0x70,0x76,0xD2,0xA3,0x28, +0xA0,0xF4,0xBB,0x9A,0x63,0x73,0xED,0x6D,0xE5,0x2A,0xDB,0xED,0x14,0xA9,0x2B,0xC6, +0x36,0x11,0xD0,0x2B,0xEB,0x07,0x8B,0xA5,0xDA,0x9E,0x5C,0x19,0x9D,0x56,0x12,0xF5, +0x54,0x29,0xC8,0x05,0xED,0xB2,0x12,0x2A,0x8D,0xF4,0x03,0x1B,0xFF,0xE7,0x92,0x10, +0x87,0xB0,0x3A,0xB5,0xC3,0x9D,0x05,0x37,0x12,0xA3,0xC7,0xF4,0x15,0xB9,0xD5,0xA4, +0x39,0x16,0x9B,0x53,0x3A,0x23,0x91,0xF1,0xA8,0x82,0xA2,0x6A,0x88,0x68,0xC1,0x79, +0x02,0x22,0xBC,0xAA,0xA6,0xD6,0xAE,0xDF,0xB0,0x14,0x5F,0xB8,0x87,0xD0,0xDD,0x7C, +0x7F,0x7B,0xFF,0xAF,0x1C,0xCF,0xE6,0xDB,0x07,0xAD,0x5E,0xDB,0x85,0x9D,0xD0,0x2B, +0x0D,0x33,0xDB,0x04,0xD1,0xE6,0x49,0x40,0x13,0x2B,0x76,0xFB,0x3E,0xE9,0x9C,0x89, +0x0F,0x15,0xCE,0x18,0xB0,0x85,0x78,0x21,0x4F,0x6B,0x4F,0x0E,0xFA,0x36,0x67,0xCD, +0x07,0xF2,0xFF,0x08,0xD0,0xE2,0xDE,0xD9,0xBF,0x2A,0xAF,0xB8,0x87,0x86,0x21,0x3C, +0x04,0xCA,0xB7,0x94,0x68,0x7F,0xCF,0x3C,0xE9,0x98,0xD7,0x38,0xFF,0xEC,0xC0,0xD9, +0x50,0xF0,0x2E,0x4B,0x58,0xAE,0x46,0x6F,0xD0,0x2E,0xC3,0x60,0xDA,0x72,0x55,0x72, +0xBD,0x4C,0x45,0x9E,0x61,0xBA,0xBF,0x84,0x81,0x92,0x03,0xD1,0xD2,0x69,0x7C,0xC5, }; -/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2008 VeriSign, Inc. - For authorized use only/CN=VeriSign Universal Root Certification Authority */ -/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2008 VeriSign, Inc. - For authorized use only/CN=VeriSign Universal Root Certification Authority */ +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root G3 */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root G3 */ -const unsigned char VeriSign_Universal_Root_Certification_Authority_certificate[1213]={ -0x30,0x82,0x04,0xB9,0x30,0x82,0x03,0xA1,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x40, -0x1A,0xC4,0x64,0x21,0xB3,0x13,0x21,0x03,0x0E,0xBB,0xE4,0x12,0x1A,0xC5,0x1D,0x30, -0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81, -0xBD,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, -0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67, -0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B, -0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74, -0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04, -0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x38,0x20,0x56,0x65,0x72,0x69, -0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72, -0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20, -0x6F,0x6E,0x6C,0x79,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x56, -0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61, -0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, -0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E, -0x17,0x0D,0x30,0x38,0x30,0x34,0x30,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17, -0x0D,0x33,0x37,0x31,0x32,0x30,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81, -0xBD,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, -0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67, -0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B, -0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74, -0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04, -0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x38,0x20,0x56,0x65,0x72,0x69, -0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72, -0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20, -0x6F,0x6E,0x6C,0x79,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x56, -0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61, -0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, -0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82, -0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05, -0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC7, -0x61,0x37,0x5E,0xB1,0x01,0x34,0xDB,0x62,0xD7,0x15,0x9B,0xFF,0x58,0x5A,0x8C,0x23, -0x23,0xD6,0x60,0x8E,0x91,0xD7,0x90,0x98,0x83,0x7A,0xE6,0x58,0x19,0x38,0x8C,0xC5, -0xF6,0xE5,0x64,0x85,0xB4,0xA2,0x71,0xFB,0xED,0xBD,0xB9,0xDA,0xCD,0x4D,0x00,0xB4, -0xC8,0x2D,0x73,0xA5,0xC7,0x69,0x71,0x95,0x1F,0x39,0x3C,0xB2,0x44,0x07,0x9C,0xE8, -0x0E,0xFA,0x4D,0x4A,0xC4,0x21,0xDF,0x29,0x61,0x8F,0x32,0x22,0x61,0x82,0xC5,0x87, -0x1F,0x6E,0x8C,0x7C,0x5F,0x16,0x20,0x51,0x44,0xD1,0x70,0x4F,0x57,0xEA,0xE3,0x1C, -0xE3,0xCC,0x79,0xEE,0x58,0xD8,0x0E,0xC2,0xB3,0x45,0x93,0xC0,0x2C,0xE7,0x9A,0x17, -0x2B,0x7B,0x00,0x37,0x7A,0x41,0x33,0x78,0xE1,0x33,0xE2,0xF3,0x10,0x1A,0x7F,0x87, -0x2C,0xBE,0xF6,0xF5,0xF7,0x42,0xE2,0xE5,0xBF,0x87,0x62,0x89,0x5F,0x00,0x4B,0xDF, -0xC5,0xDD,0xE4,0x75,0x44,0x32,0x41,0x3A,0x1E,0x71,0x6E,0x69,0xCB,0x0B,0x75,0x46, -0x08,0xD1,0xCA,0xD2,0x2B,0x95,0xD0,0xCF,0xFB,0xB9,0x40,0x6B,0x64,0x8C,0x57,0x4D, -0xFC,0x13,0x11,0x79,0x84,0xED,0x5E,0x54,0xF6,0x34,0x9F,0x08,0x01,0xF3,0x10,0x25, -0x06,0x17,0x4A,0xDA,0xF1,0x1D,0x7A,0x66,0x6B,0x98,0x60,0x66,0xA4,0xD9,0xEF,0xD2, -0x2E,0x82,0xF1,0xF0,0xEF,0x09,0xEA,0x44,0xC9,0x15,0x6A,0xE2,0x03,0x6E,0x33,0xD3, -0xAC,0x9F,0x55,0x00,0xC7,0xF6,0x08,0x6A,0x94,0xB9,0x5F,0xDC,0xE0,0x33,0xF1,0x84, -0x60,0xF9,0x5B,0x27,0x11,0xB4,0xFC,0x16,0xF2,0xBB,0x56,0x6A,0x80,0x25,0x8D,0x02, -0x03,0x01,0x00,0x01,0xA3,0x81,0xB2,0x30,0x81,0xAF,0x30,0x0F,0x06,0x03,0x55,0x1D, -0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, -0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x6D,0x06,0x08,0x2B, -0x06,0x01,0x05,0x05,0x07,0x01,0x0C,0x04,0x61,0x30,0x5F,0xA1,0x5D,0xA0,0x5B,0x30, -0x59,0x30,0x57,0x30,0x55,0x16,0x09,0x69,0x6D,0x61,0x67,0x65,0x2F,0x67,0x69,0x66, -0x30,0x21,0x30,0x1F,0x30,0x07,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x04,0x14,0x8F, -0xE5,0xD3,0x1A,0x86,0xAC,0x8D,0x8E,0x6B,0xC3,0xCF,0x80,0x6A,0xD4,0x48,0x18,0x2C, -0x7B,0x19,0x2E,0x30,0x25,0x16,0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6C,0x6F, -0x67,0x6F,0x2E,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F, -0x76,0x73,0x6C,0x6F,0x67,0x6F,0x2E,0x67,0x69,0x66,0x30,0x1D,0x06,0x03,0x55,0x1D, -0x0E,0x04,0x16,0x04,0x14,0xB6,0x77,0xFA,0x69,0x48,0x47,0x9F,0x53,0x12,0xD5,0xC2, -0xEA,0x07,0x32,0x76,0x07,0xD1,0x97,0x07,0x19,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, -0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x4A,0xF8,0xF8, -0xB0,0x03,0xE6,0x2C,0x67,0x7B,0xE4,0x94,0x77,0x63,0xCC,0x6E,0x4C,0xF9,0x7D,0x0E, -0x0D,0xDC,0xC8,0xB9,0x35,0xB9,0x70,0x4F,0x63,0xFA,0x24,0xFA,0x6C,0x83,0x8C,0x47, -0x9D,0x3B,0x63,0xF3,0x9A,0xF9,0x76,0x32,0x95,0x91,0xB1,0x77,0xBC,0xAC,0x9A,0xBE, -0xB1,0xE4,0x31,0x21,0xC6,0x81,0x95,0x56,0x5A,0x0E,0xB1,0xC2,0xD4,0xB1,0xA6,0x59, -0xAC,0xF1,0x63,0xCB,0xB8,0x4C,0x1D,0x59,0x90,0x4A,0xEF,0x90,0x16,0x28,0x1F,0x5A, -0xAE,0x10,0xFB,0x81,0x50,0x38,0x0C,0x6C,0xCC,0xF1,0x3D,0xC3,0xF5,0x63,0xE3,0xB3, -0xE3,0x21,0xC9,0x24,0x39,0xE9,0xFD,0x15,0x66,0x46,0xF4,0x1B,0x11,0xD0,0x4D,0x73, -0xA3,0x7D,0x46,0xF9,0x3D,0xED,0xA8,0x5F,0x62,0xD4,0xF1,0x3F,0xF8,0xE0,0x74,0x57, -0x2B,0x18,0x9D,0x81,0xB4,0xC4,0x28,0xDA,0x94,0x97,0xA5,0x70,0xEB,0xAC,0x1D,0xBE, -0x07,0x11,0xF0,0xD5,0xDB,0xDD,0xE5,0x8C,0xF0,0xD5,0x32,0xB0,0x83,0xE6,0x57,0xE2, -0x8F,0xBF,0xBE,0xA1,0xAA,0xBF,0x3D,0x1D,0xB5,0xD4,0x38,0xEA,0xD7,0xB0,0x5C,0x3A, -0x4F,0x6A,0x3F,0x8F,0xC0,0x66,0x6C,0x63,0xAA,0xE9,0xD9,0xA4,0x16,0xF4,0x81,0xD1, -0x95,0x14,0x0E,0x7D,0xCD,0x95,0x34,0xD9,0xD2,0x8F,0x70,0x73,0x81,0x7B,0x9C,0x7E, -0xBD,0x98,0x61,0xD8,0x45,0x87,0x98,0x90,0xC5,0xEB,0x86,0x30,0xC6,0x35,0xBF,0xF0, -0xFF,0xC3,0x55,0x88,0x83,0x4B,0xEF,0x05,0x92,0x06,0x71,0xF2,0xB8,0x98,0x93,0xB7, -0xEC,0xCD,0x82,0x61,0xF1,0x38,0xE6,0x4F,0x97,0x98,0x2A,0x5A,0x8D, +const unsigned char DigiCert_Assured_ID_Root_G3_certificate[586]={ +0x30,0x82,0x02,0x46,0x30,0x82,0x01,0xCD,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0B, +0xA1,0x5A,0xFA,0x1D,0xDF,0xA0,0xB5,0x49,0x44,0xAF,0xCD,0x24,0xA0,0x6C,0xEC,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x65,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E, +0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E, +0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22, +0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20, +0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x47,0x33,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69, +0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E, +0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69, +0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49, +0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47,0x33,0x30,0x76,0x30,0x10,0x06,0x07,0x2A, +0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00, +0x04,0x19,0xE7,0xBC,0xAC,0x44,0x65,0xED,0xCD,0xB8,0x3F,0x58,0xFB,0x8D,0xB1,0x57, +0xA9,0x44,0x2D,0x05,0x15,0xF2,0xEF,0x0B,0xFF,0x10,0x74,0x9F,0xB5,0x62,0x52,0x5F, +0x66,0x7E,0x1F,0xE5,0xDC,0x1B,0x45,0x79,0x0B,0xCC,0xC6,0x53,0x0A,0x9D,0x8D,0x5D, +0x02,0xD9,0xA9,0x59,0xDE,0x02,0x5A,0xF6,0x95,0x2A,0x0E,0x8D,0x38,0x4A,0x8A,0x49, +0xC6,0xBC,0xC6,0x03,0x38,0x07,0x5F,0x55,0xDA,0x7E,0x09,0x6E,0xE2,0x7F,0x5E,0xD0, +0x45,0x20,0x0F,0x59,0x76,0x10,0xD6,0xA0,0x24,0xF0,0x2D,0xDE,0x36,0xF2,0x6C,0x29, +0x39,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0xCB,0xD0,0xBD,0xA9,0xE1,0x98,0x05,0x51,0xA1,0x4D,0x37,0xA2,0x83,0x79,0xCE, +0x8D,0x1D,0x2A,0xE4,0x84,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03, +0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30,0x25,0xA4,0x81,0x45,0x02,0x6B,0x12,0x4B, +0x75,0x74,0x4F,0xC8,0x23,0xE3,0x70,0xF2,0x75,0x72,0xDE,0x7C,0x89,0xF0,0xCF,0x91, +0x72,0x61,0x9E,0x5E,0x10,0x92,0x59,0x56,0xB9,0x83,0xC7,0x10,0xE7,0x38,0xE9,0x58, +0x26,0x36,0x7D,0xD5,0xE4,0x34,0x86,0x39,0x02,0x30,0x7C,0x36,0x53,0xF0,0x30,0xE5, +0x62,0x63,0x3A,0x99,0xE2,0xB6,0xA3,0x3B,0x9B,0x34,0xFA,0x1E,0xDA,0x10,0x92,0x71, +0x5E,0x91,0x13,0xA7,0xDD,0xA4,0x6E,0x92,0xCC,0x32,0xD6,0xF5,0x21,0x66,0xC7,0x2F, +0xEA,0x96,0x63,0x6A,0x65,0x45,0x92,0x95,0x01,0xB4, }; -/* subject:/C=US/OU=www.xrampsecurity.com/O=XRamp Security Services Inc/CN=XRamp Global Certification Authority */ -/* issuer :/C=US/OU=www.xrampsecurity.com/O=XRamp Security Services Inc/CN=XRamp Global Certification Authority */ +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Certification Authority */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Certification Authority */ -const unsigned char XRamp_Global_CA_Root_certificate[1076]={ -0x30,0x82,0x04,0x30,0x30,0x82,0x03,0x18,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x50, -0x94,0x6C,0xEC,0x18,0xEA,0xD5,0x9C,0x4D,0xD5,0x97,0xEF,0x75,0x8F,0xA0,0xAD,0x30, +const unsigned char COMODO_Certification_Authority_certificate[1057]={ +0x30,0x82,0x04,0x1D,0x30,0x82,0x03,0x05,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4E, +0x81,0x2D,0x8A,0x82,0x65,0xE0,0x0B,0x02,0xEE,0x3E,0x35,0x02,0x46,0xE5,0x3D,0x30, 0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, -0x82,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1E, -0x30,0x1C,0x06,0x03,0x55,0x04,0x0B,0x13,0x15,0x77,0x77,0x77,0x2E,0x78,0x72,0x61, -0x6D,0x70,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x2E,0x63,0x6F,0x6D,0x31,0x24, -0x30,0x22,0x06,0x03,0x55,0x04,0x0A,0x13,0x1B,0x58,0x52,0x61,0x6D,0x70,0x20,0x53, -0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, -0x20,0x49,0x6E,0x63,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x03,0x13,0x24,0x58, -0x52,0x61,0x6D,0x70,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x65,0x72,0x74, +0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30,0x25,0x06,0x03,0x55, +0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5A,0x30,0x81,0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65, +0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72, +0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F, +0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30, +0x25,0x06,0x03,0x55,0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, +0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD0,0x40,0x8B,0x8B,0x72,0xE3,0x91,0x1B,0xF7, +0x51,0xC1,0x1B,0x54,0x04,0x98,0xD3,0xA9,0xBF,0xC1,0xE6,0x8A,0x5D,0x3B,0x87,0xFB, +0xBB,0x88,0xCE,0x0D,0xE3,0x2F,0x3F,0x06,0x96,0xF0,0xA2,0x29,0x50,0x99,0xAE,0xDB, +0x3B,0xA1,0x57,0xB0,0x74,0x51,0x71,0xCD,0xED,0x42,0x91,0x4D,0x41,0xFE,0xA9,0xC8, +0xD8,0x6A,0x86,0x77,0x44,0xBB,0x59,0x66,0x97,0x50,0x5E,0xB4,0xD4,0x2C,0x70,0x44, +0xCF,0xDA,0x37,0x95,0x42,0x69,0x3C,0x30,0xC4,0x71,0xB3,0x52,0xF0,0x21,0x4D,0xA1, +0xD8,0xBA,0x39,0x7C,0x1C,0x9E,0xA3,0x24,0x9D,0xF2,0x83,0x16,0x98,0xAA,0x16,0x7C, +0x43,0x9B,0x15,0x5B,0xB7,0xAE,0x34,0x91,0xFE,0xD4,0x62,0x26,0x18,0x46,0x9A,0x3F, +0xEB,0xC1,0xF9,0xF1,0x90,0x57,0xEB,0xAC,0x7A,0x0D,0x8B,0xDB,0x72,0x30,0x6A,0x66, +0xD5,0xE0,0x46,0xA3,0x70,0xDC,0x68,0xD9,0xFF,0x04,0x48,0x89,0x77,0xDE,0xB5,0xE9, +0xFB,0x67,0x6D,0x41,0xE9,0xBC,0x39,0xBD,0x32,0xD9,0x62,0x02,0xF1,0xB1,0xA8,0x3D, +0x6E,0x37,0x9C,0xE2,0x2F,0xE2,0xD3,0xA2,0x26,0x8B,0xC6,0xB8,0x55,0x43,0x88,0xE1, +0x23,0x3E,0xA5,0xD2,0x24,0x39,0x6A,0x47,0xAB,0x00,0xD4,0xA1,0xB3,0xA9,0x25,0xFE, +0x0D,0x3F,0xA7,0x1D,0xBA,0xD3,0x51,0xC1,0x0B,0xA4,0xDA,0xAC,0x38,0xEF,0x55,0x50, +0x24,0x05,0x65,0x46,0x93,0x34,0x4F,0x2D,0x8D,0xAD,0xC6,0xD4,0x21,0x19,0xD2,0x8E, +0xCA,0x05,0x61,0x71,0x07,0x73,0x47,0xE5,0x8A,0x19,0x12,0xBD,0x04,0x4D,0xCE,0x4E, +0x9C,0xA5,0x48,0xAC,0xBB,0x26,0xF7,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x8E,0x30, +0x81,0x8B,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x0B,0x58,0xE5, +0x8B,0xC6,0x4C,0x15,0x37,0xA4,0x40,0xA9,0x30,0xA9,0x21,0xBE,0x47,0x36,0x5A,0x56, +0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, +0x01,0xFF,0x30,0x49,0x06,0x03,0x55,0x1D,0x1F,0x04,0x42,0x30,0x40,0x30,0x3E,0xA0, +0x3C,0xA0,0x3A,0x86,0x38,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E, +0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D, +0x4F,0x44,0x4F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x3E,0x98,0x9E,0x9B,0xF6,0x1B,0xE9,0xD7,0x39,0xB7,0x78,0xAE,0x1D,0x72,0x18, +0x49,0xD3,0x87,0xE4,0x43,0x82,0xEB,0x3F,0xC9,0xAA,0xF5,0xA8,0xB5,0xEF,0x55,0x7C, +0x21,0x52,0x65,0xF9,0xD5,0x0D,0xE1,0x6C,0xF4,0x3E,0x8C,0x93,0x73,0x91,0x2E,0x02, +0xC4,0x4E,0x07,0x71,0x6F,0xC0,0x8F,0x38,0x61,0x08,0xA8,0x1E,0x81,0x0A,0xC0,0x2F, +0x20,0x2F,0x41,0x8B,0x91,0xDC,0x48,0x45,0xBC,0xF1,0xC6,0xDE,0xBA,0x76,0x6B,0x33, +0xC8,0x00,0x2D,0x31,0x46,0x4C,0xED,0xE7,0x9D,0xCF,0x88,0x94,0xFF,0x33,0xC0,0x56, +0xE8,0x24,0x86,0x26,0xB8,0xD8,0x38,0x38,0xDF,0x2A,0x6B,0xDD,0x12,0xCC,0xC7,0x3F, +0x47,0x17,0x4C,0xA2,0xC2,0x06,0x96,0x09,0xD6,0xDB,0xFE,0x3F,0x3C,0x46,0x41,0xDF, +0x58,0xE2,0x56,0x0F,0x3C,0x3B,0xC1,0x1C,0x93,0x35,0xD9,0x38,0x52,0xAC,0xEE,0xC8, +0xEC,0x2E,0x30,0x4E,0x94,0x35,0xB4,0x24,0x1F,0x4B,0x78,0x69,0xDA,0xF2,0x02,0x38, +0xCC,0x95,0x52,0x93,0xF0,0x70,0x25,0x59,0x9C,0x20,0x67,0xC4,0xEE,0xF9,0x8B,0x57, +0x61,0xF4,0x92,0x76,0x7D,0x3F,0x84,0x8D,0x55,0xB7,0xE8,0xE5,0xAC,0xD5,0xF1,0xF5, +0x19,0x56,0xA6,0x5A,0xFB,0x90,0x1C,0xAF,0x93,0xEB,0xE5,0x1C,0xD4,0x67,0x97,0x5D, +0x04,0x0E,0xBE,0x0B,0x83,0xA6,0x17,0x83,0xB9,0x30,0x12,0xA0,0xC5,0x33,0x15,0x05, +0xB9,0x0D,0xFB,0xC7,0x05,0x76,0xE3,0xD8,0x4A,0x8D,0xFC,0x34,0x17,0xA3,0xC6,0x21, +0x28,0xBE,0x30,0x45,0x31,0x1E,0xC7,0x78,0xBE,0x58,0x61,0x38,0xAC,0x3B,0xE2,0x01, +0x65, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */ + + +const unsigned char DigiCert_Global_Root_CA_certificate[947]={ +0x30,0x82,0x03,0xAF,0x30,0x82,0x02,0x97,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x08, +0x3B,0xE0,0x56,0x90,0x42,0x46,0xB1,0xA1,0x75,0x6A,0xC9,0x59,0x91,0xC7,0x4A,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x61, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x30,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43, +0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B, +0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63, +0x6F,0x6D,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67, +0x69,0x43,0x65,0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xE2,0x3B,0xE1,0x11,0x72,0xDE,0xA8,0xA4,0xD3,0xA3,0x57, +0xAA,0x50,0xA2,0x8F,0x0B,0x77,0x90,0xC9,0xA2,0xA5,0xEE,0x12,0xCE,0x96,0x5B,0x01, +0x09,0x20,0xCC,0x01,0x93,0xA7,0x4E,0x30,0xB7,0x53,0xF7,0x43,0xC4,0x69,0x00,0x57, +0x9D,0xE2,0x8D,0x22,0xDD,0x87,0x06,0x40,0x00,0x81,0x09,0xCE,0xCE,0x1B,0x83,0xBF, +0xDF,0xCD,0x3B,0x71,0x46,0xE2,0xD6,0x66,0xC7,0x05,0xB3,0x76,0x27,0x16,0x8F,0x7B, +0x9E,0x1E,0x95,0x7D,0xEE,0xB7,0x48,0xA3,0x08,0xDA,0xD6,0xAF,0x7A,0x0C,0x39,0x06, +0x65,0x7F,0x4A,0x5D,0x1F,0xBC,0x17,0xF8,0xAB,0xBE,0xEE,0x28,0xD7,0x74,0x7F,0x7A, +0x78,0x99,0x59,0x85,0x68,0x6E,0x5C,0x23,0x32,0x4B,0xBF,0x4E,0xC0,0xE8,0x5A,0x6D, +0xE3,0x70,0xBF,0x77,0x10,0xBF,0xFC,0x01,0xF6,0x85,0xD9,0xA8,0x44,0x10,0x58,0x32, +0xA9,0x75,0x18,0xD5,0xD1,0xA2,0xBE,0x47,0xE2,0x27,0x6A,0xF4,0x9A,0x33,0xF8,0x49, +0x08,0x60,0x8B,0xD4,0x5F,0xB4,0x3A,0x84,0xBF,0xA1,0xAA,0x4A,0x4C,0x7D,0x3E,0xCF, +0x4F,0x5F,0x6C,0x76,0x5E,0xA0,0x4B,0x37,0x91,0x9E,0xDC,0x22,0xE6,0x6D,0xCE,0x14, +0x1A,0x8E,0x6A,0xCB,0xFE,0xCD,0xB3,0x14,0x64,0x17,0xC7,0x5B,0x29,0x9E,0x32,0xBF, +0xF2,0xEE,0xFA,0xD3,0x0B,0x42,0xD4,0xAB,0xB7,0x41,0x32,0xDA,0x0C,0xD4,0xEF,0xF8, +0x81,0xD5,0xBB,0x8D,0x58,0x3F,0xB5,0x1B,0xE8,0x49,0x28,0xA2,0x70,0xDA,0x31,0x04, +0xDD,0xF7,0xB2,0x16,0xF2,0x4C,0x0A,0x4E,0x07,0xA8,0xED,0x4A,0x3D,0x5E,0xB5,0x7F, +0xA3,0x90,0xC3,0xAF,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x03,0xDE,0x50,0x35,0x56,0xD1, +0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30,0x1F, +0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x03,0xDE,0x50,0x35,0x56, +0xD1,0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0xCB,0x9C,0x37,0xAA,0x48,0x13,0x12,0x0A,0xFA,0xDD,0x44,0x9C,0x4F, +0x52,0xB0,0xF4,0xDF,0xAE,0x04,0xF5,0x79,0x79,0x08,0xA3,0x24,0x18,0xFC,0x4B,0x2B, +0x84,0xC0,0x2D,0xB9,0xD5,0xC7,0xFE,0xF4,0xC1,0x1F,0x58,0xCB,0xB8,0x6D,0x9C,0x7A, +0x74,0xE7,0x98,0x29,0xAB,0x11,0xB5,0xE3,0x70,0xA0,0xA1,0xCD,0x4C,0x88,0x99,0x93, +0x8C,0x91,0x70,0xE2,0xAB,0x0F,0x1C,0xBE,0x93,0xA9,0xFF,0x63,0xD5,0xE4,0x07,0x60, +0xD3,0xA3,0xBF,0x9D,0x5B,0x09,0xF1,0xD5,0x8E,0xE3,0x53,0xF4,0x8E,0x63,0xFA,0x3F, +0xA7,0xDB,0xB4,0x66,0xDF,0x62,0x66,0xD6,0xD1,0x6E,0x41,0x8D,0xF2,0x2D,0xB5,0xEA, +0x77,0x4A,0x9F,0x9D,0x58,0xE2,0x2B,0x59,0xC0,0x40,0x23,0xED,0x2D,0x28,0x82,0x45, +0x3E,0x79,0x54,0x92,0x26,0x98,0xE0,0x80,0x48,0xA8,0x37,0xEF,0xF0,0xD6,0x79,0x60, +0x16,0xDE,0xAC,0xE8,0x0E,0xCD,0x6E,0xAC,0x44,0x17,0x38,0x2F,0x49,0xDA,0xE1,0x45, +0x3E,0x2A,0xB9,0x36,0x53,0xCF,0x3A,0x50,0x06,0xF7,0x2E,0xE8,0xC4,0x57,0x49,0x6C, +0x61,0x21,0x18,0xD5,0x04,0xAD,0x78,0x3C,0x2C,0x3A,0x80,0x6B,0xA7,0xEB,0xAF,0x15, +0x14,0xE9,0xD8,0x89,0xC1,0xB9,0x38,0x6C,0xE2,0x91,0x6C,0x8A,0xFF,0x64,0xB9,0x77, +0x25,0x57,0x30,0xC0,0x1B,0x24,0xA3,0xE1,0xDC,0xE9,0xDF,0x47,0x7C,0xB5,0xB4,0x24, +0x08,0x05,0x30,0xEC,0x2D,0xBD,0x0B,0xBF,0x45,0xBF,0x50,0xB9,0xA9,0xF3,0xEB,0x98, +0x01,0x12,0xAD,0xC8,0x88,0xC6,0x98,0x34,0x5F,0x8D,0x0A,0x3C,0xC6,0xE9,0xD5,0x95, +0x95,0x6D,0xDE, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services */ + + +const unsigned char Comodo_AAA_Services_root_certificate[1078]={ +0x30,0x82,0x04,0x32,0x30,0x82,0x03,0x1A,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x7B,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, +0x04,0x03,0x0C,0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x1E,0x17,0x0D, +0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32, +0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x7B,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, +0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, +0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, +0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, +0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43,0x41,0x20,0x4C, +0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C, +0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65, +0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, +0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBE,0x40,0x9D,0xF4,0x6E,0xE1, +0xEA,0x76,0x87,0x1C,0x4D,0x45,0x44,0x8E,0xBE,0x46,0xC8,0x83,0x06,0x9D,0xC1,0x2A, +0xFE,0x18,0x1F,0x8E,0xE4,0x02,0xFA,0xF3,0xAB,0x5D,0x50,0x8A,0x16,0x31,0x0B,0x9A, +0x06,0xD0,0xC5,0x70,0x22,0xCD,0x49,0x2D,0x54,0x63,0xCC,0xB6,0x6E,0x68,0x46,0x0B, +0x53,0xEA,0xCB,0x4C,0x24,0xC0,0xBC,0x72,0x4E,0xEA,0xF1,0x15,0xAE,0xF4,0x54,0x9A, +0x12,0x0A,0xC3,0x7A,0xB2,0x33,0x60,0xE2,0xDA,0x89,0x55,0xF3,0x22,0x58,0xF3,0xDE, +0xDC,0xCF,0xEF,0x83,0x86,0xA2,0x8C,0x94,0x4F,0x9F,0x68,0xF2,0x98,0x90,0x46,0x84, +0x27,0xC7,0x76,0xBF,0xE3,0xCC,0x35,0x2C,0x8B,0x5E,0x07,0x64,0x65,0x82,0xC0,0x48, +0xB0,0xA8,0x91,0xF9,0x61,0x9F,0x76,0x20,0x50,0xA8,0x91,0xC7,0x66,0xB5,0xEB,0x78, +0x62,0x03,0x56,0xF0,0x8A,0x1A,0x13,0xEA,0x31,0xA3,0x1E,0xA0,0x99,0xFD,0x38,0xF6, +0xF6,0x27,0x32,0x58,0x6F,0x07,0xF5,0x6B,0xB8,0xFB,0x14,0x2B,0xAF,0xB7,0xAA,0xCC, +0xD6,0x63,0x5F,0x73,0x8C,0xDA,0x05,0x99,0xA8,0x38,0xA8,0xCB,0x17,0x78,0x36,0x51, +0xAC,0xE9,0x9E,0xF4,0x78,0x3A,0x8D,0xCF,0x0F,0xD9,0x42,0xE2,0x98,0x0C,0xAB,0x2F, +0x9F,0x0E,0x01,0xDE,0xEF,0x9F,0x99,0x49,0xF1,0x2D,0xDF,0xAC,0x74,0x4D,0x1B,0x98, +0xB5,0x47,0xC5,0xE5,0x29,0xD1,0xF9,0x90,0x18,0xC7,0x62,0x9C,0xBE,0x83,0xC7,0x26, +0x7B,0x3E,0x8A,0x25,0xC7,0xC0,0xDD,0x9D,0xE6,0x35,0x68,0x10,0x20,0x9D,0x8F,0xD8, +0xDE,0xD2,0xC3,0x84,0x9C,0x0D,0x5E,0xE8,0x2F,0xC9,0x02,0x03,0x01,0x00,0x01,0xA3, +0x81,0xC0,0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, +0xA0,0x11,0x0A,0x23,0x3E,0x96,0xF1,0x07,0xEC,0xE2,0xAF,0x29,0xEF,0x82,0xA5,0x7F, +0xD0,0x30,0xA4,0xB4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x7B,0x06,0x03,0x55,0x1D,0x1F,0x04,0x74,0x30,0x72, +0x30,0x38,0xA0,0x36,0xA0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63, +0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F, +0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65, +0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30,0x36,0xA0,0x34,0xA0,0x32, +0x86,0x30,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D, +0x6F,0x64,0x6F,0x2E,0x6E,0x65,0x74,0x2F,0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63, +0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05, +0x00,0x03,0x82,0x01,0x01,0x00,0x08,0x56,0xFC,0x02,0xF0,0x9B,0xE8,0xFF,0xA4,0xFA, +0xD6,0x7B,0xC6,0x44,0x80,0xCE,0x4F,0xC4,0xC5,0xF6,0x00,0x58,0xCC,0xA6,0xB6,0xBC, +0x14,0x49,0x68,0x04,0x76,0xE8,0xE6,0xEE,0x5D,0xEC,0x02,0x0F,0x60,0xD6,0x8D,0x50, +0x18,0x4F,0x26,0x4E,0x01,0xE3,0xE6,0xB0,0xA5,0xEE,0xBF,0xBC,0x74,0x54,0x41,0xBF, +0xFD,0xFC,0x12,0xB8,0xC7,0x4F,0x5A,0xF4,0x89,0x60,0x05,0x7F,0x60,0xB7,0x05,0x4A, +0xF3,0xF6,0xF1,0xC2,0xBF,0xC4,0xB9,0x74,0x86,0xB6,0x2D,0x7D,0x6B,0xCC,0xD2,0xF3, +0x46,0xDD,0x2F,0xC6,0xE0,0x6A,0xC3,0xC3,0x34,0x03,0x2C,0x7D,0x96,0xDD,0x5A,0xC2, +0x0E,0xA7,0x0A,0x99,0xC1,0x05,0x8B,0xAB,0x0C,0x2F,0xF3,0x5C,0x3A,0xCF,0x6C,0x37, +0x55,0x09,0x87,0xDE,0x53,0x40,0x6C,0x58,0xEF,0xFC,0xB6,0xAB,0x65,0x6E,0x04,0xF6, +0x1B,0xDC,0x3C,0xE0,0x5A,0x15,0xC6,0x9E,0xD9,0xF1,0x59,0x48,0x30,0x21,0x65,0x03, +0x6C,0xEC,0xE9,0x21,0x73,0xEC,0x9B,0x03,0xA1,0xE0,0x37,0xAD,0xA0,0x15,0x18,0x8F, +0xFA,0xBA,0x02,0xCE,0xA7,0x2C,0xA9,0x10,0x13,0x2C,0xD4,0xE5,0x08,0x26,0xAB,0x22, +0x97,0x60,0xF8,0x90,0x5E,0x74,0xD4,0xA2,0x9A,0x53,0xBD,0xF2,0xA9,0x68,0xE0,0xA2, +0x6E,0xC2,0xD7,0x6C,0xB1,0xA3,0x0F,0x9E,0xBF,0xEB,0x68,0xE7,0x56,0xF2,0xAE,0xF2, +0xE3,0x2B,0x38,0x3A,0x09,0x81,0xB5,0x6B,0x85,0xD7,0xBE,0x2D,0xED,0x3F,0x1A,0xB7, +0xB2,0x63,0xE2,0xF5,0x62,0x2C,0x82,0xD4,0x6A,0x00,0x41,0x50,0xF1,0x39,0x83,0x9F, +0x95,0xE9,0x36,0x96,0x98,0x6E, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */ + + +const unsigned char DigiCert_High_Assurance_EV_Root_CA_certificate[969]={ +0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x02, +0xAC,0x5C,0x26,0x6A,0x0B,0x40,0x9B,0x8F,0x0B,0x79,0xF2,0xAE,0x46,0x25,0x77,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x6C, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63, +0x65,0x20,0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D, +0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33, +0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x6C,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49, +0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77, +0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x2B,0x30, +0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,0x65,0x20, +0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC6,0xCC,0xE5,0x73,0xE6, +0xFB,0xD4,0xBB,0xE5,0x2D,0x2D,0x32,0xA6,0xDF,0xE5,0x81,0x3F,0xC9,0xCD,0x25,0x49, +0xB6,0x71,0x2A,0xC3,0xD5,0x94,0x34,0x67,0xA2,0x0A,0x1C,0xB0,0x5F,0x69,0xA6,0x40, +0xB1,0xC4,0xB7,0xB2,0x8F,0xD0,0x98,0xA4,0xA9,0x41,0x59,0x3A,0xD3,0xDC,0x94,0xD6, +0x3C,0xDB,0x74,0x38,0xA4,0x4A,0xCC,0x4D,0x25,0x82,0xF7,0x4A,0xA5,0x53,0x12,0x38, +0xEE,0xF3,0x49,0x6D,0x71,0x91,0x7E,0x63,0xB6,0xAB,0xA6,0x5F,0xC3,0xA4,0x84,0xF8, +0x4F,0x62,0x51,0xBE,0xF8,0xC5,0xEC,0xDB,0x38,0x92,0xE3,0x06,0xE5,0x08,0x91,0x0C, +0xC4,0x28,0x41,0x55,0xFB,0xCB,0x5A,0x89,0x15,0x7E,0x71,0xE8,0x35,0xBF,0x4D,0x72, +0x09,0x3D,0xBE,0x3A,0x38,0x50,0x5B,0x77,0x31,0x1B,0x8D,0xB3,0xC7,0x24,0x45,0x9A, +0xA7,0xAC,0x6D,0x00,0x14,0x5A,0x04,0xB7,0xBA,0x13,0xEB,0x51,0x0A,0x98,0x41,0x41, +0x22,0x4E,0x65,0x61,0x87,0x81,0x41,0x50,0xA6,0x79,0x5C,0x89,0xDE,0x19,0x4A,0x57, +0xD5,0x2E,0xE6,0x5D,0x1C,0x53,0x2C,0x7E,0x98,0xCD,0x1A,0x06,0x16,0xA4,0x68,0x73, +0xD0,0x34,0x04,0x13,0x5C,0xA1,0x71,0xD3,0x5A,0x7C,0x55,0xDB,0x5E,0x64,0xE1,0x37, +0x87,0x30,0x56,0x04,0xE5,0x11,0xB4,0x29,0x80,0x12,0xF1,0x79,0x39,0x88,0xA2,0x02, +0x11,0x7C,0x27,0x66,0xB7,0x88,0xB7,0x78,0xF2,0xCA,0x0A,0xA8,0x38,0xAB,0x0A,0x64, +0xC2,0xBF,0x66,0x5D,0x95,0x84,0xC1,0xA1,0x25,0x1E,0x87,0x5D,0x1A,0x50,0x0B,0x20, +0x12,0xCC,0x41,0xBB,0x6E,0x0B,0x51,0x38,0xB8,0x4B,0xCB,0x02,0x03,0x01,0x00,0x01, +0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, +0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02,0xEF, +0x63,0x64,0x2B,0xC3,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80, +0x14,0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02, +0xEF,0x63,0x64,0x2B,0xC3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x1C,0x1A,0x06,0x97,0xDC,0xD7,0x9C, +0x9F,0x3C,0x88,0x66,0x06,0x08,0x57,0x21,0xDB,0x21,0x47,0xF8,0x2A,0x67,0xAA,0xBF, +0x18,0x32,0x76,0x40,0x10,0x57,0xC1,0x8A,0xF3,0x7A,0xD9,0x11,0x65,0x8E,0x35,0xFA, +0x9E,0xFC,0x45,0xB5,0x9E,0xD9,0x4C,0x31,0x4B,0xB8,0x91,0xE8,0x43,0x2C,0x8E,0xB3, +0x78,0xCE,0xDB,0xE3,0x53,0x79,0x71,0xD6,0xE5,0x21,0x94,0x01,0xDA,0x55,0x87,0x9A, +0x24,0x64,0xF6,0x8A,0x66,0xCC,0xDE,0x9C,0x37,0xCD,0xA8,0x34,0xB1,0x69,0x9B,0x23, +0xC8,0x9E,0x78,0x22,0x2B,0x70,0x43,0xE3,0x55,0x47,0x31,0x61,0x19,0xEF,0x58,0xC5, +0x85,0x2F,0x4E,0x30,0xF6,0xA0,0x31,0x16,0x23,0xC8,0xE7,0xE2,0x65,0x16,0x33,0xCB, +0xBF,0x1A,0x1B,0xA0,0x3D,0xF8,0xCA,0x5E,0x8B,0x31,0x8B,0x60,0x08,0x89,0x2D,0x0C, +0x06,0x5C,0x52,0xB7,0xC4,0xF9,0x0A,0x98,0xD1,0x15,0x5F,0x9F,0x12,0xBE,0x7C,0x36, +0x63,0x38,0xBD,0x44,0xA4,0x7F,0xE4,0x26,0x2B,0x0A,0xC4,0x97,0x69,0x0D,0xE9,0x8C, +0xE2,0xC0,0x10,0x57,0xB8,0xC8,0x76,0x12,0x91,0x55,0xF2,0x48,0x69,0xD8,0xBC,0x2A, +0x02,0x5B,0x0F,0x44,0xD4,0x20,0x31,0xDB,0xF4,0xBA,0x70,0x26,0x5D,0x90,0x60,0x9E, +0xBC,0x4B,0x17,0x09,0x2F,0xB4,0xCB,0x1E,0x43,0x68,0xC9,0x07,0x27,0xC1,0xD2,0x5C, +0xF7,0xEA,0x21,0xB9,0x68,0x12,0x9C,0x3C,0x9C,0xBF,0x9E,0xFC,0x80,0x5C,0x9B,0x63, +0xCD,0xEC,0x47,0xAA,0x25,0x27,0x67,0xA0,0x37,0xF3,0x00,0x82,0x7D,0x54,0xD7,0xA9, +0xF8,0xE9,0x2E,0x13,0xA3,0x77,0xE8,0x1F,0x4A, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA */ + + +const unsigned char GeoTrust_Universal_CA_certificate[1388]={ +0x30,0x82,0x05,0x68,0x30,0x82,0x03,0x50,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x13, +0x15,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x55,0x6E,0x69,0x76,0x65,0x72, +0x73,0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x33,0x30,0x34, +0x30,0x35,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x30,0x33,0x30,0x34,0x30, +0x35,0x30,0x30,0x30,0x30,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D, +0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1E,0x30, +0x1C,0x06,0x03,0x55,0x04,0x03,0x13,0x15,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74, +0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x30,0x82,0x02, +0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, +0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xA6,0x15, +0x55,0xA0,0xA3,0xC6,0xE0,0x1F,0x8C,0x9D,0x21,0x50,0xD7,0xC1,0xBE,0x2B,0x5B,0xB5, +0xA4,0x9E,0xA1,0xD9,0x72,0x58,0xBD,0x00,0x1B,0x4C,0xBF,0x61,0xC9,0x14,0x1D,0x45, +0x82,0xAB,0xC6,0x1D,0x80,0xD6,0x3D,0xEB,0x10,0x9C,0x3A,0xAF,0x6D,0x24,0xF8,0xBC, +0x71,0x01,0x9E,0x06,0xF5,0x7C,0x5F,0x1E,0xC1,0x0E,0x55,0xCA,0x83,0x9A,0x59,0x30, +0xAE,0x19,0xCB,0x30,0x48,0x95,0xED,0x22,0x37,0x8D,0xF4,0x4A,0x9A,0x72,0x66,0x3E, +0xAD,0x95,0xC0,0xE0,0x16,0x00,0xE0,0x10,0x1F,0x2B,0x31,0x0E,0xD7,0x94,0x54,0xD3, +0x42,0x33,0xA0,0x34,0x1D,0x1E,0x45,0x76,0xDD,0x4F,0xCA,0x18,0x37,0xEC,0x85,0x15, +0x7A,0x19,0x08,0xFC,0xD5,0xC7,0x9C,0xF0,0xF2,0xA9,0x2E,0x10,0xA9,0x92,0xE6,0x3D, +0x58,0x3D,0xA9,0x16,0x68,0x3C,0x2F,0x75,0x21,0x18,0x7F,0x28,0x77,0xA5,0xE1,0x61, +0x17,0xB7,0xA6,0xE9,0xF8,0x1E,0x99,0xDB,0x73,0x6E,0xF4,0x0A,0xA2,0x21,0x6C,0xEE, +0xDA,0xAA,0x85,0x92,0x66,0xAF,0xF6,0x7A,0x6B,0x82,0xDA,0xBA,0x22,0x08,0x35,0x0F, +0xCF,0x42,0xF1,0x35,0xFA,0x6A,0xEE,0x7E,0x2B,0x25,0xCC,0x3A,0x11,0xE4,0x6D,0xAF, +0x73,0xB2,0x76,0x1D,0xAD,0xD0,0xB2,0x78,0x67,0x1A,0xA4,0x39,0x1C,0x51,0x0B,0x67, +0x56,0x83,0xFD,0x38,0x5D,0x0D,0xCE,0xDD,0xF0,0xBB,0x2B,0x96,0x1F,0xDE,0x7B,0x32, +0x52,0xFD,0x1D,0xBB,0xB5,0x06,0xA1,0xB2,0x21,0x5E,0xA5,0xD6,0x95,0x68,0x7F,0xF0, +0x99,0x9E,0xDC,0x45,0x08,0x3E,0xE7,0xD2,0x09,0x0D,0x35,0x94,0xDD,0x80,0x4E,0x53, +0x97,0xD7,0xB5,0x09,0x44,0x20,0x64,0x16,0x17,0x03,0x02,0x4C,0x53,0x0D,0x68,0xDE, +0xD5,0xAA,0x72,0x4D,0x93,0x6D,0x82,0x0E,0xDB,0x9C,0xBD,0xCF,0xB4,0xF3,0x5C,0x5D, +0x54,0x7A,0x69,0x09,0x96,0xD6,0xDB,0x11,0xC1,0x8D,0x75,0xA8,0xB4,0xCF,0x39,0xC8, +0xCE,0x3C,0xBC,0x24,0x7C,0xE6,0x62,0xCA,0xE1,0xBD,0x7D,0xA7,0xBD,0x57,0x65,0x0B, +0xE4,0xFE,0x25,0xED,0xB6,0x69,0x10,0xDC,0x28,0x1A,0x46,0xBD,0x01,0x1D,0xD0,0x97, +0xB5,0xE1,0x98,0x3B,0xC0,0x37,0x64,0xD6,0x3D,0x94,0xEE,0x0B,0xE1,0xF5,0x28,0xAE, +0x0B,0x56,0xBF,0x71,0x8B,0x23,0x29,0x41,0x8E,0x86,0xC5,0x4B,0x52,0x7B,0xD8,0x71, +0xAB,0x1F,0x8A,0x15,0xA6,0x3B,0x83,0x5A,0xD7,0x58,0x01,0x51,0xC6,0x4C,0x41,0xD9, +0x7F,0xD8,0x41,0x67,0x72,0xA2,0x28,0xDF,0x60,0x83,0xA9,0x9E,0xC8,0x7B,0xFC,0x53, +0x73,0x72,0x59,0xF5,0x93,0x7A,0x17,0x76,0x0E,0xCE,0xF7,0xE5,0x5C,0xD9,0x0B,0x55, +0x34,0xA2,0xAA,0x5B,0xB5,0x6A,0x54,0xE7,0x13,0xCA,0x57,0xEC,0x97,0x6D,0xF4,0x5E, +0x06,0x2F,0x45,0x8B,0x58,0xD4,0x23,0x16,0x92,0xE4,0x16,0x6E,0x28,0x63,0x59,0x30, +0xDF,0x50,0x01,0x9C,0x63,0x89,0x1A,0x9F,0xDB,0x17,0x94,0x82,0x70,0x37,0xC3,0x24, +0x9E,0x9A,0x47,0xD6,0x5A,0xCA,0x4E,0xA8,0x69,0x89,0x72,0x1F,0x91,0x6C,0xDB,0x7E, +0x9E,0x1B,0xAD,0xC7,0x1F,0x73,0xDD,0x2C,0x4F,0x19,0x65,0xFD,0x7F,0x93,0x40,0x10, +0x2E,0xD2,0xF0,0xED,0x3C,0x9E,0x2E,0x28,0x3E,0x69,0x26,0x33,0xC5,0x7B,0x02,0x03, +0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, +0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0xDA,0xBB,0x2E,0xAA,0xB0,0x0C,0xB8,0x88,0x26,0x51,0x74,0x5C,0x6D, +0x03,0xD3,0xC0,0xD8,0x8F,0x7A,0xD6,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, +0x30,0x16,0x80,0x14,0xDA,0xBB,0x2E,0xAA,0xB0,0x0C,0xB8,0x88,0x26,0x51,0x74,0x5C, +0x6D,0x03,0xD3,0xC0,0xD8,0x8F,0x7A,0xD6,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01, +0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x31,0x78,0xE6,0xC7, +0xB5,0xDF,0xB8,0x94,0x40,0xC9,0x71,0xC4,0xA8,0x35,0xEC,0x46,0x1D,0xC2,0x85,0xF3, +0x28,0x58,0x86,0xB0,0x0B,0xFC,0x8E,0xB2,0x39,0x8F,0x44,0x55,0xAB,0x64,0x84,0x5C, +0x69,0xA9,0xD0,0x9A,0x38,0x3C,0xFA,0xE5,0x1F,0x35,0xE5,0x44,0xE3,0x80,0x79,0x94, +0x68,0xA4,0xBB,0xC4,0x9F,0x3D,0xE1,0x34,0xCD,0x30,0x46,0x8B,0x54,0x2B,0x95,0xA5, +0xEF,0xF7,0x3F,0x99,0x84,0xFD,0x35,0xE6,0xCF,0x31,0xC6,0xDC,0x6A,0xBF,0xA7,0xD7, +0x23,0x08,0xE1,0x98,0x5E,0xC3,0x5A,0x08,0x76,0xA9,0xA6,0xAF,0x77,0x2F,0xB7,0x60, +0xBD,0x44,0x46,0x6A,0xEF,0x97,0xFF,0x73,0x95,0xC1,0x8E,0xE8,0x93,0xFB,0xFD,0x31, +0xB7,0xEC,0x57,0x11,0x11,0x45,0x9B,0x30,0xF1,0x1A,0x88,0x39,0xC1,0x4F,0x3C,0xA7, +0x00,0xD5,0xC7,0xFC,0xAB,0x6D,0x80,0x22,0x70,0xA5,0x0C,0xE0,0x5D,0x04,0x29,0x02, +0xFB,0xCB,0xA0,0x91,0xD1,0x7C,0xD6,0xC3,0x7E,0x50,0xD5,0x9D,0x58,0xBE,0x41,0x38, +0xEB,0xB9,0x75,0x3C,0x15,0xD9,0x9B,0xC9,0x4A,0x83,0x59,0xC0,0xDA,0x53,0xFD,0x33, +0xBB,0x36,0x18,0x9B,0x85,0x0F,0x15,0xDD,0xEE,0x2D,0xAC,0x76,0x93,0xB9,0xD9,0x01, +0x8D,0x48,0x10,0xA8,0xFB,0xF5,0x38,0x86,0xF1,0xDB,0x0A,0xC6,0xBD,0x84,0xA3,0x23, +0x41,0xDE,0xD6,0x77,0x6F,0x85,0xD4,0x85,0x1C,0x50,0xE0,0xAE,0x51,0x8A,0xBA,0x8D, +0x3E,0x76,0xE2,0xB9,0xCA,0x27,0xF2,0x5F,0x9F,0xEF,0x6E,0x59,0x0D,0x06,0xD8,0x2B, +0x17,0xA4,0xD2,0x7C,0x6B,0xBB,0x5F,0x14,0x1A,0x48,0x8F,0x1A,0x4C,0xE7,0xB3,0x47, +0x1C,0x8E,0x4C,0x45,0x2B,0x20,0xEE,0x48,0xDF,0xE7,0xDD,0x09,0x8E,0x18,0xA8,0xDA, +0x40,0x8D,0x92,0x26,0x11,0x53,0x61,0x73,0x5D,0xEB,0xBD,0xE7,0xC4,0x4D,0x29,0x37, +0x61,0xEB,0xAC,0x39,0x2D,0x67,0x2E,0x16,0xD6,0xF5,0x00,0x83,0x85,0xA1,0xCC,0x7F, +0x76,0xC4,0x7D,0xE4,0xB7,0x4B,0x66,0xEF,0x03,0x45,0x60,0x69,0xB6,0x0C,0x52,0x96, +0x92,0x84,0x5E,0xA6,0xA3,0xB5,0xA4,0x3E,0x2B,0xD9,0xCC,0xD8,0x1B,0x47,0xAA,0xF2, +0x44,0xDA,0x4F,0xF9,0x03,0xE8,0xF0,0x14,0xCB,0x3F,0xF3,0x83,0xDE,0xD0,0xC1,0x54, +0xE3,0xB7,0xE8,0x0A,0x37,0x4D,0x8B,0x20,0x59,0x03,0x30,0x19,0xA1,0x2C,0xC8,0xBD, +0x11,0x1F,0xDF,0xAE,0xC9,0x4A,0xC5,0xF3,0x27,0x66,0x66,0x86,0xAC,0x68,0x91,0xFF, +0xD9,0xE6,0x53,0x1C,0x0F,0x8B,0x5C,0x69,0x65,0x0A,0x26,0xC8,0x1E,0x34,0xC3,0x5D, +0x51,0x7B,0xD7,0xA9,0x9C,0x06,0xA1,0x36,0xDD,0xD5,0x89,0x94,0xBC,0xD9,0xE4,0x2D, +0x0C,0x5E,0x09,0x6C,0x08,0x97,0x7C,0xA3,0x3D,0x7C,0x93,0xFF,0x3F,0xA1,0x14,0xA7, +0xCF,0xB5,0x5D,0xEB,0xDB,0xDB,0x1C,0xC4,0x76,0xDF,0x88,0xB9,0xBD,0x45,0x05,0x95, +0x1B,0xAE,0xFC,0x46,0x6A,0x4C,0xAF,0x48,0xE3,0xCE,0xAE,0x0F,0xD2,0x7E,0xEB,0xE6, +0x6C,0x9C,0x4F,0x81,0x6A,0x7A,0x64,0xAC,0xBB,0x3E,0xD5,0xE7,0xCB,0x76,0x2E,0xC5, +0xA7,0x48,0xC1,0x5C,0x90,0x0F,0xCB,0xC8,0x3F,0xFA,0xE6,0x32,0xE1,0x8D,0x1B,0x6F, +0xA4,0xE6,0x8E,0xD8,0xF9,0x29,0x48,0x8A,0xCE,0x73,0xFE,0x2C, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Certification Authority */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Certification Authority */ + + +const unsigned char COMODO_ECC_Certification_Authority_certificate[653]={ +0x30,0x82,0x02,0x89,0x30,0x82,0x02,0x0F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x1F, +0x47,0xAF,0xAA,0x62,0x00,0x70,0x50,0x54,0x4C,0x01,0x9E,0x9B,0x63,0x99,0x2A,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x85,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, +0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, +0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, +0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, +0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C, +0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13, +0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74, 0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, -0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x31,0x31,0x30,0x31,0x31,0x37,0x31, -0x34,0x30,0x34,0x5A,0x17,0x0D,0x33,0x35,0x30,0x31,0x30,0x31,0x30,0x35,0x33,0x37, -0x31,0x39,0x5A,0x30,0x81,0x82,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, -0x02,0x55,0x53,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0B,0x13,0x15,0x77,0x77, -0x77,0x2E,0x78,0x72,0x61,0x6D,0x70,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x2E, -0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0A,0x13,0x1B,0x58,0x52, -0x61,0x6D,0x70,0x20,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x53,0x65,0x72, -0x76,0x69,0x63,0x65,0x73,0x20,0x49,0x6E,0x63,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55, -0x04,0x03,0x13,0x24,0x58,0x52,0x61,0x6D,0x70,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C, +0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x38,0x30,0x33,0x30,0x36,0x30,0x30,0x30, +0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32,0x33,0x35,0x39, +0x35,0x39,0x5A,0x30,0x81,0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72, +0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72, +0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F, +0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D, +0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B, +0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20, +0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, +0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x76,0x30,0x10,0x06, +0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03, +0x62,0x00,0x04,0x03,0x47,0x7B,0x2F,0x75,0xC9,0x82,0x15,0x85,0xFB,0x75,0xE4,0x91, +0x16,0xD4,0xAB,0x62,0x99,0xF5,0x3E,0x52,0x0B,0x06,0xCE,0x41,0x00,0x7F,0x97,0xE1, +0x0A,0x24,0x3C,0x1D,0x01,0x04,0xEE,0x3D,0xD2,0x8D,0x09,0x97,0x0C,0xE0,0x75,0xE4, +0xFA,0xFB,0x77,0x8A,0x2A,0xF5,0x03,0x60,0x4B,0x36,0x8B,0x16,0x23,0x16,0xAD,0x09, +0x71,0xF4,0x4A,0xF4,0x28,0x50,0xB4,0xFE,0x88,0x1C,0x6E,0x3F,0x6C,0x2F,0x2F,0x09, +0x59,0x5B,0xA5,0x5B,0x0B,0x33,0x99,0xE2,0xC3,0x3D,0x89,0xF9,0x6A,0x2C,0xEF,0xB2, +0xD3,0x06,0xE9,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x75,0x71,0xA7,0x19,0x48,0x19,0xBC,0x9D,0x9D,0xEA,0x41,0x47,0xDF,0x94, +0xC4,0x48,0x77,0x99,0xD3,0x79,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, +0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31,0x00,0xEF,0x03,0x5B,0x7A,0xAC, +0xB7,0x78,0x0A,0x72,0xB7,0x88,0xDF,0xFF,0xB5,0x46,0x14,0x09,0x0A,0xFA,0xA0,0xE6, +0x7D,0x08,0xC6,0x1A,0x87,0xBD,0x18,0xA8,0x73,0xBD,0x26,0xCA,0x60,0x0C,0x9D,0xCE, +0x99,0x9F,0xCF,0x5C,0x0F,0x30,0xE1,0xBE,0x14,0x31,0xEA,0x02,0x30,0x14,0xF4,0x93, +0x3C,0x49,0xA7,0x33,0x7A,0x90,0x46,0x47,0xB3,0x63,0x7D,0x13,0x9B,0x4E,0xB7,0x6F, +0x18,0x37,0x80,0x53,0xFE,0xDD,0x20,0xE0,0x35,0x9A,0x36,0xD1,0xC7,0x01,0xB9,0xE6, +0xDC,0xDD,0xF3,0xFF,0x1D,0x2C,0x3A,0x16,0x57,0xD9,0x92,0x39,0xD6, +}; + + +/* subject:/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2009 Entrust, Inc. - for authorized use only/CN=Entrust Root Certification Authority - G2 */ +/* issuer :/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2009 Entrust, Inc. - for authorized use only/CN=Entrust Root Certification Authority - G2 */ + + +const unsigned char Entrust_Root_Certification_Authority___G2_certificate[1090]={ +0x30,0x82,0x04,0x3E,0x30,0x82,0x03,0x26,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x4A, +0x53,0x8C,0x28,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B, +0x05,0x00,0x30,0x81,0xBE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03, +0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65,0x20,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6C,0x65,0x67,0x61,0x6C,0x2D,0x74, +0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28, +0x63,0x29,0x20,0x32,0x30,0x30,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x66,0x6F,0x72,0x20,0x61,0x75,0x74,0x68, +0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x45,0x6E,0x74,0x72,0x75,0x73, +0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D, +0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x37,0x30,0x37,0x31,0x37,0x32, +0x35,0x35,0x34,0x5A,0x17,0x0D,0x33,0x30,0x31,0x32,0x30,0x37,0x31,0x37,0x35,0x35, +0x35,0x34,0x5A,0x30,0x81,0xBE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E, +0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06, +0x03,0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65,0x20,0x77,0x77,0x77,0x2E,0x65,0x6E, +0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6C,0x65,0x67,0x61,0x6C,0x2D, +0x74,0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x66,0x6F,0x72,0x20,0x61,0x75,0x74, +0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, +0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x45,0x6E,0x74,0x72,0x75, +0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xBA,0x84,0xB6,0x72,0xDB,0x9E,0x0C,0x6B,0xE2,0x99,0xE9, +0x30,0x01,0xA7,0x76,0xEA,0x32,0xB8,0x95,0x41,0x1A,0xC9,0xDA,0x61,0x4E,0x58,0x72, +0xCF,0xFE,0xF6,0x82,0x79,0xBF,0x73,0x61,0x06,0x0A,0xA5,0x27,0xD8,0xB3,0x5F,0xD3, +0x45,0x4E,0x1C,0x72,0xD6,0x4E,0x32,0xF2,0x72,0x8A,0x0F,0xF7,0x83,0x19,0xD0,0x6A, +0x80,0x80,0x00,0x45,0x1E,0xB0,0xC7,0xE7,0x9A,0xBF,0x12,0x57,0x27,0x1C,0xA3,0x68, +0x2F,0x0A,0x87,0xBD,0x6A,0x6B,0x0E,0x5E,0x65,0xF3,0x1C,0x77,0xD5,0xD4,0x85,0x8D, +0x70,0x21,0xB4,0xB3,0x32,0xE7,0x8B,0xA2,0xD5,0x86,0x39,0x02,0xB1,0xB8,0xD2,0x47, +0xCE,0xE4,0xC9,0x49,0xC4,0x3B,0xA7,0xDE,0xFB,0x54,0x7D,0x57,0xBE,0xF0,0xE8,0x6E, +0xC2,0x79,0xB2,0x3A,0x0B,0x55,0xE2,0x50,0x98,0x16,0x32,0x13,0x5C,0x2F,0x78,0x56, +0xC1,0xC2,0x94,0xB3,0xF2,0x5A,0xE4,0x27,0x9A,0x9F,0x24,0xD7,0xC6,0xEC,0xD0,0x9B, +0x25,0x82,0xE3,0xCC,0xC2,0xC4,0x45,0xC5,0x8C,0x97,0x7A,0x06,0x6B,0x2A,0x11,0x9F, +0xA9,0x0A,0x6E,0x48,0x3B,0x6F,0xDB,0xD4,0x11,0x19,0x42,0xF7,0x8F,0x07,0xBF,0xF5, +0x53,0x5F,0x9C,0x3E,0xF4,0x17,0x2C,0xE6,0x69,0xAC,0x4E,0x32,0x4C,0x62,0x77,0xEA, +0xB7,0xE8,0xE5,0xBB,0x34,0xBC,0x19,0x8B,0xAE,0x9C,0x51,0xE7,0xB7,0x7E,0xB5,0x53, +0xB1,0x33,0x22,0xE5,0x6D,0xCF,0x70,0x3C,0x1A,0xFA,0xE2,0x9B,0x67,0xB6,0x83,0xF4, +0x8D,0xA5,0xAF,0x62,0x4C,0x4D,0xE0,0x58,0xAC,0x64,0x34,0x12,0x03,0xF8,0xB6,0x8D, +0x94,0x63,0x24,0xA4,0x71,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x6A,0x72,0x26,0x7A,0xD0,0x1E, +0xEF,0x7D,0xE7,0x3B,0x69,0x51,0xD4,0x6C,0x8D,0x9F,0x90,0x12,0x66,0xAB,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x79,0x9F,0x1D,0x96,0xC6,0xB6,0x79,0x3F,0x22,0x8D,0x87,0xD3,0x87,0x03, +0x04,0x60,0x6A,0x6B,0x9A,0x2E,0x59,0x89,0x73,0x11,0xAC,0x43,0xD1,0xF5,0x13,0xFF, +0x8D,0x39,0x2B,0xC0,0xF2,0xBD,0x4F,0x70,0x8C,0xA9,0x2F,0xEA,0x17,0xC4,0x0B,0x54, +0x9E,0xD4,0x1B,0x96,0x98,0x33,0x3C,0xA8,0xAD,0x62,0xA2,0x00,0x76,0xAB,0x59,0x69, +0x6E,0x06,0x1D,0x7E,0xC4,0xB9,0x44,0x8D,0x98,0xAF,0x12,0xD4,0x61,0xDB,0x0A,0x19, +0x46,0x47,0xF3,0xEB,0xF7,0x63,0xC1,0x40,0x05,0x40,0xA5,0xD2,0xB7,0xF4,0xB5,0x9A, +0x36,0xBF,0xA9,0x88,0x76,0x88,0x04,0x55,0x04,0x2B,0x9C,0x87,0x7F,0x1A,0x37,0x3C, +0x7E,0x2D,0xA5,0x1A,0xD8,0xD4,0x89,0x5E,0xCA,0xBD,0xAC,0x3D,0x6C,0xD8,0x6D,0xAF, +0xD5,0xF3,0x76,0x0F,0xCD,0x3B,0x88,0x38,0x22,0x9D,0x6C,0x93,0x9A,0xC4,0x3D,0xBF, +0x82,0x1B,0x65,0x3F,0xA6,0x0F,0x5D,0xAA,0xFC,0xE5,0xB2,0x15,0xCA,0xB5,0xAD,0xC6, +0xBC,0x3D,0xD0,0x84,0xE8,0xEA,0x06,0x72,0xB0,0x4D,0x39,0x32,0x78,0xBF,0x3E,0x11, +0x9C,0x0B,0xA4,0x9D,0x9A,0x21,0xF3,0xF0,0x9B,0x0B,0x30,0x78,0xDB,0xC1,0xDC,0x87, +0x43,0xFE,0xBC,0x63,0x9A,0xCA,0xC5,0xC2,0x1C,0xC9,0xC7,0x8D,0xFF,0x3B,0x12,0x58, +0x08,0xE6,0xB6,0x3D,0xEC,0x7A,0x2C,0x4E,0xFB,0x83,0x96,0xCE,0x0C,0x3C,0x69,0x87, +0x54,0x73,0xA4,0x73,0xC2,0x93,0xFF,0x51,0x10,0xAC,0x15,0x54,0x01,0xD8,0xFC,0x05, +0xB1,0x89,0xA1,0x7F,0x74,0x83,0x9A,0x49,0xD7,0xDC,0x4E,0x7B,0x8A,0x48,0x6F,0x8B, +0x45,0xF6, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root G2 */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root G2 */ + + +const unsigned char DigiCert_Assured_ID_Root_G2_certificate[922]={ +0x30,0x82,0x03,0x96,0x30,0x82,0x02,0x7E,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0B, +0x93,0x1C,0x3A,0xD6,0x39,0x67,0xEA,0x67,0x23,0xBF,0xC3,0xAF,0x9A,0xF4,0x4B,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x65, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F, +0x6F,0x74,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31, +0x32,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32, +0x30,0x30,0x30,0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44, +0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06, +0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13, +0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65, +0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47,0x32,0x30,0x82,0x01,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD9,0xE7,0x28, +0x2F,0x52,0x3F,0x36,0x72,0x49,0x88,0x93,0x34,0xF3,0xF8,0x6A,0x1E,0x31,0x54,0x80, +0x9F,0xAD,0x54,0x41,0xB5,0x47,0xDF,0x96,0xA8,0xD4,0xAF,0x80,0x2D,0xB9,0x0A,0xCF, +0x75,0xFD,0x89,0xA5,0x7D,0x24,0xFA,0xE3,0x22,0x0C,0x2B,0xBC,0x95,0x17,0x0B,0x33, +0xBF,0x19,0x4D,0x41,0x06,0x90,0x00,0xBD,0x0C,0x4D,0x10,0xFE,0x07,0xB5,0xE7,0x1C, +0x6E,0x22,0x55,0x31,0x65,0x97,0xBD,0xD3,0x17,0xD2,0x1E,0x62,0xF3,0xDB,0xEA,0x6C, +0x50,0x8C,0x3F,0x84,0x0C,0x96,0xCF,0xB7,0xCB,0x03,0xE0,0xCA,0x6D,0xA1,0x14,0x4C, +0x1B,0x89,0xDD,0xED,0x00,0xB0,0x52,0x7C,0xAF,0x91,0x6C,0xB1,0x38,0x13,0xD1,0xE9, +0x12,0x08,0xC0,0x00,0xB0,0x1C,0x2B,0x11,0xDA,0x77,0x70,0x36,0x9B,0xAE,0xCE,0x79, +0x87,0xDC,0x82,0x70,0xE6,0x09,0x74,0x70,0x55,0x69,0xAF,0xA3,0x68,0x9F,0xBF,0xDD, +0xB6,0x79,0xB3,0xF2,0x9D,0x70,0x29,0x55,0xF4,0xAB,0xFF,0x95,0x61,0xF3,0xC9,0x40, +0x6F,0x1D,0xD1,0xBE,0x93,0xBB,0xD3,0x88,0x2A,0xBB,0x9D,0xBF,0x72,0x5A,0x56,0x71, +0x3B,0x3F,0xD4,0xF3,0xD1,0x0A,0xFE,0x28,0xEF,0xA3,0xEE,0xD9,0x99,0xAF,0x03,0xD3, +0x8F,0x60,0xB7,0xF2,0x92,0xA1,0xB1,0xBD,0x89,0x89,0x1F,0x30,0xCD,0xC3,0xA6,0x2E, +0x62,0x33,0xAE,0x16,0x02,0x77,0x44,0x5A,0xE7,0x81,0x0A,0x3C,0xA7,0x44,0x2E,0x79, +0xB8,0x3F,0x04,0xBC,0x5C,0xA0,0x87,0xE1,0x1B,0xAF,0x51,0x8E,0xCD,0xEC,0x2C,0xFA, +0xF8,0xFE,0x6D,0xF0,0x3A,0x7C,0xAA,0x8B,0xE4,0x67,0x95,0x31,0x8D,0x02,0x03,0x01, +0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0xCE,0xC3,0x4A,0xB9,0x99,0x55,0xF2,0xB8,0xDB,0x60,0xBF,0xA9,0x7E,0xBD, +0x56,0xB5,0x97,0x36,0xA7,0xD6,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xCA,0xA5,0x55,0x8C,0xE3,0xC8, +0x41,0x6E,0x69,0x27,0xA7,0x75,0x11,0xEF,0x3C,0x86,0x36,0x6F,0xD2,0x9D,0xC6,0x78, +0x38,0x1D,0x69,0x96,0xA2,0x92,0x69,0x2E,0x38,0x6C,0x9B,0x7D,0x04,0xD4,0x89,0xA5, +0xB1,0x31,0x37,0x8A,0xC9,0x21,0xCC,0xAB,0x6C,0xCD,0x8B,0x1C,0x9A,0xD6,0xBF,0x48, +0xD2,0x32,0x66,0xC1,0x8A,0xC0,0xF3,0x2F,0x3A,0xEF,0xC0,0xE3,0xD4,0x91,0x86,0xD1, +0x50,0xE3,0x03,0xDB,0x73,0x77,0x6F,0x4A,0x39,0x53,0xED,0xDE,0x26,0xC7,0xB5,0x7D, +0xAF,0x2B,0x42,0xD1,0x75,0x62,0xE3,0x4A,0x2B,0x02,0xC7,0x50,0x4B,0xE0,0x69,0xE2, +0x96,0x6C,0x0E,0x44,0x66,0x10,0x44,0x8F,0xAD,0x05,0xEB,0xF8,0x79,0xAC,0xA6,0x1B, +0xE8,0x37,0x34,0x9D,0x53,0xC9,0x61,0xAA,0xA2,0x52,0xAF,0x4A,0x70,0x16,0x86,0xC2, +0x3A,0xC8,0xB1,0x13,0x70,0x36,0xD8,0xCF,0xEE,0xF4,0x0A,0x34,0xD5,0x5B,0x4C,0xFD, +0x07,0x9C,0xA2,0xBA,0xD9,0x01,0x72,0x5C,0xF3,0x4D,0xC1,0xDD,0x0E,0xB1,0x1C,0x0D, +0xC4,0x63,0xBE,0xAD,0xF4,0x14,0xFB,0x89,0xEC,0xA2,0x41,0x0E,0x4C,0xCC,0xC8,0x57, +0x40,0xD0,0x6E,0x03,0xAA,0xCD,0x0C,0x8E,0x89,0x99,0x99,0x6C,0xF0,0x3C,0x30,0xAF, +0x38,0xDF,0x6F,0xBC,0xA3,0xBE,0x29,0x20,0x27,0xAB,0x74,0xFF,0x13,0x22,0x78,0xDE, +0x97,0x52,0x55,0x1E,0x83,0xB5,0x54,0x20,0x03,0xEE,0xAE,0xC0,0x4F,0x56,0xDE,0x37, +0xCC,0xC3,0x7F,0xAA,0x04,0x27,0xBB,0xD3,0x77,0xB8,0x62,0xDB,0x17,0x7C,0x9C,0x28, +0x22,0x13,0x73,0x6C,0xCF,0x26,0xF5,0x8A,0x29,0xE7, +}; + + +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Commercial */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Commercial */ + + +const unsigned char AffirmTrust_Commercial_certificate[848]={ +0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x77, +0x77,0x06,0x27,0x26,0xA9,0xB1,0x7C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, +0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69,0x61,0x6C,0x30,0x1E,0x17,0x0D, +0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x17,0x0D,0x33, +0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x30,0x44,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, +0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69, +0x61,0x6C,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xF6,0x1B,0x4F,0x67,0x07,0x2B,0xA1,0x15,0xF5,0x06,0x22,0xCB,0x1F, +0x01,0xB2,0xE3,0x73,0x45,0x06,0x44,0x49,0x2C,0xBB,0x49,0x25,0x14,0xD6,0xCE,0xC3, +0xB7,0xAB,0x2C,0x4F,0xC6,0x41,0x32,0x94,0x57,0xFA,0x12,0xA7,0x5B,0x0E,0xE2,0x8F, +0x1F,0x1E,0x86,0x19,0xA7,0xAA,0xB5,0x2D,0xB9,0x5F,0x0D,0x8A,0xC2,0xAF,0x85,0x35, +0x79,0x32,0x2D,0xBB,0x1C,0x62,0x37,0xF2,0xB1,0x5B,0x4A,0x3D,0xCA,0xCD,0x71,0x5F, +0xE9,0x42,0xBE,0x94,0xE8,0xC8,0xDE,0xF9,0x22,0x48,0x64,0xC6,0xE5,0xAB,0xC6,0x2B, +0x6D,0xAD,0x05,0xF0,0xFA,0xD5,0x0B,0xCF,0x9A,0xE5,0xF0,0x50,0xA4,0x8B,0x3B,0x47, +0xA5,0x23,0x5B,0x7A,0x7A,0xF8,0x33,0x3F,0xB8,0xEF,0x99,0x97,0xE3,0x20,0xC1,0xD6, +0x28,0x89,0xCF,0x94,0xFB,0xB9,0x45,0xED,0xE3,0x40,0x17,0x11,0xD4,0x74,0xF0,0x0B, +0x31,0xE2,0x2B,0x26,0x6A,0x9B,0x4C,0x57,0xAE,0xAC,0x20,0x3E,0xBA,0x45,0x7A,0x05, +0xF3,0xBD,0x9B,0x69,0x15,0xAE,0x7D,0x4E,0x20,0x63,0xC4,0x35,0x76,0x3A,0x07,0x02, +0xC9,0x37,0xFD,0xC7,0x47,0xEE,0xE8,0xF1,0x76,0x1D,0x73,0x15,0xF2,0x97,0xA4,0xB5, +0xC8,0x7A,0x79,0xD9,0x42,0xAA,0x2B,0x7F,0x5C,0xFE,0xCE,0x26,0x4F,0xA3,0x66,0x81, +0x35,0xAF,0x44,0xBA,0x54,0x1E,0x1C,0x30,0x32,0x65,0x9D,0xE6,0x3C,0x93,0x5E,0x50, +0x4E,0x7A,0xE3,0x3A,0xD4,0x6E,0xCC,0x1A,0xFB,0xF9,0xD2,0x37,0xAE,0x24,0x2A,0xAB, +0x57,0x03,0x22,0x28,0x0D,0x49,0x75,0x7F,0xB7,0x28,0xDA,0x75,0xBF,0x8E,0xE3,0xDC, +0x0E,0x79,0x31,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9D,0x93,0xC6,0x53,0x8B,0x5E,0xCA,0xAF,0x3F, +0x9F,0x1E,0x0F,0xE5,0x99,0x95,0xBC,0x24,0xF6,0x94,0x8F,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x58,0xAC,0xF4,0x04,0x0E,0xCD,0xC0,0x0D,0xFF,0x0A,0xFD,0xD4,0xBA,0x16,0x5F,0x29, +0xBD,0x7B,0x68,0x99,0x58,0x49,0xD2,0xB4,0x1D,0x37,0x4D,0x7F,0x27,0x7D,0x46,0x06, +0x5D,0x43,0xC6,0x86,0x2E,0x3E,0x73,0xB2,0x26,0x7D,0x4F,0x93,0xA9,0xB6,0xC4,0x2A, +0x9A,0xAB,0x21,0x97,0x14,0xB1,0xDE,0x8C,0xD3,0xAB,0x89,0x15,0xD8,0x6B,0x24,0xD4, +0xF1,0x16,0xAE,0xD8,0xA4,0x5C,0xD4,0x7F,0x51,0x8E,0xED,0x18,0x01,0xB1,0x93,0x63, +0xBD,0xBC,0xF8,0x61,0x80,0x9A,0x9E,0xB1,0xCE,0x42,0x70,0xE2,0xA9,0x7D,0x06,0x25, +0x7D,0x27,0xA1,0xFE,0x6F,0xEC,0xB3,0x1E,0x24,0xDA,0xE3,0x4B,0x55,0x1A,0x00,0x3B, +0x35,0xB4,0x3B,0xD9,0xD7,0x5D,0x30,0xFD,0x81,0x13,0x89,0xF2,0xC2,0x06,0x2B,0xED, +0x67,0xC4,0x8E,0xC9,0x43,0xB2,0x5C,0x6B,0x15,0x89,0x02,0xBC,0x62,0xFC,0x4E,0xF2, +0xB5,0x33,0xAA,0xB2,0x6F,0xD3,0x0A,0xA2,0x50,0xE3,0xF6,0x3B,0xE8,0x2E,0x44,0xC2, +0xDB,0x66,0x38,0xA9,0x33,0x56,0x48,0xF1,0x6D,0x1B,0x33,0x8D,0x0D,0x8C,0x3F,0x60, +0x37,0x9D,0xD3,0xCA,0x6D,0x7E,0x34,0x7E,0x0D,0x9F,0x72,0x76,0x8B,0x1B,0x9F,0x72, +0xFD,0x52,0x35,0x41,0x45,0x02,0x96,0x2F,0x1C,0xB2,0x9A,0x73,0x49,0x21,0xB1,0x49, +0x47,0x45,0x47,0xB4,0xEF,0x6A,0x34,0x11,0xC9,0x4D,0x9A,0xCC,0x59,0xB7,0xD6,0x02, +0x9E,0x5A,0x4E,0x65,0xB5,0x94,0xAE,0x1B,0xDF,0x29,0xB0,0x16,0xF1,0xBF,0x00,0x9E, +0x07,0x3A,0x17,0x64,0xB5,0x04,0xB5,0x23,0x21,0x99,0x0A,0x95,0x3B,0x97,0x7C,0xEF, +}; + + +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Premium */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Premium */ + + +const unsigned char AffirmTrust_Premium_certificate[1354]={ +0x30,0x82,0x05,0x46,0x30,0x82,0x03,0x2E,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x6D, +0x8C,0x14,0x46,0xB1,0xA6,0x0A,0xEE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30, +0x31,0x32,0x39,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x17,0x0D,0x34,0x30,0x31,0x32, +0x33,0x31,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x30,0x41,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, +0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C, +0x30,0x1A,0x06,0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54, +0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x82,0x02,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xC4,0x12,0xDF, +0xA9,0x5F,0xFE,0x41,0xDD,0xDD,0xF5,0x9F,0x8A,0xE3,0xF6,0xAC,0xE1,0x3C,0x78,0x9A, +0xBC,0xD8,0xF0,0x7F,0x7A,0xA0,0x33,0x2A,0xDC,0x8D,0x20,0x5B,0xAE,0x2D,0x6F,0xE7, +0x93,0xD9,0x36,0x70,0x6A,0x68,0xCF,0x8E,0x51,0xA3,0x85,0x5B,0x67,0x04,0xA0,0x10, +0x24,0x6F,0x5D,0x28,0x82,0xC1,0x97,0x57,0xD8,0x48,0x29,0x13,0xB6,0xE1,0xBE,0x91, +0x4D,0xDF,0x85,0x0C,0x53,0x18,0x9A,0x1E,0x24,0xA2,0x4F,0x8F,0xF0,0xA2,0x85,0x0B, +0xCB,0xF4,0x29,0x7F,0xD2,0xA4,0x58,0xEE,0x26,0x4D,0xC9,0xAA,0xA8,0x7B,0x9A,0xD9, +0xFA,0x38,0xDE,0x44,0x57,0x15,0xE5,0xF8,0x8C,0xC8,0xD9,0x48,0xE2,0x0D,0x16,0x27, +0x1D,0x1E,0xC8,0x83,0x85,0x25,0xB7,0xBA,0xAA,0x55,0x41,0xCC,0x03,0x22,0x4B,0x2D, +0x91,0x8D,0x8B,0xE6,0x89,0xAF,0x66,0xC7,0xE9,0xFF,0x2B,0xE9,0x3C,0xAC,0xDA,0xD2, +0xB3,0xC3,0xE1,0x68,0x9C,0x89,0xF8,0x7A,0x00,0x56,0xDE,0xF4,0x55,0x95,0x6C,0xFB, +0xBA,0x64,0xDD,0x62,0x8B,0xDF,0x0B,0x77,0x32,0xEB,0x62,0xCC,0x26,0x9A,0x9B,0xBB, +0xAA,0x62,0x83,0x4C,0xB4,0x06,0x7A,0x30,0xC8,0x29,0xBF,0xED,0x06,0x4D,0x97,0xB9, +0x1C,0xC4,0x31,0x2B,0xD5,0x5F,0xBC,0x53,0x12,0x17,0x9C,0x99,0x57,0x29,0x66,0x77, +0x61,0x21,0x31,0x07,0x2E,0x25,0x49,0x9D,0x18,0xF2,0xEE,0xF3,0x2B,0x71,0x8C,0xB5, +0xBA,0x39,0x07,0x49,0x77,0xFC,0xEF,0x2E,0x92,0x90,0x05,0x8D,0x2D,0x2F,0x77,0x7B, +0xEF,0x43,0xBF,0x35,0xBB,0x9A,0xD8,0xF9,0x73,0xA7,0x2C,0xF2,0xD0,0x57,0xEE,0x28, +0x4E,0x26,0x5F,0x8F,0x90,0x68,0x09,0x2F,0xB8,0xF8,0xDC,0x06,0xE9,0x2E,0x9A,0x3E, +0x51,0xA7,0xD1,0x22,0xC4,0x0A,0xA7,0x38,0x48,0x6C,0xB3,0xF9,0xFF,0x7D,0xAB,0x86, +0x57,0xE3,0xBA,0xD6,0x85,0x78,0x77,0xBA,0x43,0xEA,0x48,0x7F,0xF6,0xD8,0xBE,0x23, +0x6D,0x1E,0xBF,0xD1,0x36,0x6C,0x58,0x5C,0xF1,0xEE,0xA4,0x19,0x54,0x1A,0xF5,0x03, +0xD2,0x76,0xE6,0xE1,0x8C,0xBD,0x3C,0xB3,0xD3,0x48,0x4B,0xE2,0xC8,0xF8,0x7F,0x92, +0xA8,0x76,0x46,0x9C,0x42,0x65,0x3E,0xA4,0x1E,0xC1,0x07,0x03,0x5A,0x46,0x2D,0xB8, +0x97,0xF3,0xB7,0xD5,0xB2,0x55,0x21,0xEF,0xBA,0xDC,0x4C,0x00,0x97,0xFB,0x14,0x95, +0x27,0x33,0xBF,0xE8,0x43,0x47,0x46,0xD2,0x08,0x99,0x16,0x60,0x3B,0x9A,0x7E,0xD2, +0xE6,0xED,0x38,0xEA,0xEC,0x01,0x1E,0x3C,0x48,0x56,0x49,0x09,0xC7,0x4C,0x37,0x00, +0x9E,0x88,0x0E,0xC0,0x73,0xE1,0x6F,0x66,0xE9,0x72,0x47,0x30,0x3E,0x10,0xE5,0x0B, +0x03,0xC9,0x9A,0x42,0x00,0x6C,0xC5,0x94,0x7E,0x61,0xC4,0x8A,0xDF,0x7F,0x82,0x1A, +0x0B,0x59,0xC4,0x59,0x32,0x77,0xB3,0xBC,0x60,0x69,0x56,0x39,0xFD,0xB4,0x06,0x7B, +0x2C,0xD6,0x64,0x36,0xD9,0xBD,0x48,0xED,0x84,0x1F,0x7E,0xA5,0x22,0x8F,0x2A,0xB8, +0x42,0xF4,0x82,0xB7,0xD4,0x53,0x90,0x78,0x4E,0x2D,0x1A,0xFD,0x81,0x6F,0x44,0xD7, +0x3B,0x01,0x74,0x96,0x42,0xE0,0x00,0xE2,0x2E,0x6B,0xEA,0xC5,0xEE,0x72,0xAC,0xBB, +0xBF,0xFE,0xEA,0xAA,0xA8,0xF8,0xDC,0xF6,0xB2,0x79,0x8A,0xB6,0x67,0x02,0x03,0x01, +0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x9D,0xC0,0x67,0xA6,0x0C,0x22,0xD9,0x26,0xF5,0x45,0xAB,0xA6,0x65,0x52,0x11, +0x27,0xD8,0x45,0xAC,0x63,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0xB3,0x57,0x4D,0x10,0x62,0x4E, +0x3A,0xE4,0xAC,0xEA,0xB8,0x1C,0xAF,0x32,0x23,0xC8,0xB3,0x49,0x5A,0x51,0x9C,0x76, +0x28,0x8D,0x79,0xAA,0x57,0x46,0x17,0xD5,0xF5,0x52,0xF6,0xB7,0x44,0xE8,0x08,0x44, +0xBF,0x18,0x84,0xD2,0x0B,0x80,0xCD,0xC5,0x12,0xFD,0x00,0x55,0x05,0x61,0x87,0x41, +0xDC,0xB5,0x24,0x9E,0x3C,0xC4,0xD8,0xC8,0xFB,0x70,0x9E,0x2F,0x78,0x96,0x83,0x20, +0x36,0xDE,0x7C,0x0F,0x69,0x13,0x88,0xA5,0x75,0x36,0x98,0x08,0xA6,0xC6,0xDF,0xAC, +0xCE,0xE3,0x58,0xD6,0xB7,0x3E,0xDE,0xBA,0xF3,0xEB,0x34,0x40,0xD8,0xA2,0x81,0xF5, +0x78,0x3F,0x2F,0xD5,0xA5,0xFC,0xD9,0xA2,0xD4,0x5E,0x04,0x0E,0x17,0xAD,0xFE,0x41, +0xF0,0xE5,0xB2,0x72,0xFA,0x44,0x82,0x33,0x42,0xE8,0x2D,0x58,0xF7,0x56,0x8C,0x62, +0x3F,0xBA,0x42,0xB0,0x9C,0x0C,0x5C,0x7E,0x2E,0x65,0x26,0x5C,0x53,0x4F,0x00,0xB2, +0x78,0x7E,0xA1,0x0D,0x99,0x2D,0x8D,0xB8,0x1D,0x8E,0xA2,0xC4,0xB0,0xFD,0x60,0xD0, +0x30,0xA4,0x8E,0xC8,0x04,0x62,0xA9,0xC4,0xED,0x35,0xDE,0x7A,0x97,0xED,0x0E,0x38, +0x5E,0x92,0x2F,0x93,0x70,0xA5,0xA9,0x9C,0x6F,0xA7,0x7D,0x13,0x1D,0x7E,0xC6,0x08, +0x48,0xB1,0x5E,0x67,0xEB,0x51,0x08,0x25,0xE9,0xE6,0x25,0x6B,0x52,0x29,0x91,0x9C, +0xD2,0x39,0x73,0x08,0x57,0xDE,0x99,0x06,0xB4,0x5B,0x9D,0x10,0x06,0xE1,0xC2,0x00, +0xA8,0xB8,0x1C,0x4A,0x02,0x0A,0x14,0xD0,0xC1,0x41,0xCA,0xFB,0x8C,0x35,0x21,0x7D, +0x82,0x38,0xF2,0xA9,0x54,0x91,0x19,0x35,0x93,0x94,0x6D,0x6A,0x3A,0xC5,0xB2,0xD0, +0xBB,0x89,0x86,0x93,0xE8,0x9B,0xC9,0x0F,0x3A,0xA7,0x7A,0xB8,0xA1,0xF0,0x78,0x46, +0xFA,0xFC,0x37,0x2F,0xE5,0x8A,0x84,0xF3,0xDF,0xFE,0x04,0xD9,0xA1,0x68,0xA0,0x2F, +0x24,0xE2,0x09,0x95,0x06,0xD5,0x95,0xCA,0xE1,0x24,0x96,0xEB,0x7C,0xF6,0x93,0x05, +0xBB,0xED,0x73,0xE9,0x2D,0xD1,0x75,0x39,0xD7,0xE7,0x24,0xDB,0xD8,0x4E,0x5F,0x43, +0x8F,0x9E,0xD0,0x14,0x39,0xBF,0x55,0x70,0x48,0x99,0x57,0x31,0xB4,0x9C,0xEE,0x4A, +0x98,0x03,0x96,0x30,0x1F,0x60,0x06,0xEE,0x1B,0x23,0xFE,0x81,0x60,0x23,0x1A,0x47, +0x62,0x85,0xA5,0xCC,0x19,0x34,0x80,0x6F,0xB3,0xAC,0x1A,0xE3,0x9F,0xF0,0x7B,0x48, +0xAD,0xD5,0x01,0xD9,0x67,0xB6,0xA9,0x72,0x93,0xEA,0x2D,0x66,0xB5,0xB2,0xB8,0xE4, +0x3D,0x3C,0xB2,0xEF,0x4C,0x8C,0xEA,0xEB,0x07,0xBF,0xAB,0x35,0x9A,0x55,0x86,0xBC, +0x18,0xA6,0xB5,0xA8,0x5E,0xB4,0x83,0x6C,0x6B,0x69,0x40,0xD3,0x9F,0xDC,0xF1,0xC3, +0x69,0x6B,0xB9,0xE1,0x6D,0x09,0xF4,0xF1,0xAA,0x50,0x76,0x0A,0x7A,0x7D,0x7A,0x17, +0xA1,0x55,0x96,0x42,0x99,0x31,0x09,0xDD,0x60,0x11,0x8D,0x05,0x30,0x7E,0xE6,0x8E, +0x46,0xD1,0x9D,0x14,0xDA,0xC7,0x17,0xE4,0x05,0x96,0x8C,0xC4,0x24,0xB5,0x1B,0xCF, +0x14,0x07,0xB2,0x40,0xF8,0xA3,0x9E,0x41,0x86,0xBC,0x04,0xD0,0x6B,0x96,0xC8,0x2A, +0x80,0x34,0xFD,0xBF,0xEF,0x06,0xA3,0xDD,0x58,0xC5,0x85,0x3D,0x3E,0x8F,0xFE,0x9E, +0x29,0xE0,0xB6,0xB8,0x09,0x68,0x19,0x1C,0x18,0x43, +}; + + +/* subject:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2 */ +/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2 */ + + +const unsigned char Go_Daddy_Root_Certificate_Authority___G2_certificate[969]={ +0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, +0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, +0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13, +0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63,0x6F,0x6D,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28,0x47,0x6F,0x20, +0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, +0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07, +0x41,0x72,0x69,0x7A,0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07, +0x13,0x0A,0x53,0x63,0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18, +0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63, +0x6F,0x6D,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04, +0x03,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBF,0x71,0x62,0x08, +0xF1,0xFA,0x59,0x34,0xF7,0x1B,0xC9,0x18,0xA3,0xF7,0x80,0x49,0x58,0xE9,0x22,0x83, +0x13,0xA6,0xC5,0x20,0x43,0x01,0x3B,0x84,0xF1,0xE6,0x85,0x49,0x9F,0x27,0xEA,0xF6, +0x84,0x1B,0x4E,0xA0,0xB4,0xDB,0x70,0x98,0xC7,0x32,0x01,0xB1,0x05,0x3E,0x07,0x4E, +0xEE,0xF4,0xFA,0x4F,0x2F,0x59,0x30,0x22,0xE7,0xAB,0x19,0x56,0x6B,0xE2,0x80,0x07, +0xFC,0xF3,0x16,0x75,0x80,0x39,0x51,0x7B,0xE5,0xF9,0x35,0xB6,0x74,0x4E,0xA9,0x8D, +0x82,0x13,0xE4,0xB6,0x3F,0xA9,0x03,0x83,0xFA,0xA2,0xBE,0x8A,0x15,0x6A,0x7F,0xDE, +0x0B,0xC3,0xB6,0x19,0x14,0x05,0xCA,0xEA,0xC3,0xA8,0x04,0x94,0x3B,0x46,0x7C,0x32, +0x0D,0xF3,0x00,0x66,0x22,0xC8,0x8D,0x69,0x6D,0x36,0x8C,0x11,0x18,0xB7,0xD3,0xB2, +0x1C,0x60,0xB4,0x38,0xFA,0x02,0x8C,0xCE,0xD3,0xDD,0x46,0x07,0xDE,0x0A,0x3E,0xEB, +0x5D,0x7C,0xC8,0x7C,0xFB,0xB0,0x2B,0x53,0xA4,0x92,0x62,0x69,0x51,0x25,0x05,0x61, +0x1A,0x44,0x81,0x8C,0x2C,0xA9,0x43,0x96,0x23,0xDF,0xAC,0x3A,0x81,0x9A,0x0E,0x29, +0xC5,0x1C,0xA9,0xE9,0x5D,0x1E,0xB6,0x9E,0x9E,0x30,0x0A,0x39,0xCE,0xF1,0x88,0x80, +0xFB,0x4B,0x5D,0xCC,0x32,0xEC,0x85,0x62,0x43,0x25,0x34,0x02,0x56,0x27,0x01,0x91, +0xB4,0x3B,0x70,0x2A,0x3F,0x6E,0xB1,0xE8,0x9C,0x88,0x01,0x7D,0x9F,0xD4,0xF9,0xDB, +0x53,0x6D,0x60,0x9D,0xBF,0x2C,0xE7,0x58,0xAB,0xB8,0x5F,0x46,0xFC,0xCE,0xC4,0x1B, +0x03,0x3C,0x09,0xEB,0x49,0x31,0x5C,0x69,0x46,0xB3,0xE0,0x47,0x02,0x03,0x01,0x00, +0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x3A,0x9A,0x85,0x07,0x10,0x67,0x28,0xB6,0xEF,0xF6,0xBD,0x05,0x41,0x6E,0x20, +0xC1,0x94,0xDA,0x0F,0xDE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x99,0xDB,0x5D,0x79,0xD5,0xF9,0x97, +0x59,0x67,0x03,0x61,0xF1,0x7E,0x3B,0x06,0x31,0x75,0x2D,0xA1,0x20,0x8E,0x4F,0x65, +0x87,0xB4,0xF7,0xA6,0x9C,0xBC,0xD8,0xE9,0x2F,0xD0,0xDB,0x5A,0xEE,0xCF,0x74,0x8C, +0x73,0xB4,0x38,0x42,0xDA,0x05,0x7B,0xF8,0x02,0x75,0xB8,0xFD,0xA5,0xB1,0xD7,0xAE, +0xF6,0xD7,0xDE,0x13,0xCB,0x53,0x10,0x7E,0x8A,0x46,0xD1,0x97,0xFA,0xB7,0x2E,0x2B, +0x11,0xAB,0x90,0xB0,0x27,0x80,0xF9,0xE8,0x9F,0x5A,0xE9,0x37,0x9F,0xAB,0xE4,0xDF, +0x6C,0xB3,0x85,0x17,0x9D,0x3D,0xD9,0x24,0x4F,0x79,0x91,0x35,0xD6,0x5F,0x04,0xEB, +0x80,0x83,0xAB,0x9A,0x02,0x2D,0xB5,0x10,0xF4,0xD8,0x90,0xC7,0x04,0x73,0x40,0xED, +0x72,0x25,0xA0,0xA9,0x9F,0xEC,0x9E,0xAB,0x68,0x12,0x99,0x57,0xC6,0x8F,0x12,0x3A, +0x09,0xA4,0xBD,0x44,0xFD,0x06,0x15,0x37,0xC1,0x9B,0xE4,0x32,0xA3,0xED,0x38,0xE8, +0xD8,0x64,0xF3,0x2C,0x7E,0x14,0xFC,0x02,0xEA,0x9F,0xCD,0xFF,0x07,0x68,0x17,0xDB, +0x22,0x90,0x38,0x2D,0x7A,0x8D,0xD1,0x54,0xF1,0x69,0xE3,0x5F,0x33,0xCA,0x7A,0x3D, +0x7B,0x0A,0xE3,0xCA,0x7F,0x5F,0x39,0xE5,0xE2,0x75,0xBA,0xC5,0x76,0x18,0x33,0xCE, +0x2C,0xF0,0x2F,0x4C,0xAD,0xF7,0xB1,0xE7,0xCE,0x4F,0xA8,0xC4,0x9B,0x4A,0x54,0x06, +0xC5,0x7F,0x7D,0xD5,0x08,0x0F,0xE2,0x1C,0xFE,0x7E,0x17,0xB8,0xAC,0x5E,0xF6,0xD4, +0x16,0xB2,0x43,0x09,0x0C,0x4D,0xF6,0xA7,0x6B,0xB4,0x99,0x84,0x65,0xCA,0x7A,0x88, +0xE2,0xE2,0x44,0xBE,0x5C,0xF7,0xEA,0x1C,0xF5, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Secure Certificate Services */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Secure Certificate Services */ + + +const unsigned char Comodo_Secure_Services_root_certificate[1091]={ +0x30,0x82,0x04,0x3F,0x30,0x82,0x03,0x27,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x03,0x0C,0x1B,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30, +0x1E,0x17,0x0D,0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A, +0x17,0x0D,0x32,0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30, +0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x03,0x0C,0x1B,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30, +0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01, +0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00, +0xC0,0x71,0x33,0x82,0x8A,0xD0,0x70,0xEB,0x73,0x87,0x82,0x40,0xD5,0x1D,0xE4,0xCB, +0xC9,0x0E,0x42,0x90,0xF9,0xDE,0x34,0xB9,0xA1,0xBA,0x11,0xF4,0x25,0x85,0xF3,0xCC, +0x72,0x6D,0xF2,0x7B,0x97,0x6B,0xB3,0x07,0xF1,0x77,0x24,0x91,0x5F,0x25,0x8F,0xF6, +0x74,0x3D,0xE4,0x80,0xC2,0xF8,0x3C,0x0D,0xF3,0xBF,0x40,0xEA,0xF7,0xC8,0x52,0xD1, +0x72,0x6F,0xEF,0xC8,0xAB,0x41,0xB8,0x6E,0x2E,0x17,0x2A,0x95,0x69,0x0C,0xCD,0xD2, +0x1E,0x94,0x7B,0x2D,0x94,0x1D,0xAA,0x75,0xD7,0xB3,0x98,0xCB,0xAC,0xBC,0x64,0x53, +0x40,0xBC,0x8F,0xAC,0xAC,0x36,0xCB,0x5C,0xAD,0xBB,0xDD,0xE0,0x94,0x17,0xEC,0xD1, +0x5C,0xD0,0xBF,0xEF,0xA5,0x95,0xC9,0x90,0xC5,0xB0,0xAC,0xFB,0x1B,0x43,0xDF,0x7A, +0x08,0x5D,0xB7,0xB8,0xF2,0x40,0x1B,0x2B,0x27,0x9E,0x50,0xCE,0x5E,0x65,0x82,0x88, +0x8C,0x5E,0xD3,0x4E,0x0C,0x7A,0xEA,0x08,0x91,0xB6,0x36,0xAA,0x2B,0x42,0xFB,0xEA, +0xC2,0xA3,0x39,0xE5,0xDB,0x26,0x38,0xAD,0x8B,0x0A,0xEE,0x19,0x63,0xC7,0x1C,0x24, +0xDF,0x03,0x78,0xDA,0xE6,0xEA,0xC1,0x47,0x1A,0x0B,0x0B,0x46,0x09,0xDD,0x02,0xFC, +0xDE,0xCB,0x87,0x5F,0xD7,0x30,0x63,0x68,0xA1,0xAE,0xDC,0x32,0xA1,0xBA,0xBE,0xFE, +0x44,0xAB,0x68,0xB6,0xA5,0x17,0x15,0xFD,0xBD,0xD5,0xA7,0xA7,0x9A,0xE4,0x44,0x33, +0xE9,0x88,0x8E,0xFC,0xED,0x51,0xEB,0x93,0x71,0x4E,0xAD,0x01,0xE7,0x44,0x8E,0xAB, +0x2D,0xCB,0xA8,0xFE,0x01,0x49,0x48,0xF0,0xC0,0xDD,0xC7,0x68,0xD8,0x92,0xFE,0x3D, +0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xC7,0x30,0x81,0xC4,0x30,0x1D,0x06,0x03,0x55, +0x1D,0x0E,0x04,0x16,0x04,0x14,0x3C,0xD8,0x93,0x88,0xC2,0xC0,0x82,0x09,0xCC,0x01, +0x99,0x06,0x93,0x20,0xE9,0x9E,0x70,0x09,0x63,0x4F,0x30,0x0E,0x06,0x03,0x55,0x1D, +0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x81,0x06,0x03, +0x55,0x1D,0x1F,0x04,0x7A,0x30,0x78,0x30,0x3B,0xA0,0x39,0xA0,0x37,0x86,0x35,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F, +0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x53,0x65,0x63,0x75,0x72,0x65,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, +0x2E,0x63,0x72,0x6C,0x30,0x39,0xA0,0x37,0xA0,0x35,0x86,0x33,0x68,0x74,0x74,0x70, +0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x6E,0x65, +0x74,0x2F,0x53,0x65,0x63,0x75,0x72,0x65,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x87,0x01,0x6D,0x23,0x1D,0x7E,0x5B,0x17,0x7D,0xC1,0x61,0x32,0xCF, +0x8F,0xE7,0xF3,0x8A,0x94,0x59,0x66,0xE0,0x9E,0x28,0xA8,0x5E,0xD3,0xB7,0xF4,0x34, +0xE6,0xAA,0x39,0xB2,0x97,0x16,0xC5,0x82,0x6F,0x32,0xA4,0xE9,0x8C,0xE7,0xAF,0xFD, +0xEF,0xC2,0xE8,0xB9,0x4B,0xAA,0xA3,0xF4,0xE6,0xDA,0x8D,0x65,0x21,0xFB,0xBA,0x80, +0xEB,0x26,0x28,0x85,0x1A,0xFE,0x39,0x8C,0xDE,0x5B,0x04,0x04,0xB4,0x54,0xF9,0xA3, +0x67,0x9E,0x41,0xFA,0x09,0x52,0xCC,0x05,0x48,0xA8,0xC9,0x3F,0x21,0x04,0x1E,0xCE, +0x48,0x6B,0xFC,0x85,0xE8,0xC2,0x7B,0xAF,0x7F,0xB7,0xCC,0xF8,0x5F,0x3A,0xFD,0x35, +0xC6,0x0D,0xEF,0x97,0xDC,0x4C,0xAB,0x11,0xE1,0x6B,0xCB,0x31,0xD1,0x6C,0xFB,0x48, +0x80,0xAB,0xDC,0x9C,0x37,0xB8,0x21,0x14,0x4B,0x0D,0x71,0x3D,0xEC,0x83,0x33,0x6E, +0xD1,0x6E,0x32,0x16,0xEC,0x98,0xC7,0x16,0x8B,0x59,0xA6,0x34,0xAB,0x05,0x57,0x2D, +0x93,0xF7,0xAA,0x13,0xCB,0xD2,0x13,0xE2,0xB7,0x2E,0x3B,0xCD,0x6B,0x50,0x17,0x09, +0x68,0x3E,0xB5,0x26,0x57,0xEE,0xB6,0xE0,0xB6,0xDD,0xB9,0x29,0x80,0x79,0x7D,0x8F, +0xA3,0xF0,0xA4,0x28,0xA4,0x15,0xC4,0x85,0xF4,0x27,0xD4,0x6B,0xBF,0xE5,0x5C,0xE4, +0x65,0x02,0x76,0x54,0xB4,0xE3,0x37,0x66,0x24,0xD3,0x19,0x61,0xC8,0x52,0x10,0xE5, +0x8B,0x37,0x9A,0xB9,0xA9,0xF9,0x1D,0xBF,0xEA,0x99,0x92,0x61,0x96,0xFF,0x01,0xCD, +0xA1,0x5F,0x0D,0xBC,0x71,0xBC,0x0E,0xAC,0x0B,0x1D,0x47,0x45,0x1D,0xC1,0xEC,0x7C, +0xEC,0xFD,0x29, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Trusted Root G4 */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Trusted Root G4 */ + + +const unsigned char DigiCert_Trusted_Root_G4_certificate[1428]={ +0x30,0x82,0x05,0x90,0x30,0x82,0x03,0x78,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x05, +0x9B,0x1B,0x57,0x9E,0x8E,0x21,0x32,0xE2,0x39,0x07,0xBD,0xA7,0x77,0x75,0x5C,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x62, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x47,0x34,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x30,0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69, +0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E, +0x63,0x6F,0x6D,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x44,0x69, +0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x52, +0x6F,0x6F,0x74,0x20,0x47,0x34,0x30,0x82,0x02,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F,0x00,0x30,0x82, +0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xBF,0xE6,0x90,0x73,0x68,0xDE,0xBB,0xE4,0x5D, +0x4A,0x3C,0x30,0x22,0x30,0x69,0x33,0xEC,0xC2,0xA7,0x25,0x2E,0xC9,0x21,0x3D,0xF2, +0x8A,0xD8,0x59,0xC2,0xE1,0x29,0xA7,0x3D,0x58,0xAB,0x76,0x9A,0xCD,0xAE,0x7B,0x1B, +0x84,0x0D,0xC4,0x30,0x1F,0xF3,0x1B,0xA4,0x38,0x16,0xEB,0x56,0xC6,0x97,0x6D,0x1D, +0xAB,0xB2,0x79,0xF2,0xCA,0x11,0xD2,0xE4,0x5F,0xD6,0x05,0x3C,0x52,0x0F,0x52,0x1F, +0xC6,0x9E,0x15,0xA5,0x7E,0xBE,0x9F,0xA9,0x57,0x16,0x59,0x55,0x72,0xAF,0x68,0x93, +0x70,0xC2,0xB2,0xBA,0x75,0x99,0x6A,0x73,0x32,0x94,0xD1,0x10,0x44,0x10,0x2E,0xDF, +0x82,0xF3,0x07,0x84,0xE6,0x74,0x3B,0x6D,0x71,0xE2,0x2D,0x0C,0x1B,0xEE,0x20,0xD5, +0xC9,0x20,0x1D,0x63,0x29,0x2D,0xCE,0xEC,0x5E,0x4E,0xC8,0x93,0xF8,0x21,0x61,0x9B, +0x34,0xEB,0x05,0xC6,0x5E,0xEC,0x5B,0x1A,0xBC,0xEB,0xC9,0xCF,0xCD,0xAC,0x34,0x40, +0x5F,0xB1,0x7A,0x66,0xEE,0x77,0xC8,0x48,0xA8,0x66,0x57,0x57,0x9F,0x54,0x58,0x8E, +0x0C,0x2B,0xB7,0x4F,0xA7,0x30,0xD9,0x56,0xEE,0xCA,0x7B,0x5D,0xE3,0xAD,0xC9,0x4F, +0x5E,0xE5,0x35,0xE7,0x31,0xCB,0xDA,0x93,0x5E,0xDC,0x8E,0x8F,0x80,0xDA,0xB6,0x91, +0x98,0x40,0x90,0x79,0xC3,0x78,0xC7,0xB6,0xB1,0xC4,0xB5,0x6A,0x18,0x38,0x03,0x10, +0x8D,0xD8,0xD4,0x37,0xA4,0x2E,0x05,0x7D,0x88,0xF5,0x82,0x3E,0x10,0x91,0x70,0xAB, +0x55,0x82,0x41,0x32,0xD7,0xDB,0x04,0x73,0x2A,0x6E,0x91,0x01,0x7C,0x21,0x4C,0xD4, +0xBC,0xAE,0x1B,0x03,0x75,0x5D,0x78,0x66,0xD9,0x3A,0x31,0x44,0x9A,0x33,0x40,0xBF, +0x08,0xD7,0x5A,0x49,0xA4,0xC2,0xE6,0xA9,0xA0,0x67,0xDD,0xA4,0x27,0xBC,0xA1,0x4F, +0x39,0xB5,0x11,0x58,0x17,0xF7,0x24,0x5C,0x46,0x8F,0x64,0xF7,0xC1,0x69,0x88,0x76, +0x98,0x76,0x3D,0x59,0x5D,0x42,0x76,0x87,0x89,0x97,0x69,0x7A,0x48,0xF0,0xE0,0xA2, +0x12,0x1B,0x66,0x9A,0x74,0xCA,0xDE,0x4B,0x1E,0xE7,0x0E,0x63,0xAE,0xE6,0xD4,0xEF, +0x92,0x92,0x3A,0x9E,0x3D,0xDC,0x00,0xE4,0x45,0x25,0x89,0xB6,0x9A,0x44,0x19,0x2B, +0x7E,0xC0,0x94,0xB4,0xD2,0x61,0x6D,0xEB,0x33,0xD9,0xC5,0xDF,0x4B,0x04,0x00,0xCC, +0x7D,0x1C,0x95,0xC3,0x8F,0xF7,0x21,0xB2,0xB2,0x11,0xB7,0xBB,0x7F,0xF2,0xD5,0x8C, +0x70,0x2C,0x41,0x60,0xAA,0xB1,0x63,0x18,0x44,0x95,0x1A,0x76,0x62,0x7E,0xF6,0x80, +0xB0,0xFB,0xE8,0x64,0xA6,0x33,0xD1,0x89,0x07,0xE1,0xBD,0xB7,0xE6,0x43,0xA4,0x18, +0xB8,0xA6,0x77,0x01,0xE1,0x0F,0x94,0x0C,0x21,0x1D,0xB2,0x54,0x29,0x25,0x89,0x6C, +0xE5,0x0E,0x52,0x51,0x47,0x74,0xBE,0x26,0xAC,0xB6,0x41,0x75,0xDE,0x7A,0xAC,0x5F, +0x8D,0x3F,0xC9,0xBC,0xD3,0x41,0x11,0x12,0x5B,0xE5,0x10,0x50,0xEB,0x31,0xC5,0xCA, +0x72,0x16,0x22,0x09,0xDF,0x7C,0x4C,0x75,0x3F,0x63,0xEC,0x21,0x5F,0xC4,0x20,0x51, +0x6B,0x6F,0xB1,0xAB,0x86,0x8B,0x4F,0xC2,0xD6,0x45,0x5F,0x9D,0x20,0xFC,0xA1,0x1E, +0xC5,0xC0,0x8F,0xA2,0xB1,0x7E,0x0A,0x26,0x99,0xF5,0xE4,0x69,0x2F,0x98,0x1D,0x2D, +0xF5,0xD9,0xA9,0xB2,0x1D,0xE5,0x1B,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40, +0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01, +0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x86,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xEC,0xD7,0xE3,0x82, +0xD2,0x71,0x5D,0x64,0x4C,0xDF,0x2E,0x67,0x3F,0xE7,0xBA,0x98,0xAE,0x1C,0x0F,0x4F, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03, +0x82,0x02,0x01,0x00,0xBB,0x61,0xD9,0x7D,0xA9,0x6C,0xBE,0x17,0xC4,0x91,0x1B,0xC3, +0xA1,0xA2,0x00,0x8D,0xE3,0x64,0x68,0x0F,0x56,0xCF,0x77,0xAE,0x70,0xF9,0xFD,0x9A, +0x4A,0x99,0xB9,0xC9,0x78,0x5C,0x0C,0x0C,0x5F,0xE4,0xE6,0x14,0x29,0x56,0x0B,0x36, +0x49,0x5D,0x44,0x63,0xE0,0xAD,0x9C,0x96,0x18,0x66,0x1B,0x23,0x0D,0x3D,0x79,0xE9, +0x6D,0x6B,0xD6,0x54,0xF8,0xD2,0x3C,0xC1,0x43,0x40,0xAE,0x1D,0x50,0xF5,0x52,0xFC, +0x90,0x3B,0xBB,0x98,0x99,0x69,0x6B,0xC7,0xC1,0xA7,0xA8,0x68,0xA4,0x27,0xDC,0x9D, +0xF9,0x27,0xAE,0x30,0x85,0xB9,0xF6,0x67,0x4D,0x3A,0x3E,0x8F,0x59,0x39,0x22,0x53, +0x44,0xEB,0xC8,0x5D,0x03,0xCA,0xED,0x50,0x7A,0x7D,0x62,0x21,0x0A,0x80,0xC8,0x73, +0x66,0xD1,0xA0,0x05,0x60,0x5F,0xE8,0xA5,0xB4,0xA7,0xAF,0xA8,0xF7,0x6D,0x35,0x9C, +0x7C,0x5A,0x8A,0xD6,0xA2,0x38,0x99,0xF3,0x78,0x8B,0xF4,0x4D,0xD2,0x20,0x0B,0xDE, +0x04,0xEE,0x8C,0x9B,0x47,0x81,0x72,0x0D,0xC0,0x14,0x32,0xEF,0x30,0x59,0x2E,0xAE, +0xE0,0x71,0xF2,0x56,0xE4,0x6A,0x97,0x6F,0x92,0x50,0x6D,0x96,0x8D,0x68,0x7A,0x9A, +0xB2,0x36,0x14,0x7A,0x06,0xF2,0x24,0xB9,0x09,0x11,0x50,0xD7,0x08,0xB1,0xB8,0x89, +0x7A,0x84,0x23,0x61,0x42,0x29,0xE5,0xA3,0xCD,0xA2,0x20,0x41,0xD7,0xD1,0x9C,0x64, +0xD9,0xEA,0x26,0xA1,0x8B,0x14,0xD7,0x4C,0x19,0xB2,0x50,0x41,0x71,0x3D,0x3F,0x4D, +0x70,0x23,0x86,0x0C,0x4A,0xDC,0x81,0xD2,0xCC,0x32,0x94,0x84,0x0D,0x08,0x09,0x97, +0x1C,0x4F,0xC0,0xEE,0x6B,0x20,0x74,0x30,0xD2,0xE0,0x39,0x34,0x10,0x85,0x21,0x15, +0x01,0x08,0xE8,0x55,0x32,0xDE,0x71,0x49,0xD9,0x28,0x17,0x50,0x4D,0xE6,0xBE,0x4D, +0xD1,0x75,0xAC,0xD0,0xCA,0xFB,0x41,0xB8,0x43,0xA5,0xAA,0xD3,0xC3,0x05,0x44,0x4F, +0x2C,0x36,0x9B,0xE2,0xFA,0xE2,0x45,0xB8,0x23,0x53,0x6C,0x06,0x6F,0x67,0x55,0x7F, +0x46,0xB5,0x4C,0x3F,0x6E,0x28,0x5A,0x79,0x26,0xD2,0xA4,0xA8,0x62,0x97,0xD2,0x1E, +0xE2,0xED,0x4A,0x8B,0xBC,0x1B,0xFD,0x47,0x4A,0x0D,0xDF,0x67,0x66,0x7E,0xB2,0x5B, +0x41,0xD0,0x3B,0xE4,0xF4,0x3B,0xF4,0x04,0x63,0xE9,0xEF,0xC2,0x54,0x00,0x51,0xA0, +0x8A,0x2A,0xC9,0xCE,0x78,0xCC,0xD5,0xEA,0x87,0x04,0x18,0xB3,0xCE,0xAF,0x49,0x88, +0xAF,0xF3,0x92,0x99,0xB6,0xB3,0xE6,0x61,0x0F,0xD2,0x85,0x00,0xE7,0x50,0x1A,0xE4, +0x1B,0x95,0x9D,0x19,0xA1,0xB9,0x9C,0xB1,0x9B,0xB1,0x00,0x1E,0xEF,0xD0,0x0F,0x4F, +0x42,0x6C,0xC9,0x0A,0xBC,0xEE,0x43,0xFA,0x3A,0x71,0xA5,0xC8,0x4D,0x26,0xA5,0x35, +0xFD,0x89,0x5D,0xBC,0x85,0x62,0x1D,0x32,0xD2,0xA0,0x2B,0x54,0xED,0x9A,0x57,0xC1, +0xDB,0xFA,0x10,0xCF,0x19,0xB7,0x8B,0x4A,0x1B,0x8F,0x01,0xB6,0x27,0x95,0x53,0xE8, +0xB6,0x89,0x6D,0x5B,0xBC,0x68,0xD4,0x23,0xE8,0x8B,0x51,0xA2,0x56,0xF9,0xF0,0xA6, +0x80,0xA0,0xD6,0x1E,0xB3,0xBC,0x0F,0x0F,0x53,0x75,0x29,0xAA,0xEA,0x13,0x77,0xE4, +0xDE,0x8C,0x81,0x21,0xAD,0x07,0x10,0x47,0x11,0xAD,0x87,0x3D,0x07,0xD1,0x75,0xBC, +0xCF,0xF3,0x66,0x7E, +}; + + +/* subject:/OU=GlobalSign ECC Root CA - R5/O=GlobalSign/CN=GlobalSign */ +/* issuer :/OU=GlobalSign ECC Root CA - R5/O=GlobalSign/CN=GlobalSign */ + + +const unsigned char GlobalSign_ECC_Root_CA___R5_certificate[546]={ +0x30,0x82,0x02,0x1E,0x30,0x82,0x01,0xA4,0xA0,0x03,0x02,0x01,0x02,0x02,0x11,0x60, +0x59,0x49,0xE0,0x26,0x2E,0xBB,0x55,0xF9,0x0A,0x77,0x8A,0x71,0xF9,0x4A,0xD8,0x6C, +0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x50,0x31,0x24, +0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x20,0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20, +0x2D,0x20,0x52,0x35,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47, +0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E, +0x17,0x0D,0x31,0x32,0x31,0x31,0x31,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17, +0x0D,0x33,0x38,0x30,0x31,0x31,0x39,0x30,0x33,0x31,0x34,0x30,0x37,0x5A,0x30,0x50, +0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x20,0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x41,0x20,0x2D,0x20,0x52,0x35,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13, +0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B, +0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x47,0x45,0x0E,0x96,0xFB,0x7D,0x5D,0xBF, +0xE9,0x39,0xD1,0x21,0xF8,0x9F,0x0B,0xB6,0xD5,0x7B,0x1E,0x92,0x3A,0x48,0x59,0x1C, +0xF0,0x62,0x31,0x2D,0xC0,0x7A,0x28,0xFE,0x1A,0xA7,0x5C,0xB3,0xB6,0xCC,0x97,0xE7, +0x45,0xD4,0x58,0xFA,0xD1,0x77,0x6D,0x43,0xA2,0xC0,0x87,0x65,0x34,0x0A,0x1F,0x7A, +0xDD,0xEB,0x3C,0x33,0xA1,0xC5,0x9D,0x4D,0xA4,0x6F,0x41,0x95,0x38,0x7F,0xC9,0x1E, +0x84,0xEB,0xD1,0x9E,0x49,0x92,0x87,0x94,0x87,0x0C,0x3A,0x85,0x4A,0x66,0x9F,0x9D, +0x59,0x93,0x4D,0x97,0x61,0x06,0x86,0x4A,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x3D,0xE6,0x29,0x48,0x9B,0xEA,0x07,0xCA, +0x21,0x44,0x4A,0x26,0xDE,0x6E,0xDE,0xD2,0x83,0xD0,0x9F,0x59,0x30,0x0A,0x06,0x08, +0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31,0x00, +0xE5,0x69,0x12,0xC9,0x6E,0xDB,0xC6,0x31,0xBA,0x09,0x41,0xE1,0x97,0xF8,0xFB,0xFD, +0x9A,0xE2,0x7D,0x12,0xC9,0xED,0x7C,0x64,0xD3,0xCB,0x05,0x25,0x8B,0x56,0xD9,0xA0, +0xE7,0x5E,0x5D,0x4E,0x0B,0x83,0x9C,0x5B,0x76,0x29,0xA0,0x09,0x26,0x21,0x6A,0x62, +0x02,0x30,0x71,0xD2,0xB5,0x8F,0x5C,0xEA,0x3B,0xE1,0x78,0x09,0x85,0xA8,0x75,0x92, +0x3B,0xC8,0x5C,0xFD,0x48,0xEF,0x0D,0x74,0x22,0xA8,0x08,0xE2,0x6E,0xC5,0x49,0xCE, +0xC7,0x0C,0xBC,0xA7,0x61,0x69,0xF1,0xF7,0x3B,0xE1,0x2A,0xCB,0xF9,0x2B,0xF3,0x66, +0x90,0x37, +}; + + +/* subject:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */ +/* issuer :/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */ + + +const unsigned char UTN_USERFirst_Hardware_Root_CA_certificate[1144]={ +0x30,0x82,0x04,0x74,0x30,0x82,0x03,0x5C,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x44, +0xBE,0x0C,0x8B,0x50,0x00,0x24,0xB4,0x11,0xD3,0x36,0x2A,0xFE,0x65,0x0A,0xFD,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0x97,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20, +0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, +0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72, +0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03, +0x13,0x16,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D, +0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x37, +0x30,0x39,0x31,0x38,0x31,0x30,0x34,0x32,0x5A,0x17,0x0D,0x31,0x39,0x30,0x37,0x30, +0x39,0x31,0x38,0x31,0x39,0x32,0x32,0x5A,0x30,0x81,0x97,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0E, +0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1E, +0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45, +0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21, +0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, +0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F, +0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,0x4E,0x2D, +0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61, +0x72,0x65,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xB1,0xF7,0xC3,0x38,0x3F,0xB4,0xA8,0x7F,0xCF,0x39,0x82,0x51,0x67, +0xD0,0x6D,0x9F,0xD2,0xFF,0x58,0xF3,0xE7,0x9F,0x2B,0xEC,0x0D,0x89,0x54,0x99,0xB9, +0x38,0x99,0x16,0xF7,0xE0,0x21,0x79,0x48,0xC2,0xBB,0x61,0x74,0x12,0x96,0x1D,0x3C, +0x6A,0x72,0xD5,0x3C,0x10,0x67,0x3A,0x39,0xED,0x2B,0x13,0xCD,0x66,0xEB,0x95,0x09, +0x33,0xA4,0x6C,0x97,0xB1,0xE8,0xC6,0xEC,0xC1,0x75,0x79,0x9C,0x46,0x5E,0x8D,0xAB, +0xD0,0x6A,0xFD,0xB9,0x2A,0x55,0x17,0x10,0x54,0xB3,0x19,0xF0,0x9A,0xF6,0xF1,0xB1, +0x5D,0xB6,0xA7,0x6D,0xFB,0xE0,0x71,0x17,0x6B,0xA2,0x88,0xFB,0x00,0xDF,0xFE,0x1A, +0x31,0x77,0x0C,0x9A,0x01,0x7A,0xB1,0x32,0xE3,0x2B,0x01,0x07,0x38,0x6E,0xC3,0xA5, +0x5E,0x23,0xBC,0x45,0x9B,0x7B,0x50,0xC1,0xC9,0x30,0x8F,0xDB,0xE5,0x2B,0x7A,0xD3, +0x5B,0xFB,0x33,0x40,0x1E,0xA0,0xD5,0x98,0x17,0xBC,0x8B,0x87,0xC3,0x89,0xD3,0x5D, +0xA0,0x8E,0xB2,0xAA,0xAA,0xF6,0x8E,0x69,0x88,0x06,0xC5,0xFA,0x89,0x21,0xF3,0x08, +0x9D,0x69,0x2E,0x09,0x33,0x9B,0x29,0x0D,0x46,0x0F,0x8C,0xCC,0x49,0x34,0xB0,0x69, +0x51,0xBD,0xF9,0x06,0xCD,0x68,0xAD,0x66,0x4C,0xBC,0x3E,0xAC,0x61,0xBD,0x0A,0x88, +0x0E,0xC8,0xDF,0x3D,0xEE,0x7C,0x04,0x4C,0x9D,0x0A,0x5E,0x6B,0x91,0xD6,0xEE,0xC7, +0xED,0x28,0x8D,0xAB,0x4D,0x87,0x89,0x73,0xD0,0x6E,0xA4,0xD0,0x1E,0x16,0x8B,0x14, +0xE1,0x76,0x44,0x03,0x7F,0x63,0xAC,0xE4,0xCD,0x49,0x9C,0xC5,0x92,0xF4,0xAB,0x32, +0xA1,0x48,0x5B,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xB9,0x30,0x81,0xB6,0x30,0x0B, +0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0xC6,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xA1,0x72,0x5F,0x26,0x1B,0x28,0x98,0x43,0x95, +0x5D,0x07,0x37,0xD5,0x85,0x96,0x9D,0x4B,0xD2,0xC3,0x45,0x30,0x44,0x06,0x03,0x55, +0x1D,0x1F,0x04,0x3D,0x30,0x3B,0x30,0x39,0xA0,0x37,0xA0,0x35,0x86,0x33,0x68,0x74, +0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75, +0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46, +0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2E,0x63,0x72, +0x6C,0x30,0x31,0x06,0x03,0x55,0x1D,0x25,0x04,0x2A,0x30,0x28,0x06,0x08,0x2B,0x06, +0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x05, +0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x06,0x06,0x08,0x2B,0x06,0x01,0x05, +0x05,0x07,0x03,0x07,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x47,0x19,0x0F,0xDE,0x74,0xC6,0x99,0x97, +0xAF,0xFC,0xAD,0x28,0x5E,0x75,0x8E,0xEB,0x2D,0x67,0xEE,0x4E,0x7B,0x2B,0xD7,0x0C, +0xFF,0xF6,0xDE,0xCB,0x55,0xA2,0x0A,0xE1,0x4C,0x54,0x65,0x93,0x60,0x6B,0x9F,0x12, +0x9C,0xAD,0x5E,0x83,0x2C,0xEB,0x5A,0xAE,0xC0,0xE4,0x2D,0xF4,0x00,0x63,0x1D,0xB8, +0xC0,0x6C,0xF2,0xCF,0x49,0xBB,0x4D,0x93,0x6F,0x06,0xA6,0x0A,0x22,0xB2,0x49,0x62, +0x08,0x4E,0xFF,0xC8,0xC8,0x14,0xB2,0x88,0x16,0x5D,0xE7,0x01,0xE4,0x12,0x95,0xE5, +0x45,0x34,0xB3,0x8B,0x69,0xBD,0xCF,0xB4,0x85,0x8F,0x75,0x51,0x9E,0x7D,0x3A,0x38, +0x3A,0x14,0x48,0x12,0xC6,0xFB,0xA7,0x3B,0x1A,0x8D,0x0D,0x82,0x40,0x07,0xE8,0x04, +0x08,0x90,0xA1,0x89,0xCB,0x19,0x50,0xDF,0xCA,0x1C,0x01,0xBC,0x1D,0x04,0x19,0x7B, +0x10,0x76,0x97,0x3B,0xEE,0x90,0x90,0xCA,0xC4,0x0E,0x1F,0x16,0x6E,0x75,0xEF,0x33, +0xF8,0xD3,0x6F,0x5B,0x1E,0x96,0xE3,0xE0,0x74,0x77,0x74,0x7B,0x8A,0xA2,0x6E,0x2D, +0xDD,0x76,0xD6,0x39,0x30,0x82,0xF0,0xAB,0x9C,0x52,0xF2,0x2A,0xC7,0xAF,0x49,0x5E, +0x7E,0xC7,0x68,0xE5,0x82,0x81,0xC8,0x6A,0x27,0xF9,0x27,0x88,0x2A,0xD5,0x58,0x50, +0x95,0x1F,0xF0,0x3B,0x1C,0x57,0xBB,0x7D,0x14,0x39,0x62,0x2B,0x9A,0xC9,0x94,0x92, +0x2A,0xA3,0x22,0x0C,0xFF,0x89,0x26,0x7D,0x5F,0x23,0x2B,0x47,0xD7,0x15,0x1D,0xA9, +0x6A,0x9E,0x51,0x0D,0x2A,0x51,0x9E,0x81,0xF9,0xD4,0x3B,0x5E,0x70,0x12,0x7F,0x10, +0x32,0x9C,0x1E,0xBB,0x9D,0xF8,0x66,0xA8, +}; + + +/* subject:/OU=GlobalSign ECC Root CA - R4/O=GlobalSign/CN=GlobalSign */ +/* issuer :/OU=GlobalSign ECC Root CA - R4/O=GlobalSign/CN=GlobalSign */ + + +const unsigned char GlobalSign_ECC_Root_CA___R4_certificate[485]={ +0x30,0x82,0x01,0xE1,0x30,0x82,0x01,0x87,0xA0,0x03,0x02,0x01,0x02,0x02,0x11,0x2A, +0x38,0xA4,0x1C,0x96,0x0A,0x04,0xDE,0x42,0xB2,0x28,0xA5,0x0B,0xE8,0x34,0x98,0x02, +0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,0x30,0x50,0x31,0x24, +0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x20,0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20, +0x2D,0x20,0x52,0x34,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47, +0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E, +0x17,0x0D,0x31,0x32,0x31,0x31,0x31,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17, +0x0D,0x33,0x38,0x30,0x31,0x31,0x39,0x30,0x33,0x31,0x34,0x30,0x37,0x5A,0x30,0x50, +0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x20,0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x41,0x20,0x2D,0x20,0x52,0x34,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13, +0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x30,0x59,0x30,0x13,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x08,0x2A, +0x86,0x48,0xCE,0x3D,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0xB8,0xC6,0x79,0xD3,0x8F, +0x6C,0x25,0x0E,0x9F,0x2E,0x39,0x19,0x1C,0x03,0xA4,0xAE,0x9A,0xE5,0x39,0x07,0x09, +0x16,0xCA,0x63,0xB1,0xB9,0x86,0xF8,0x8A,0x57,0xC1,0x57,0xCE,0x42,0xFA,0x73,0xA1, +0xF7,0x65,0x42,0xFF,0x1E,0xC1,0x00,0xB2,0x6E,0x73,0x0E,0xFF,0xC7,0x21,0xE5,0x18, +0xA4,0xAA,0xD9,0x71,0x3F,0xA8,0xD4,0xB9,0xCE,0x8C,0x1D,0xA3,0x42,0x30,0x40,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30, +0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x54,0xB0,0x7B,0xAD,0x45, +0xB8,0xE2,0x40,0x7F,0xFB,0x0A,0x6E,0xFB,0xBE,0x33,0xC9,0x3C,0xA3,0x84,0xD5,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,0x03,0x48,0x00,0x30,0x45, +0x02,0x21,0x00,0xDC,0x92,0xA1,0xA0,0x13,0xA6,0xCF,0x03,0xB0,0xE6,0xC4,0x21,0x97, +0x90,0xFA,0x14,0x57,0x2D,0x03,0xEC,0xEE,0x3C,0xD3,0x6E,0xCA,0xA8,0x6C,0x76,0xBC, +0xA2,0xDE,0xBB,0x02,0x20,0x27,0xA8,0x85,0x27,0x35,0x9B,0x56,0xC6,0xA3,0xF2,0x47, +0xD2,0xB7,0x6E,0x1B,0x02,0x00,0x17,0xAA,0x67,0xA6,0x15,0x91,0xDE,0xFA,0x94,0xEC, +0x7B,0x0B,0xF8,0x9F,0x84, +}; + + +/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA I */ +/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA I */ + + +const unsigned char TC_TrustCenter_Universal_CA_I_certificate[993]={ +0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x1D, +0xA2,0x00,0x01,0x00,0x02,0xEC,0xB7,0x60,0x80,0x78,0x8D,0xB6,0x06,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x79,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, +0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x0B,0x13,0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, +0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31, +0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75, +0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73, +0x61,0x6C,0x20,0x43,0x41,0x20,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x33,0x32, +0x32,0x31,0x35,0x35,0x34,0x32,0x38,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31, +0x32,0x32,0x35,0x39,0x35,0x39,0x5A,0x30,0x79,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13, +0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20, +0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x54, +0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E, +0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,0x26,0x30,0x24,0x06,0x03, +0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E, +0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41, +0x20,0x49,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xA4,0x77,0x23,0x96,0x44,0xAF,0x90,0xF4,0x31,0xA7,0x10,0xF4,0x26, +0x87,0x9C,0xF3,0x38,0xD9,0x0F,0x5E,0xDE,0xCF,0x41,0xE8,0x31,0xAD,0xC6,0x74,0x91, +0x24,0x96,0x78,0x1E,0x09,0xA0,0x9B,0x9A,0x95,0x4A,0x4A,0xF5,0x62,0x7C,0x02,0xA8, +0xCA,0xAC,0xFB,0x5A,0x04,0x76,0x39,0xDE,0x5F,0xF1,0xF9,0xB3,0xBF,0xF3,0x03,0x58, +0x55,0xD2,0xAA,0xB7,0xE3,0x04,0x22,0xD1,0xF8,0x94,0xDA,0x22,0x08,0x00,0x8D,0xD3, +0x7C,0x26,0x5D,0xCC,0x77,0x79,0xE7,0x2C,0x78,0x39,0xA8,0x26,0x73,0x0E,0xA2,0x5D, +0x25,0x69,0x85,0x4F,0x55,0x0E,0x9A,0xEF,0xC6,0xB9,0x44,0xE1,0x57,0x3D,0xDF,0x1F, +0x54,0x22,0xE5,0x6F,0x65,0xAA,0x33,0x84,0x3A,0xF3,0xCE,0x7A,0xBE,0x55,0x97,0xAE, +0x8D,0x12,0x0F,0x14,0x33,0xE2,0x50,0x70,0xC3,0x49,0x87,0x13,0xBC,0x51,0xDE,0xD7, +0x98,0x12,0x5A,0xEF,0x3A,0x83,0x33,0x92,0x06,0x75,0x8B,0x92,0x7C,0x12,0x68,0x7B, +0x70,0x6A,0x0F,0xB5,0x9B,0xB6,0x77,0x5B,0x48,0x59,0x9D,0xE4,0xEF,0x5A,0xAD,0xF3, +0xC1,0x9E,0xD4,0xD7,0x45,0x4E,0xCA,0x56,0x34,0x21,0xBC,0x3E,0x17,0x5B,0x6F,0x77, +0x0C,0x48,0x01,0x43,0x29,0xB0,0xDD,0x3F,0x96,0x6E,0xE6,0x95,0xAA,0x0C,0xC0,0x20, +0xB6,0xFD,0x3E,0x36,0x27,0x9C,0xE3,0x5C,0xCF,0x4E,0x81,0xDC,0x19,0xBB,0x91,0x90, +0x7D,0xEC,0xE6,0x97,0x04,0x1E,0x93,0xCC,0x22,0x49,0xD7,0x97,0x86,0xB6,0x13,0x0A, +0x3C,0x43,0x23,0x77,0x7E,0xF0,0xDC,0xE6,0xCD,0x24,0x1F,0x3B,0x83,0x9B,0x34,0x3A, +0x83,0x34,0xE3,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x1F,0x06,0x03, +0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE, +0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE, +0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x28,0xD2,0xE0,0x86,0xD5,0xE6,0xF8,0x7B,0xF0,0x97,0xDC,0x22,0x6B,0x3B,0x95, +0x14,0x56,0x0F,0x11,0x30,0xA5,0x9A,0x4F,0x3A,0xB0,0x3A,0xE0,0x06,0xCB,0x65,0xF5, +0xED,0xC6,0x97,0x27,0xFE,0x25,0xF2,0x57,0xE6,0x5E,0x95,0x8C,0x3E,0x64,0x60,0x15, +0x5A,0x7F,0x2F,0x0D,0x01,0xC5,0xB1,0x60,0xFD,0x45,0x35,0xCF,0xF0,0xB2,0xBF,0x06, +0xD9,0xEF,0x5A,0xBE,0xB3,0x62,0x21,0xB4,0xD7,0xAB,0x35,0x7C,0x53,0x3E,0xA6,0x27, +0xF1,0xA1,0x2D,0xDA,0x1A,0x23,0x9D,0xCC,0xDD,0xEC,0x3C,0x2D,0x9E,0x27,0x34,0x5D, +0x0F,0xC2,0x36,0x79,0xBC,0xC9,0x4A,0x62,0x2D,0xED,0x6B,0xD9,0x7D,0x41,0x43,0x7C, +0xB6,0xAA,0xCA,0xED,0x61,0xB1,0x37,0x82,0x15,0x09,0x1A,0x8A,0x16,0x30,0xD8,0xEC, +0xC9,0xD6,0x47,0x72,0x78,0x4B,0x10,0x46,0x14,0x8E,0x5F,0x0E,0xAF,0xEC,0xC7,0x2F, +0xAB,0x10,0xD7,0xB6,0xF1,0x6E,0xEC,0x86,0xB2,0xC2,0xE8,0x0D,0x92,0x73,0xDC,0xA2, +0xF4,0x0F,0x3A,0xBF,0x61,0x23,0x10,0x89,0x9C,0x48,0x40,0x6E,0x70,0x00,0xB3,0xD3, +0xBA,0x37,0x44,0x58,0x11,0x7A,0x02,0x6A,0x88,0xF0,0x37,0x34,0xF0,0x19,0xE9,0xAC, +0xD4,0x65,0x73,0xF6,0x69,0x8C,0x64,0x94,0x3A,0x79,0x85,0x29,0xB0,0x16,0x2B,0x0C, +0x82,0x3F,0x06,0x9C,0xC7,0xFD,0x10,0x2B,0x9E,0x0F,0x2C,0xB6,0x9E,0xE3,0x15,0xBF, +0xD9,0x36,0x1C,0xBA,0x25,0x1A,0x52,0x3D,0x1A,0xEC,0x22,0x0C,0x1C,0xE0,0xA4,0xA2, +0x3D,0xF0,0xE8,0x39,0xCF,0x81,0xC0,0x7B,0xED,0x5D,0x1F,0x6F,0xC5,0xD0,0x0B,0xD7, +0x98, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Trusted Certificate Services */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Trusted Certificate Services */ + + +const unsigned char Comodo_Trusted_Services_root_certificate[1095]={ +0x30,0x82,0x04,0x43,0x30,0x82,0x03,0x2B,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x7F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x25,0x30,0x23,0x06,0x03,0x55, +0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, +0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x17,0x0D,0x32,0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A, +0x30,0x7F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31, +0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65, +0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E, +0x06,0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A, +0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20, +0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x25,0x30,0x23,0x06,0x03, +0x55,0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65, +0x73,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01, +0x01,0x00,0xDF,0x71,0x6F,0x36,0x58,0x53,0x5A,0xF2,0x36,0x54,0x57,0x80,0xC4,0x74, +0x08,0x20,0xED,0x18,0x7F,0x2A,0x1D,0xE6,0x35,0x9A,0x1E,0x25,0xAC,0x9C,0xE5,0x96, +0x7E,0x72,0x52,0xA0,0x15,0x42,0xDB,0x59,0xDD,0x64,0x7A,0x1A,0xD0,0xB8,0x7B,0xDD, +0x39,0x15,0xBC,0x55,0x48,0xC4,0xED,0x3A,0x00,0xEA,0x31,0x11,0xBA,0xF2,0x71,0x74, +0x1A,0x67,0xB8,0xCF,0x33,0xCC,0xA8,0x31,0xAF,0xA3,0xE3,0xD7,0x7F,0xBF,0x33,0x2D, +0x4C,0x6A,0x3C,0xEC,0x8B,0xC3,0x92,0xD2,0x53,0x77,0x24,0x74,0x9C,0x07,0x6E,0x70, +0xFC,0xBD,0x0B,0x5B,0x76,0xBA,0x5F,0xF2,0xFF,0xD7,0x37,0x4B,0x4A,0x60,0x78,0xF7, +0xF0,0xFA,0xCA,0x70,0xB4,0xEA,0x59,0xAA,0xA3,0xCE,0x48,0x2F,0xA9,0xC3,0xB2,0x0B, +0x7E,0x17,0x72,0x16,0x0C,0xA6,0x07,0x0C,0x1B,0x38,0xCF,0xC9,0x62,0xB7,0x3F,0xA0, +0x93,0xA5,0x87,0x41,0xF2,0xB7,0x70,0x40,0x77,0xD8,0xBE,0x14,0x7C,0xE3,0xA8,0xC0, +0x7A,0x8E,0xE9,0x63,0x6A,0xD1,0x0F,0x9A,0xC6,0xD2,0xF4,0x8B,0x3A,0x14,0x04,0x56, +0xD4,0xED,0xB8,0xCC,0x6E,0xF5,0xFB,0xE2,0x2C,0x58,0xBD,0x7F,0x4F,0x6B,0x2B,0xF7, +0x60,0x24,0x58,0x24,0xCE,0x26,0xEF,0x34,0x91,0x3A,0xD5,0xE3,0x81,0xD0,0xB2,0xF0, +0x04,0x02,0xD7,0x5B,0xB7,0x3E,0x92,0xAC,0x6B,0x12,0x8A,0xF9,0xE4,0x05,0xB0,0x3B, +0x91,0x49,0x5C,0xB2,0xEB,0x53,0xEA,0xF8,0x9F,0x47,0x86,0xEE,0xBF,0x95,0xC0,0xC0, +0x06,0x9F,0xD2,0x5B,0x5E,0x11,0x1B,0xF4,0xC7,0x04,0x35,0x29,0xD2,0x55,0x5C,0xE4, +0xED,0xEB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xC9,0x30,0x81,0xC6,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC5,0x7B,0x58,0xBD,0xED,0xDA,0x25,0x69, +0xD2,0xF7,0x59,0x16,0xA8,0xB3,0x32,0xC0,0x7B,0x27,0x5B,0xF4,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x83, +0x06,0x03,0x55,0x1D,0x1F,0x04,0x7C,0x30,0x7A,0x30,0x3C,0xA0,0x3A,0xA0,0x38,0x86, +0x36,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F, +0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x54,0x72,0x75,0x73,0x74,0x65,0x64, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69, +0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30,0x3A,0xA0,0x38,0xA0,0x36,0x86,0x34,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F, +0x2E,0x6E,0x65,0x74,0x2F,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E, +0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xC8,0x93,0x81,0x3B,0x89,0xB4,0xAF,0xB8,0x84, +0x12,0x4C,0x8D,0xD2,0xF0,0xDB,0x70,0xBA,0x57,0x86,0x15,0x34,0x10,0xB9,0x2F,0x7F, +0x1E,0xB0,0xA8,0x89,0x60,0xA1,0x8A,0xC2,0x77,0x0C,0x50,0x4A,0x9B,0x00,0x8B,0xD8, +0x8B,0xF4,0x41,0xE2,0xD0,0x83,0x8A,0x4A,0x1C,0x14,0x06,0xB0,0xA3,0x68,0x05,0x70, +0x31,0x30,0xA7,0x53,0x9B,0x0E,0xE9,0x4A,0xA0,0x58,0x69,0x67,0x0E,0xAE,0x9D,0xF6, +0xA5,0x2C,0x41,0xBF,0x3C,0x06,0x6B,0xE4,0x59,0xCC,0x6D,0x10,0xF1,0x96,0x6F,0x1F, +0xDF,0xF4,0x04,0x02,0xA4,0x9F,0x45,0x3E,0xC8,0xD8,0xFA,0x36,0x46,0x44,0x50,0x3F, +0x82,0x97,0x91,0x1F,0x28,0xDB,0x18,0x11,0x8C,0x2A,0xE4,0x65,0x83,0x57,0x12,0x12, +0x8C,0x17,0x3F,0x94,0x36,0xFE,0x5D,0xB0,0xC0,0x04,0x77,0x13,0xB8,0xF4,0x15,0xD5, +0x3F,0x38,0xCC,0x94,0x3A,0x55,0xD0,0xAC,0x98,0xF5,0xBA,0x00,0x5F,0xE0,0x86,0x19, +0x81,0x78,0x2F,0x28,0xC0,0x7E,0xD3,0xCC,0x42,0x0A,0xF5,0xAE,0x50,0xA0,0xD1,0x3E, +0xC6,0xA1,0x71,0xEC,0x3F,0xA0,0x20,0x8C,0x66,0x3A,0x89,0xB4,0x8E,0xD4,0xD8,0xB1, +0x4D,0x25,0x47,0xEE,0x2F,0x88,0xC8,0xB5,0xE1,0x05,0x45,0xC0,0xBE,0x14,0x71,0xDE, +0x7A,0xFD,0x8E,0x7B,0x7D,0x4D,0x08,0x96,0xA5,0x12,0x73,0xF0,0x2D,0xCA,0x37,0x27, +0x74,0x12,0x27,0x4C,0xCB,0xB6,0x97,0xE9,0xD9,0xAE,0x08,0x6D,0x5A,0x39,0x40,0xDD, +0x05,0x47,0x75,0x6A,0x5A,0x21,0xB3,0xA3,0x18,0xCF,0x4E,0xF7,0x2E,0x57,0xB7,0x98, +0x70,0x5E,0xC8,0xC4,0x78,0xB0,0x62, +}; + + +/* subject:/C=US/O=Entrust, Inc./OU=www.entrust.net/CPS is incorporated by reference/OU=(c) 2006 Entrust, Inc./CN=Entrust Root Certification Authority */ +/* issuer :/C=US/O=Entrust, Inc./OU=www.entrust.net/CPS is incorporated by reference/OU=(c) 2006 Entrust, Inc./CN=Entrust Root Certification Authority */ + + +const unsigned char Entrust_Root_Certification_Authority_certificate[1173]={ +0x30,0x82,0x04,0x91,0x30,0x82,0x03,0x79,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x45, +0x6B,0x50,0x54,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03, +0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69,0x6E,0x63,0x6F, +0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x65, +0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x03,0x13, +0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65, +0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68, +0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x32,0x37,0x32, +0x30,0x32,0x33,0x34,0x32,0x5A,0x17,0x0D,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30, +0x35,0x33,0x34,0x32,0x5A,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30, +0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72, +0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69, +0x6E,0x63,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72, +0x65,0x66,0x65,0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04, +0x0B,0x13,0x16,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72, +0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55, +0x04,0x03,0x13,0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74, 0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, 0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09, 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00, -0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0x98,0x24,0x1E,0xBD,0x15,0xB4,0xBA, -0xDF,0xC7,0x8C,0xA5,0x27,0xB6,0x38,0x0B,0x69,0xF3,0xB6,0x4E,0xA8,0x2C,0x2E,0x21, -0x1D,0x5C,0x44,0xDF,0x21,0x5D,0x7E,0x23,0x74,0xFE,0x5E,0x7E,0xB4,0x4A,0xB7,0xA6, -0xAD,0x1F,0xAE,0xE0,0x06,0x16,0xE2,0x9B,0x5B,0xD9,0x67,0x74,0x6B,0x5D,0x80,0x8F, -0x29,0x9D,0x86,0x1B,0xD9,0x9C,0x0D,0x98,0x6D,0x76,0x10,0x28,0x58,0xE4,0x65,0xB0, -0x7F,0x4A,0x98,0x79,0x9F,0xE0,0xC3,0x31,0x7E,0x80,0x2B,0xB5,0x8C,0xC0,0x40,0x3B, -0x11,0x86,0xD0,0xCB,0xA2,0x86,0x36,0x60,0xA4,0xD5,0x30,0x82,0x6D,0xD9,0x6E,0xD0, -0x0F,0x12,0x04,0x33,0x97,0x5F,0x4F,0x61,0x5A,0xF0,0xE4,0xF9,0x91,0xAB,0xE7,0x1D, -0x3B,0xBC,0xE8,0xCF,0xF4,0x6B,0x2D,0x34,0x7C,0xE2,0x48,0x61,0x1C,0x8E,0xF3,0x61, -0x44,0xCC,0x6F,0xA0,0x4A,0xA9,0x94,0xB0,0x4D,0xDA,0xE7,0xA9,0x34,0x7A,0x72,0x38, -0xA8,0x41,0xCC,0x3C,0x94,0x11,0x7D,0xEB,0xC8,0xA6,0x8C,0xB7,0x86,0xCB,0xCA,0x33, -0x3B,0xD9,0x3D,0x37,0x8B,0xFB,0x7A,0x3E,0x86,0x2C,0xE7,0x73,0xD7,0x0A,0x57,0xAC, -0x64,0x9B,0x19,0xEB,0xF4,0x0F,0x04,0x08,0x8A,0xAC,0x03,0x17,0x19,0x64,0xF4,0x5A, -0x25,0x22,0x8D,0x34,0x2C,0xB2,0xF6,0x68,0x1D,0x12,0x6D,0xD3,0x8A,0x1E,0x14,0xDA, -0xC4,0x8F,0xA6,0xE2,0x23,0x85,0xD5,0x7A,0x0D,0xBD,0x6A,0xE0,0xE9,0xEC,0xEC,0x17, -0xBB,0x42,0x1B,0x67,0xAA,0x25,0xED,0x45,0x83,0x21,0xFC,0xC1,0xC9,0x7C,0xD5,0x62, -0x3E,0xFA,0xF2,0xC5,0x2D,0xD3,0xFD,0xD4,0x65,0x02,0x03,0x01,0x00,0x01,0xA3,0x81, -0x9F,0x30,0x81,0x9C,0x30,0x13,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14, -0x02,0x04,0x06,0x1E,0x04,0x00,0x43,0x00,0x41,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F, -0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, -0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, -0x04,0x14,0xC6,0x4F,0xA2,0x3D,0x06,0x63,0x84,0x09,0x9C,0xCE,0x62,0xE4,0x04,0xAC, -0x8D,0x5C,0xB5,0xE9,0xB6,0x1B,0x30,0x36,0x06,0x03,0x55,0x1D,0x1F,0x04,0x2F,0x30, -0x2D,0x30,0x2B,0xA0,0x29,0xA0,0x27,0x86,0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, -0x63,0x72,0x6C,0x2E,0x78,0x72,0x61,0x6D,0x70,0x73,0x65,0x63,0x75,0x72,0x69,0x74, -0x79,0x2E,0x63,0x6F,0x6D,0x2F,0x58,0x47,0x43,0x41,0x2E,0x63,0x72,0x6C,0x30,0x10, -0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x01,0x04,0x03,0x02,0x01,0x01, -0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, -0x82,0x01,0x01,0x00,0x91,0x15,0x39,0x03,0x01,0x1B,0x67,0xFB,0x4A,0x1C,0xF9,0x0A, -0x60,0x5B,0xA1,0xDA,0x4D,0x97,0x62,0xF9,0x24,0x53,0x27,0xD7,0x82,0x64,0x4E,0x90, -0x2E,0xC3,0x49,0x1B,0x2B,0x9A,0xDC,0xFC,0xA8,0x78,0x67,0x35,0xF1,0x1D,0xF0,0x11, -0xBD,0xB7,0x48,0xE3,0x10,0xF6,0x0D,0xDF,0x3F,0xD2,0xC9,0xB6,0xAA,0x55,0xA4,0x48, -0xBA,0x02,0xDB,0xDE,0x59,0x2E,0x15,0x5B,0x3B,0x9D,0x16,0x7D,0x47,0xD7,0x37,0xEA, -0x5F,0x4D,0x76,0x12,0x36,0xBB,0x1F,0xD7,0xA1,0x81,0x04,0x46,0x20,0xA3,0x2C,0x6D, -0xA9,0x9E,0x01,0x7E,0x3F,0x29,0xCE,0x00,0x93,0xDF,0xFD,0xC9,0x92,0x73,0x89,0x89, -0x64,0x9E,0xE7,0x2B,0xE4,0x1C,0x91,0x2C,0xD2,0xB9,0xCE,0x7D,0xCE,0x6F,0x31,0x99, -0xD3,0xE6,0xBE,0xD2,0x1E,0x90,0xF0,0x09,0x14,0x79,0x5C,0x23,0xAB,0x4D,0xD2,0xDA, -0x21,0x1F,0x4D,0x99,0x79,0x9D,0xE1,0xCF,0x27,0x9F,0x10,0x9B,0x1C,0x88,0x0D,0xB0, -0x8A,0x64,0x41,0x31,0xB8,0x0E,0x6C,0x90,0x24,0xA4,0x9B,0x5C,0x71,0x8F,0xBA,0xBB, -0x7E,0x1C,0x1B,0xDB,0x6A,0x80,0x0F,0x21,0xBC,0xE9,0xDB,0xA6,0xB7,0x40,0xF4,0xB2, -0x8B,0xA9,0xB1,0xE4,0xEF,0x9A,0x1A,0xD0,0x3D,0x69,0x99,0xEE,0xA8,0x28,0xA3,0xE1, -0x3C,0xB3,0xF0,0xB2,0x11,0x9C,0xCF,0x7C,0x40,0xE6,0xDD,0xE7,0x43,0x7D,0xA2,0xD8, -0x3A,0xB5,0xA9,0x8D,0xF2,0x34,0x99,0xC4,0xD4,0x10,0xE1,0x06,0xFD,0x09,0x84,0x10, -0x3B,0xEE,0xC4,0x4C,0xF4,0xEC,0x27,0x7C,0x42,0xC2,0x74,0x7C,0x82,0x8A,0x09,0xC9, -0xB4,0x03,0x25,0xBC, +0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB6,0x95,0xB6,0x43,0x42,0xFA,0xC6, +0x6D,0x2A,0x6F,0x48,0xDF,0x94,0x4C,0x39,0x57,0x05,0xEE,0xC3,0x79,0x11,0x41,0x68, +0x36,0xED,0xEC,0xFE,0x9A,0x01,0x8F,0xA1,0x38,0x28,0xFC,0xF7,0x10,0x46,0x66,0x2E, +0x4D,0x1E,0x1A,0xB1,0x1A,0x4E,0xC6,0xD1,0xC0,0x95,0x88,0xB0,0xC9,0xFF,0x31,0x8B, +0x33,0x03,0xDB,0xB7,0x83,0x7B,0x3E,0x20,0x84,0x5E,0xED,0xB2,0x56,0x28,0xA7,0xF8, +0xE0,0xB9,0x40,0x71,0x37,0xC5,0xCB,0x47,0x0E,0x97,0x2A,0x68,0xC0,0x22,0x95,0x62, +0x15,0xDB,0x47,0xD9,0xF5,0xD0,0x2B,0xFF,0x82,0x4B,0xC9,0xAD,0x3E,0xDE,0x4C,0xDB, +0x90,0x80,0x50,0x3F,0x09,0x8A,0x84,0x00,0xEC,0x30,0x0A,0x3D,0x18,0xCD,0xFB,0xFD, +0x2A,0x59,0x9A,0x23,0x95,0x17,0x2C,0x45,0x9E,0x1F,0x6E,0x43,0x79,0x6D,0x0C,0x5C, +0x98,0xFE,0x48,0xA7,0xC5,0x23,0x47,0x5C,0x5E,0xFD,0x6E,0xE7,0x1E,0xB4,0xF6,0x68, +0x45,0xD1,0x86,0x83,0x5B,0xA2,0x8A,0x8D,0xB1,0xE3,0x29,0x80,0xFE,0x25,0x71,0x88, +0xAD,0xBE,0xBC,0x8F,0xAC,0x52,0x96,0x4B,0xAA,0x51,0x8D,0xE4,0x13,0x31,0x19,0xE8, +0x4E,0x4D,0x9F,0xDB,0xAC,0xB3,0x6A,0xD5,0xBC,0x39,0x54,0x71,0xCA,0x7A,0x7A,0x7F, +0x90,0xDD,0x7D,0x1D,0x80,0xD9,0x81,0xBB,0x59,0x26,0xC2,0x11,0xFE,0xE6,0x93,0xE2, +0xF7,0x80,0xE4,0x65,0xFB,0x34,0x37,0x0E,0x29,0x80,0x70,0x4D,0xAF,0x38,0x86,0x2E, +0x9E,0x7F,0x57,0xAF,0x9E,0x17,0xAE,0xEB,0x1C,0xCB,0x28,0x21,0x5F,0xB6,0x1C,0xD8, +0xE7,0xA2,0x04,0x22,0xF9,0xD3,0xDA,0xD8,0xCB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81, +0xB0,0x30,0x81,0xAD,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x2B,0x06,0x03,0x55,0x1D,0x10,0x04,0x24,0x30,0x22, +0x80,0x0F,0x32,0x30,0x30,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x32,0x33,0x34,0x32, +0x5A,0x81,0x0F,0x32,0x30,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x35,0x33,0x34, +0x32,0x5A,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x68, +0x90,0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB, +0x84,0xBD,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x68,0x90, +0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB,0x84, +0xBD,0x6D,0x30,0x1D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04, +0x10,0x30,0x0E,0x1B,0x08,0x56,0x37,0x2E,0x31,0x3A,0x34,0x2E,0x30,0x03,0x02,0x04, +0x90,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x82,0x01,0x01,0x00,0x93,0xD4,0x30,0xB0,0xD7,0x03,0x20,0x2A,0xD0,0xF9,0x63, +0xE8,0x91,0x0C,0x05,0x20,0xA9,0x5F,0x19,0xCA,0x7B,0x72,0x4E,0xD4,0xB1,0xDB,0xD0, +0x96,0xFB,0x54,0x5A,0x19,0x2C,0x0C,0x08,0xF7,0xB2,0xBC,0x85,0xA8,0x9D,0x7F,0x6D, +0x3B,0x52,0xB3,0x2A,0xDB,0xE7,0xD4,0x84,0x8C,0x63,0xF6,0x0F,0xCB,0x26,0x01,0x91, +0x50,0x6C,0xF4,0x5F,0x14,0xE2,0x93,0x74,0xC0,0x13,0x9E,0x30,0x3A,0x50,0xE3,0xB4, +0x60,0xC5,0x1C,0xF0,0x22,0x44,0x8D,0x71,0x47,0xAC,0xC8,0x1A,0xC9,0xE9,0x9B,0x9A, +0x00,0x60,0x13,0xFF,0x70,0x7E,0x5F,0x11,0x4D,0x49,0x1B,0xB3,0x15,0x52,0x7B,0xC9, +0x54,0xDA,0xBF,0x9D,0x95,0xAF,0x6B,0x9A,0xD8,0x9E,0xE9,0xF1,0xE4,0x43,0x8D,0xE2, +0x11,0x44,0x3A,0xBF,0xAF,0xBD,0x83,0x42,0x73,0x52,0x8B,0xAA,0xBB,0xA7,0x29,0xCF, +0xF5,0x64,0x1C,0x0A,0x4D,0xD1,0xBC,0xAA,0xAC,0x9F,0x2A,0xD0,0xFF,0x7F,0x7F,0xDA, +0x7D,0xEA,0xB1,0xED,0x30,0x25,0xC1,0x84,0xDA,0x34,0xD2,0x5B,0x78,0x83,0x56,0xEC, +0x9C,0x36,0xC3,0x26,0xE2,0x11,0xF6,0x67,0x49,0x1D,0x92,0xAB,0x8C,0xFB,0xEB,0xFF, +0x7A,0xEE,0x85,0x4A,0xA7,0x50,0x80,0xF0,0xA7,0x5C,0x4A,0x94,0x2E,0x5F,0x05,0x99, +0x3C,0x52,0x41,0xE0,0xCD,0xB4,0x63,0xCF,0x01,0x43,0xBA,0x9C,0x83,0xDC,0x8F,0x60, +0x3B,0xF3,0x5A,0xB4,0xB4,0x7B,0xAE,0xDA,0x0B,0x90,0x38,0x75,0xEF,0x81,0x1D,0x66, +0xD2,0xF7,0x57,0x70,0x36,0xB3,0xBF,0xFC,0x28,0xAF,0x71,0x25,0x85,0x5B,0x13,0xFE, +0x1E,0x7F,0x5A,0xB4,0x3C, +}; + + +/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 2 CA/CN=TC TrustCenter Class 2 CA II */ +/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 2 CA/CN=TC TrustCenter Class 2 CA II */ + + +const unsigned char TC_TrustCenter_Class_2_CA_II_certificate[1198]={ +0x30,0x82,0x04,0xAA,0x30,0x82,0x03,0x92,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x2E, +0x6A,0x00,0x01,0x00,0x02,0x1F,0xD7,0x52,0x21,0x2C,0x11,0x5C,0x3B,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x76,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, +0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55, +0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, +0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x41,0x31,0x25,0x30, +0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74, +0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43, +0x41,0x20,0x49,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x31,0x31,0x32,0x31,0x34, +0x33,0x38,0x34,0x33,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31,0x32,0x32,0x35, +0x39,0x35,0x39,0x5A,0x30,0x76,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43, +0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62, +0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54, +0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73, +0x20,0x32,0x20,0x43,0x41,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C, +0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43, +0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x41,0x20,0x49,0x49,0x30,0x82,0x01,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAB,0x80,0x87, +0x9B,0x8E,0xF0,0xC3,0x7C,0x87,0xD7,0xE8,0x24,0x82,0x11,0xB3,0x3C,0xDD,0x43,0x62, +0xEE,0xF8,0xC3,0x45,0xDA,0xE8,0xE1,0xA0,0x5F,0xD1,0x2A,0xB2,0xEA,0x93,0x68,0xDF, +0xB4,0xC8,0xD6,0x43,0xE9,0xC4,0x75,0x59,0x7F,0xFC,0xE1,0x1D,0xF8,0x31,0x70,0x23, +0x1B,0x88,0x9E,0x27,0xB9,0x7B,0xFD,0x3A,0xD2,0xC9,0xA9,0xE9,0x14,0x2F,0x90,0xBE, +0x03,0x52,0xC1,0x49,0xCD,0xF6,0xFD,0xE4,0x08,0x66,0x0B,0x57,0x8A,0xA2,0x42,0xA0, +0xB8,0xD5,0x7F,0x69,0x5C,0x90,0x32,0xB2,0x97,0x0D,0xCA,0x4A,0xDC,0x46,0x3E,0x02, +0x55,0x89,0x53,0xE3,0x1A,0x5A,0xCB,0x36,0xC6,0x07,0x56,0xF7,0x8C,0xCF,0x11,0xF4, +0x4C,0xBB,0x30,0x70,0x04,0x95,0xA5,0xF6,0x39,0x8C,0xFD,0x73,0x81,0x08,0x7D,0x89, +0x5E,0x32,0x1E,0x22,0xA9,0x22,0x45,0x4B,0xB0,0x66,0x2E,0x30,0xCC,0x9F,0x65,0xFD, +0xFC,0xCB,0x81,0xA9,0xF1,0xE0,0x3B,0xAF,0xA3,0x86,0xD1,0x89,0xEA,0xC4,0x45,0x79, +0x50,0x5D,0xAE,0xE9,0x21,0x74,0x92,0x4D,0x8B,0x59,0x82,0x8F,0x94,0xE3,0xE9,0x4A, +0xF1,0xE7,0x49,0xB0,0x14,0xE3,0xF5,0x62,0xCB,0xD5,0x72,0xBD,0x1F,0xB9,0xD2,0x9F, +0xA0,0xCD,0xA8,0xFA,0x01,0xC8,0xD9,0x0D,0xDF,0xDA,0xFC,0x47,0x9D,0xB3,0xC8,0x54, +0xDF,0x49,0x4A,0xF1,0x21,0xA9,0xFE,0x18,0x4E,0xEE,0x48,0xD4,0x19,0xBB,0xEF,0x7D, +0xE4,0xE2,0x9D,0xCB,0x5B,0xB6,0x6E,0xFF,0xE3,0xCD,0x5A,0xE7,0x74,0x82,0x05,0xBA, +0x80,0x25,0x38,0xCB,0xE4,0x69,0x9E,0xAF,0x41,0xAA,0x1A,0x84,0xF5,0x02,0x03,0x01, +0x00,0x01,0xA3,0x82,0x01,0x34,0x30,0x82,0x01,0x30,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, +0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55, +0x1D,0x0E,0x04,0x16,0x04,0x14,0xE3,0xAB,0x54,0x4C,0x80,0xA1,0xDB,0x56,0x43,0xB7, +0x91,0x4A,0xCB,0xF3,0x82,0x7A,0x13,0x5C,0x08,0xAB,0x30,0x81,0xED,0x06,0x03,0x55, +0x1D,0x1F,0x04,0x81,0xE5,0x30,0x81,0xE2,0x30,0x81,0xDF,0xA0,0x81,0xDC,0xA0,0x81, +0xD9,0x86,0x35,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72, +0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x72,0x6C, +0x2F,0x76,0x32,0x2F,0x74,0x63,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x32,0x5F,0x63, +0x61,0x5F,0x49,0x49,0x2E,0x63,0x72,0x6C,0x86,0x81,0x9F,0x6C,0x64,0x61,0x70,0x3A, +0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65, +0x72,0x2E,0x64,0x65,0x2F,0x43,0x4E,0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75, +0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x25,0x32,0x30,0x43,0x6C,0x61,0x73,0x73, +0x25,0x32,0x30,0x32,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x49,0x49,0x2C,0x4F, +0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65, +0x72,0x25,0x32,0x30,0x47,0x6D,0x62,0x48,0x2C,0x4F,0x55,0x3D,0x72,0x6F,0x6F,0x74, +0x63,0x65,0x72,0x74,0x73,0x2C,0x44,0x43,0x3D,0x74,0x72,0x75,0x73,0x74,0x63,0x65, +0x6E,0x74,0x65,0x72,0x2C,0x44,0x43,0x3D,0x64,0x65,0x3F,0x63,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x52,0x65,0x76,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E, +0x4C,0x69,0x73,0x74,0x3F,0x62,0x61,0x73,0x65,0x3F,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x8C,0xD7, +0xDF,0x7E,0xEE,0x1B,0x80,0x10,0xB3,0x83,0xF5,0xDB,0x11,0xEA,0x6B,0x4B,0xA8,0x92, +0x18,0xD9,0xF7,0x07,0x39,0xF5,0x2C,0xBE,0x06,0x75,0x7A,0x68,0x53,0x15,0x1C,0xEA, +0x4A,0xED,0x5E,0xFC,0x23,0xB2,0x13,0xA0,0xD3,0x09,0xFF,0xF6,0xF6,0x2E,0x6B,0x41, +0x71,0x79,0xCD,0xE2,0x6D,0xFD,0xAE,0x59,0x6B,0x85,0x1D,0xB8,0x4E,0x22,0x9A,0xED, +0x66,0x39,0x6E,0x4B,0x94,0xE6,0x55,0xFC,0x0B,0x1B,0x8B,0x77,0xC1,0x53,0x13,0x66, +0x89,0xD9,0x28,0xD6,0x8B,0xF3,0x45,0x4A,0x63,0xB7,0xFD,0x7B,0x0B,0x61,0x5D,0xB8, +0x6D,0xBE,0xC3,0xDC,0x5B,0x79,0xD2,0xED,0x86,0xE5,0xA2,0x4D,0xBE,0x5E,0x74,0x7C, +0x6A,0xED,0x16,0x38,0x1F,0x7F,0x58,0x81,0x5A,0x1A,0xEB,0x32,0x88,0x2D,0xB2,0xF3, +0x39,0x77,0x80,0xAF,0x5E,0xB6,0x61,0x75,0x29,0xDB,0x23,0x4D,0x88,0xCA,0x50,0x28, +0xCB,0x85,0xD2,0xD3,0x10,0xA2,0x59,0x6E,0xD3,0x93,0x54,0x00,0x7A,0xA2,0x46,0x95, +0x86,0x05,0x9C,0xA9,0x19,0x98,0xE5,0x31,0x72,0x0C,0x00,0xE2,0x67,0xD9,0x40,0xE0, +0x24,0x33,0x7B,0x6F,0x2C,0xB9,0x5C,0xAB,0x65,0x9D,0x2C,0xAC,0x76,0xEA,0x35,0x99, +0xF5,0x97,0xB9,0x0F,0x24,0xEC,0xC7,0x76,0x21,0x28,0x65,0xAE,0x57,0xE8,0x07,0x88, +0x75,0x4A,0x56,0xA0,0xD2,0x05,0x3A,0xA4,0xE6,0x8D,0x92,0x88,0x2C,0xF3,0xF2,0xE1, +0xC1,0xC6,0x61,0xDB,0x41,0xC5,0xC7,0x9B,0xF7,0x0E,0x1A,0x51,0x45,0xC2,0x61,0x6B, +0xDC,0x64,0x27,0x17,0x8C,0x5A,0xB7,0xDA,0x74,0x28,0xCD,0x97,0xE4,0xBD, +}; + + +/* subject:/O=Cybertrust, Inc/CN=Cybertrust Global Root */ +/* issuer :/O=Cybertrust, Inc/CN=Cybertrust Global Root */ + + +const unsigned char Cybertrust_Global_Root_certificate[933]={ +0x30,0x82,0x03,0xA1,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x0F,0x85,0xAA,0x2D,0x48,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x3B,0x31,0x18,0x30,0x16,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0F,0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74, +0x2C,0x20,0x49,0x6E,0x63,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16, +0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x31,0x35, +0x30,0x38,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x31,0x31,0x32,0x31,0x35,0x30, +0x38,0x30,0x30,0x30,0x30,0x5A,0x30,0x3B,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0F,0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49, +0x6E,0x63,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x43,0x79,0x62, +0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52, +0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02, +0x82,0x01,0x01,0x00,0xF8,0xC8,0xBC,0xBD,0x14,0x50,0x66,0x13,0xFF,0xF0,0xD3,0x79, +0xEC,0x23,0xF2,0xB7,0x1A,0xC7,0x8E,0x85,0xF1,0x12,0x73,0xA6,0x19,0xAA,0x10,0xDB, +0x9C,0xA2,0x65,0x74,0x5A,0x77,0x3E,0x51,0x7D,0x56,0xF6,0xDC,0x23,0xB6,0xD4,0xED, +0x5F,0x58,0xB1,0x37,0x4D,0xD5,0x49,0x0E,0x6E,0xF5,0x6A,0x87,0xD6,0xD2,0x8C,0xD2, +0x27,0xC6,0xE2,0xFF,0x36,0x9F,0x98,0x65,0xA0,0x13,0x4E,0xC6,0x2A,0x64,0x9B,0xD5, +0x90,0x12,0xCF,0x14,0x06,0xF4,0x3B,0xE3,0xD4,0x28,0xBE,0xE8,0x0E,0xF8,0xAB,0x4E, +0x48,0x94,0x6D,0x8E,0x95,0x31,0x10,0x5C,0xED,0xA2,0x2D,0xBD,0xD5,0x3A,0x6D,0xB2, +0x1C,0xBB,0x60,0xC0,0x46,0x4B,0x01,0xF5,0x49,0xAE,0x7E,0x46,0x8A,0xD0,0x74,0x8D, +0xA1,0x0C,0x02,0xCE,0xEE,0xFC,0xE7,0x8F,0xB8,0x6B,0x66,0xF3,0x7F,0x44,0x00,0xBF, +0x66,0x25,0x14,0x2B,0xDD,0x10,0x30,0x1D,0x07,0x96,0x3F,0x4D,0xF6,0x6B,0xB8,0x8F, +0xB7,0x7B,0x0C,0xA5,0x38,0xEB,0xDE,0x47,0xDB,0xD5,0x5D,0x39,0xFC,0x88,0xA7,0xF3, +0xD7,0x2A,0x74,0xF1,0xE8,0x5A,0xA2,0x3B,0x9F,0x50,0xBA,0xA6,0x8C,0x45,0x35,0xC2, +0x50,0x65,0x95,0xDC,0x63,0x82,0xEF,0xDD,0xBF,0x77,0x4D,0x9C,0x62,0xC9,0x63,0x73, +0x16,0xD0,0x29,0x0F,0x49,0xA9,0x48,0xF0,0xB3,0xAA,0xB7,0x6C,0xC5,0xA7,0x30,0x39, +0x40,0x5D,0xAE,0xC4,0xE2,0x5D,0x26,0x53,0xF0,0xCE,0x1C,0x23,0x08,0x61,0xA8,0x94, +0x19,0xBA,0x04,0x62,0x40,0xEC,0x1F,0x38,0x70,0x77,0x12,0x06,0x71,0xA7,0x30,0x18, +0x5D,0x25,0x27,0xA5,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xA5,0x30,0x81,0xA2,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30, +0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB6,0x08,0x7B,0x0D,0x7A, +0xCC,0xAC,0x20,0x4C,0x86,0x56,0x32,0x5E,0xCF,0xAB,0x6E,0x85,0x2D,0x70,0x57,0x30, +0x3F,0x06,0x03,0x55,0x1D,0x1F,0x04,0x38,0x30,0x36,0x30,0x34,0xA0,0x32,0xA0,0x30, +0x86,0x2E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x32,0x2E,0x70,0x75, +0x62,0x6C,0x69,0x63,0x2D,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x63, +0x72,0x6C,0x2F,0x63,0x74,0x2F,0x63,0x74,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C, +0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xB6,0x08,0x7B, +0x0D,0x7A,0xCC,0xAC,0x20,0x4C,0x86,0x56,0x32,0x5E,0xCF,0xAB,0x6E,0x85,0x2D,0x70, +0x57,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x82,0x01,0x01,0x00,0x56,0xEF,0x0A,0x23,0xA0,0x54,0x4E,0x95,0x97,0xC9,0xF8, +0x89,0xDA,0x45,0xC1,0xD4,0xA3,0x00,0x25,0xF4,0x1F,0x13,0xAB,0xB7,0xA3,0x85,0x58, +0x69,0xC2,0x30,0xAD,0xD8,0x15,0x8A,0x2D,0xE3,0xC9,0xCD,0x81,0x5A,0xF8,0x73,0x23, +0x5A,0xA7,0x7C,0x05,0xF3,0xFD,0x22,0x3B,0x0E,0xD1,0x06,0xC4,0xDB,0x36,0x4C,0x73, +0x04,0x8E,0xE5,0xB0,0x22,0xE4,0xC5,0xF3,0x2E,0xA5,0xD9,0x23,0xE3,0xB8,0x4E,0x4A, +0x20,0xA7,0x6E,0x02,0x24,0x9F,0x22,0x60,0x67,0x7B,0x8B,0x1D,0x72,0x09,0xC5,0x31, +0x5C,0xE9,0x79,0x9F,0x80,0x47,0x3D,0xAD,0xA1,0x0B,0x07,0x14,0x3D,0x47,0xFF,0x03, +0x69,0x1A,0x0C,0x0B,0x44,0xE7,0x63,0x25,0xA7,0x7F,0xB2,0xC9,0xB8,0x76,0x84,0xED, +0x23,0xF6,0x7D,0x07,0xAB,0x45,0x7E,0xD3,0xDF,0xB3,0xBF,0xE9,0x8A,0xB6,0xCD,0xA8, +0xA2,0x67,0x2B,0x52,0xD5,0xB7,0x65,0xF0,0x39,0x4C,0x63,0xA0,0x91,0x79,0x93,0x52, +0x0F,0x54,0xDD,0x83,0xBB,0x9F,0xD1,0x8F,0xA7,0x53,0x73,0xC3,0xCB,0xFF,0x30,0xEC, +0x7C,0x04,0xB8,0xD8,0x44,0x1F,0x93,0x5F,0x71,0x09,0x22,0xB7,0x6E,0x3E,0xEA,0x1C, +0x03,0x4E,0x9D,0x1A,0x20,0x61,0xFB,0x81,0x37,0xEC,0x5E,0xFC,0x0A,0x45,0xAB,0xD7, +0xE7,0x17,0x55,0xD0,0xA0,0xEA,0x60,0x9B,0xA6,0xF6,0xE3,0x8C,0x5B,0x29,0xC2,0x06, +0x60,0x14,0x9D,0x2D,0x97,0x4C,0xA9,0x93,0x15,0x9D,0x61,0xC4,0x01,0x5F,0x48,0xD6, +0x58,0xBD,0x56,0x31,0x12,0x4E,0x11,0xC8,0x21,0xE0,0xB3,0x11,0x91,0x65,0xDB,0xB4, +0xA6,0x88,0x38,0xCE,0x55, +}; + + +/* subject:/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2012 Entrust, Inc. - for authorized use only/CN=Entrust Root Certification Authority - EC1 */ +/* issuer :/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2012 Entrust, Inc. - for authorized use only/CN=Entrust Root Certification Authority - EC1 */ + + +const unsigned char Entrust_Root_Certification_Authority___EC1_certificate[765]={ +0x30,0x82,0x02,0xF9,0x30,0x82,0x02,0x80,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x00, +0xA6,0x8B,0x79,0x29,0x00,0x00,0x00,0x00,0x50,0xD0,0x91,0xF9,0x30,0x0A,0x06,0x08, +0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0xBF,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0D,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E, +0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65,0x20,0x77, +0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6C, +0x65,0x67,0x61,0x6C,0x2D,0x74,0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37,0x06,0x03, +0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x32,0x20,0x45,0x6E, +0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x66,0x6F, +0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65, +0x20,0x6F,0x6E,0x6C,0x79,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03,0x13,0x2A, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x45,0x43,0x31,0x30,0x1E,0x17,0x0D,0x31,0x32, +0x31,0x32,0x31,0x38,0x31,0x35,0x32,0x35,0x33,0x36,0x5A,0x17,0x0D,0x33,0x37,0x31, +0x32,0x31,0x38,0x31,0x35,0x35,0x35,0x33,0x36,0x5A,0x30,0x81,0xBF,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65, +0x20,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74, +0x2F,0x6C,0x65,0x67,0x61,0x6C,0x2D,0x74,0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37, +0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x32,0x20, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20, +0x66,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75, +0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03, +0x13,0x2A,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x45,0x43,0x31,0x30,0x76,0x30,0x10, +0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22, +0x03,0x62,0x00,0x04,0x84,0x13,0xC9,0xD0,0xBA,0x6D,0x41,0x7B,0xE2,0x6C,0xD0,0xEB, +0x55,0x5F,0x66,0x02,0x1A,0x24,0xF4,0x5B,0x89,0x69,0x47,0xE3,0xB8,0xC2,0x7D,0xF1, +0xF2,0x02,0xC5,0x9F,0xA0,0xF6,0x5B,0xD5,0x8B,0x06,0x19,0x86,0x4F,0x53,0x10,0x6D, +0x07,0x24,0x27,0xA1,0xA0,0xF8,0xD5,0x47,0x19,0x61,0x4C,0x7D,0xCA,0x93,0x27,0xEA, +0x74,0x0C,0xEF,0x6F,0x96,0x09,0xFE,0x63,0xEC,0x70,0x5D,0x36,0xAD,0x67,0x77,0xAE, +0xC9,0x9D,0x7C,0x55,0x44,0x3A,0xA2,0x63,0x51,0x1F,0xF5,0xE3,0x62,0xD4,0xA9,0x47, +0x07,0x3E,0xCC,0x20,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01, +0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01, +0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E, +0x04,0x16,0x04,0x14,0xB7,0x63,0xE7,0x1A,0xDD,0x8D,0xE9,0x08,0xA6,0x55,0x83,0xA4, +0xE0,0x6A,0x50,0x41,0x65,0x11,0x42,0x49,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE, +0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30,0x61,0x79,0xD8,0xE5,0x42, +0x47,0xDF,0x1C,0xAE,0x53,0x99,0x17,0xB6,0x6F,0x1C,0x7D,0xE1,0xBF,0x11,0x94,0xD1, +0x03,0x88,0x75,0xE4,0x8D,0x89,0xA4,0x8A,0x77,0x46,0xDE,0x6D,0x61,0xEF,0x02,0xF5, +0xFB,0xB5,0xDF,0xCC,0xFE,0x4E,0xFF,0xFE,0xA9,0xE6,0xA7,0x02,0x30,0x5B,0x99,0xD7, +0x85,0x37,0x06,0xB5,0x7B,0x08,0xFD,0xEB,0x27,0x8B,0x4A,0x94,0xF9,0xE1,0xFA,0xA7, +0x8E,0x26,0x08,0xE8,0x7C,0x92,0x68,0x6D,0x73,0xD8,0x6F,0x26,0xAC,0x21,0x02,0xB8, +0x99,0xB7,0x26,0x41,0x5B,0x25,0x60,0xAE,0xD0,0x48,0x1A,0xEE,0x06, +}; + + +/* subject:/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ +/* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ + + +const unsigned char GeoTrust_Primary_Certification_Authority___G2_certificate[690]={ +0x30,0x82,0x02,0xAE,0x30,0x82,0x02,0x35,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x3C, +0xB2,0xF4,0x48,0x0A,0x00,0xE2,0xFE,0xEB,0x24,0x3B,0x5E,0x60,0x3E,0xC3,0x6B,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x98,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49, +0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63, +0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, +0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F, +0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x36, +0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66, +0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31,0x30,0x35, +0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, +0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x98,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13, +0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39, +0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x30, +0x37,0x20,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x20, +0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64, +0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x36,0x30,0x34,0x06,0x03,0x55, +0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x69, +0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, +0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47, +0x32,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x15,0xB1,0xE8,0xFD,0x03,0x15,0x43, +0xE5,0xAC,0xEB,0x87,0x37,0x11,0x62,0xEF,0xD2,0x83,0x36,0x52,0x7D,0x45,0x57,0x0B, +0x4A,0x8D,0x7B,0x54,0x3B,0x3A,0x6E,0x5F,0x15,0x02,0xC0,0x50,0xA6,0xCF,0x25,0x2F, +0x7D,0xCA,0x48,0xB8,0xC7,0x50,0x63,0x1C,0x2A,0x21,0x08,0x7C,0x9A,0x36,0xD8,0x0B, +0xFE,0xD1,0x26,0xC5,0x58,0x31,0x30,0x28,0x25,0xF3,0x5D,0x5D,0xA3,0xB8,0xB6,0xA5, +0xB4,0x92,0xED,0x6C,0x2C,0x9F,0xEB,0xDD,0x43,0x89,0xA2,0x3C,0x4B,0x48,0x91,0x1D, +0x50,0xEC,0x26,0xDF,0xD6,0x60,0x2E,0xBD,0x21,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x15,0x5F,0x35,0x57,0x51,0x55,0xFB, +0x25,0xB2,0xAD,0x03,0x69,0xFC,0x01,0xA3,0xFA,0xBE,0x11,0x55,0xD5,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30, +0x64,0x96,0x59,0xA6,0xE8,0x09,0xDE,0x8B,0xBA,0xFA,0x5A,0x88,0x88,0xF0,0x1F,0x91, +0xD3,0x46,0xA8,0xF2,0x4A,0x4C,0x02,0x63,0xFB,0x6C,0x5F,0x38,0xDB,0x2E,0x41,0x93, +0xA9,0x0E,0xE6,0x9D,0xDC,0x31,0x1C,0xB2,0xA0,0xA7,0x18,0x1C,0x79,0xE1,0xC7,0x36, +0x02,0x30,0x3A,0x56,0xAF,0x9A,0x74,0x6C,0xF6,0xFB,0x83,0xE0,0x33,0xD3,0x08,0x5F, +0xA1,0x9C,0xC2,0x5B,0x9F,0x46,0xD6,0xB6,0xCB,0x91,0x06,0x63,0xA2,0x06,0xE7,0x33, +0xAC,0x3E,0xA8,0x81,0x12,0xD0,0xCB,0xBA,0xD0,0x92,0x0B,0xB6,0x9E,0x96,0xAA,0x04, +0x0F,0x8A, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 */ + + +const unsigned char GeoTrust_Global_CA_2_certificate[874]={ +0x30,0x82,0x03,0x66,0x30,0x82,0x02,0x4E,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x03,0x13, +0x14,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C, +0x20,0x43,0x41,0x20,0x32,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x33,0x30,0x34,0x30, +0x35,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x31,0x39,0x30,0x33,0x30,0x34,0x30,0x35, +0x30,0x30,0x30,0x30,0x5A,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47, +0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B, +0x06,0x03,0x55,0x04,0x03,0x13,0x14,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x41,0x20,0x32,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xEF,0x3C,0x4D,0x40, +0x3D,0x10,0xDF,0x3B,0x53,0x00,0xE1,0x67,0xFE,0x94,0x60,0x15,0x3E,0x85,0x88,0xF1, +0x89,0x0D,0x90,0xC8,0x28,0x23,0x99,0x05,0xE8,0x2B,0x20,0x9D,0xC6,0xF3,0x60,0x46, +0xD8,0xC1,0xB2,0xD5,0x8C,0x31,0xD9,0xDC,0x20,0x79,0x24,0x81,0xBF,0x35,0x32,0xFC, +0x63,0x69,0xDB,0xB1,0x2A,0x6B,0xEE,0x21,0x58,0xF2,0x08,0xE9,0x78,0xCB,0x6F,0xCB, +0xFC,0x16,0x52,0xC8,0x91,0xC4,0xFF,0x3D,0x73,0xDE,0xB1,0x3E,0xA7,0xC2,0x7D,0x66, +0xC1,0xF5,0x7E,0x52,0x24,0x1A,0xE2,0xD5,0x67,0x91,0xD0,0x82,0x10,0xD7,0x78,0x4B, +0x4F,0x2B,0x42,0x39,0xBD,0x64,0x2D,0x40,0xA0,0xB0,0x10,0xD3,0x38,0x48,0x46,0x88, +0xA1,0x0C,0xBB,0x3A,0x33,0x2A,0x62,0x98,0xFB,0x00,0x9D,0x13,0x59,0x7F,0x6F,0x3B, +0x72,0xAA,0xEE,0xA6,0x0F,0x86,0xF9,0x05,0x61,0xEA,0x67,0x7F,0x0C,0x37,0x96,0x8B, +0xE6,0x69,0x16,0x47,0x11,0xC2,0x27,0x59,0x03,0xB3,0xA6,0x60,0xC2,0x21,0x40,0x56, +0xFA,0xA0,0xC7,0x7D,0x3A,0x13,0xE3,0xEC,0x57,0xC7,0xB3,0xD6,0xAE,0x9D,0x89,0x80, +0xF7,0x01,0xE7,0x2C,0xF6,0x96,0x2B,0x13,0x0D,0x79,0x2C,0xD9,0xC0,0xE4,0x86,0x7B, +0x4B,0x8C,0x0C,0x72,0x82,0x8A,0xFB,0x17,0xCD,0x00,0x6C,0x3A,0x13,0x3C,0xB0,0x84, +0x87,0x4B,0x16,0x7A,0x29,0xB2,0x4F,0xDB,0x1D,0xD4,0x0B,0xF3,0x66,0x37,0xBD,0xD8, +0xF6,0x57,0xBB,0x5E,0x24,0x7A,0xB8,0x3C,0x8B,0xB9,0xFA,0x92,0x1A,0x1A,0x84,0x9E, +0xD8,0x74,0x8F,0xAA,0x1B,0x7F,0x5E,0xF4,0xFE,0x45,0x22,0x21,0x02,0x03,0x01,0x00, +0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x71,0x38,0x36,0xF2,0x02,0x31,0x53,0x47,0x2B,0x6E,0xBA,0x65,0x46,0xA9,0x10, +0x15,0x58,0x20,0x05,0x09,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16, +0x80,0x14,0x71,0x38,0x36,0xF2,0x02,0x31,0x53,0x47,0x2B,0x6E,0xBA,0x65,0x46,0xA9, +0x10,0x15,0x58,0x20,0x05,0x09,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x03,0xF7,0xB5,0x2B,0xAB,0x5D, +0x10,0xFC,0x7B,0xB2,0xB2,0x5E,0xAC,0x9B,0x0E,0x7E,0x53,0x78,0x59,0x3E,0x42,0x04, +0xFE,0x75,0xA3,0xAD,0xAC,0x81,0x4E,0xD7,0x02,0x8B,0x5E,0xC4,0x2D,0xC8,0x52,0x76, +0xC7,0x2C,0x1F,0xFC,0x81,0x32,0x98,0xD1,0x4B,0xC6,0x92,0x93,0x33,0x35,0x31,0x2F, +0xFC,0xD8,0x1D,0x44,0xDD,0xE0,0x81,0x7F,0x9D,0xE9,0x8B,0xE1,0x64,0x91,0x62,0x0B, +0x39,0x08,0x8C,0xAC,0x74,0x9D,0x59,0xD9,0x7A,0x59,0x52,0x97,0x11,0xB9,0x16,0x7B, +0x6F,0x45,0xD3,0x96,0xD9,0x31,0x7D,0x02,0x36,0x0F,0x9C,0x3B,0x6E,0xCF,0x2C,0x0D, +0x03,0x46,0x45,0xEB,0xA0,0xF4,0x7F,0x48,0x44,0xC6,0x08,0x40,0xCC,0xDE,0x1B,0x70, +0xB5,0x29,0xAD,0xBA,0x8B,0x3B,0x34,0x65,0x75,0x1B,0x71,0x21,0x1D,0x2C,0x14,0x0A, +0xB0,0x96,0x95,0xB8,0xD6,0xEA,0xF2,0x65,0xFB,0x29,0xBA,0x4F,0xEA,0x91,0x93,0x74, +0x69,0xB6,0xF2,0xFF,0xE1,0x1A,0xD0,0x0C,0xD1,0x76,0x85,0xCB,0x8A,0x25,0xBD,0x97, +0x5E,0x2C,0x6F,0x15,0x99,0x26,0xE7,0xB6,0x29,0xFF,0x22,0xEC,0xC9,0x02,0xC7,0x56, +0x00,0xCD,0x49,0xB9,0xB3,0x6C,0x7B,0x53,0x04,0x1A,0xE2,0xA8,0xC9,0xAA,0x12,0x05, +0x23,0xC2,0xCE,0xE7,0xBB,0x04,0x02,0xCC,0xC0,0x47,0xA2,0xE4,0xC4,0x29,0x2F,0x5B, +0x45,0x57,0x89,0x51,0xEE,0x3C,0xEB,0x52,0x08,0xFF,0x07,0x35,0x1E,0x9F,0x35,0x6A, +0x47,0x4A,0x56,0x98,0xD1,0x5A,0x85,0x1F,0x8C,0xF5,0x22,0xBF,0xAB,0xCE,0x83,0xF3, +0xE2,0x22,0x29,0xAE,0x7D,0x83,0x40,0xA8,0xBA,0x6C, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */ + + +const unsigned char COMODO_RSA_Certification_Authority_certificate[1500]={ +0x30,0x82,0x05,0xD8,0x30,0x82,0x03,0xC0,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4C, +0xAA,0xF9,0xCA,0xDB,0x63,0x6F,0xE0,0x1F,0xF7,0x4E,0xD8,0x5B,0x03,0x86,0x9D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81, +0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55, +0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30,0x31,0x31,0x39, +0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, +0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13, +0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73, +0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61, +0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11, +0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65, +0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F, +0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82, +0x02,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05, +0x00,0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0x91, +0xE8,0x54,0x92,0xD2,0x0A,0x56,0xB1,0xAC,0x0D,0x24,0xDD,0xC5,0xCF,0x44,0x67,0x74, +0x99,0x2B,0x37,0xA3,0x7D,0x23,0x70,0x00,0x71,0xBC,0x53,0xDF,0xC4,0xFA,0x2A,0x12, +0x8F,0x4B,0x7F,0x10,0x56,0xBD,0x9F,0x70,0x72,0xB7,0x61,0x7F,0xC9,0x4B,0x0F,0x17, +0xA7,0x3D,0xE3,0xB0,0x04,0x61,0xEE,0xFF,0x11,0x97,0xC7,0xF4,0x86,0x3E,0x0A,0xFA, +0x3E,0x5C,0xF9,0x93,0xE6,0x34,0x7A,0xD9,0x14,0x6B,0xE7,0x9C,0xB3,0x85,0xA0,0x82, +0x7A,0x76,0xAF,0x71,0x90,0xD7,0xEC,0xFD,0x0D,0xFA,0x9C,0x6C,0xFA,0xDF,0xB0,0x82, +0xF4,0x14,0x7E,0xF9,0xBE,0xC4,0xA6,0x2F,0x4F,0x7F,0x99,0x7F,0xB5,0xFC,0x67,0x43, +0x72,0xBD,0x0C,0x00,0xD6,0x89,0xEB,0x6B,0x2C,0xD3,0xED,0x8F,0x98,0x1C,0x14,0xAB, +0x7E,0xE5,0xE3,0x6E,0xFC,0xD8,0xA8,0xE4,0x92,0x24,0xDA,0x43,0x6B,0x62,0xB8,0x55, +0xFD,0xEA,0xC1,0xBC,0x6C,0xB6,0x8B,0xF3,0x0E,0x8D,0x9A,0xE4,0x9B,0x6C,0x69,0x99, +0xF8,0x78,0x48,0x30,0x45,0xD5,0xAD,0xE1,0x0D,0x3C,0x45,0x60,0xFC,0x32,0x96,0x51, +0x27,0xBC,0x67,0xC3,0xCA,0x2E,0xB6,0x6B,0xEA,0x46,0xC7,0xC7,0x20,0xA0,0xB1,0x1F, +0x65,0xDE,0x48,0x08,0xBA,0xA4,0x4E,0xA9,0xF2,0x83,0x46,0x37,0x84,0xEB,0xE8,0xCC, +0x81,0x48,0x43,0x67,0x4E,0x72,0x2A,0x9B,0x5C,0xBD,0x4C,0x1B,0x28,0x8A,0x5C,0x22, +0x7B,0xB4,0xAB,0x98,0xD9,0xEE,0xE0,0x51,0x83,0xC3,0x09,0x46,0x4E,0x6D,0x3E,0x99, +0xFA,0x95,0x17,0xDA,0x7C,0x33,0x57,0x41,0x3C,0x8D,0x51,0xED,0x0B,0xB6,0x5C,0xAF, +0x2C,0x63,0x1A,0xDF,0x57,0xC8,0x3F,0xBC,0xE9,0x5D,0xC4,0x9B,0xAF,0x45,0x99,0xE2, +0xA3,0x5A,0x24,0xB4,0xBA,0xA9,0x56,0x3D,0xCF,0x6F,0xAA,0xFF,0x49,0x58,0xBE,0xF0, +0xA8,0xFF,0xF4,0xB8,0xAD,0xE9,0x37,0xFB,0xBA,0xB8,0xF4,0x0B,0x3A,0xF9,0xE8,0x43, +0x42,0x1E,0x89,0xD8,0x84,0xCB,0x13,0xF1,0xD9,0xBB,0xE1,0x89,0x60,0xB8,0x8C,0x28, +0x56,0xAC,0x14,0x1D,0x9C,0x0A,0xE7,0x71,0xEB,0xCF,0x0E,0xDD,0x3D,0xA9,0x96,0xA1, +0x48,0xBD,0x3C,0xF7,0xAF,0xB5,0x0D,0x22,0x4C,0xC0,0x11,0x81,0xEC,0x56,0x3B,0xF6, +0xD3,0xA2,0xE2,0x5B,0xB7,0xB2,0x04,0x22,0x52,0x95,0x80,0x93,0x69,0xE8,0x8E,0x4C, +0x65,0xF1,0x91,0x03,0x2D,0x70,0x74,0x02,0xEA,0x8B,0x67,0x15,0x29,0x69,0x52,0x02, +0xBB,0xD7,0xDF,0x50,0x6A,0x55,0x46,0xBF,0xA0,0xA3,0x28,0x61,0x7F,0x70,0xD0,0xC3, +0xA2,0xAA,0x2C,0x21,0xAA,0x47,0xCE,0x28,0x9C,0x06,0x45,0x76,0xBF,0x82,0x18,0x27, +0xB4,0xD5,0xAE,0xB4,0xCB,0x50,0xE6,0x6B,0xF4,0x4C,0x86,0x71,0x30,0xE9,0xA6,0xDF, +0x16,0x86,0xE0,0xD8,0xFF,0x40,0xDD,0xFB,0xD0,0x42,0x88,0x7F,0xA3,0x33,0x3A,0x2E, +0x5C,0x1E,0x41,0x11,0x81,0x63,0xCE,0x18,0x71,0x6B,0x2B,0xEC,0xA6,0x8A,0xB7,0x31, +0x5C,0x3A,0x6A,0x47,0xE0,0xC3,0x79,0x59,0xD6,0x20,0x1A,0xAF,0xF2,0x6A,0x98,0xAA, +0x72,0xBC,0x57,0x4A,0xD2,0x4B,0x9D,0xBB,0x10,0xFC,0xB0,0x4C,0x41,0xE5,0xED,0x1D, +0x3D,0x5E,0x28,0x9D,0x9C,0xCC,0xBF,0xB3,0x51,0xDA,0xA7,0x47,0xE5,0x84,0x53,0x02, +0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0xBB,0xAF,0x7E,0x02,0x3D,0xFA,0xA6,0xF1,0x3C,0x84,0x8E,0xAD,0xEE, +0x38,0x98,0xEC,0xD9,0x32,0x32,0xD4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, +0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x0A,0xF1,0xD5,0x46, +0x84,0xB7,0xAE,0x51,0xBB,0x6C,0xB2,0x4D,0x41,0x14,0x00,0x93,0x4C,0x9C,0xCB,0xE5, +0xC0,0x54,0xCF,0xA0,0x25,0x8E,0x02,0xF9,0xFD,0xB0,0xA2,0x0D,0xF5,0x20,0x98,0x3C, +0x13,0x2D,0xAC,0x56,0xA2,0xB0,0xD6,0x7E,0x11,0x92,0xE9,0x2E,0xBA,0x9E,0x2E,0x9A, +0x72,0xB1,0xBD,0x19,0x44,0x6C,0x61,0x35,0xA2,0x9A,0xB4,0x16,0x12,0x69,0x5A,0x8C, +0xE1,0xD7,0x3E,0xA4,0x1A,0xE8,0x2F,0x03,0xF4,0xAE,0x61,0x1D,0x10,0x1B,0x2A,0xA4, +0x8B,0x7A,0xC5,0xFE,0x05,0xA6,0xE1,0xC0,0xD6,0xC8,0xFE,0x9E,0xAE,0x8F,0x2B,0xBA, +0x3D,0x99,0xF8,0xD8,0x73,0x09,0x58,0x46,0x6E,0xA6,0x9C,0xF4,0xD7,0x27,0xD3,0x95, +0xDA,0x37,0x83,0x72,0x1C,0xD3,0x73,0xE0,0xA2,0x47,0x99,0x03,0x38,0x5D,0xD5,0x49, +0x79,0x00,0x29,0x1C,0xC7,0xEC,0x9B,0x20,0x1C,0x07,0x24,0x69,0x57,0x78,0xB2,0x39, +0xFC,0x3A,0x84,0xA0,0xB5,0x9C,0x7C,0x8D,0xBF,0x2E,0x93,0x62,0x27,0xB7,0x39,0xDA, +0x17,0x18,0xAE,0xBD,0x3C,0x09,0x68,0xFF,0x84,0x9B,0x3C,0xD5,0xD6,0x0B,0x03,0xE3, +0x57,0x9E,0x14,0xF7,0xD1,0xEB,0x4F,0xC8,0xBD,0x87,0x23,0xB7,0xB6,0x49,0x43,0x79, +0x85,0x5C,0xBA,0xEB,0x92,0x0B,0xA1,0xC6,0xE8,0x68,0xA8,0x4C,0x16,0xB1,0x1A,0x99, +0x0A,0xE8,0x53,0x2C,0x92,0xBB,0xA1,0x09,0x18,0x75,0x0C,0x65,0xA8,0x7B,0xCB,0x23, +0xB7,0x1A,0xC2,0x28,0x85,0xC3,0x1B,0xFF,0xD0,0x2B,0x62,0xEF,0xA4,0x7B,0x09,0x91, +0x98,0x67,0x8C,0x14,0x01,0xCD,0x68,0x06,0x6A,0x63,0x21,0x75,0x03,0x80,0x88,0x8A, +0x6E,0x81,0xC6,0x85,0xF2,0xA9,0xA4,0x2D,0xE7,0xF4,0xA5,0x24,0x10,0x47,0x83,0xCA, +0xCD,0xF4,0x8D,0x79,0x58,0xB1,0x06,0x9B,0xE7,0x1A,0x2A,0xD9,0x9D,0x01,0xD7,0x94, +0x7D,0xED,0x03,0x4A,0xCA,0xF0,0xDB,0xE8,0xA9,0x01,0x3E,0xF5,0x56,0x99,0xC9,0x1E, +0x8E,0x49,0x3D,0xBB,0xE5,0x09,0xB9,0xE0,0x4F,0x49,0x92,0x3D,0x16,0x82,0x40,0xCC, +0xCC,0x59,0xC6,0xE6,0x3A,0xED,0x12,0x2E,0x69,0x3C,0x6C,0x95,0xB1,0xFD,0xAA,0x1D, +0x7B,0x7F,0x86,0xBE,0x1E,0x0E,0x32,0x46,0xFB,0xFB,0x13,0x8F,0x75,0x7F,0x4C,0x8B, +0x4B,0x46,0x63,0xFE,0x00,0x34,0x40,0x70,0xC1,0xC3,0xB9,0xA1,0xDD,0xA6,0x70,0xE2, +0x04,0xB3,0x41,0xBC,0xE9,0x80,0x91,0xEA,0x64,0x9C,0x7A,0xE1,0x22,0x03,0xA9,0x9C, +0x6E,0x6F,0x0E,0x65,0x4F,0x6C,0x87,0x87,0x5E,0xF3,0x6E,0xA0,0xF9,0x75,0xA5,0x9B, +0x40,0xE8,0x53,0xB2,0x27,0x9D,0x4A,0xB9,0xC0,0x77,0x21,0x8D,0xFF,0x87,0xF2,0xDE, +0xBC,0x8C,0xEF,0x17,0xDF,0xB7,0x49,0x0B,0xD1,0xF2,0x6E,0x30,0x0B,0x1A,0x0E,0x4E, +0x76,0xED,0x11,0xFC,0xF5,0xE9,0x56,0xB2,0x7D,0xBF,0xC7,0x6D,0x0A,0x93,0x8C,0xA5, +0xD0,0xC0,0xB6,0x1D,0xBE,0x3A,0x4E,0x94,0xA2,0xD7,0x6E,0x6C,0x0B,0xC2,0x8A,0x7C, +0xFA,0x20,0xF3,0xC4,0xE4,0xE5,0xCD,0x0D,0xA8,0xCB,0x91,0x92,0xB1,0x7C,0x85,0xEC, +0xB5,0x14,0x69,0x66,0x0E,0x82,0xE7,0xCD,0xCE,0xC8,0x2D,0xA6,0x51,0x7F,0x21,0xC1, +0x35,0x53,0x85,0x06,0x4A,0x5D,0x9F,0xAD,0xBB,0x1B,0x5F,0x74, +}; + + +/* subject:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC */ +/* issuer :/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC */ + + +const unsigned char UTN_DATACorp_SGC_Root_CA_certificate[1122]={ +0x30,0x82,0x04,0x5E,0x30,0x82,0x03,0x46,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x44, +0xBE,0x0C,0x8B,0x50,0x00,0x21,0xB4,0x11,0xD3,0x2A,0x68,0x06,0xA9,0xAD,0x69,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0x93,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20, +0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, +0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72, +0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03, +0x13,0x12,0x55,0x54,0x4E,0x20,0x2D,0x20,0x44,0x41,0x54,0x41,0x43,0x6F,0x72,0x70, +0x20,0x53,0x47,0x43,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36,0x32,0x34,0x31,0x38, +0x35,0x37,0x32,0x31,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32,0x34,0x31,0x39,0x30, +0x36,0x33,0x30,0x5A,0x30,0x81,0x93,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55, +0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74, +0x20,0x4C,0x61,0x6B,0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03, +0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55, +0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03, +0x55,0x04,0x0B,0x13,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E, +0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1B,0x30, +0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x55,0x54,0x4E,0x20,0x2D,0x20,0x44,0x41, +0x54,0x41,0x43,0x6F,0x72,0x70,0x20,0x53,0x47,0x43,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDF,0xEE,0x58,0x10,0xA2, +0x2B,0x6E,0x55,0xC4,0x8E,0xBF,0x2E,0x46,0x09,0xE7,0xE0,0x08,0x0F,0x2E,0x2B,0x7A, +0x13,0x94,0x1B,0xBD,0xF6,0xB6,0x80,0x8E,0x65,0x05,0x93,0x00,0x1E,0xBC,0xAF,0xE2, +0x0F,0x8E,0x19,0x0D,0x12,0x47,0xEC,0xAC,0xAD,0xA3,0xFA,0x2E,0x70,0xF8,0xDE,0x6E, +0xFB,0x56,0x42,0x15,0x9E,0x2E,0x5C,0xEF,0x23,0xDE,0x21,0xB9,0x05,0x76,0x27,0x19, +0x0F,0x4F,0xD6,0xC3,0x9C,0xB4,0xBE,0x94,0x19,0x63,0xF2,0xA6,0x11,0x0A,0xEB,0x53, +0x48,0x9C,0xBE,0xF2,0x29,0x3B,0x16,0xE8,0x1A,0xA0,0x4C,0xA6,0xC9,0xF4,0x18,0x59, +0x68,0xC0,0x70,0xF2,0x53,0x00,0xC0,0x5E,0x50,0x82,0xA5,0x56,0x6F,0x36,0xF9,0x4A, +0xE0,0x44,0x86,0xA0,0x4D,0x4E,0xD6,0x47,0x6E,0x49,0x4A,0xCB,0x67,0xD7,0xA6,0xC4, +0x05,0xB9,0x8E,0x1E,0xF4,0xFC,0xFF,0xCD,0xE7,0x36,0xE0,0x9C,0x05,0x6C,0xB2,0x33, +0x22,0x15,0xD0,0xB4,0xE0,0xCC,0x17,0xC0,0xB2,0xC0,0xF4,0xFE,0x32,0x3F,0x29,0x2A, +0x95,0x7B,0xD8,0xF2,0xA7,0x4E,0x0F,0x54,0x7C,0xA1,0x0D,0x80,0xB3,0x09,0x03,0xC1, +0xFF,0x5C,0xDD,0x5E,0x9A,0x3E,0xBC,0xAE,0xBC,0x47,0x8A,0x6A,0xAE,0x71,0xCA,0x1F, +0xB1,0x2A,0xB8,0x5F,0x42,0x05,0x0B,0xEC,0x46,0x30,0xD1,0x72,0x0B,0xCA,0xE9,0x56, +0x6D,0xF5,0xEF,0xDF,0x78,0xBE,0x61,0xBA,0xB2,0xA5,0xAE,0x04,0x4C,0xBC,0xA8,0xAC, +0x69,0x15,0x97,0xBD,0xEF,0xEB,0xB4,0x8C,0xBF,0x35,0xF8,0xD4,0xC3,0xD1,0x28,0x0E, +0x5C,0x3A,0x9F,0x70,0x18,0x33,0x20,0x77,0xC4,0xA2,0xAF,0x02,0x03,0x01,0x00,0x01, +0xA3,0x81,0xAB,0x30,0x81,0xA8,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03, +0x02,0x01,0xC6,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x53, +0x32,0xD1,0xB3,0xCF,0x7F,0xFA,0xE0,0xF1,0xA0,0x5D,0x85,0x4E,0x92,0xD2,0x9E,0x45, +0x1D,0xB4,0x4F,0x30,0x3D,0x06,0x03,0x55,0x1D,0x1F,0x04,0x36,0x30,0x34,0x30,0x32, +0xA0,0x30,0xA0,0x2E,0x86,0x2C,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C, +0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x55, +0x54,0x4E,0x2D,0x44,0x41,0x54,0x41,0x43,0x6F,0x72,0x70,0x53,0x47,0x43,0x2E,0x63, +0x72,0x6C,0x30,0x2A,0x06,0x03,0x55,0x1D,0x25,0x04,0x23,0x30,0x21,0x06,0x08,0x2B, +0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37, +0x0A,0x03,0x03,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x27,0x35,0x97,0x00,0x8A,0x8B,0x28,0xBD,0xC6,0x33,0x30,0x1E,0x29,0xFC, +0xE2,0xF7,0xD5,0x98,0xD4,0x40,0xBB,0x60,0xCA,0xBF,0xAB,0x17,0x2C,0x09,0x36,0x7F, +0x50,0xFA,0x41,0xDC,0xAE,0x96,0x3A,0x0A,0x23,0x3E,0x89,0x59,0xC9,0xA3,0x07,0xED, +0x1B,0x37,0xAD,0xFC,0x7C,0xBE,0x51,0x49,0x5A,0xDE,0x3A,0x0A,0x54,0x08,0x16,0x45, +0xC2,0x99,0xB1,0x87,0xCD,0x8C,0x68,0xE0,0x69,0x03,0xE9,0xC4,0x4E,0x98,0xB2,0x3B, +0x8C,0x16,0xB3,0x0E,0xA0,0x0C,0x98,0x50,0x9B,0x93,0xA9,0x70,0x09,0xC8,0x2C,0xA3, +0x8F,0xDF,0x02,0xE4,0xE0,0x71,0x3A,0xF1,0xB4,0x23,0x72,0xA0,0xAA,0x01,0xDF,0xDF, +0x98,0x3E,0x14,0x50,0xA0,0x31,0x26,0xBD,0x28,0xE9,0x5A,0x30,0x26,0x75,0xF9,0x7B, +0x60,0x1C,0x8D,0xF3,0xCD,0x50,0x26,0x6D,0x04,0x27,0x9A,0xDF,0xD5,0x0D,0x45,0x47, +0x29,0x6B,0x2C,0xE6,0x76,0xD9,0xA9,0x29,0x7D,0x32,0xDD,0xC9,0x36,0x3C,0xBD,0xAE, +0x35,0xF1,0x11,0x9E,0x1D,0xBB,0x90,0x3F,0x12,0x47,0x4E,0x8E,0xD7,0x7E,0x0F,0x62, +0x73,0x1D,0x52,0x26,0x38,0x1C,0x18,0x49,0xFD,0x30,0x74,0x9A,0xC4,0xE5,0x22,0x2F, +0xD8,0xC0,0x8D,0xED,0x91,0x7A,0x4C,0x00,0x8F,0x72,0x7F,0x5D,0xDA,0xDD,0x1B,0x8B, +0x45,0x6B,0xE7,0xDD,0x69,0x97,0xA8,0xC5,0x56,0x4C,0x0F,0x0C,0xF6,0x9F,0x7A,0x91, +0x37,0xF6,0x97,0x82,0xE0,0xDD,0x71,0x69,0xFF,0x76,0x3F,0x60,0x4D,0x3C,0xCF,0xF7, +0x99,0xF9,0xC6,0x57,0xF4,0xC9,0x55,0x39,0x78,0xBA,0x2C,0x79,0xC9,0xA6,0x88,0x2B, +0xF4,0x08, }; const unsigned char* kSSLCertCertificateList[] = { - AddTrust_External_Root_certificate, + GlobalSign_Root_CA_certificate, + USERTrust_RSA_Certification_Authority_certificate, + Starfield_Class_2_CA_certificate, + Verisign_Class_3_Public_Primary_Certification_Authority___G3_certificate, + USERTrust_ECC_Certification_Authority_certificate, + GeoTrust_Global_CA_certificate, + Starfield_Root_Certificate_Authority___G2_certificate, + DigiCert_Global_Root_G3_certificate, + thawte_Primary_Root_CA___G2_certificate, + VeriSign_Universal_Root_Certification_Authority_certificate, + VeriSign_Class_3_Public_Primary_Certification_Authority___G4_certificate, + DigiCert_Global_Root_G2_certificate, AddTrust_Low_Value_Services_Root_certificate, + AffirmTrust_Premium_ECC_certificate, + Verisign_Class_4_Public_Primary_Certification_Authority___G3_certificate, + thawte_Primary_Root_CA_certificate, AddTrust_Public_Services_Root_certificate, AddTrust_Qualified_Certificates_Root_certificate, - AffirmTrust_Commercial_certificate, - AffirmTrust_Networking_certificate, - AffirmTrust_Premium_certificate, - AffirmTrust_Premium_ECC_certificate, - America_Online_Root_Certification_Authority_1_certificate, - America_Online_Root_Certification_Authority_2_certificate, - Baltimore_CyberTrust_Root_certificate, - Comodo_AAA_Services_root_certificate, - COMODO_Certification_Authority_certificate, - COMODO_ECC_Certification_Authority_certificate, - Comodo_Secure_Services_root_certificate, - Comodo_Trusted_Services_root_certificate, - Cybertrust_Global_Root_certificate, - DigiCert_Assured_ID_Root_CA_certificate, - DigiCert_Global_Root_CA_certificate, - DigiCert_High_Assurance_EV_Root_CA_certificate, - Entrust_net_Premium_2048_Secure_Server_CA_certificate, - Entrust_net_Secure_Server_CA_certificate, - Entrust_Root_Certification_Authority_certificate, - Equifax_Secure_CA_certificate, - Equifax_Secure_eBusiness_CA_1_certificate, - Equifax_Secure_eBusiness_CA_2_certificate, - Equifax_Secure_Global_eBusiness_CA_certificate, - GeoTrust_Global_CA_certificate, - GeoTrust_Global_CA_2_certificate, - GeoTrust_Primary_Certification_Authority_certificate, - GeoTrust_Primary_Certification_Authority___G2_certificate, GeoTrust_Primary_Certification_Authority___G3_certificate, - GeoTrust_Universal_CA_certificate, GeoTrust_Universal_CA_2_certificate, - GlobalSign_Root_CA_certificate, + Baltimore_CyberTrust_Root_certificate, GlobalSign_Root_CA___R2_certificate, GlobalSign_Root_CA___R3_certificate, - Go_Daddy_Class_2_CA_certificate, - Go_Daddy_Root_Certificate_Authority___G2_certificate, - GTE_CyberTrust_Global_Root_certificate, - Network_Solutions_Certificate_Authority_certificate, - RSA_Root_Certificate_1_certificate, - Starfield_Class_2_CA_certificate, - Starfield_Root_Certificate_Authority___G2_certificate, - Starfield_Services_Root_Certificate_Authority___G2_certificate, - StartCom_Certification_Authority_certificate, - StartCom_Certification_Authority_G2_certificate, - TC_TrustCenter_Class_2_CA_II_certificate, - TC_TrustCenter_Class_3_CA_II_certificate, - TC_TrustCenter_Universal_CA_I_certificate, - TC_TrustCenter_Universal_CA_III_certificate, - Thawte_Premium_Server_CA_certificate, - thawte_Primary_Root_CA_certificate, - thawte_Primary_Root_CA___G2_certificate, + AffirmTrust_Networking_certificate, + AddTrust_External_Root_certificate, thawte_Primary_Root_CA___G3_certificate, - Thawte_Server_CA_certificate, - UTN_DATACorp_SGC_Root_CA_certificate, - UTN_USERFirst_Hardware_Root_CA_certificate, - ValiCert_Class_1_VA_certificate, - ValiCert_Class_2_VA_certificate, - Verisign_Class_3_Public_Primary_Certification_Authority_certificate, - Verisign_Class_3_Public_Primary_Certification_Authority___G2_certificate, - Verisign_Class_3_Public_Primary_Certification_Authority___G3_certificate, - VeriSign_Class_3_Public_Primary_Certification_Authority___G4_certificate, + DigiCert_Assured_ID_Root_CA_certificate, + Go_Daddy_Class_2_CA_certificate, + GeoTrust_Primary_Certification_Authority_certificate, VeriSign_Class_3_Public_Primary_Certification_Authority___G5_certificate, - Verisign_Class_4_Public_Primary_Certification_Authority___G3_certificate, - VeriSign_Universal_Root_Certification_Authority_certificate, - XRamp_Global_CA_Root_certificate, + Equifax_Secure_CA_certificate, + Entrust_net_Premium_2048_Secure_Server_CA_certificate, + DigiCert_Assured_ID_Root_G3_certificate, + COMODO_Certification_Authority_certificate, + DigiCert_Global_Root_CA_certificate, + Comodo_AAA_Services_root_certificate, + DigiCert_High_Assurance_EV_Root_CA_certificate, + GeoTrust_Universal_CA_certificate, + COMODO_ECC_Certification_Authority_certificate, + Entrust_Root_Certification_Authority___G2_certificate, + DigiCert_Assured_ID_Root_G2_certificate, + AffirmTrust_Commercial_certificate, + AffirmTrust_Premium_certificate, + Go_Daddy_Root_Certificate_Authority___G2_certificate, + Comodo_Secure_Services_root_certificate, + DigiCert_Trusted_Root_G4_certificate, + GlobalSign_ECC_Root_CA___R5_certificate, + UTN_USERFirst_Hardware_Root_CA_certificate, + GlobalSign_ECC_Root_CA___R4_certificate, + TC_TrustCenter_Universal_CA_I_certificate, + Comodo_Trusted_Services_root_certificate, + Entrust_Root_Certification_Authority_certificate, + TC_TrustCenter_Class_2_CA_II_certificate, + Cybertrust_Global_Root_certificate, + Entrust_Root_Certification_Authority___EC1_certificate, + GeoTrust_Primary_Certification_Authority___G2_certificate, + GeoTrust_Global_CA_2_certificate, + COMODO_RSA_Certification_Authority_certificate, + UTN_DATACorp_SGC_Root_CA_certificate, }; const size_t kSSLCertCertificateSizeList[] = { - 1082, + 889, + 1506, + 1043, + 1054, + 659, + 856, + 993, + 579, + 652, + 1213, + 904, + 914, 1052, + 514, + 1054, + 1060, 1049, 1058, - 848, - 848, - 1354, - 514, - 936, - 1448, - 891, - 1078, - 1057, - 653, - 1091, - 1095, - 933, - 955, - 947, - 969, - 1120, - 1244, - 1173, - 804, - 646, - 804, - 660, - 856, - 874, - 896, - 690, 1026, - 1388, 1392, - 889, + 891, 958, 867, - 1028, - 969, - 606, - 1002, - 747, - 1043, - 993, - 1011, - 1931, - 1383, - 1198, - 1198, - 993, - 997, - 811, - 1060, - 652, + 848, + 1082, 1070, - 791, - 1122, - 1144, - 747, - 747, - 576, - 774, - 1054, - 904, + 955, + 1028, + 896, 1239, - 1054, - 1213, - 1076, + 804, + 1120, + 586, + 1057, + 947, + 1078, + 969, + 1388, + 653, + 1090, + 922, + 848, + 1354, + 969, + 1091, + 1428, + 546, + 1144, + 485, + 993, + 1095, + 1173, + 1198, + 933, + 765, + 690, + 874, + 1500, + 1122, }; -} // namspace rtc
diff --git a/webrtc/base/sslstreamadapter.cc b/webrtc/base/sslstreamadapter.cc index b9ba9d3..a2cff3e 100644 --- a/webrtc/base/sslstreamadapter.cc +++ b/webrtc/base/sslstreamadapter.cc
@@ -30,12 +30,20 @@ const char CS_AES_CM_128_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80"; const char CS_AES_CM_128_HMAC_SHA1_32[] = "AES_CM_128_HMAC_SHA1_32"; -int GetSrtpCryptoSuiteFromName(const std::string& cipher) { - if (cipher == CS_AES_CM_128_HMAC_SHA1_32) +std::string SrtpCryptoSuiteToName(int crypto_suite) { + if (crypto_suite == SRTP_AES128_CM_SHA1_32) + return CS_AES_CM_128_HMAC_SHA1_32; + if (crypto_suite == SRTP_AES128_CM_SHA1_80) + return CS_AES_CM_128_HMAC_SHA1_80; + return std::string(); +} + +int SrtpCryptoSuiteFromName(const std::string& crypto_suite) { + if (crypto_suite == CS_AES_CM_128_HMAC_SHA1_32) return SRTP_AES128_CM_SHA1_32; - if (cipher == CS_AES_CM_128_HMAC_SHA1_80) + if (crypto_suite == CS_AES_CM_128_HMAC_SHA1_80) return SRTP_AES128_CM_SHA1_80; - return 0; + return SRTP_INVALID_CRYPTO_SUITE; } SSLStreamAdapter* SSLStreamAdapter::Create(StreamInterface* stream) { @@ -46,7 +54,7 @@ #endif // SSL_USE_OPENSSL } -bool SSLStreamAdapter::GetSslCipherSuite(int* cipher) { +bool SSLStreamAdapter::GetSslCipherSuite(int* cipher_suite) { return false; } @@ -59,12 +67,12 @@ return false; // Default is unsupported } -bool SSLStreamAdapter::SetDtlsSrtpCiphers( - const std::vector<std::string>& ciphers) { +bool SSLStreamAdapter::SetDtlsSrtpCryptoSuites( + const std::vector<int>& crypto_suites) { return false; } -bool SSLStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) { +bool SSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) { return false; } @@ -83,8 +91,8 @@ return OpenSSLStreamAdapter::GetDefaultSslCipherForTest(version, key_type); } -std::string SSLStreamAdapter::GetSslCipherSuiteName(int cipher) { - return OpenSSLStreamAdapter::GetSslCipherSuiteName(cipher); +std::string SSLStreamAdapter::SslCipherSuiteToName(int cipher_suite) { + return OpenSSLStreamAdapter::SslCipherSuiteToName(cipher_suite); } #endif // SSL_USE_OPENSSL
diff --git a/webrtc/base/sslstreamadapter.h b/webrtc/base/sslstreamadapter.h index 65a7729..c57056b 100644 --- a/webrtc/base/sslstreamadapter.h +++ b/webrtc/base/sslstreamadapter.h
@@ -19,7 +19,11 @@ namespace rtc { +// Constants for SSL profile. +const int TLS_NULL_WITH_NULL_NULL = 0; + // Constants for SRTP profiles. +const int SRTP_INVALID_CRYPTO_SUITE = 0; const int SRTP_AES128_CM_SHA1_80 = 0x0001; const int SRTP_AES128_CM_SHA1_32 = 0x0002; @@ -31,10 +35,13 @@ // 128-bit AES with 32-bit SHA-1 HMAC. extern const char CS_AES_CM_128_HMAC_SHA1_32[]; -// Returns the DTLS-SRTP protection profile ID, as defined in -// https://tools.ietf.org/html/rfc5764#section-4.1.2, for the given SRTP -// Crypto-suite, as defined in https://tools.ietf.org/html/rfc4568#section-6.2 -int GetSrtpCryptoSuiteFromName(const std::string& cipher_rfc_name); +// Given the DTLS-SRTP protection profile ID, as defined in +// https://tools.ietf.org/html/rfc4568#section-6.2 , return the SRTP profile +// name, as defined in https://tools.ietf.org/html/rfc5764#section-4.1.2. +std::string SrtpCryptoSuiteToName(int crypto_suite); + +// The reverse of above conversion. +int SrtpCryptoSuiteFromName(const std::string& crypto_suite); // SSLStreamAdapter : A StreamInterfaceAdapter that does SSL/TLS. // After SSL has been started, the stream will only open on successful @@ -152,7 +159,7 @@ // Retrieves the IANA registration id of the cipher suite used for the // connection (e.g. 0x2F for "TLS_RSA_WITH_AES_128_CBC_SHA"). - virtual bool GetSslCipherSuite(int* cipher); + virtual bool GetSslCipherSuite(int* cipher_suite); // Key Exporter interface from RFC 5705 // Arguments are: @@ -174,8 +181,8 @@ size_t result_len); // DTLS-SRTP interface - virtual bool SetDtlsSrtpCiphers(const std::vector<std::string>& ciphers); - virtual bool GetDtlsSrtpCipher(std::string* cipher); + virtual bool SetDtlsSrtpCryptoSuites(const std::vector<int>& crypto_suites); + virtual bool GetDtlsSrtpCryptoSuite(int* crypto_suite); // Capabilities testing static bool HaveDtls(); @@ -191,7 +198,7 @@ // TODO(guoweis): Move this away from a static class method. Currently this is // introduced such that any caller could depend on sslstreamadapter.h without // depending on specific SSL implementation. - static std::string GetSslCipherSuiteName(int cipher); + static std::string SslCipherSuiteToName(int cipher_suite); private: // If true, the server certificate need not match the configured
diff --git a/webrtc/base/sslstreamadapter_unittest.cc b/webrtc/base/sslstreamadapter_unittest.cc index a3e8d9c..1ed06c3 100644 --- a/webrtc/base/sslstreamadapter_unittest.cc +++ b/webrtc/base/sslstreamadapter_unittest.cc
@@ -13,6 +13,7 @@ #include <set> #include <string> +#include "webrtc/base/bufferqueue.h" #include "webrtc/base/gunit.h" #include "webrtc/base/helpers.h" #include "webrtc/base/scoped_ptr.h" @@ -21,7 +22,6 @@ #include "webrtc/base/sslidentity.h" #include "webrtc/base/sslstreamadapter.h" #include "webrtc/base/stream.h" -#include "webrtc/test/testsupport/gtest_disable.h" using ::testing::WithParamInterface; using ::testing::Values; @@ -29,8 +29,6 @@ using ::testing::tuple; static const int kBlockSize = 4096; -static const char kAES_CM_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80"; -static const char kAES_CM_HMAC_SHA1_32[] = "AES_CM_128_HMAC_SHA1_32"; static const char kExporterLabel[] = "label"; static const unsigned char kExporterContext[] = "context"; static int kExporterContextLen = sizeof(kExporterContext); @@ -74,26 +72,26 @@ class SSLStreamAdapterTestBase; -class SSLDummyStream : public rtc::StreamInterface, - public sigslot::has_slots<> { +class SSLDummyStreamBase : public rtc::StreamInterface, + public sigslot::has_slots<> { public: - explicit SSLDummyStream(SSLStreamAdapterTestBase *test, - const std::string &side, - rtc::FifoBuffer *in, - rtc::FifoBuffer *out) : - test_(test), + SSLDummyStreamBase(SSLStreamAdapterTestBase* test, + const std::string &side, + rtc::StreamInterface* in, + rtc::StreamInterface* out) : + test_base_(test), side_(side), in_(in), out_(out), first_packet_(true) { - in_->SignalEvent.connect(this, &SSLDummyStream::OnEventIn); - out_->SignalEvent.connect(this, &SSLDummyStream::OnEventOut); + in_->SignalEvent.connect(this, &SSLDummyStreamBase::OnEventIn); + out_->SignalEvent.connect(this, &SSLDummyStreamBase::OnEventOut); } - virtual rtc::StreamState GetState() const { return rtc::SS_OPEN; } + rtc::StreamState GetState() const override { return rtc::SS_OPEN; } - virtual rtc::StreamResult Read(void* buffer, size_t buffer_len, - size_t* read, int* error) { + rtc::StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error) override { rtc::StreamResult r; r = in_->Read(buffer, buffer_len, read, error); @@ -111,22 +109,20 @@ } // Catch readability events on in and pass them up. - virtual void OnEventIn(rtc::StreamInterface *stream, int sig, - int err) { + void OnEventIn(rtc::StreamInterface* stream, int sig, int err) { int mask = (rtc::SE_READ | rtc::SE_CLOSE); if (sig & mask) { - LOG(LS_INFO) << "SSLDummyStream::OnEvent side=" << side_ << " sig=" + LOG(LS_INFO) << "SSLDummyStreamBase::OnEvent side=" << side_ << " sig=" << sig << " forwarding upward"; PostEvent(sig & mask, 0); } } // Catch writeability events on out and pass them up. - virtual void OnEventOut(rtc::StreamInterface *stream, int sig, - int err) { + void OnEventOut(rtc::StreamInterface* stream, int sig, int err) { if (sig & rtc::SE_WRITE) { - LOG(LS_INFO) << "SSLDummyStream::OnEvent side=" << side_ << " sig=" + LOG(LS_INFO) << "SSLDummyStreamBase::OnEvent side=" << side_ << " sig=" << sig << " forwarding upward"; PostEvent(sig & rtc::SE_WRITE, 0); @@ -135,28 +131,92 @@ // Write to the outgoing FifoBuffer rtc::StreamResult WriteData(const void* data, size_t data_len, - size_t* written, int* error) { + size_t* written, int* error) { return out_->Write(data, data_len, written, error); } - // Defined later - virtual rtc::StreamResult Write(const void* data, size_t data_len, - size_t* written, int* error); + rtc::StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error) override; - virtual void Close() { + void Close() override { LOG(LS_INFO) << "Closing outbound stream"; out_->Close(); } - private: - SSLStreamAdapterTestBase *test_; + protected: + SSLStreamAdapterTestBase* test_base_; const std::string side_; - rtc::FifoBuffer *in_; - rtc::FifoBuffer *out_; + rtc::StreamInterface* in_; + rtc::StreamInterface* out_; bool first_packet_; }; +class SSLDummyStreamTLS : public SSLDummyStreamBase { + public: + SSLDummyStreamTLS(SSLStreamAdapterTestBase* test, + const std::string& side, + rtc::FifoBuffer* in, + rtc::FifoBuffer* out) : + SSLDummyStreamBase(test, side, in, out) { + } +}; + +class BufferQueueStream : public rtc::BufferQueue, + public rtc::StreamInterface { + public: + BufferQueueStream(size_t capacity, size_t default_size) + : rtc::BufferQueue(capacity, default_size) { + } + + // Implementation of abstract StreamInterface methods. + + // A buffer queue stream is always "open". + rtc::StreamState GetState() const override { return rtc::SS_OPEN; } + + // Reading a buffer queue stream will either succeed or block. + rtc::StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error) override { + if (!ReadFront(buffer, buffer_len, read)) { + return rtc::SR_BLOCK; + } + return rtc::SR_SUCCESS; + } + + // Writing to a buffer queue stream will either succeed or block. + rtc::StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error) override { + if (!WriteBack(data, data_len, written)) { + return rtc::SR_BLOCK; + } + return rtc::SR_SUCCESS; + } + + // A buffer queue stream can not be closed. + void Close() override {} + + protected: + void NotifyReadableForTest() override { + PostEvent(rtc::SE_READ, 0); + } + + void NotifyWritableForTest() override { + PostEvent(rtc::SE_WRITE, 0); + } +}; + +class SSLDummyStreamDTLS : public SSLDummyStreamBase { + public: + SSLDummyStreamDTLS(SSLStreamAdapterTestBase* test, + const std::string& side, + BufferQueueStream* in, + BufferQueueStream* out) : + SSLDummyStreamBase(test, side, in, out) { + } +}; + static const int kFifoBufferSize = 4096; +static const int kBufferCapacity = 1; +static const size_t kDefaultBufferSize = 2048; class SSLStreamAdapterTestBase : public testing::Test, public sigslot::has_slots<> { @@ -167,14 +227,12 @@ bool dtls, rtc::KeyParams client_key_type = rtc::KeyParams(rtc::KT_DEFAULT), rtc::KeyParams server_key_type = rtc::KeyParams(rtc::KT_DEFAULT)) - : client_buffer_(kFifoBufferSize), - server_buffer_(kFifoBufferSize), - client_stream_( - new SSLDummyStream(this, "c2s", &client_buffer_, &server_buffer_)), - server_stream_( - new SSLDummyStream(this, "s2c", &server_buffer_, &client_buffer_)), - client_ssl_(rtc::SSLStreamAdapter::Create(client_stream_)), - server_ssl_(rtc::SSLStreamAdapter::Create(server_stream_)), + : client_cert_pem_(client_cert_pem), + client_private_key_pem_(client_private_key_pem), + client_key_type_(client_key_type), + server_key_type_(server_key_type), + client_stream_(NULL), + server_stream_(NULL), client_identity_(NULL), server_identity_(NULL), delay_(0), @@ -187,21 +245,6 @@ identities_set_(false) { // Set use of the test RNG to get predictable loss patterns. rtc::SetRandomTestMode(true); - - // Set up the slots - client_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); - server_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); - - if (!client_cert_pem.empty() && !client_private_key_pem.empty()) { - client_identity_ = rtc::SSLIdentity::FromPEMStrings( - client_private_key_pem, client_cert_pem); - } else { - client_identity_ = rtc::SSLIdentity::Generate("client", client_key_type); - } - server_identity_ = rtc::SSLIdentity::Generate("server", server_key_type); - - client_ssl_->SetIdentity(client_identity_); - server_ssl_->SetIdentity(server_identity_); } ~SSLStreamAdapterTestBase() { @@ -209,14 +252,40 @@ rtc::SetRandomTestMode(false); } + void SetUp() override { + CreateStreams(); + + client_ssl_.reset(rtc::SSLStreamAdapter::Create(client_stream_)); + server_ssl_.reset(rtc::SSLStreamAdapter::Create(server_stream_)); + + // Set up the slots + client_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); + server_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); + + if (!client_cert_pem_.empty() && !client_private_key_pem_.empty()) { + client_identity_ = rtc::SSLIdentity::FromPEMStrings( + client_private_key_pem_, client_cert_pem_); + } else { + client_identity_ = rtc::SSLIdentity::Generate("client", client_key_type_); + } + server_identity_ = rtc::SSLIdentity::Generate("server", server_key_type_); + + client_ssl_->SetIdentity(client_identity_); + server_ssl_->SetIdentity(server_identity_); + } + + void TearDown() override { + client_ssl_.reset(nullptr); + server_ssl_.reset(nullptr); + } + + virtual void CreateStreams() = 0; + // Recreate the client/server identities with the specified validity period. // |not_before| and |not_after| are offsets from the current time in number // of seconds. void ResetIdentitiesWithValidity(int not_before, int not_after) { - client_stream_ = - new SSLDummyStream(this, "c2s", &client_buffer_, &server_buffer_); - server_stream_ = - new SSLDummyStream(this, "s2c", &server_buffer_, &client_buffer_); + CreateStreams(); client_ssl_.reset(rtc::SSLStreamAdapter::Create(client_stream_)); server_ssl_.reset(rtc::SSLStreamAdapter::Create(server_stream_)); @@ -224,18 +293,20 @@ client_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); server_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); + time_t now = time(nullptr); + rtc::SSLIdentityParams client_params; client_params.key_params = rtc::KeyParams(rtc::KT_DEFAULT); client_params.common_name = "client"; - client_params.not_before = not_before; - client_params.not_after = not_after; + client_params.not_before = now + not_before; + client_params.not_after = now + not_after; client_identity_ = rtc::SSLIdentity::GenerateForTest(client_params); rtc::SSLIdentityParams server_params; server_params.key_params = rtc::KeyParams(rtc::KT_DEFAULT); server_params.common_name = "server"; - server_params.not_before = not_before; - server_params.not_after = not_after; + server_params.not_before = now + not_before; + server_params.not_after = now + not_after; server_identity_ = rtc::SSLIdentity::GenerateForTest(server_params); client_ssl_->SetIdentity(client_identity_); @@ -331,9 +402,9 @@ } } - rtc::StreamResult DataWritten(SSLDummyStream *from, const void *data, - size_t data_len, size_t *written, - int *error) { + rtc::StreamResult DataWritten(SSLDummyStreamBase *from, const void *data, + size_t data_len, size_t *written, + int *error) { // Randomly drop loss_ percent of packets if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) { LOG(LS_INFO) << "Randomly dropping packet, size=" << data_len; @@ -389,19 +460,18 @@ handshake_wait_ = wait; } - void SetDtlsSrtpCiphers(const std::vector<std::string> &ciphers, - bool client) { + void SetDtlsSrtpCryptoSuites(const std::vector<int>& ciphers, bool client) { if (client) - client_ssl_->SetDtlsSrtpCiphers(ciphers); + client_ssl_->SetDtlsSrtpCryptoSuites(ciphers); else - server_ssl_->SetDtlsSrtpCiphers(ciphers); + server_ssl_->SetDtlsSrtpCryptoSuites(ciphers); } - bool GetDtlsSrtpCipher(bool client, std::string *retval) { + bool GetDtlsSrtpCryptoSuite(bool client, int* retval) { if (client) - return client_ssl_->GetDtlsSrtpCipher(retval); + return client_ssl_->GetDtlsSrtpCryptoSuite(retval); else - return server_ssl_->GetDtlsSrtpCipher(retval); + return server_ssl_->GetDtlsSrtpCryptoSuite(retval); } bool GetPeerCertificate(bool client, rtc::SSLCertificate** cert) { @@ -443,10 +513,12 @@ virtual void TestTransfer(int size) = 0; protected: - rtc::FifoBuffer client_buffer_; - rtc::FifoBuffer server_buffer_; - SSLDummyStream *client_stream_; // freed by client_ssl_ destructor - SSLDummyStream *server_stream_; // freed by server_ssl_ destructor + std::string client_cert_pem_; + std::string client_private_key_pem_; + rtc::KeyParams client_key_type_; + rtc::KeyParams server_key_type_; + SSLDummyStreamBase *client_stream_; // freed by client_ssl_ destructor + SSLDummyStreamBase *server_stream_; // freed by server_ssl_ destructor rtc::scoped_ptr<rtc::SSLStreamAdapter> client_ssl_; rtc::scoped_ptr<rtc::SSLStreamAdapter> server_ssl_; rtc::SSLIdentity *client_identity_; // freed by client_ssl_ destructor @@ -470,7 +542,17 @@ "", false, ::testing::get<0>(GetParam()), - ::testing::get<1>(GetParam())){}; + ::testing::get<1>(GetParam())), + client_buffer_(kFifoBufferSize), + server_buffer_(kFifoBufferSize) { + } + + void CreateStreams() override { + client_stream_ = + new SSLDummyStreamTLS(this, "c2s", &client_buffer_, &server_buffer_); + server_stream_ = + new SSLDummyStreamTLS(this, "s2c", &server_buffer_, &client_buffer_); + } // Test data transfer for TLS virtual void TestTransfer(int size) { @@ -549,7 +631,7 @@ if (r == rtc::SR_ERROR || r == rtc::SR_EOS) { // Unfortunately, errors are the way that the stream adapter - // signals close in OpenSSL + // signals close in OpenSSL. stream->Close(); return; } @@ -565,6 +647,8 @@ } private: + rtc::FifoBuffer client_buffer_; + rtc::FifoBuffer server_buffer_; rtc::MemoryStream send_stream_; rtc::MemoryStream recv_stream_; }; @@ -579,6 +663,8 @@ true, ::testing::get<0>(GetParam()), ::testing::get<1>(GetParam())), + client_buffer_(kBufferCapacity, kDefaultBufferSize), + server_buffer_(kBufferCapacity, kDefaultBufferSize), packet_size_(1000), count_(0), sent_(0) {} @@ -586,18 +672,32 @@ SSLStreamAdapterTestDTLS(const std::string& cert_pem, const std::string& private_key_pem) : SSLStreamAdapterTestBase(cert_pem, private_key_pem, true), + client_buffer_(kBufferCapacity, kDefaultBufferSize), + server_buffer_(kBufferCapacity, kDefaultBufferSize), packet_size_(1000), count_(0), sent_(0) { } + void CreateStreams() override { + client_stream_ = + new SSLDummyStreamDTLS(this, "c2s", &client_buffer_, &server_buffer_); + server_stream_ = + new SSLDummyStreamDTLS(this, "s2c", &server_buffer_, &client_buffer_); + } + virtual void WriteData() { unsigned char *packet = new unsigned char[1600]; - do { - memset(packet, sent_ & 0xff, packet_size_); - *(reinterpret_cast<uint32_t *>(packet)) = sent_; + while (sent_ < count_) { + unsigned int rand_state = sent_; + packet[0] = sent_; + for (size_t i = 1; i < packet_size_; i++) { + // This is a simple LC PRNG. Keep in synch with identical code below. + rand_state = (rand_state * 251 + 19937) >> 7; + packet[i] = rand_state & 0xff; + } size_t sent; - int rv = client_ssl_->Write(packet, packet_size_, &sent, 0); + rtc::StreamResult rv = client_ssl_->Write(packet, packet_size_, &sent, 0); if (rv == rtc::SR_SUCCESS) { LOG(LS_VERBOSE) << "Sent: " << sent_; sent_++; @@ -608,7 +708,7 @@ ADD_FAILURE(); break; } - } while (sent_ < count_); + } delete [] packet; } @@ -637,11 +737,13 @@ // Now parse the datagram ASSERT_EQ(packet_size_, bread); - unsigned char* ptr_to_buffer = buffer; - uint32_t packet_num = *(reinterpret_cast<uint32_t *>(ptr_to_buffer)); + unsigned char packet_num = buffer[0]; - for (size_t i = 4; i < packet_size_; i++) { - ASSERT_EQ((packet_num & 0xff), buffer[i]); + unsigned int rand_state = packet_num; + for (size_t i = 1; i < packet_size_; i++) { + // This is a simple LC PRNG. Keep in synch with identical code above. + rand_state = (rand_state * 251 + 19937) >> 7; + ASSERT_EQ(rand_state & 0xff, buffer[i]); } received_.insert(packet_num); } @@ -667,6 +769,8 @@ }; private: + BufferQueueStream client_buffer_; + BufferQueueStream server_buffer_; size_t packet_size_; int count_; int sent_; @@ -674,23 +778,20 @@ }; -rtc::StreamResult SSLDummyStream::Write(const void* data, size_t data_len, +rtc::StreamResult SSLDummyStreamBase::Write(const void* data, size_t data_len, size_t* written, int* error) { - *written = data_len; - LOG(LS_INFO) << "Writing to loopback " << data_len; if (first_packet_) { first_packet_ = false; - if (test_->GetLoseFirstPacket()) { + if (test_base_->GetLoseFirstPacket()) { LOG(LS_INFO) << "Losing initial packet of length " << data_len; + *written = data_len; // Fake successful writing also to writer. return rtc::SR_SUCCESS; } } - return test_->DataWritten(this, data, data_len, written, error); - - return rtc::SR_SUCCESS; + return test_base_->DataWritten(this, data, data_len, written, error); }; class SSLStreamAdapterTestDTLSFromPEMStrings : public SSLStreamAdapterTestDTLS { @@ -782,23 +883,20 @@ }; // Test transfer -- trivial -// Disabled due to https://code.google.com/p/webrtc/issues/detail?id=5005 -TEST_P(SSLStreamAdapterTestDTLS, DISABLED_TestDTLSTransfer) { +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransfer) { MAYBE_SKIP_TEST(HaveDtls); TestHandshake(); TestTransfer(100); }; -// Disabled due to https://code.google.com/p/webrtc/issues/detail?id=5005 -TEST_P(SSLStreamAdapterTestDTLS, DISABLED_TestDTLSTransferWithLoss) { +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithLoss) { MAYBE_SKIP_TEST(HaveDtls); TestHandshake(); SetLoss(10); TestTransfer(100); }; -// Disabled due to https://code.google.com/p/webrtc/issues/detail?id=5005 -TEST_P(SSLStreamAdapterTestDTLS, DISABLED_TestDTLSTransferWithDamage) { +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithDamage) { MAYBE_SKIP_TEST(HaveDtls); SetDamage(); // Must be called first because first packet // write happens at end of handshake. @@ -809,74 +907,74 @@ // Test DTLS-SRTP with all high ciphers TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHigh) { MAYBE_SKIP_TEST(HaveDtlsSrtp); - std::vector<std::string> high; - high.push_back(kAES_CM_HMAC_SHA1_80); - SetDtlsSrtpCiphers(high, true); - SetDtlsSrtpCiphers(high, false); + std::vector<int> high; + high.push_back(rtc::SRTP_AES128_CM_SHA1_80); + SetDtlsSrtpCryptoSuites(high, true); + SetDtlsSrtpCryptoSuites(high, false); TestHandshake(); - std::string client_cipher; - ASSERT_TRUE(GetDtlsSrtpCipher(true, &client_cipher)); - std::string server_cipher; - ASSERT_TRUE(GetDtlsSrtpCipher(false, &server_cipher)); + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); ASSERT_EQ(client_cipher, server_cipher); - ASSERT_EQ(client_cipher, kAES_CM_HMAC_SHA1_80); + ASSERT_EQ(client_cipher, rtc::SRTP_AES128_CM_SHA1_80); }; // Test DTLS-SRTP with all low ciphers TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpLow) { MAYBE_SKIP_TEST(HaveDtlsSrtp); - std::vector<std::string> low; - low.push_back(kAES_CM_HMAC_SHA1_32); - SetDtlsSrtpCiphers(low, true); - SetDtlsSrtpCiphers(low, false); + std::vector<int> low; + low.push_back(rtc::SRTP_AES128_CM_SHA1_32); + SetDtlsSrtpCryptoSuites(low, true); + SetDtlsSrtpCryptoSuites(low, false); TestHandshake(); - std::string client_cipher; - ASSERT_TRUE(GetDtlsSrtpCipher(true, &client_cipher)); - std::string server_cipher; - ASSERT_TRUE(GetDtlsSrtpCipher(false, &server_cipher)); + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); ASSERT_EQ(client_cipher, server_cipher); - ASSERT_EQ(client_cipher, kAES_CM_HMAC_SHA1_32); + ASSERT_EQ(client_cipher, rtc::SRTP_AES128_CM_SHA1_32); }; // Test DTLS-SRTP with a mismatch -- should not converge TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHighLow) { MAYBE_SKIP_TEST(HaveDtlsSrtp); - std::vector<std::string> high; - high.push_back(kAES_CM_HMAC_SHA1_80); - std::vector<std::string> low; - low.push_back(kAES_CM_HMAC_SHA1_32); - SetDtlsSrtpCiphers(high, true); - SetDtlsSrtpCiphers(low, false); + std::vector<int> high; + high.push_back(rtc::SRTP_AES128_CM_SHA1_80); + std::vector<int> low; + low.push_back(rtc::SRTP_AES128_CM_SHA1_32); + SetDtlsSrtpCryptoSuites(high, true); + SetDtlsSrtpCryptoSuites(low, false); TestHandshake(); - std::string client_cipher; - ASSERT_FALSE(GetDtlsSrtpCipher(true, &client_cipher)); - std::string server_cipher; - ASSERT_FALSE(GetDtlsSrtpCipher(false, &server_cipher)); + int client_cipher; + ASSERT_FALSE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_FALSE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); }; // Test DTLS-SRTP with each side being mixed -- should select high TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpMixed) { MAYBE_SKIP_TEST(HaveDtlsSrtp); - std::vector<std::string> mixed; - mixed.push_back(kAES_CM_HMAC_SHA1_80); - mixed.push_back(kAES_CM_HMAC_SHA1_32); - SetDtlsSrtpCiphers(mixed, true); - SetDtlsSrtpCiphers(mixed, false); + std::vector<int> mixed; + mixed.push_back(rtc::SRTP_AES128_CM_SHA1_80); + mixed.push_back(rtc::SRTP_AES128_CM_SHA1_32); + SetDtlsSrtpCryptoSuites(mixed, true); + SetDtlsSrtpCryptoSuites(mixed, false); TestHandshake(); - std::string client_cipher; - ASSERT_TRUE(GetDtlsSrtpCipher(true, &client_cipher)); - std::string server_cipher; - ASSERT_TRUE(GetDtlsSrtpCipher(false, &server_cipher)); + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); ASSERT_EQ(client_cipher, server_cipher); - ASSERT_EQ(client_cipher, kAES_CM_HMAC_SHA1_80); + ASSERT_EQ(client_cipher, rtc::SRTP_AES128_CM_SHA1_80); }; // Test an exporter @@ -921,14 +1019,14 @@ } // Test data transfer using certs created from strings. -TEST_P(SSLStreamAdapterTestDTLSFromPEMStrings, TestTransfer) { +TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestTransfer) { MAYBE_SKIP_TEST(HaveDtls); TestHandshake(); TestTransfer(100); } // Test getting the remote certificate. -TEST_P(SSLStreamAdapterTestDTLSFromPEMStrings, TestDTLSGetPeerCertificate) { +TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestDTLSGetPeerCertificate) { MAYBE_SKIP_TEST(HaveDtls); // Peer certificates haven't been received yet. @@ -1052,6 +1150,10 @@ Values(rtc::KeyParams::RSA(1024, 65537), rtc::KeyParams::RSA(1152, 65537), rtc::KeyParams::ECDSA(rtc::EC_NIST_P256)))); + +#if !defined(MEMORY_SANITIZER) +// Fails under MemorySanitizer: +// See https://code.google.com/p/webrtc/issues/detail?id=5381. INSTANTIATE_TEST_CASE_P( SSLStreamAdapterTestsDTLS, SSLStreamAdapterTestDTLS, @@ -1061,3 +1163,4 @@ Values(rtc::KeyParams::RSA(1024, 65537), rtc::KeyParams::RSA(1152, 65537), rtc::KeyParams::ECDSA(rtc::EC_NIST_P256)))); +#endif
diff --git a/webrtc/base/sslstreamadapterhelper.cc b/webrtc/base/sslstreamadapterhelper.cc index c3be4ea..61c0e43 100644 --- a/webrtc/base/sslstreamadapterhelper.cc +++ b/webrtc/base/sslstreamadapterhelper.cc
@@ -29,8 +29,7 @@ role_(SSL_CLIENT), ssl_error_code_(0), // Not meaningful yet ssl_mode_(SSL_MODE_TLS), - ssl_max_version_(SSL_PROTOCOL_TLS_11) { -} + ssl_max_version_(SSL_PROTOCOL_TLS_12) {} SSLStreamAdapterHelper::~SSLStreamAdapterHelper() = default;
diff --git a/webrtc/base/stream_unittest.cc b/webrtc/base/stream_unittest.cc index 4172a97..8cfd052 100644 --- a/webrtc/base/stream_unittest.cc +++ b/webrtc/base/stream_unittest.cc
@@ -12,7 +12,6 @@ #include "webrtc/base/gunit.h" #include "webrtc/base/pathutils.h" #include "webrtc/base/stream.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace rtc {
diff --git a/webrtc/base/stringencode_unittest.cc b/webrtc/base/stringencode_unittest.cc index 406d9c7..588e9d8 100644 --- a/webrtc/base/stringencode_unittest.cc +++ b/webrtc/base/stringencode_unittest.cc
@@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/gunit.h" #include "webrtc/base/stringencode.h" @@ -48,7 +49,7 @@ } char buffer[5]; - memset(buffer, 0x01, ARRAY_SIZE(buffer)); + memset(buffer, 0x01, arraysize(buffer)); ASSERT_EQ(kTests[i].enclen, utf8_encode(buffer, kTests[i].encsize, kTests[i].decoded)); @@ -56,7 +57,7 @@ // Make sure remainder of buffer is unchanged ASSERT_TRUE(memory_check(buffer + kTests[i].enclen, 0x1, - ARRAY_SIZE(buffer) - kTests[i].enclen)); + arraysize(buffer) - kTests[i].enclen)); } }
diff --git a/webrtc/base/stringutils.cc b/webrtc/base/stringutils.cc index 868e475..9580253 100644 --- a/webrtc/base/stringutils.cc +++ b/webrtc/base/stringutils.cc
@@ -77,11 +77,11 @@ } else if (srclen >= buflen) { srclen = buflen - 1; } -#if _DEBUG +#if !defined(NDEBUG) // Double check that characters are not UTF-8 for (size_t pos = 0; pos < srclen; ++pos) RTC_DCHECK_LT(static_cast<unsigned char>(source[pos]), 128); -#endif // _DEBUG +#endif std::copy(source, source + srclen, buffer); buffer[srclen] = 0; return srclen;
diff --git a/webrtc/base/systeminfo.cc b/webrtc/base/systeminfo.cc index bfc96b3..b400aa0 100644 --- a/webrtc/base/systeminfo.cc +++ b/webrtc/base/systeminfo.cc
@@ -110,7 +110,7 @@ DWORD_PTR process_mask = 0; DWORD_PTR system_mask = 0; ::GetProcessAffinityMask(::GetCurrentProcess(), &process_mask, &system_mask); - for (int i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { + for (size_t i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { if (process_mask & 1) ++cur_cpus; process_mask >>= 1;
diff --git a/webrtc/base/task.cc b/webrtc/base/task.cc index bdf8f1d..b09ced1 100644 --- a/webrtc/base/task.cc +++ b/webrtc/base/task.cc
@@ -68,7 +68,7 @@ void Task::Step() { if (done_) { -#ifdef _DEBUG +#if !defined(NDEBUG) // we do not know how !blocked_ happens when done_ - should be impossible. // But it causes problems, so in retail build, we force blocked_, and // under debug we assert. @@ -88,7 +88,7 @@ // SignalDone(); Stop(); -#ifdef _DEBUG +#if !defined(NDEBUG) // verify that stop removed this from its parent ASSERT(!parent()->IsChildTask(this)); #endif @@ -125,7 +125,7 @@ // SignalDone(); Stop(); -#if _DEBUG +#if !defined(NDEBUG) // verify that stop removed this from its parent ASSERT(!parent()->IsChildTask(this)); #endif @@ -150,7 +150,7 @@ // "done_" is set before calling "Stop()" to ensure that this code // doesn't execute more than once (recursively) for the same task. Stop(); -#ifdef _DEBUG +#if !defined(NDEBUG) // verify that stop removed this from its parent ASSERT(!parent()->IsChildTask(this)); #endif
diff --git a/webrtc/base/task_unittest.cc b/webrtc/base/task_unittest.cc index 7f67841..7492436 100644 --- a/webrtc/base/task_unittest.cc +++ b/webrtc/base/task_unittest.cc
@@ -20,6 +20,7 @@ #include "webrtc/base/win32.h" #endif // WEBRTC_WIN +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/gunit.h" #include "webrtc/base/logging.h" @@ -27,7 +28,6 @@ #include "webrtc/base/taskrunner.h" #include "webrtc/base/thread.h" #include "webrtc/base/timeutils.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace rtc { @@ -408,7 +408,7 @@ class TimeoutChangeTest : public sigslot::has_slots<> { public: TimeoutChangeTest() - : task_count_(ARRAY_SIZE(stuck_tasks_)) {} + : task_count_(arraysize(stuck_tasks_)) {} // no need to delete any tasks; the task runner owns them ~TimeoutChangeTest() {} @@ -463,7 +463,7 @@ private: void OnTimeoutId(const int id) { - for (int i = 0; i < ARRAY_SIZE(stuck_tasks_); ++i) { + for (size_t i = 0; i < arraysize(stuck_tasks_); ++i) { if (stuck_tasks_[i] && stuck_tasks_[i]->unique_id() == id) { task_count_--; stuck_tasks_[i] = NULL;
diff --git a/webrtc/base/taskparent.cc b/webrtc/base/taskparent.cc index db6db37..14d236d 100644 --- a/webrtc/base/taskparent.cc +++ b/webrtc/base/taskparent.cc
@@ -46,7 +46,7 @@ children_->insert(child); } -#ifdef _DEBUG +#if !defined(NDEBUG) bool TaskParent::IsChildTask(Task *task) { ASSERT(task != NULL); return task->parent_ == this && children_->find(task) != children_->end(); @@ -69,7 +69,7 @@ void TaskParent::AbortAllChildren() { if (children_->size() > 0) { -#ifdef _DEBUG +#if !defined(NDEBUG) runner_->IncrementAbortCount(); #endif @@ -78,7 +78,7 @@ (*it)->Abort(true); // Note we do not wake } -#ifdef _DEBUG +#if !defined(NDEBUG) runner_->DecrementAbortCount(); #endif }
diff --git a/webrtc/base/taskparent.h b/webrtc/base/taskparent.h index e9342c1..41008fa 100644 --- a/webrtc/base/taskparent.h +++ b/webrtc/base/taskparent.h
@@ -32,7 +32,7 @@ bool AllChildrenDone(); bool AnyChildError(); -#ifdef _DEBUG +#if !defined(NDEBUG) bool IsChildTask(Task *task); #endif
diff --git a/webrtc/base/taskrunner.cc b/webrtc/base/taskrunner.cc index e7278f1..c50c9f8 100644 --- a/webrtc/base/taskrunner.cc +++ b/webrtc/base/taskrunner.cc
@@ -23,7 +23,7 @@ : TaskParent(this), next_timeout_task_(NULL), tasks_running_(false) -#ifdef _DEBUG +#if !defined(NDEBUG) , abort_count_(0), deleting_task_(NULL) #endif @@ -88,11 +88,11 @@ need_timeout_recalc = true; } -#ifdef _DEBUG +#if !defined(NDEBUG) deleting_task_ = task; #endif delete task; -#ifdef _DEBUG +#if !defined(NDEBUG) deleting_task_ = NULL; #endif tasks_[i] = NULL;
diff --git a/webrtc/base/taskrunner.h b/webrtc/base/taskrunner.h index 9a43aac0..e0cf175 100644 --- a/webrtc/base/taskrunner.h +++ b/webrtc/base/taskrunner.h
@@ -44,7 +44,7 @@ void UpdateTaskTimeout(Task* task, int64_t previous_task_timeout_time); -#ifdef _DEBUG +#if !defined(NDEBUG) bool is_ok_to_delete(Task* task) { return task == deleting_task_; } @@ -87,7 +87,7 @@ std::vector<Task *> tasks_; Task *next_timeout_task_; bool tasks_running_; -#ifdef _DEBUG +#if !defined(NDEBUG) int abort_count_; Task* deleting_task_; #endif
diff --git a/webrtc/base/testclient_unittest.cc b/webrtc/base/testclient_unittest.cc index 17bf4e6..bdd06b3 100644 --- a/webrtc/base/testclient_unittest.cc +++ b/webrtc/base/testclient_unittest.cc
@@ -14,7 +14,6 @@ #include "webrtc/base/testclient.h" #include "webrtc/base/testechoserver.h" #include "webrtc/base/thread.h" -#include "webrtc/test/testsupport/gtest_disable.h" using namespace rtc;
diff --git a/webrtc/base/testutils.h b/webrtc/base/testutils.h index e56895d..6e7e22a 100644 --- a/webrtc/base/testutils.h +++ b/webrtc/base/testutils.h
@@ -25,6 +25,7 @@ #include <algorithm> #include <map> #include <vector> +#include "webrtc/base/arraysize.h" #include "webrtc/base/asyncsocket.h" #include "webrtc/base/common.h" #include "webrtc/base/gunit.h" @@ -357,7 +358,7 @@ } void OnReadEvent(AsyncSocket* socket) { char data[64 * 1024]; - int result = socket_->Recv(data, ARRAY_SIZE(data)); + int result = socket_->Recv(data, arraysize(data)); if (result > 0) { recv_buffer_.insert(recv_buffer_.end(), data, data + result); }
diff --git a/webrtc/base/thread.cc b/webrtc/base/thread.cc index 8ab381f..4197d28 100644 --- a/webrtc/base/thread.cc +++ b/webrtc/base/thread.cc
@@ -140,7 +140,6 @@ Thread::Thread(SocketServer* ss) : MessageQueue(ss), - priority_(PRIORITY_NORMAL), running_(true, false), #if defined(WEBRTC_WIN) thread_(NULL), @@ -188,34 +187,6 @@ return true; } -bool Thread::SetPriority(ThreadPriority priority) { -#if defined(WEBRTC_WIN) - if (running()) { - ASSERT(thread_ != NULL); - BOOL ret = FALSE; - if (priority == PRIORITY_NORMAL) { - ret = ::SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL); - } else if (priority == PRIORITY_HIGH) { - ret = ::SetThreadPriority(thread_, THREAD_PRIORITY_HIGHEST); - } else if (priority == PRIORITY_ABOVE_NORMAL) { - ret = ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); - } else if (priority == PRIORITY_IDLE) { - ret = ::SetThreadPriority(thread_, THREAD_PRIORITY_IDLE); - } - if (!ret) { - return false; - } - } - priority_ = priority; - return true; -#else - // TODO: Implement for Linux/Mac if possible. - if (running()) return false; - priority_ = priority; - return true; -#endif -} - bool Thread::Start(Runnable* runnable) { ASSERT(owned_); if (!owned_) return false; @@ -232,18 +203,10 @@ init->thread = this; init->runnable = runnable; #if defined(WEBRTC_WIN) - DWORD flags = 0; - if (priority_ != PRIORITY_NORMAL) { - flags = CREATE_SUSPENDED; - } - thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, flags, + thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, 0, &thread_id_); if (thread_) { running_.Set(); - if (priority_ != PRIORITY_NORMAL) { - SetPriority(priority_); - ::ResumeThread(thread_); - } } else { return false; } @@ -251,37 +214,6 @@ pthread_attr_t attr; pthread_attr_init(&attr); - // Thread priorities are not supported in NaCl. -#if !defined(__native_client__) - if (priority_ != PRIORITY_NORMAL) { - if (priority_ == PRIORITY_IDLE) { - // There is no POSIX-standard way to set a below-normal priority for an - // individual thread (only whole process), so let's not support it. - LOG(LS_WARNING) << "PRIORITY_IDLE not supported"; - } else { - // Set real-time round-robin policy. - if (pthread_attr_setschedpolicy(&attr, SCHED_RR) != 0) { - LOG(LS_ERROR) << "pthread_attr_setschedpolicy"; - } - struct sched_param param; - if (pthread_attr_getschedparam(&attr, ¶m) != 0) { - LOG(LS_ERROR) << "pthread_attr_getschedparam"; - } else { - // The numbers here are arbitrary. - if (priority_ == PRIORITY_HIGH) { - param.sched_priority = 6; // 6 = HIGH - } else { - ASSERT(priority_ == PRIORITY_ABOVE_NORMAL); - param.sched_priority = 4; // 4 = ABOVE_NORMAL - } - if (pthread_attr_setschedparam(&attr, ¶m) != 0) { - LOG(LS_ERROR) << "pthread_attr_setschedparam"; - } - } - } - } -#endif // !defined(__native_client__) - int error_code = pthread_create(&thread_, &attr, PreRun, init); if (0 != error_code) { LOG(LS_ERROR) << "Unable to create pthread, error " << error_code; @@ -345,7 +277,7 @@ // static void Thread::AssertBlockingIsAllowedOnCurrentThread() { -#ifdef _DEBUG +#if !defined(NDEBUG) Thread* current = Thread::Current(); ASSERT(!current || current->blocking_calls_allowed_); #endif
diff --git a/webrtc/base/thread.h b/webrtc/base/thread.h index 9cbe8ec..f91aa56 100644 --- a/webrtc/base/thread.h +++ b/webrtc/base/thread.h
@@ -78,13 +78,6 @@ bool *ready; }; -enum ThreadPriority { - PRIORITY_IDLE = -1, - PRIORITY_NORMAL = 0, - PRIORITY_ABOVE_NORMAL = 1, - PRIORITY_HIGH = 2, -}; - class Runnable { public: virtual ~Runnable() {} @@ -137,10 +130,6 @@ const std::string& name() const { return name_; } bool SetName(const std::string& name, const void* obj); - // Sets the thread's priority. Must be called before Start(). - ThreadPriority priority() const { return priority_; } - bool SetPriority(ThreadPriority priority); - // Starts the execution of the thread. bool Start(Runnable* runnable = NULL); @@ -271,7 +260,6 @@ std::list<_SendMessage> sendlist_; std::string name_; - ThreadPriority priority_; Event running_; // Signalled means running. #if defined(WEBRTC_POSIX)
diff --git a/webrtc/base/thread_checker_impl.cc b/webrtc/base/thread_checker_impl.cc index ea88308..79be606 100644 --- a/webrtc/base/thread_checker_impl.cc +++ b/webrtc/base/thread_checker_impl.cc
@@ -12,6 +12,8 @@ #include "webrtc/base/thread_checker_impl.h" +#include "webrtc/base/platform_thread.h" + namespace rtc { ThreadCheckerImpl::ThreadCheckerImpl() : valid_thread_(CurrentThreadRef()) {
diff --git a/webrtc/base/thread_checker_impl.h b/webrtc/base/thread_checker_impl.h index 7b39ada..0455835 100644 --- a/webrtc/base/thread_checker_impl.h +++ b/webrtc/base/thread_checker_impl.h
@@ -14,7 +14,7 @@ #define WEBRTC_BASE_THREAD_CHECKER_IMPL_H_ #include "webrtc/base/criticalsection.h" -#include "webrtc/base/platform_thread.h" +#include "webrtc/base/platform_thread_types.h" namespace rtc {
diff --git a/webrtc/base/thread_checker_unittest.cc b/webrtc/base/thread_checker_unittest.cc index bcffb52..3381900 100644 --- a/webrtc/base/thread_checker_unittest.cc +++ b/webrtc/base/thread_checker_unittest.cc
@@ -15,7 +15,6 @@ #include "webrtc/base/thread.h" #include "webrtc/base/thread_checker.h" #include "webrtc/base/scoped_ptr.h" -#include "webrtc/test/testsupport/gtest_disable.h" // Duplicated from base/threading/thread_checker.h so that we can be // good citizens there and undef the macro.
diff --git a/webrtc/base/thread_unittest.cc b/webrtc/base/thread_unittest.cc index e50e45c..7ed4326 100644 --- a/webrtc/base/thread_unittest.cc +++ b/webrtc/base/thread_unittest.cc
@@ -15,7 +15,6 @@ #include "webrtc/base/physicalsocketserver.h" #include "webrtc/base/socketaddress.h" #include "webrtc/base/thread.h" -#include "webrtc/test/testsupport/gtest_disable.h" #if defined(WEBRTC_WIN) #include <comdef.h> // NOLINT @@ -137,16 +136,48 @@ Event* event_; }; +// A bool wrapped in a mutex, to avoid data races. Using a volatile +// bool should be sufficient for correct code ("eventual consistency" +// between caches is sufficient), but we can't tell the compiler about +// that, and then tsan complains about a data race. + +// See also discussion at +// http://stackoverflow.com/questions/7223164/is-mutex-needed-to-synchronize-a-simple-flag-between-pthreads + +// Using std::atomic<bool> or std::atomic_flag in C++11 is probably +// the right thing to do, but those features are not yet allowed. Or +// rtc::AtomicInt, if/when that is added. Since the use isn't +// performance critical, use a plain critical section for the time +// being. + +class AtomicBool { + public: + explicit AtomicBool(bool value = false) : flag_(value) {} + AtomicBool& operator=(bool value) { + CritScope scoped_lock(&cs_); + flag_ = value; + return *this; + } + bool get() const { + CritScope scoped_lock(&cs_); + return flag_; + } + + private: + mutable CriticalSection cs_; + bool flag_; +}; + // Function objects to test Thread::Invoke. struct FunctorA { int operator()() { return 42; } }; class FunctorB { public: - explicit FunctorB(bool* flag) : flag_(flag) {} + explicit FunctorB(AtomicBool* flag) : flag_(flag) {} void operator()() { if (flag_) *flag_ = true; } private: - bool* flag_; + AtomicBool* flag_; }; struct FunctorC { int operator()() { @@ -220,33 +251,6 @@ delete thread; } -// Test that setting thread priorities doesn't cause a malfunction. -// There's no easy way to verify the priority was set properly at this time. -TEST(ThreadTest, Priorities) { - Thread *thread; - thread = new Thread(); - EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH)); - EXPECT_TRUE(thread->Start()); - thread->Stop(); - delete thread; - thread = new Thread(); - EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL)); - EXPECT_TRUE(thread->Start()); - thread->Stop(); - delete thread; - - thread = new Thread(); - EXPECT_TRUE(thread->Start()); -#if defined(WEBRTC_WIN) - EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL)); -#else - EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL)); -#endif - thread->Stop(); - delete thread; - -} - TEST(ThreadTest, Wrap) { Thread* current_thread = Thread::Current(); current_thread->UnwrapCurrent(); @@ -266,10 +270,10 @@ thread.Start(); // Try calling functors. EXPECT_EQ(42, thread.Invoke<int>(FunctorA())); - bool called = false; + AtomicBool called; FunctorB f2(&called); thread.Invoke<void>(f2); - EXPECT_TRUE(called); + EXPECT_TRUE(called.get()); // Try calling bare functions. struct LocalFuncs { static int Func1() { return 999; } @@ -408,9 +412,9 @@ Thread thread; thread.Start(); // Try calling functor. - bool called = false; + AtomicBool called; invoker.AsyncInvoke<void>(&thread, FunctorB(&called)); - EXPECT_TRUE_WAIT(called, kWaitTimeout); + EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); } TEST_F(AsyncInvokeTest, WithCallback) { @@ -478,26 +482,26 @@ TEST_F(AsyncInvokeTest, Flush) { AsyncInvoker invoker; - bool flag1 = false; - bool flag2 = false; + AtomicBool flag1; + AtomicBool flag2; // Queue two async calls to the current thread. invoker.AsyncInvoke<void>(Thread::Current(), FunctorB(&flag1)); invoker.AsyncInvoke<void>(Thread::Current(), FunctorB(&flag2)); // Because we haven't pumped messages, these should not have run yet. - EXPECT_FALSE(flag1); - EXPECT_FALSE(flag2); + EXPECT_FALSE(flag1.get()); + EXPECT_FALSE(flag2.get()); // Force them to run now. invoker.Flush(Thread::Current()); - EXPECT_TRUE(flag1); - EXPECT_TRUE(flag2); + EXPECT_TRUE(flag1.get()); + EXPECT_TRUE(flag2.get()); } TEST_F(AsyncInvokeTest, FlushWithIds) { AsyncInvoker invoker; - bool flag1 = false; - bool flag2 = false; + AtomicBool flag1; + AtomicBool flag2; // Queue two async calls to the current thread, one with a message id. invoker.AsyncInvoke<void>(Thread::Current(), FunctorB(&flag1), @@ -505,17 +509,17 @@ invoker.AsyncInvoke<void>(Thread::Current(), FunctorB(&flag2)); // Because we haven't pumped messages, these should not have run yet. - EXPECT_FALSE(flag1); - EXPECT_FALSE(flag2); + EXPECT_FALSE(flag1.get()); + EXPECT_FALSE(flag2.get()); // Execute pending calls with id == 5. invoker.Flush(Thread::Current(), 5); - EXPECT_TRUE(flag1); - EXPECT_FALSE(flag2); + EXPECT_TRUE(flag1.get()); + EXPECT_FALSE(flag2.get()); flag1 = false; // Execute all pending calls. The id == 5 call should not execute again. invoker.Flush(Thread::Current()); - EXPECT_FALSE(flag1); - EXPECT_TRUE(flag2); + EXPECT_FALSE(flag1.get()); + EXPECT_TRUE(flag2.get()); } class GuardedAsyncInvokeTest : public testing::Test { @@ -564,11 +568,11 @@ // Kill |thread|. thread = nullptr; // Try calling functor. - bool called = false; + AtomicBool called; EXPECT_FALSE(invoker->AsyncInvoke<void>(FunctorB(&called))); // With thread gone, nothing should happen. - WAIT(called, kWaitTimeout); - EXPECT_FALSE(called); + WAIT(called.get(), kWaitTimeout); + EXPECT_FALSE(called.get()); } // Test that we can call AsyncInvoke with callback after the thread died. @@ -595,9 +599,9 @@ TEST_F(GuardedAsyncInvokeTest, FireAndForget) { GuardedAsyncInvoker invoker; // Try calling functor. - bool called = false; + AtomicBool called; EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&called))); - EXPECT_TRUE_WAIT(called, kWaitTimeout); + EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); } TEST_F(GuardedAsyncInvokeTest, WithCallback) { @@ -660,39 +664,39 @@ TEST_F(GuardedAsyncInvokeTest, Flush) { GuardedAsyncInvoker invoker; - bool flag1 = false; - bool flag2 = false; + AtomicBool flag1; + AtomicBool flag2; // Queue two async calls to the current thread. EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1))); EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2))); // Because we haven't pumped messages, these should not have run yet. - EXPECT_FALSE(flag1); - EXPECT_FALSE(flag2); + EXPECT_FALSE(flag1.get()); + EXPECT_FALSE(flag2.get()); // Force them to run now. EXPECT_TRUE(invoker.Flush()); - EXPECT_TRUE(flag1); - EXPECT_TRUE(flag2); + EXPECT_TRUE(flag1.get()); + EXPECT_TRUE(flag2.get()); } TEST_F(GuardedAsyncInvokeTest, FlushWithIds) { GuardedAsyncInvoker invoker; - bool flag1 = false; - bool flag2 = false; + AtomicBool flag1; + AtomicBool flag2; // Queue two async calls to the current thread, one with a message id. EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1), 5)); EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2))); // Because we haven't pumped messages, these should not have run yet. - EXPECT_FALSE(flag1); - EXPECT_FALSE(flag2); + EXPECT_FALSE(flag1.get()); + EXPECT_FALSE(flag2.get()); // Execute pending calls with id == 5. EXPECT_TRUE(invoker.Flush(5)); - EXPECT_TRUE(flag1); - EXPECT_FALSE(flag2); + EXPECT_TRUE(flag1.get()); + EXPECT_FALSE(flag2.get()); flag1 = false; // Execute all pending calls. The id == 5 call should not execute again. EXPECT_TRUE(invoker.Flush()); - EXPECT_FALSE(flag1); - EXPECT_TRUE(flag2); + EXPECT_FALSE(flag1.get()); + EXPECT_TRUE(flag2.get()); } #if defined(WEBRTC_WIN)
diff --git a/webrtc/base/timeutils.cc b/webrtc/base/timeutils.cc index fac5b66..05e9ad8 100644 --- a/webrtc/base/timeutils.cc +++ b/webrtc/base/timeutils.cc
@@ -204,4 +204,48 @@ return unwrapped_ts; } +int64_t TmToSeconds(const std::tm& tm) { + static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334}; + int year = tm.tm_year + 1900; + int month = tm.tm_mon; + int day = tm.tm_mday - 1; // Make 0-based like the rest. + int hour = tm.tm_hour; + int min = tm.tm_min; + int sec = tm.tm_sec; + + bool expiry_in_leap_year = (year % 4 == 0 && + (year % 100 != 0 || year % 400 == 0)); + + if (year < 1970) + return -1; + if (month < 0 || month > 11) + return -1; + if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1)) + return -1; + if (hour < 0 || hour > 23) + return -1; + if (min < 0 || min > 59) + return -1; + if (sec < 0 || sec > 59) + return -1; + + day += cumul_mdays[month]; + + // Add number of leap days between 1970 and the expiration year, inclusive. + day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) + + (year / 400 - 1970 / 400)); + + // We will have added one day too much above if expiration is during a leap + // year, and expiration is in January or February. + if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based. + day -= 1; + + // Combine all variables into seconds from 1970-01-01 00:00 (except |month| + // which was accumulated into |day| above). + return (((static_cast<int64_t> + (year - 1970) * 365 + day) * 24 + hour) * 60 + min) * 60 + sec; +} + } // namespace rtc
diff --git a/webrtc/base/timeutils.h b/webrtc/base/timeutils.h index bdeccc3..3ade430 100644 --- a/webrtc/base/timeutils.h +++ b/webrtc/base/timeutils.h
@@ -11,6 +11,7 @@ #ifndef WEBRTC_BASE_TIMEUTILS_H_ #define WEBRTC_BASE_TIMEUTILS_H_ +#include <ctime> #include <time.h> #include "webrtc/base/basictypes.h" @@ -93,6 +94,11 @@ int64_t num_wrap_; }; +// Convert from std::tm, which is relative to 1900-01-01 00:00 to number of +// seconds from 1970-01-01 00:00 ("epoch"). Don't return time_t since that +// is still 32 bits on many systems. +int64_t TmToSeconds(const std::tm& tm); + } // namespace rtc #endif // WEBRTC_BASE_TIMEUTILS_H_
diff --git a/webrtc/base/timeutils_unittest.cc b/webrtc/base/timeutils_unittest.cc index d1b9ad4..688658b 100644 --- a/webrtc/base/timeutils_unittest.cc +++ b/webrtc/base/timeutils_unittest.cc
@@ -10,6 +10,7 @@ #include "webrtc/base/common.h" #include "webrtc/base/gunit.h" +#include "webrtc/base/helpers.h" #include "webrtc/base/thread.h" #include "webrtc/base/timeutils.h" @@ -166,4 +167,99 @@ EXPECT_EQ(unwrapped_ts, wraparound_handler_.Unwrap(ts)); } +class TmToSeconds : public testing::Test { + public: + TmToSeconds() { + // Set use of the test RNG to get deterministic expiration timestamp. + rtc::SetRandomTestMode(true); + } + ~TmToSeconds() { + // Put it back for the next test. + rtc::SetRandomTestMode(false); + } + + void TestTmToSeconds(int times) { + static char mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + for (int i = 0; i < times; i++) { + + // First generate something correct and check that TmToSeconds is happy. + int year = rtc::CreateRandomId() % 400 + 1970; + + bool leap_year = false; + if (year % 4 == 0) + leap_year = true; + if (year % 100 == 0) + leap_year = false; + if (year % 400 == 0) + leap_year = true; + + std::tm tm; + tm.tm_year = year - 1900; // std::tm is year 1900 based. + tm.tm_mon = rtc::CreateRandomId() % 12; + tm.tm_mday = rtc::CreateRandomId() % mdays[tm.tm_mon] + 1; + tm.tm_hour = rtc::CreateRandomId() % 24; + tm.tm_min = rtc::CreateRandomId() % 60; + tm.tm_sec = rtc::CreateRandomId() % 60; + int64_t t = rtc::TmToSeconds(tm); + EXPECT_TRUE(t >= 0); + + // Now damage a random field and check that TmToSeconds is unhappy. + switch (rtc::CreateRandomId() % 11) { + case 0: + tm.tm_year = 1969 - 1900; + break; + case 1: + tm.tm_mon = -1; + break; + case 2: + tm.tm_mon = 12; + break; + case 3: + tm.tm_mday = 0; + break; + case 4: + tm.tm_mday = mdays[tm.tm_mon] + (leap_year && tm.tm_mon == 1) + 1; + break; + case 5: + tm.tm_hour = -1; + break; + case 6: + tm.tm_hour = 24; + break; + case 7: + tm.tm_min = -1; + break; + case 8: + tm.tm_min = 60; + break; + case 9: + tm.tm_sec = -1; + break; + case 10: + tm.tm_sec = 60; + break; + } + EXPECT_EQ(rtc::TmToSeconds(tm), -1); + } + // Check consistency with the system gmtime_r. With time_t, we can only + // portably test dates until 2038, which is achieved by the % 0x80000000. + for (int i = 0; i < times; i++) { + time_t t = rtc::CreateRandomId() % 0x80000000; +#if defined(WEBRTC_WIN) + std::tm* tm = std::gmtime(&t); + EXPECT_TRUE(tm); + EXPECT_TRUE(rtc::TmToSeconds(*tm) == t); +#else + std::tm tm; + EXPECT_TRUE(gmtime_r(&t, &tm)); + EXPECT_TRUE(rtc::TmToSeconds(tm) == t); +#endif + } + } +}; + +TEST_F(TmToSeconds, TestTmToSeconds) { + TestTmToSeconds(100000); +} + } // namespace rtc
diff --git a/webrtc/base/trace_event.h b/webrtc/base/trace_event.h index c14cbff..3916af4 100644 --- a/webrtc/base/trace_event.h +++ b/webrtc/base/trace_event.h
@@ -701,7 +701,7 @@ explicit TraceID(const void* id, unsigned char* flags) : data_(static_cast<unsigned long long>( - reinterpret_cast<unsigned long>(id))) { + reinterpret_cast<uintptr_t>(id))) { *flags |= TRACE_EVENT_FLAG_MANGLE_ID; } explicit TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
diff --git a/webrtc/base/unittest_main.cc b/webrtc/base/unittest_main.cc index f952b2d..167570d 100644 --- a/webrtc/base/unittest_main.cc +++ b/webrtc/base/unittest_main.cc
@@ -78,12 +78,12 @@ _CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, TestCrtReportHandler); } -#ifdef _DEBUG // Turn on memory leak checking on Windows. +#if !defined(NDEBUG) // Turn on memory leak checking on Windows. _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF |_CRTDBG_LEAK_CHECK_DF); if (FLAG_crt_break_alloc >= 0) { _crtBreakAlloc = FLAG_crt_break_alloc; } -#endif // _DEBUG +#endif #endif // WEBRTC_WIN rtc::Filesystem::SetOrganizationName("google"); @@ -93,6 +93,10 @@ rtc::LogMessage::LogTimestamps(); if (*FLAG_log != '\0') { rtc::LogMessage::ConfigureLogging(FLAG_log); + } else if (rtc::LogMessage::GetLogToDebug() > rtc::LS_INFO) { + // Default to LS_INFO, even for release builds to provide better test + // logging. + rtc::LogMessage::LogToDebug(rtc::LS_INFO); } // Initialize SSL which are used by several tests.
diff --git a/webrtc/base/unixfilesystem.cc b/webrtc/base/unixfilesystem.cc index 30d6e78..b474324 100644 --- a/webrtc/base/unixfilesystem.cc +++ b/webrtc/base/unixfilesystem.cc
@@ -44,6 +44,7 @@ #include <sys/syslimits.h> #endif +#include "webrtc/base/arraysize.h" #include "webrtc/base/fileutils.h" #include "webrtc/base/pathutils.h" #include "webrtc/base/stream.h" @@ -176,7 +177,7 @@ kCreateFolder, &fr)) return false; unsigned char buffer[NAME_MAX+1]; - if (0 != FSRefMakePath(&fr, buffer, ARRAY_SIZE(buffer))) + if (0 != FSRefMakePath(&fr, buffer, arraysize(buffer))) return false; pathname.SetPathname(reinterpret_cast<char*>(buffer), ""); #elif defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) @@ -303,7 +304,7 @@ #endif // WEBRTC_MAC && !defined(WEBRTC_IOS) #endif // WEBRTC_ANDROID || WEBRTC_IOS }; - for (size_t i = 0; i < ARRAY_SIZE(kTempPrefixes); ++i) { + for (size_t i = 0; i < arraysize(kTempPrefixes); ++i) { if (0 == strncmp(pathname.pathname().c_str(), kTempPrefixes[i], strlen(kTempPrefixes[i]))) return true; @@ -372,12 +373,12 @@ return success; #elif defined(__native_client__) return false; -#elif IOS +#elif WEBRTC_IOS IOSAppName(path); return true; #else // WEBRTC_MAC && !defined(WEBRTC_IOS) char buffer[PATH_MAX + 2]; - ssize_t len = readlink("/proc/self/exe", buffer, ARRAY_SIZE(buffer) - 1); + ssize_t len = readlink("/proc/self/exe", buffer, arraysize(buffer) - 1); if ((len <= 0) || (len == PATH_MAX + 1)) return false; buffer[len] = '\0'; @@ -399,7 +400,7 @@ kCreateFolder, &fr)) return false; unsigned char buffer[NAME_MAX+1]; - if (0 != FSRefMakePath(&fr, buffer, ARRAY_SIZE(buffer))) + if (0 != FSRefMakePath(&fr, buffer, arraysize(buffer))) return false; path->SetPathname(reinterpret_cast<char*>(buffer), ""); } else { @@ -487,7 +488,7 @@ // Create a random directory as /tmp/<appname>-<pid>-<timestamp> char buffer[128]; - sprintfn(buffer, ARRAY_SIZE(buffer), "-%d-%d", + sprintfn(buffer, arraysize(buffer), "-%d-%d", static_cast<int>(getpid()), static_cast<int>(time(0))); std::string folder(application_name_);
diff --git a/webrtc/base/urlencode_unittest.cc b/webrtc/base/urlencode_unittest.cc index 5216913..6a61db3 100644 --- a/webrtc/base/urlencode_unittest.cc +++ b/webrtc/base/urlencode_unittest.cc
@@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/gunit.h" #include "webrtc/base/thread.h" @@ -19,7 +20,7 @@ char source[] = "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"; char dest[1]; - ASSERT_EQ(0, UrlEncode(source, dest, ARRAY_SIZE(dest))); + ASSERT_EQ(0, UrlEncode(source, dest, arraysize(dest))); ASSERT_EQ('\0', dest[0]); dest[0] = 'a'; @@ -30,7 +31,7 @@ TEST(Urlencode, OneCharacterConversion) { char source[] = "^"; char dest[4]; - ASSERT_EQ(3, UrlEncode(source, dest, ARRAY_SIZE(dest))); + ASSERT_EQ(3, UrlEncode(source, dest, arraysize(dest))); ASSERT_STREQ("%5E", dest); } @@ -40,7 +41,7 @@ // hold the text given. char source[] = "aa"; char dest[3]; - ASSERT_EQ(2, UrlEncode(source, dest, ARRAY_SIZE(dest))); + ASSERT_EQ(2, UrlEncode(source, dest, arraysize(dest))); ASSERT_STREQ("aa", dest); } @@ -49,14 +50,14 @@ // big enough to hold the encoding. char source[] = "&"; char dest[3]; - ASSERT_EQ(0, UrlEncode(source, dest, ARRAY_SIZE(dest))); + ASSERT_EQ(0, UrlEncode(source, dest, arraysize(dest))); ASSERT_EQ('\0', dest[0]); } TEST(Urlencode, Encoding1) { char source[] = "A^ "; char dest[8]; - ASSERT_EQ(5, UrlEncode(source, dest, ARRAY_SIZE(dest))); + ASSERT_EQ(5, UrlEncode(source, dest, arraysize(dest))); ASSERT_STREQ("A%5E+", dest); } @@ -64,7 +65,7 @@ char source[] = "A^ "; char dest[8]; ASSERT_EQ(7, rtc::UrlEncodeWithoutEncodingSpaceAsPlus(source, dest, - ARRAY_SIZE(dest))); + arraysize(dest))); ASSERT_STREQ("A%5E%20", dest); }
diff --git a/webrtc/base/virtualsocket_unittest.cc b/webrtc/base/virtualsocket_unittest.cc index 694b154..2cd2b5e 100644 --- a/webrtc/base/virtualsocket_unittest.cc +++ b/webrtc/base/virtualsocket_unittest.cc
@@ -14,6 +14,7 @@ #include <netinet/in.h> #endif +#include "webrtc/base/arraysize.h" #include "webrtc/base/logging.h" #include "webrtc/base/gunit.h" #include "webrtc/base/testclient.h" @@ -21,7 +22,6 @@ #include "webrtc/base/thread.h" #include "webrtc/base/timeutils.h" #include "webrtc/base/virtualsocketserver.h" -#include "webrtc/test/testsupport/gtest_disable.h" using namespace rtc; @@ -1022,9 +1022,9 @@ const double kTestDev[] = { 0.25, 0.1, 0.01 }; // TODO: The current code only works for 1000 data points or more. const uint32_t kTestSamples[] = {/*10, 100,*/ 1000}; - for (size_t midx = 0; midx < ARRAY_SIZE(kTestMean); ++midx) { - for (size_t didx = 0; didx < ARRAY_SIZE(kTestDev); ++didx) { - for (size_t sidx = 0; sidx < ARRAY_SIZE(kTestSamples); ++sidx) { + for (size_t midx = 0; midx < arraysize(kTestMean); ++midx) { + for (size_t didx = 0; didx < arraysize(kTestDev); ++didx) { + for (size_t sidx = 0; sidx < arraysize(kTestSamples); ++sidx) { ASSERT_LT(0u, kTestSamples[sidx]); const uint32_t kStdDev = static_cast<uint32_t>(kTestDev[didx] * kTestMean[midx]);
diff --git a/webrtc/base/win32.cc b/webrtc/base/win32.cc index 6e09829..182b84f 100644 --- a/webrtc/base/win32.cc +++ b/webrtc/base/win32.cc
@@ -14,6 +14,7 @@ #include <ws2tcpip.h> #include <algorithm> +#include "webrtc/base/arraysize.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/byteorder.h" #include "webrtc/base/common.h" @@ -87,7 +88,7 @@ int current = 1; int max = 0; int maxpos = -1; - int run_array_size = ARRAY_SIZE(runpos); + int run_array_size = arraysize(runpos); // Run over the address marking runs of 0s. for (int i = 0; i < run_array_size; ++i) { if (as_shorts[i] == 0) {
diff --git a/webrtc/base/win32filesystem.cc b/webrtc/base/win32filesystem.cc index 8ac918f..b731974 100644 --- a/webrtc/base/win32filesystem.cc +++ b/webrtc/base/win32filesystem.cc
@@ -15,6 +15,7 @@ #include <shlobj.h> #include <tchar.h> +#include "webrtc/base/arraysize.h" #include "webrtc/base/fileutils.h" #include "webrtc/base/pathutils.h" #include "webrtc/base/scoped_ptr.h" @@ -197,16 +198,16 @@ bool Win32Filesystem::GetTemporaryFolder(Pathname &pathname, bool create, const std::string *append) { wchar_t buffer[MAX_PATH + 1]; - if (!::GetTempPath(ARRAY_SIZE(buffer), buffer)) + if (!::GetTempPath(arraysize(buffer), buffer)) return false; if (!IsCurrentProcessLowIntegrity() && - !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer))) + !::GetLongPathName(buffer, buffer, arraysize(buffer))) return false; size_t len = strlen(buffer); if ((len > 0) && (buffer[len-1] != '\\')) { - len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, L"\\"); + len += strcpyn(buffer + len, arraysize(buffer) - len, L"\\"); } - if (len >= ARRAY_SIZE(buffer) - 1) + if (len >= arraysize(buffer) - 1) return false; pathname.clear(); pathname.SetFolder(ToUtf8(buffer)); @@ -295,10 +296,10 @@ bool Win32Filesystem::IsTemporaryPath(const Pathname& pathname) { TCHAR buffer[MAX_PATH + 1]; - if (!::GetTempPath(ARRAY_SIZE(buffer), buffer)) + if (!::GetTempPath(arraysize(buffer), buffer)) return false; if (!IsCurrentProcessLowIntegrity() && - !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer))) + !::GetLongPathName(buffer, buffer, arraysize(buffer))) return false; return (::strnicmp(ToUtf16(pathname.pathname()).c_str(), buffer, strlen(buffer)) == 0); @@ -337,7 +338,7 @@ bool Win32Filesystem::GetAppPathname(Pathname* path) { TCHAR buffer[MAX_PATH + 1]; - if (0 == ::GetModuleFileName(NULL, buffer, ARRAY_SIZE(buffer))) + if (0 == ::GetModuleFileName(NULL, buffer, arraysize(buffer))) return false; path->SetPathname(ToUtf8(buffer)); return true; @@ -351,20 +352,20 @@ if (!::SHGetSpecialFolderPath(NULL, buffer, csidl, TRUE)) return false; if (!IsCurrentProcessLowIntegrity() && - !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer))) + !::GetLongPathName(buffer, buffer, arraysize(buffer))) return false; - size_t len = strcatn(buffer, ARRAY_SIZE(buffer), __T("\\")); - len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, + size_t len = strcatn(buffer, arraysize(buffer), __T("\\")); + len += strcpyn(buffer + len, arraysize(buffer) - len, ToUtf16(organization_name_).c_str()); if ((len > 0) && (buffer[len-1] != __T('\\'))) { - len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, __T("\\")); + len += strcpyn(buffer + len, arraysize(buffer) - len, __T("\\")); } - len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, + len += strcpyn(buffer + len, arraysize(buffer) - len, ToUtf16(application_name_).c_str()); if ((len > 0) && (buffer[len-1] != __T('\\'))) { - len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, __T("\\")); + len += strcpyn(buffer + len, arraysize(buffer) - len, __T("\\")); } - if (len >= ARRAY_SIZE(buffer) - 1) + if (len >= arraysize(buffer) - 1) return false; path->clear(); path->SetFolder(ToUtf8(buffer));
diff --git a/webrtc/base/win32regkey_unittest.cc b/webrtc/base/win32regkey_unittest.cc index 389c3a2..1702ef7 100644 --- a/webrtc/base/win32regkey_unittest.cc +++ b/webrtc/base/win32regkey_unittest.cc
@@ -10,6 +10,7 @@ // Unittest for registry access API +#include "webrtc/base/arraysize.h" #include "webrtc/base/gunit.h" #include "webrtc/base/common.h" #include "webrtc/base/win32regkey.h" @@ -564,8 +565,8 @@ #ifdef IS_PRIVATE_BUILD // get a temp file name wchar_t temp_path[MAX_PATH] = {0}; - EXPECT_LT(::GetTempPath(ARRAY_SIZE(temp_path), temp_path), - static_cast<DWORD>(ARRAY_SIZE(temp_path))); + EXPECT_LT(::GetTempPath(arraysize(temp_path), temp_path), + static_cast<DWORD>(arraysize(temp_path))); wchar_t temp_file[MAX_PATH] = {0}; EXPECT_NE(::GetTempFileName(temp_path, L"rkut_", ::GetTickCount(), temp_file), 0);
diff --git a/webrtc/base/win32socketserver.cc b/webrtc/base/win32socketserver.cc index f466bf1..72ce4eb 100644 --- a/webrtc/base/win32socketserver.cc +++ b/webrtc/base/win32socketserver.cc
@@ -55,7 +55,7 @@ static const int ICMP_PING_TIMEOUT_MILLIS = 10000u; // TODO: Enable for production builds also? Use FormatMessage? -#ifdef _DEBUG +#if !defined(NDEBUG) LPCSTR WSAErrorToString(int error, LPCSTR *description_result) { LPCSTR string = "Unspecified"; LPCSTR description = "Unspecified description"; @@ -626,7 +626,7 @@ case FD_CONNECT: if (error != ERROR_SUCCESS) { ReportWSAError("WSAAsync:connect notify", error, addr_); -#ifdef _DEBUG +#if !defined(NDEBUG) int32_t duration = TimeSince(connect_time_); LOG(LS_INFO) << "WSAAsync:connect error (" << duration << " ms), faking close"; @@ -639,7 +639,7 @@ // though the connect event never did occur. SignalCloseEvent(this, error); } else { -#ifdef _DEBUG +#if !defined(NDEBUG) int32_t duration = TimeSince(connect_time_); LOG(LS_INFO) << "WSAAsync:connect (" << duration << " ms)"; #endif
diff --git a/webrtc/base/win32windowpicker.cc b/webrtc/base/win32windowpicker.cc index b4550ae..da05a5c 100644 --- a/webrtc/base/win32windowpicker.cc +++ b/webrtc/base/win32windowpicker.cc
@@ -12,6 +12,7 @@ #include <string> #include <vector> +#include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" @@ -58,7 +59,7 @@ } TCHAR window_title[500]; - GetWindowText(hwnd, window_title, ARRAY_SIZE(window_title)); + GetWindowText(hwnd, window_title, arraysize(window_title)); std::string title = ToUtf8(window_title); WindowId id(hwnd);
diff --git a/webrtc/base/win32windowpicker_unittest.cc b/webrtc/base/win32windowpicker_unittest.cc index 71e8af6..701bb27 100644 --- a/webrtc/base/win32windowpicker_unittest.cc +++ b/webrtc/base/win32windowpicker_unittest.cc
@@ -7,6 +7,7 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ +#include "webrtc/base/arraysize.h" #include "webrtc/base/gunit.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" @@ -71,7 +72,7 @@ EXPECT_EQ(window_picker.visible_window()->handle(), desc.id().id()); TCHAR window_title[500]; GetWindowText(window_picker.visible_window()->handle(), window_title, - ARRAY_SIZE(window_title)); + arraysize(window_title)); EXPECT_EQ(0, wcscmp(window_title, kVisibleWindowTitle)); }
diff --git a/webrtc/build/android/AndroidManifest.xml b/webrtc/build/android/AndroidManifest.xml new file mode 100644 index 0000000..bb6d354 --- /dev/null +++ b/webrtc/build/android/AndroidManifest.xml
@@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + This is a dummy manifest which is required by: + 1. aapt when generating R.java in java.gypi: + Nothing in the manifest is used, but it is still required by aapt. + 2. lint: [min|target]SdkVersion are required by lint and should + be kept up-to-date. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="dummy.package"> + + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + +</manifest>
diff --git a/webrtc/build/android/suppressions.xml b/webrtc/build/android/suppressions.xml new file mode 100644 index 0000000..0fc22e0 --- /dev/null +++ b/webrtc/build/android/suppressions.xml
@@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<lint> + <!-- These lint settings is for the Android linter that gets run by + lint_action.gypi on compile of WebRTC java code. All WebRTC java code + should lint cleanly for the issues below. --> + <!-- TODO(phoglund): make work with suppress.py or remove printout referring + to suppress.py. --> + <issue id="NewApi"></issue> + + <issue id="Locale" severity="ignore"/> + <issue id="SdCardPath" severity="ignore"/> + <issue id="UseValueOf" severity="ignore"/> + <issue id="InlinedApi" severity="ignore"/> + <issue id="DefaultLocale" severity="ignore"/> + <issue id="Assert" severity="ignore"/> + <issue id="UseSparseArrays" severity="ignore"/> + + <!-- These are just from the dummy AndroidManifest.xml we use for linting. + It's in the same directory as this file. --> + <issue id="MissingApplicationIcon" severity="ignore"/> + <issue id="AllowBackup" severity="ignore"/> + <issue id="MissingVersion" severity="ignore"/> +</lint>
diff --git a/webrtc/build/android/test_runner.py b/webrtc/build/android/test_runner.py index 7996982..78a7a19 100755 --- a/webrtc/build/android/test_runner.py +++ b/webrtc/build/android/test_runner.py
@@ -38,6 +38,8 @@ 'webrtc/common_audio/common_audio_unittests.isolate', 'common_video_unittests': 'webrtc/common_video/common_video_unittests.isolate', + 'libjingle_peerconnection_unittest': + 'talk/libjingle_peerconnection_unittest.isolate', 'modules_tests': 'webrtc/modules/modules_tests.isolate', 'modules_unittests': 'webrtc/modules/modules_unittests.isolate', 'rtc_unittests': 'webrtc/rtc_unittests.isolate', @@ -48,8 +50,6 @@ 'video_capture_tests': 'webrtc/modules/video_capture/video_capture_tests.isolate', 'video_engine_tests': 'webrtc/video_engine_tests.isolate', - 'video_engine_core_unittests': - 'webrtc/video_engine/video_engine_core_unittests.isolate', 'voice_engine_unittests': 'webrtc/voice_engine/voice_engine_unittests.isolate', 'webrtc_nonparallel_tests': 'webrtc/webrtc_nonparallel_tests.isolate',
diff --git a/webrtc/build/apk_test.gypi b/webrtc/build/apk_test.gypi new file mode 100644 index 0000000..a41e436 --- /dev/null +++ b/webrtc/build/apk_test.gypi
@@ -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. + +# This is almost an identical copy of src/build/apk_test.gypi with minor +# modifications to allow test executables starting with "lib". +# See http://crbug.com/543820 for more details. + +{ + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base_java', + '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands', + '<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk', + '<(DEPTH)/testing/android/appurify_support.gyp:appurify_support_java', + '<(DEPTH)/testing/android/on_device_instrumentation.gyp:reporter_java', + '<(DEPTH)/tools/android/android_tools.gyp:android_tools', + ], + 'conditions': [ + ['OS == "android"', { + 'variables': { + # These are used to configure java_apk.gypi included below. + 'test_type': 'gtest', + 'apk_name': '<(test_suite_name)', + 'intermediate_dir': '<(PRODUCT_DIR)/<(test_suite_name)_apk', + 'final_apk_path': '<(intermediate_dir)/<(test_suite_name)-debug.apk', + 'java_in_dir': '<(DEPTH)/testing/android/native_test/java', + 'native_lib_target': '<(test_suite_name)', + 'gyp_managed_install': 0, + }, + 'includes': [ + '../../build/java_apk.gypi', + '../../build/android/test_runner.gypi', + ], + }], # 'OS == "android" + ], # conditions +}
diff --git a/webrtc/build/apk_tests.gyp b/webrtc/build/apk_tests.gyp index a3833ff..02a1342 100644 --- a/webrtc/build/apk_tests.gyp +++ b/webrtc/build/apk_tests.gyp
@@ -61,6 +61,23 @@ ], }, { + 'target_name': 'libjingle_peerconnection_unittest_apk', + 'type': 'none', + 'variables': { + 'test_suite_name': 'libjingle_peerconnection_unittest', + 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)libjingle_peerconnection_unittest<(SHARED_LIB_SUFFIX)', + }, + 'dependencies': [ + '<(DEPTH)/talk/libjingle_tests.gyp:libjingle_peerconnection_unittest', + '<(DEPTH)/talk/libjingle.gyp:libjingle_peerconnection_java', + ], + 'includes': [ + # Use webrtc copy of apk_test.gypi to allow test executables starting + # with "lib". See http://crbug.com/543820 for more details. + '../build/apk_test.gypi', + ], + }, + { 'target_name': 'modules_tests_apk', 'type': 'none', 'variables': { @@ -146,20 +163,6 @@ ], }, { - 'target_name': 'video_engine_core_unittests_apk', - 'type': 'none', - 'variables': { - 'test_suite_name': 'video_engine_core_unittests', - 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)video_engine_core_unittests<(SHARED_LIB_SUFFIX)', - }, - 'dependencies': [ - '<(webrtc_root)/video_engine/video_engine_core_unittests.gyp:video_engine_core_unittests', - ], - 'includes': [ - '../../build/apk_test.gypi', - ], - }, - { 'target_name': 'video_engine_tests_apk', 'type': 'none', 'variables': {
diff --git a/webrtc/build/apk_tests_noop.gyp b/webrtc/build/apk_tests_noop.gyp index 719bddb..ed9249a 100644 --- a/webrtc/build/apk_tests_noop.gyp +++ b/webrtc/build/apk_tests_noop.gyp
@@ -22,6 +22,10 @@ 'type': 'none', }, { + 'target_name': 'libjingle_peerconnection_unittest_apk', + 'type': 'none', + }, + { 'target_name': 'modules_tests_apk', 'type': 'none', }, @@ -46,10 +50,6 @@ 'type': 'none', }, { - 'target_name': 'video_engine_core_unittests_apk', - 'type': 'none', - }, - { 'target_name': 'video_engine_tests_apk', 'type': 'none', },
diff --git a/webrtc/build/common.gypi b/webrtc/build/common.gypi index 2b05168..8d8583f 100644 --- a/webrtc/build/common.gypi +++ b/webrtc/build/common.gypi
@@ -21,12 +21,10 @@ 'conditions': [ ['build_with_chromium==1', { - 'build_with_libjingle': 1, 'webrtc_root%': '<(DEPTH)/third_party/webrtc', 'apk_tests_path%': '<(DEPTH)/third_party/webrtc/build/apk_tests_noop.gyp', 'modules_java_gyp_path%': '<(DEPTH)/third_party/webrtc/modules/modules_java_chromium.gyp', }, { - 'build_with_libjingle%': 0, 'webrtc_root%': '<(DEPTH)/webrtc', 'apk_tests_path%': '<(DEPTH)/webrtc/build/apk_tests.gyp', 'modules_java_gyp_path%': '<(DEPTH)/webrtc/modules/modules_java.gyp', @@ -34,7 +32,6 @@ ], }, 'build_with_chromium%': '<(build_with_chromium)', - 'build_with_libjingle%': '<(build_with_libjingle)', 'webrtc_root%': '<(webrtc_root)', 'apk_tests_path%': '<(apk_tests_path)', 'modules_java_gyp_path%': '<(modules_java_gyp_path)', @@ -47,7 +44,6 @@ 'build_with_mozilla%': 0, }, 'build_with_chromium%': '<(build_with_chromium)', - 'build_with_libjingle%': '<(build_with_libjingle)', 'build_with_mozilla%': '<(build_with_mozilla)', 'webrtc_root%': '<(webrtc_root)', 'apk_tests_path%': '<(apk_tests_path)', @@ -89,15 +85,14 @@ # Disable these to not build components which can be externally provided. 'build_expat%': 1, - 'build_icu%': 1, 'build_json%': 1, 'build_libjpeg%': 1, 'build_libvpx%': 1, 'build_libyuv%': 1, 'build_openmax_dl%': 1, 'build_opus%': 1, + 'build_protobuf%': 1, 'build_ssl%': 1, - 'build_vp9%': 1, # Disable by default 'have_dbus_glib%': 0, @@ -129,6 +124,17 @@ # Enabling this may break interop with Android clients that support H264. 'use_objc_h264%': 0, + # Enable this to build H.264 encoder/decoder using third party libraries. + # Encoding uses OpenH264 and decoding uses FFmpeg. Because of this, OpenH264 + # and FFmpeg have to be correctly enabled separately. + # - use_openh264=1 is required for OpenH264 targets to be defined. + # - ffmpeg_branding=Chrome is one way to support H.264 decoding in FFmpeg. + # FFmpeg can be built with/without H.264 support, see 'ffmpeg_branding'. + # Without it, it compiles but H264DecoderImpl fails to initialize. + # CHECK THE OPENH264, FFMPEG AND H.264 LICENSES/PATENTS BEFORE BUILDING. + # http://www.openh264.org, https://www.ffmpeg.org/ + 'use_third_party_h264%': 0, # TODO(hbos): To be used in follow-up CL(s). + 'conditions': [ ['build_with_chromium==1', { # Exclude pulse audio on Chromium since its prerequisites don't require @@ -137,6 +143,10 @@ # Exclude internal ADM since Chromium uses its own IO handling. 'include_internal_audio_device%': 0, + + # Remove tests for Chromium to avoid slowing down GYP generation. + 'include_tests%': 0, + 'restrict_webrtc_logging%': 1, }, { # Settings for the standalone (not-in-Chromium) build. # TODO(andrew): For now, disable the Chrome plugins, which causes a # flood of chromium-style warnings. Investigate enabling them: @@ -145,17 +155,11 @@ 'include_pulse_audio%': 1, 'include_internal_audio_device%': 1, - }], - ['build_with_libjingle==1', { - 'include_tests%': 0, - 'restrict_webrtc_logging%': 1, - }, { 'include_tests%': 1, 'restrict_webrtc_logging%': 0, }], ['OS=="ios"', { 'build_libjpeg%': 0, - 'enable_protobuf%': 0, }], ['target_arch=="arm" or target_arch=="arm64"', { 'prefer_fixed_point%': 1,
diff --git a/webrtc/build/protoc.gypi b/webrtc/build/protoc.gypi index 5e486f1..682bc22 100644 --- a/webrtc/build/protoc.gypi +++ b/webrtc/build/protoc.gypi
@@ -109,10 +109,6 @@ 'process_outputs_as_sources': 1, }, ], - 'dependencies': [ - '<(DEPTH)/third_party/protobuf/protobuf.gyp:protoc#host', - '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite', - ], 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/protoc_out', '<(DEPTH)', @@ -123,12 +119,20 @@ '<(DEPTH)', ] }, - 'export_dependent_settings': [ - # The generated headers reference headers within protobuf_lite, - # so dependencies must be able to find those headers too. - '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite', - ], # This target exports a hard dependency because it generates header # files. 'hard_dependency': 1, + 'conditions': [ + ['build_protobuf==1', { + 'dependencies': [ + '<(DEPTH)/third_party/protobuf/protobuf.gyp:protoc#host', + '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite', + ], + 'export_dependent_settings': [ + # The generated headers reference headers within protobuf_lite, + # so dependencies must be able to find those headers too. + '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite', + ], + }], + ], }
diff --git a/webrtc/build/sanitizers/tsan_suppressions_webrtc.cc b/webrtc/build/sanitizers/tsan_suppressions_webrtc.cc index 4022160..1150990 100644 --- a/webrtc/build/sanitizers/tsan_suppressions_webrtc.cc +++ b/webrtc/build/sanitizers/tsan_suppressions_webrtc.cc
@@ -42,6 +42,10 @@ "race:webrtc/modules/audio_processing/aec/aec_core.c\n" "race:webrtc/modules/audio_processing/aec/aec_rdft.c\n" +// Race in pulse initialization. +// https://code.google.com/p/webrtc/issues/detail?id=5152 +"race:webrtc::AudioDeviceLinuxPulse::Init\n" + // rtc_unittest // https://code.google.com/p/webrtc/issues/detail?id=3911 for details. "race:rtc::AsyncInvoker::OnMessage\n" @@ -68,6 +72,9 @@ // TODO(jiayl): https://code.google.com/p/webrtc/issues/detail?id=3492 "race:user_sctp_timer_iterate\n" +// https://code.google.com/p/webrtc/issues/detail?id=5151 +"race:sctp_close\n" + // Potential deadlocks detected after roll in r6516. // https://code.google.com/p/webrtc/issues/detail?id=3509 "deadlock:webrtc::RTCPReceiver::SetSsrcs\n" @@ -85,7 +92,7 @@ // Race between InitCpuFlags and TestCpuFlag in libyuv. // https://code.google.com/p/libyuv/issues/detail?id=508 -"race:libyuv::TestCpuFlag\n" +"race:InitCpuFlags\n" // End of suppressions. ; // Please keep this semicolon.
diff --git a/webrtc/build/webrtc.gni b/webrtc/build/webrtc.gni index 1d33e89..c55f423 100644 --- a/webrtc/build/webrtc.gni +++ b/webrtc/build/webrtc.gni
@@ -36,7 +36,6 @@ # Disable these to not build components which can be externally provided. rtc_build_expat = true - rtc_build_icu = true rtc_build_json = true rtc_build_libjpeg = true rtc_build_libvpx = true @@ -44,7 +43,6 @@ rtc_build_openmax_dl = true rtc_build_opus = true rtc_build_ssl = true - rtc_build_vp9 = true # Disable by default. rtc_have_dbus_glib = false @@ -92,6 +90,17 @@ # Enable this to use HW H.264 encoder/decoder on iOS PeerConnections. # Enabling this may break interop with Android clients that support H264. rtc_use_objc_h264 = false + + # Enable this to build H.264 encoder/decoder using third party libraries. + # Encoding uses OpenH264 and decoding uses FFmpeg. Because of this, OpenH264 + # and FFmpeg have to be correctly enabled separately. + # - use_openh264=true is required for OpenH264 targets to be defined. + # - ffmpeg_branding="Chrome" is one way to support H.264 decoding in FFmpeg. + # FFmpeg can be built with/without H.264 support, see 'ffmpeg_branding'. + # Without it, it compiles but H264DecoderImpl fails to initialize. + # CHECK THE OPENH264, FFMPEG AND H.264 LICENSES/PATENTS BEFORE BUILDING. + # http://www.openh264.org, https://www.ffmpeg.org/ + use_third_party_h264 = false # TODO(hbos): To be used in follow-up CL(s). } # Make it possible to provide custom locations for some libraries (move these
diff --git a/webrtc/call.h b/webrtc/call.h index e6e8cde..313c5e5 100644 --- a/webrtc/call.h +++ b/webrtc/call.h
@@ -16,16 +16,14 @@ #include "webrtc/common_types.h" #include "webrtc/audio_receive_stream.h" #include "webrtc/audio_send_stream.h" +#include "webrtc/audio_state.h" #include "webrtc/base/socket.h" #include "webrtc/video_receive_stream.h" #include "webrtc/video_send_stream.h" namespace webrtc { -class AudioDeviceModule; class AudioProcessing; -class VoiceEngine; -class VoiceEngineObserver; const char* Version(); @@ -74,9 +72,6 @@ struct Config { static const int kDefaultStartBitrateBps; - // VoiceEngine used for audio/video synchronization for this Call. - VoiceEngine* voice_engine = nullptr; - // Bitrate config used until valid bitrate estimates are calculated. Also // used to cap total bitrate used. struct BitrateConfig { @@ -85,11 +80,13 @@ int max_bitrate_bps = -1; } bitrate_config; - struct AudioConfig { - AudioDeviceModule* audio_device_module = nullptr; - AudioProcessing* audio_processing = nullptr; - VoiceEngineObserver* voice_engine_observer = nullptr; - } audio_config; + // AudioState which is possibly shared between multiple calls. + // TODO(solenberg): Change this to a shared_ptr once we can use C++11. + rtc::scoped_refptr<AudioState> audio_state; + + // Audio Processing Module to be used in this call. + // TODO(solenberg): Change this to a shared_ptr once we can use C++11. + AudioProcessing* audio_processing = nullptr; }; struct Stats {
diff --git a/webrtc/call/BUILD.gn b/webrtc/call/BUILD.gn index 3abc762..498c724 100644 --- a/webrtc/call/BUILD.gn +++ b/webrtc/call/BUILD.gn
@@ -10,6 +10,7 @@ source_set("call") { sources = [ + "bitrate_allocator.cc", "call.cc", "congestion_controller.cc", "transport_adapter.cc",
diff --git a/webrtc/call/bitrate_allocator.cc b/webrtc/call/bitrate_allocator.cc new file mode 100644 index 0000000..b3789d3 --- /dev/null +++ b/webrtc/call/bitrate_allocator.cc
@@ -0,0 +1,194 @@ +/* + * 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/call/bitrate_allocator.h" + +#include <algorithm> +#include <utility> + +#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" + +namespace webrtc { + +// Allow packets to be transmitted in up to 2 times max video bitrate if the +// bandwidth estimate allows it. +const int kTransmissionMaxBitrateMultiplier = 2; +const int kDefaultBitrateBps = 300000; + +BitrateAllocator::BitrateAllocator() + : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), + bitrate_observers_(), + bitrate_observers_modified_(false), + enforce_min_bitrate_(true), + last_bitrate_bps_(kDefaultBitrateBps), + last_fraction_loss_(0), + last_rtt_(0) {} + +uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate, + uint8_t fraction_loss, + int64_t rtt) { + CriticalSectionScoped lock(crit_sect_.get()); + last_bitrate_bps_ = bitrate; + last_fraction_loss_ = fraction_loss; + last_rtt_ = rtt; + uint32_t allocated_bitrate_bps = 0; + ObserverBitrateMap allocation = AllocateBitrates(); + for (const auto& kv : allocation) { + kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_); + allocated_bitrate_bps += kv.second; + } + return allocated_bitrate_bps; +} + +BitrateAllocator::ObserverBitrateMap BitrateAllocator::AllocateBitrates() { + if (bitrate_observers_.empty()) + return ObserverBitrateMap(); + + uint32_t sum_min_bitrates = 0; + for (const auto& observer : bitrate_observers_) + sum_min_bitrates += observer.second.min_bitrate; + if (last_bitrate_bps_ <= sum_min_bitrates) + return LowRateAllocation(last_bitrate_bps_); + else + return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates); +} + +int BitrateAllocator::AddBitrateObserver(BitrateObserver* observer, + uint32_t min_bitrate_bps, + uint32_t max_bitrate_bps) { + CriticalSectionScoped lock(crit_sect_.get()); + + BitrateObserverConfList::iterator it = + FindObserverConfigurationPair(observer); + + // Allow the max bitrate to be exceeded for FEC and retransmissions. + // TODO(holmer): We have to get rid of this hack as it makes it difficult to + // properly allocate bitrate. The allocator should instead distribute any + // extra bitrate after all streams have maxed out. + max_bitrate_bps *= kTransmissionMaxBitrateMultiplier; + if (it != bitrate_observers_.end()) { + // Update current configuration. + it->second.min_bitrate = min_bitrate_bps; + it->second.max_bitrate = max_bitrate_bps; + } else { + // Add new settings. + bitrate_observers_.push_back(BitrateObserverConfiguration( + observer, BitrateConfiguration(min_bitrate_bps, max_bitrate_bps))); + bitrate_observers_modified_ = true; + } + + ObserverBitrateMap allocation = AllocateBitrates(); + int new_observer_bitrate_bps = 0; + for (auto& kv : allocation) { + kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_); + if (kv.first == observer) + new_observer_bitrate_bps = kv.second; + } + return new_observer_bitrate_bps; +} + +void BitrateAllocator::RemoveBitrateObserver(BitrateObserver* observer) { + CriticalSectionScoped lock(crit_sect_.get()); + BitrateObserverConfList::iterator it = + FindObserverConfigurationPair(observer); + if (it != bitrate_observers_.end()) { + bitrate_observers_.erase(it); + bitrate_observers_modified_ = true; + } +} + +void BitrateAllocator::GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps, + int* max_bitrate_sum_bps) const { + *min_bitrate_sum_bps = 0; + *max_bitrate_sum_bps = 0; + + CriticalSectionScoped lock(crit_sect_.get()); + for (const auto& observer : bitrate_observers_) { + *min_bitrate_sum_bps += observer.second.min_bitrate; + *max_bitrate_sum_bps += observer.second.max_bitrate; + } +} + +BitrateAllocator::BitrateObserverConfList::iterator +BitrateAllocator::FindObserverConfigurationPair( + const BitrateObserver* observer) { + for (auto it = bitrate_observers_.begin(); it != bitrate_observers_.end(); + ++it) { + if (it->first == observer) + return it; + } + return bitrate_observers_.end(); +} + +void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) { + CriticalSectionScoped lock(crit_sect_.get()); + enforce_min_bitrate_ = enforce_min_bitrate; +} + +BitrateAllocator::ObserverBitrateMap BitrateAllocator::NormalRateAllocation( + uint32_t bitrate, + uint32_t sum_min_bitrates) { + uint32_t number_of_observers = + static_cast<uint32_t>(bitrate_observers_.size()); + uint32_t bitrate_per_observer = + (bitrate - sum_min_bitrates) / number_of_observers; + // Use map to sort list based on max bitrate. + ObserverSortingMap list_max_bitrates; + for (const auto& observer : bitrate_observers_) { + list_max_bitrates.insert(std::pair<uint32_t, ObserverConfiguration>( + observer.second.max_bitrate, + ObserverConfiguration(observer.first, observer.second.min_bitrate))); + } + ObserverBitrateMap allocation; + ObserverSortingMap::iterator max_it = list_max_bitrates.begin(); + while (max_it != list_max_bitrates.end()) { + number_of_observers--; + uint32_t observer_allowance = + max_it->second.min_bitrate + bitrate_per_observer; + if (max_it->first < observer_allowance) { + // We have more than enough for this observer. + // Carry the remainder forward. + uint32_t remainder = observer_allowance - max_it->first; + if (number_of_observers != 0) { + bitrate_per_observer += remainder / number_of_observers; + } + allocation[max_it->second.observer] = max_it->first; + } else { + allocation[max_it->second.observer] = observer_allowance; + } + list_max_bitrates.erase(max_it); + // Prepare next iteration. + max_it = list_max_bitrates.begin(); + } + return allocation; +} + +BitrateAllocator::ObserverBitrateMap BitrateAllocator::LowRateAllocation( + uint32_t bitrate) { + ObserverBitrateMap allocation; + if (enforce_min_bitrate_) { + // Min bitrate to all observers. + for (const auto& observer : bitrate_observers_) + allocation[observer.first] = observer.second.min_bitrate; + } else { + // Allocate up to |min_bitrate| to one observer at a time, until + // |bitrate| is depleted. + uint32_t remainder = bitrate; + for (const auto& observer : bitrate_observers_) { + uint32_t allocated_bitrate = + std::min(remainder, observer.second.min_bitrate); + allocation[observer.first] = allocated_bitrate; + remainder -= allocated_bitrate; + } + } + return allocation; +} +} // namespace webrtc
diff --git a/webrtc/call/bitrate_allocator.h b/webrtc/call/bitrate_allocator.h new file mode 100644 index 0000000..4a3fd59 --- /dev/null +++ b/webrtc/call/bitrate_allocator.h
@@ -0,0 +1,102 @@ +/* + * 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. + * + * Usage: this class will register multiple RtcpBitrateObserver's one at each + * RTCP module. It will aggregate the results and run one bandwidth estimation + * and push the result to the encoders via BitrateObserver(s). + */ + +#ifndef WEBRTC_CALL_BITRATE_ALLOCATOR_H_ +#define WEBRTC_CALL_BITRATE_ALLOCATOR_H_ + +#include <list> +#include <map> +#include <utility> + +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/thread_annotations.h" +#include "webrtc/system_wrappers/include/critical_section_wrapper.h" + +namespace webrtc { + +class BitrateObserver; + +class BitrateAllocator { + public: + BitrateAllocator(); + + // Allocate target_bitrate across the registered BitrateObservers. + // Returns actual bitrate allocated (might be higher than target_bitrate if + // for instance EnforceMinBitrate() is enabled. + uint32_t OnNetworkChanged(uint32_t target_bitrate, + uint8_t fraction_loss, + int64_t rtt); + + // Set the start and max send bitrate used by the bandwidth management. + // + // |observer| updates bitrates if already in use. + // |min_bitrate_bps| = 0 equals no min bitrate. + // |max_bitrate_bps| = 0 equals no max bitrate. + // Returns bitrate allocated for the bitrate observer. + int AddBitrateObserver(BitrateObserver* observer, + uint32_t min_bitrate_bps, + uint32_t max_bitrate_bps); + + void RemoveBitrateObserver(BitrateObserver* observer); + + void GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps, + int* max_bitrate_sum_bps) const; + + // This method controls the behavior when the available bitrate is lower than + // the minimum bitrate, or the sum of minimum bitrates. + // When true, the bitrate will never be set lower than the minimum bitrate(s). + // When false, the bitrate observers will be allocated rates up to their + // respective minimum bitrate, satisfying one observer after the other. + void EnforceMinBitrate(bool enforce_min_bitrate); + + private: + struct BitrateConfiguration { + BitrateConfiguration(uint32_t min_bitrate, uint32_t max_bitrate) + : min_bitrate(min_bitrate), max_bitrate(max_bitrate) {} + uint32_t min_bitrate; + uint32_t max_bitrate; + }; + struct ObserverConfiguration { + ObserverConfiguration(BitrateObserver* observer, uint32_t bitrate) + : observer(observer), min_bitrate(bitrate) {} + BitrateObserver* const observer; + uint32_t min_bitrate; + }; + typedef std::pair<BitrateObserver*, BitrateConfiguration> + BitrateObserverConfiguration; + typedef std::list<BitrateObserverConfiguration> BitrateObserverConfList; + typedef std::multimap<uint32_t, ObserverConfiguration> ObserverSortingMap; + typedef std::map<BitrateObserver*, int> ObserverBitrateMap; + + BitrateObserverConfList::iterator FindObserverConfigurationPair( + const BitrateObserver* observer) EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); + ObserverBitrateMap AllocateBitrates() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); + ObserverBitrateMap NormalRateAllocation(uint32_t bitrate, + uint32_t sum_min_bitrates) + EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); + + ObserverBitrateMap LowRateAllocation(uint32_t bitrate) + EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); + + rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_; + // Stored in a list to keep track of the insertion order. + BitrateObserverConfList bitrate_observers_ GUARDED_BY(crit_sect_); + bool bitrate_observers_modified_ GUARDED_BY(crit_sect_); + bool enforce_min_bitrate_ GUARDED_BY(crit_sect_); + uint32_t last_bitrate_bps_ GUARDED_BY(crit_sect_); + uint8_t last_fraction_loss_ GUARDED_BY(crit_sect_); + int64_t last_rtt_ GUARDED_BY(crit_sect_); +}; +} // namespace webrtc +#endif // WEBRTC_CALL_BITRATE_ALLOCATOR_H_
diff --git a/webrtc/call/bitrate_allocator_unittest.cc b/webrtc/call/bitrate_allocator_unittest.cc new file mode 100644 index 0000000..86f75a4 --- /dev/null +++ b/webrtc/call/bitrate_allocator_unittest.cc
@@ -0,0 +1,212 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/call/bitrate_allocator.h" +#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" + +namespace webrtc { + +class TestBitrateObserver : public BitrateObserver { + public: + TestBitrateObserver() + : last_bitrate_(0), last_fraction_loss_(0), last_rtt_(0) {} + + virtual void OnNetworkChanged(uint32_t bitrate, + uint8_t fraction_loss, + int64_t rtt) { + last_bitrate_ = bitrate; + last_fraction_loss_ = fraction_loss; + last_rtt_ = rtt; + } + uint32_t last_bitrate_; + uint8_t last_fraction_loss_; + int64_t last_rtt_; +}; + +class BitrateAllocatorTest : public ::testing::Test { + protected: + BitrateAllocatorTest() : allocator_(new BitrateAllocator()) { + allocator_->OnNetworkChanged(300000u, 0, 0); + } + ~BitrateAllocatorTest() {} + + rtc::scoped_ptr<BitrateAllocator> allocator_; +}; + +TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) { + TestBitrateObserver bitrate_observer; + int start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer, 100000, 1500000); + EXPECT_EQ(300000, start_bitrate); + allocator_->OnNetworkChanged(200000, 0, 0); + EXPECT_EQ(200000u, bitrate_observer.last_bitrate_); + + // TODO(pbos): Expect capping to 1.5M instead of 3M when not boosting the max + // bitrate for FEC/retransmissions (see todo in BitrateAllocator). + allocator_->OnNetworkChanged(4000000, 0, 0); + EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_); + start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer, 100000, 4000000); + EXPECT_EQ(4000000, start_bitrate); + + start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer, 100000, 1500000); + EXPECT_EQ(3000000, start_bitrate); + EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_); + allocator_->OnNetworkChanged(1500000, 0, 0); + EXPECT_EQ(1500000u, bitrate_observer.last_bitrate_); +} + +TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) { + TestBitrateObserver bitrate_observer_1; + TestBitrateObserver bitrate_observer_2; + int start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 300000); + EXPECT_EQ(300000, start_bitrate); + start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_2, 200000, 300000); + EXPECT_EQ(200000, start_bitrate); + + // Test too low start bitrate, hence lower than sum of min. Min bitrates will + // be allocated to all observers. + allocator_->OnNetworkChanged(200000, 0, 50); + EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); + EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_); + EXPECT_EQ(50, bitrate_observer_1.last_rtt_); + EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); + EXPECT_EQ(0, bitrate_observer_2.last_fraction_loss_); + EXPECT_EQ(50, bitrate_observer_2.last_rtt_); + + // Test a bitrate which should be distributed equally. + allocator_->OnNetworkChanged(500000, 0, 50); + const uint32_t kBitrateToShare = 500000 - 200000 - 100000; + EXPECT_EQ(100000u + kBitrateToShare / 2, bitrate_observer_1.last_bitrate_); + EXPECT_EQ(200000u + kBitrateToShare / 2, bitrate_observer_2.last_bitrate_); + + // Limited by 2x max bitrates since we leave room for FEC and retransmissions. + allocator_->OnNetworkChanged(1500000, 0, 50); + EXPECT_EQ(600000u, bitrate_observer_1.last_bitrate_); + EXPECT_EQ(600000u, bitrate_observer_2.last_bitrate_); +} + +class BitrateAllocatorTestNoEnforceMin : public ::testing::Test { + protected: + BitrateAllocatorTestNoEnforceMin() : allocator_(new BitrateAllocator()) { + allocator_->EnforceMinBitrate(false); + allocator_->OnNetworkChanged(300000u, 0, 0); + } + ~BitrateAllocatorTestNoEnforceMin() {} + + rtc::scoped_ptr<BitrateAllocator> allocator_; +}; + +// The following three tests verify that the EnforceMinBitrate() method works +// as intended. +TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserver) { + TestBitrateObserver bitrate_observer_1; + int start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 400000); + EXPECT_EQ(300000, start_bitrate); + + // High REMB. + allocator_->OnNetworkChanged(150000, 0, 0); + EXPECT_EQ(150000u, bitrate_observer_1.last_bitrate_); + + // Low REMB. + allocator_->OnNetworkChanged(10000, 0, 0); + EXPECT_EQ(10000u, bitrate_observer_1.last_bitrate_); + + allocator_->RemoveBitrateObserver(&bitrate_observer_1); +} + +TEST_F(BitrateAllocatorTestNoEnforceMin, ThreeBitrateObservers) { + TestBitrateObserver bitrate_observer_1; + TestBitrateObserver bitrate_observer_2; + TestBitrateObserver bitrate_observer_3; + // Set up the observers with min bitrates at 100000, 200000, and 300000. + int start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 400000); + EXPECT_EQ(300000, start_bitrate); + + start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_2, 200000, 400000); + EXPECT_EQ(200000, start_bitrate); + EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); + + start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_3, 300000, 400000); + EXPECT_EQ(0, start_bitrate); + EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); + EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); + + // High REMB. Make sure the controllers get a fair share of the surplus + // (i.e., what is left after each controller gets its min rate). + allocator_->OnNetworkChanged(690000, 0, 0); + // Verify that each observer gets its min rate (sum of min rates is 600000), + // and that the remaining 90000 is divided equally among the three. + uint32_t bitrate_to_share = 690000u - 100000u - 200000u - 300000u; + EXPECT_EQ(100000u + bitrate_to_share / 3, bitrate_observer_1.last_bitrate_); + EXPECT_EQ(200000u + bitrate_to_share / 3, bitrate_observer_2.last_bitrate_); + EXPECT_EQ(300000u + bitrate_to_share / 3, bitrate_observer_3.last_bitrate_); + + // High REMB, but below the sum of min bitrates. + allocator_->OnNetworkChanged(500000, 0, 0); + // Verify that the first and second observers get their min bitrates, and the + // third gets the remainder. + EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); // Min bitrate. + EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); // Min bitrate. + EXPECT_EQ(200000u, bitrate_observer_3.last_bitrate_); // Remainder. + + // Low REMB. + allocator_->OnNetworkChanged(10000, 0, 0); + // Verify that the first observer gets all the rate, and the rest get zero. + EXPECT_EQ(10000u, bitrate_observer_1.last_bitrate_); + EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_); + EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_); + + allocator_->RemoveBitrateObserver(&bitrate_observer_1); + allocator_->RemoveBitrateObserver(&bitrate_observer_2); + allocator_->RemoveBitrateObserver(&bitrate_observer_3); +} + +TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowRembEnforceMin) { + TestBitrateObserver bitrate_observer_1; + TestBitrateObserver bitrate_observer_2; + TestBitrateObserver bitrate_observer_3; + int start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 400000); + EXPECT_EQ(300000, start_bitrate); + + start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_2, 200000, 400000); + EXPECT_EQ(200000, start_bitrate); + EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); + + start_bitrate = + allocator_->AddBitrateObserver(&bitrate_observer_3, 300000, 400000); + EXPECT_EQ(300000, start_bitrate); + EXPECT_EQ(100000, static_cast<int>(bitrate_observer_1.last_bitrate_)); + EXPECT_EQ(200000, static_cast<int>(bitrate_observer_2.last_bitrate_)); + + // Low REMB. Verify that all observers still get their respective min bitrate. + allocator_->OnNetworkChanged(1000, 0, 0); + EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); // Min cap. + EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); // Min cap. + EXPECT_EQ(300000u, bitrate_observer_3.last_bitrate_); // Min cap. + + allocator_->RemoveBitrateObserver(&bitrate_observer_1); + allocator_->RemoveBitrateObserver(&bitrate_observer_2); + allocator_->RemoveBitrateObserver(&bitrate_observer_3); +} +} // namespace webrtc
diff --git a/webrtc/call/bitrate_estimator_tests.cc b/webrtc/call/bitrate_estimator_tests.cc index 685f3fd..4b24bbd 100644 --- a/webrtc/call/bitrate_estimator_tests.cc +++ b/webrtc/call/bitrate_estimator_tests.cc
@@ -13,66 +13,54 @@ #include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/audio_state.h" #include "webrtc/base/checks.h" +#include "webrtc/base/event.h" +#include "webrtc/base/logging.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/call.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" -#include "webrtc/system_wrappers/include/event_wrapper.h" #include "webrtc/system_wrappers/include/trace.h" #include "webrtc/test/call_test.h" #include "webrtc/test/direct_transport.h" #include "webrtc/test/encoder_settings.h" #include "webrtc/test/fake_decoder.h" #include "webrtc/test/fake_encoder.h" -#include "webrtc/test/fake_voice_engine.h" +#include "webrtc/test/mock_voice_engine.h" #include "webrtc/test/frame_generator_capturer.h" namespace webrtc { namespace { // Note: If you consider to re-use this class, think twice and instead consider -// writing tests that don't depend on the trace system. -class TraceObserver { +// writing tests that don't depend on the logging system. +class LogObserver { public: - TraceObserver() { - Trace::set_level_filter(kTraceTerseInfo); + LogObserver() { rtc::LogMessage::AddLogToStream(&callback_, rtc::LS_INFO); } - Trace::CreateTrace(); - Trace::SetTraceCallback(&callback_); - - // Call webrtc trace to initialize the tracer that would otherwise trigger a - // data-race if left to be initialized by multiple threads (i.e. threads - // spawned by test::DirectTransport members in BitrateEstimatorTest). - WEBRTC_TRACE(kTraceStateInfo, - kTraceUtility, - -1, - "Instantiate without data races."); - } - - ~TraceObserver() { - Trace::SetTraceCallback(nullptr); - Trace::ReturnTrace(); - } + ~LogObserver() { rtc::LogMessage::RemoveLogToStream(&callback_); } void PushExpectedLogLine(const std::string& expected_log_line) { callback_.PushExpectedLogLine(expected_log_line); } - EventTypeWrapper Wait() { - return callback_.Wait(); - } + bool Wait() { return callback_.Wait(); } private: - class Callback : public TraceCallback { + class Callback : public rtc::LogSink { public: - Callback() : done_(EventWrapper::Create()) {} + Callback() : done_(false, false) {} - void Print(TraceLevel level, const char* message, int length) override { + void OnLogMessage(const std::string& message) override { rtc::CritScope lock(&crit_sect_); - std::string msg(message); - if (msg.find("BitrateEstimator") != std::string::npos) { - received_log_lines_.push_back(msg); + // Ignore log lines that are due to missing AST extensions, these are + // logged when we switch back from AST to TOF until the wrapping bitrate + // estimator gives up on using AST. + if (message.find("BitrateEstimator") != std::string::npos && + message.find("packet is missing") == std::string::npos) { + received_log_lines_.push_back(message); } + int num_popped = 0; while (!received_log_lines_.empty() && !expected_log_lines_.empty()) { std::string a = received_log_lines_.front(); @@ -80,19 +68,17 @@ received_log_lines_.pop_front(); expected_log_lines_.pop_front(); num_popped++; - EXPECT_TRUE(a.find(b) != std::string::npos); + EXPECT_TRUE(a.find(b) != std::string::npos) << a << " != " << b; } if (expected_log_lines_.size() <= 0) { if (num_popped > 0) { - done_->Set(); + done_.Set(); } return; } } - EventTypeWrapper Wait() { - return done_->Wait(test::CallTest::kDefaultTimeoutMs); - } + bool Wait() { return done_.Wait(test::CallTest::kDefaultTimeoutMs); } void PushExpectedLogLine(const std::string& expected_log_line) { rtc::CritScope lock(&crit_sect_); @@ -104,7 +90,7 @@ rtc::CriticalSection crit_sect_; Strings received_log_lines_ GUARDED_BY(crit_sect_); Strings expected_log_lines_ GUARDED_BY(crit_sect_); - rtc::scoped_ptr<EventWrapper> done_; + rtc::Event done_; }; Callback callback_; @@ -118,13 +104,13 @@ public: BitrateEstimatorTest() : receive_config_(nullptr) {} - virtual ~BitrateEstimatorTest() { - EXPECT_TRUE(streams_.empty()); - } + virtual ~BitrateEstimatorTest() { EXPECT_TRUE(streams_.empty()); } virtual void SetUp() { + AudioState::Config audio_state_config; + audio_state_config.voice_engine = &mock_voice_engine_; Call::Config config; - config.voice_engine = &fake_voice_engine_; + config.audio_state = AudioState::Create(audio_state_config); receiver_call_.reset(Call::Create(config)); sender_call_.reset(Call::Create(config)); @@ -133,18 +119,19 @@ receive_transport_.reset(new test::DirectTransport(receiver_call_.get())); receive_transport_->SetReceiver(sender_call_->Receiver()); - send_config_ = VideoSendStream::Config(send_transport_.get()); - send_config_.rtp.ssrcs.push_back(kSendSsrcs[0]); + video_send_config_ = VideoSendStream::Config(send_transport_.get()); + video_send_config_.rtp.ssrcs.push_back(kVideoSendSsrcs[0]); // Encoders will be set separately per stream. - send_config_.encoder_settings.encoder = nullptr; - send_config_.encoder_settings.payload_name = "FAKE"; - send_config_.encoder_settings.payload_type = kFakeSendPayloadType; - encoder_config_.streams = test::CreateVideoStreams(1); + video_send_config_.encoder_settings.encoder = nullptr; + video_send_config_.encoder_settings.payload_name = "FAKE"; + video_send_config_.encoder_settings.payload_type = + kFakeVideoSendPayloadType; + video_encoder_config_.streams = test::CreateVideoStreams(1); receive_config_ = VideoReceiveStream::Config(receive_transport_.get()); // receive_config_.decoders will be set by every stream separately. - receive_config_.rtp.remote_ssrc = send_config_.rtp.ssrcs[0]; - receive_config_.rtp.local_ssrc = kReceiverLocalSsrc; + receive_config_.rtp.remote_ssrc = video_send_config_.rtp.ssrcs[0]; + receive_config_.rtp.local_ssrc = kReceiverLocalVideoSsrc; receive_config_.rtp.remb = true; receive_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); @@ -154,7 +141,7 @@ virtual void TearDown() { std::for_each(streams_.begin(), streams_.end(), - std::mem_fun(&Stream::StopSending)); + std::mem_fun(&Stream::StopSending)); send_transport_->StopSending(); receive_transport_->StopSending(); @@ -165,6 +152,7 @@ } receiver_call_.reset(); + sender_call_.reset(); } protected: @@ -181,23 +169,21 @@ frame_generator_capturer_(), fake_encoder_(Clock::GetRealTimeClock()), fake_decoder_() { - test_->send_config_.rtp.ssrcs[0]++; - test_->send_config_.encoder_settings.encoder = &fake_encoder_; + test_->video_send_config_.rtp.ssrcs[0]++; + test_->video_send_config_.encoder_settings.encoder = &fake_encoder_; send_stream_ = test_->sender_call_->CreateVideoSendStream( - test_->send_config_, test_->encoder_config_); - RTC_DCHECK_EQ(1u, test_->encoder_config_.streams.size()); + test_->video_send_config_, test_->video_encoder_config_); + RTC_DCHECK_EQ(1u, test_->video_encoder_config_.streams.size()); frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( - send_stream_->Input(), - test_->encoder_config_.streams[0].width, - test_->encoder_config_.streams[0].height, - 30, + send_stream_->Input(), test_->video_encoder_config_.streams[0].width, + test_->video_encoder_config_.streams[0].height, 30, Clock::GetRealTimeClock())); send_stream_->Start(); frame_generator_capturer_->Start(); if (receive_audio) { AudioReceiveStream::Config receive_config; - receive_config.rtp.remote_ssrc = test_->send_config_.rtp.ssrcs[0]; + receive_config.rtp.remote_ssrc = test_->video_send_config_.rtp.ssrcs[0]; // Bogus non-default id to prevent hitting a RTC_DCHECK when creating // the AudioReceiveStream. Every receive stream has to correspond to // an underlying channel id. @@ -211,12 +197,13 @@ VideoReceiveStream::Decoder decoder; decoder.decoder = &fake_decoder_; decoder.payload_type = - test_->send_config_.encoder_settings.payload_type; + test_->video_send_config_.encoder_settings.payload_type; decoder.payload_name = - test_->send_config_.encoder_settings.payload_name; + test_->video_send_config_.encoder_settings.payload_name; + test_->receive_config_.decoders.clear(); test_->receive_config_.decoders.push_back(decoder); test_->receive_config_.rtp.remote_ssrc = - test_->send_config_.rtp.ssrcs[0]; + test_->video_send_config_.rtp.ssrcs[0]; test_->receive_config_.rtp.local_ssrc++; video_receive_stream_ = test_->receiver_call_->CreateVideoReceiveStream( test_->receive_config_); @@ -262,8 +249,8 @@ test::FakeDecoder fake_decoder_; }; - test::FakeVoiceEngine fake_voice_engine_; - TraceObserver receiver_trace_; + testing::NiceMock<test::MockVoiceEngine> mock_voice_engine_; + LogObserver receiver_log_; rtc::scoped_ptr<test::DirectTransport> send_transport_; rtc::scoped_ptr<test::DirectTransport> receive_transport_; rtc::scoped_ptr<Call> sender_call_; @@ -278,89 +265,89 @@ "RemoteBitrateEstimatorSingleStream: Instantiating."; TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefaultForVideo) { - send_config_.rtp.extensions.push_back( + video_send_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this, false)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); } TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForAudio) { - send_config_.rtp.extensions.push_back( + video_send_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId)); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); - receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); + receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); streams_.push_back(new Stream(this, true)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); } TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForVideo) { - send_config_.rtp.extensions.push_back( + video_send_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId)); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); - receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); + receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); streams_.push_back(new Stream(this, false)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); } TEST_F(BitrateEstimatorTest, SwitchesToASTForAudio) { - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this, true)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); - send_config_.rtp.extensions.push_back( + video_send_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId)); - receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); - receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog); + receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); + receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); streams_.push_back(new Stream(this, true)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); } TEST_F(BitrateEstimatorTest, SwitchesToASTForVideo) { - send_config_.rtp.extensions.push_back( + video_send_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this, false)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); - send_config_.rtp.extensions[0] = + video_send_config_.rtp.extensions[0] = RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId); - receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); - receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog); + receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); + receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); streams_.push_back(new Stream(this, false)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); } TEST_F(BitrateEstimatorTest, SwitchesToASTThenBackToTOFForVideo) { - send_config_.rtp.extensions.push_back( + video_send_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this, false)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); - send_config_.rtp.extensions[0] = + video_send_config_.rtp.extensions[0] = RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId); - receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); - receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog); + receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); + receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); streams_.push_back(new Stream(this, false)); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); - send_config_.rtp.extensions[0] = + video_send_config_.rtp.extensions[0] = RtpExtension(RtpExtension::kTOffset, kTOFExtensionId); - receiver_trace_.PushExpectedLogLine( + receiver_log_.PushExpectedLogLine( "WrappingBitrateEstimator: Switching to transmission time offset RBE."); - receiver_trace_.PushExpectedLogLine(kSingleStreamLog); + receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this, false)); streams_[0]->StopSending(); streams_[1]->StopSending(); - EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); + EXPECT_TRUE(receiver_log_.Wait()); } } // namespace webrtc
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc index 594ddf5..5c46a48 100644 --- a/webrtc/call/call.cc +++ b/webrtc/call/call.cc
@@ -15,27 +15,33 @@ #include "webrtc/audio/audio_receive_stream.h" #include "webrtc/audio/audio_send_stream.h" +#include "webrtc/audio/audio_state.h" +#include "webrtc/audio/scoped_voe_interface.h" #include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/base/thread_checker.h" #include "webrtc/base/trace_event.h" #include "webrtc/call.h" +#include "webrtc/call/bitrate_allocator.h" #include "webrtc/call/congestion_controller.h" #include "webrtc/call/rtc_event_log.h" #include "webrtc/common.h" #include "webrtc/config.h" -#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" +#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" +#include "webrtc/modules/pacing/paced_sender.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" -#include "webrtc/modules/utility/interface/process_thread.h" +#include "webrtc/modules/utility/include/process_thread.h" #include "webrtc/system_wrappers/include/cpu_info.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" -#include "webrtc/system_wrappers/include/logging.h" +#include "webrtc/system_wrappers/include/metrics.h" #include "webrtc/system_wrappers/include/rw_lock_wrapper.h" #include "webrtc/system_wrappers/include/trace.h" +#include "webrtc/video/call_stats.h" #include "webrtc/video/video_receive_stream.h" #include "webrtc/video/video_send_stream.h" -#include "webrtc/video_engine/call_stats.h" #include "webrtc/voice_engine/include/voe_codec.h" namespace webrtc { @@ -44,7 +50,8 @@ namespace internal { -class Call : public webrtc::Call, public PacketReceiver { +class Call : public webrtc::Call, public PacketReceiver, + public BitrateObserver { public: explicit Call(const Call::Config& config); virtual ~Call(); @@ -83,6 +90,10 @@ void OnSentPacket(const rtc::SentPacket& sent_packet) override; + // Implements BitrateObserver. + void OnNetworkChanged(uint32_t bitrate_bps, uint8_t fraction_loss, + int64_t rtt_ms) override; + private: DeliveryStatus DeliverRtcp(MediaType media_type, const uint8_t* packet, size_t length); @@ -94,14 +105,28 @@ void ConfigureSync(const std::string& sync_group) EXCLUSIVE_LOCKS_REQUIRED(receive_crit_); + VoiceEngine* voice_engine() { + internal::AudioState* audio_state = + static_cast<internal::AudioState*>(config_.audio_state.get()); + if (audio_state) + return audio_state->voice_engine(); + else + return nullptr; + } + + void UpdateSendHistograms() EXCLUSIVE_LOCKS_REQUIRED(&bitrate_crit_); + void UpdateReceiveHistograms(); + + Clock* const clock_; + const int num_cpu_cores_; const rtc::scoped_ptr<ProcessThread> module_process_thread_; const rtc::scoped_ptr<CallStats> call_stats_; - const rtc::scoped_ptr<CongestionController> congestion_controller_; + const rtc::scoped_ptr<BitrateAllocator> bitrate_allocator_; Call::Config config_; rtc::ThreadChecker configuration_thread_checker_; - bool network_enabled_; + bool network_enabled_; rtc::scoped_ptr<RWLockWrapper> receive_crit_; // Audio and Video receive streams are owned by the client that creates them. @@ -123,7 +148,25 @@ VideoSendStream::RtpStateMap suspended_video_send_ssrcs_; RtcEventLog* event_log_ = nullptr; - VoECodec* voe_codec_ = nullptr; + + // The following members are only accessed (exclusively) from one thread and + // from the destructor, and therefore doesn't need any explicit + // synchronization. + int64_t received_video_bytes_; + int64_t received_audio_bytes_; + int64_t received_rtcp_bytes_; + int64_t first_rtp_packet_received_ms_; + int64_t last_rtp_packet_received_ms_; + int64_t first_packet_sent_ms_; + + // TODO(holmer): Remove this lock once BitrateController no longer calls + // OnNetworkChanged from multiple threads. + rtc::CriticalSection bitrate_crit_; + int64_t estimated_send_bitrate_sum_kbits_ GUARDED_BY(&bitrate_crit_); + int64_t pacer_bitrate_sum_kbits_ GUARDED_BY(&bitrate_crit_); + int64_t num_bitrate_updates_ GUARDED_BY(&bitrate_crit_); + + const rtc::scoped_ptr<CongestionController> congestion_controller_; RTC_DISALLOW_COPY_AND_ASSIGN(Call); }; @@ -136,15 +179,29 @@ namespace internal { Call::Call(const Call::Config& config) - : num_cpu_cores_(CpuInfo::DetectNumberOfCores()), + : clock_(Clock::GetRealTimeClock()), + num_cpu_cores_(CpuInfo::DetectNumberOfCores()), module_process_thread_(ProcessThread::Create("ModuleProcessThread")), - call_stats_(new CallStats()), - congestion_controller_(new CongestionController( - module_process_thread_.get(), call_stats_.get())), + call_stats_(new CallStats(clock_)), + bitrate_allocator_(new BitrateAllocator()), config_(config), network_enabled_(true), receive_crit_(RWLockWrapper::CreateRWLock()), - send_crit_(RWLockWrapper::CreateRWLock()) { + send_crit_(RWLockWrapper::CreateRWLock()), + received_video_bytes_(0), + received_audio_bytes_(0), + received_rtcp_bytes_(0), + first_rtp_packet_received_ms_(-1), + last_rtp_packet_received_ms_(-1), + first_packet_sent_ms_(-1), + estimated_send_bitrate_sum_kbits_(0), + pacer_bitrate_sum_kbits_(0), + num_bitrate_updates_(0), + congestion_controller_( + new CongestionController(module_process_thread_.get(), + call_stats_.get(), + this)) { + RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); RTC_DCHECK_GE(config.bitrate_config.min_bitrate_bps, 0); RTC_DCHECK_GE(config.bitrate_config.start_bitrate_bps, config.bitrate_config.min_bitrate_bps); @@ -152,12 +209,9 @@ RTC_DCHECK_GE(config.bitrate_config.max_bitrate_bps, config.bitrate_config.start_bitrate_bps); } - if (config.voice_engine) { - // Keep a reference to VoECodec, so we're sure the VoiceEngine lives for the - // duration of the call. - voe_codec_ = VoECodec::GetInterface(config.voice_engine); - if (voe_codec_) - event_log_ = voe_codec_->GetEventLog(); + if (config.audio_state.get()) { + ScopedVoEInterface<VoECodec> voe_codec(voice_engine()); + event_log_ = voe_codec->GetEventLog(); } Trace::CreateTrace(); @@ -168,10 +222,14 @@ config_.bitrate_config.min_bitrate_bps, config_.bitrate_config.start_bitrate_bps, config_.bitrate_config.max_bitrate_bps); + + congestion_controller_->GetBitrateController()->SetEventLog(event_log_); } Call::~Call() { RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + UpdateSendHistograms(); + UpdateReceiveHistograms(); RTC_CHECK(audio_send_ssrcs_.empty()); RTC_CHECK(video_send_ssrcs_.empty()); RTC_CHECK(video_send_streams_.empty()); @@ -182,9 +240,53 @@ module_process_thread_->DeRegisterModule(call_stats_.get()); module_process_thread_->Stop(); Trace::ReturnTrace(); +} - if (voe_codec_) - voe_codec_->Release(); +void Call::UpdateSendHistograms() { + if (num_bitrate_updates_ == 0 || first_packet_sent_ms_ == -1) + return; + int64_t elapsed_sec = + (clock_->TimeInMilliseconds() - first_packet_sent_ms_) / 1000; + if (elapsed_sec < metrics::kMinRunTimeInSeconds) + return; + int send_bitrate_kbps = + estimated_send_bitrate_sum_kbits_ / num_bitrate_updates_; + int pacer_bitrate_kbps = pacer_bitrate_sum_kbits_ / num_bitrate_updates_; + if (send_bitrate_kbps > 0) { + RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.EstimatedSendBitrateInKbps", + send_bitrate_kbps); + } + if (pacer_bitrate_kbps > 0) { + RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.PacerBitrateInKbps", + pacer_bitrate_kbps); + } +} + +void Call::UpdateReceiveHistograms() { + if (first_rtp_packet_received_ms_ == -1) + return; + int64_t elapsed_sec = + (last_rtp_packet_received_ms_ - first_rtp_packet_received_ms_) / 1000; + if (elapsed_sec < metrics::kMinRunTimeInSeconds) + return; + int audio_bitrate_kbps = received_audio_bytes_ * 8 / elapsed_sec / 1000; + int video_bitrate_kbps = received_video_bytes_ * 8 / elapsed_sec / 1000; + int rtcp_bitrate_bps = received_rtcp_bytes_ * 8 / elapsed_sec; + if (video_bitrate_kbps > 0) { + RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.VideoBitrateReceivedInKbps", + video_bitrate_kbps); + } + if (audio_bitrate_kbps > 0) { + RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.AudioBitrateReceivedInKbps", + audio_bitrate_kbps); + } + if (rtcp_bitrate_bps > 0) { + RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.RtcpBitrateReceivedInBps", + rtcp_bitrate_bps); + } + RTC_HISTOGRAM_COUNTS_SPARSE_100000( + "WebRTC.Call.BitrateReceivedInKbps", + audio_bitrate_kbps + video_bitrate_kbps + rtcp_bitrate_bps / 1000); } PacketReceiver* Call::Receiver() { @@ -198,8 +300,8 @@ const webrtc::AudioSendStream::Config& config) { TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream"); RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); - AudioSendStream* send_stream = - new AudioSendStream(config, config_.voice_engine); + AudioSendStream* send_stream = new AudioSendStream( + config, config_.audio_state, congestion_controller_.get()); if (!network_enabled_) send_stream->SignalNetworkState(kNetworkDown); { @@ -234,8 +336,7 @@ TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream"); RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); AudioReceiveStream* receive_stream = new AudioReceiveStream( - congestion_controller_->GetRemoteBitrateEstimator(false), config, - config_.voice_engine); + congestion_controller_.get(), config, config_.audio_state); { WriteLockScoped write_lock(*receive_crit_); RTC_DCHECK(audio_receive_ssrcs_.find(config.rtp.remote_ssrc) == @@ -279,8 +380,8 @@ // the call has already started. VideoSendStream* send_stream = new VideoSendStream( num_cpu_cores_, module_process_thread_.get(), call_stats_.get(), - congestion_controller_.get(), config, encoder_config, - suspended_video_send_ssrcs_); + congestion_controller_.get(), bitrate_allocator_.get(), config, + encoder_config, suspended_video_send_ssrcs_); if (!network_enabled_) send_stream->SignalNetworkState(kNetworkDown); @@ -338,7 +439,7 @@ RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); VideoReceiveStream* receive_stream = new VideoReceiveStream( num_cpu_cores_, congestion_controller_.get(), config, - config_.voice_engine, module_process_thread_.get(), call_stats_.get()); + voice_engine(), module_process_thread_.get(), call_stats_.get()); WriteLockScoped write_lock(*receive_crit_); RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) == @@ -463,12 +564,48 @@ } void Call::OnSentPacket(const rtc::SentPacket& sent_packet) { + if (first_packet_sent_ms_ == -1) + first_packet_sent_ms_ = clock_->TimeInMilliseconds(); congestion_controller_->OnSentPacket(sent_packet); } +void Call::OnNetworkChanged(uint32_t target_bitrate_bps, uint8_t fraction_loss, + int64_t rtt_ms) { + uint32_t allocated_bitrate_bps = bitrate_allocator_->OnNetworkChanged( + target_bitrate_bps, fraction_loss, rtt_ms); + + int pad_up_to_bitrate_bps = 0; + { + ReadLockScoped read_lock(*send_crit_); + // No need to update as long as we're not sending. + if (video_send_streams_.empty()) + return; + + for (VideoSendStream* stream : video_send_streams_) + pad_up_to_bitrate_bps += stream->GetPaddingNeededBps(); + } + // Allocated bitrate might be higher than bitrate estimate if enforcing min + // bitrate, or lower if estimate is higher than the sum of max bitrates, so + // set the pacer bitrate to the maximum of the two. + uint32_t pacer_bitrate_bps = + std::max(target_bitrate_bps, allocated_bitrate_bps); + { + rtc::CritScope lock(&bitrate_crit_); + // We only update these stats if we have send streams, and assume that + // OnNetworkChanged is called roughly with a fixed frequency. + estimated_send_bitrate_sum_kbits_ += target_bitrate_bps / 1000; + pacer_bitrate_sum_kbits_ += pacer_bitrate_bps / 1000; + ++num_bitrate_updates_; + } + congestion_controller_->UpdatePacerBitrate( + target_bitrate_bps / 1000, + PacedSender::kDefaultPaceMultiplier * pacer_bitrate_bps / 1000, + pad_up_to_bitrate_bps / 1000); +} + void Call::ConfigureSync(const std::string& sync_group) { // Set sync only if there was no previous one. - if (config_.voice_engine == nullptr || sync_group.empty()) + if (voice_engine() == nullptr || sync_group.empty()) return; AudioReceiveStream* sync_audio_stream = nullptr; @@ -506,10 +643,10 @@ } // Only sync the first A/V pair within this sync group. if (sync_audio_stream != nullptr && num_synced_streams == 1) { - video_stream->SetSyncChannel(config_.voice_engine, + video_stream->SetSyncChannel(voice_engine(), sync_audio_stream->config().voe_channel_id); } else { - video_stream->SetSyncChannel(config_.voice_engine, -1); + video_stream->SetSyncChannel(voice_engine(), -1); } } } @@ -517,10 +654,12 @@ PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type, const uint8_t* packet, size_t length) { + TRACE_EVENT0("webrtc", "Call::DeliverRtcp"); // TODO(pbos): Figure out what channel needs it actually. // Do NOT broadcast! Also make sure it's a valid packet. // Return DELIVERY_UNKNOWN_SSRC if it can be determined that // there's no receiver of the packet. + received_rtcp_bytes_ += length; bool rtcp_delivered = false; if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) { ReadLockScoped read_lock(*receive_crit_); @@ -549,16 +688,21 @@ const uint8_t* packet, size_t length, const PacketTime& packet_time) { + TRACE_EVENT0("webrtc", "Call::DeliverRtp"); // Minimum RTP header size. if (length < 12) return DELIVERY_PACKET_ERROR; - uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(&packet[8]); + last_rtp_packet_received_ms_ = clock_->TimeInMilliseconds(); + if (first_rtp_packet_received_ms_ == -1) + first_rtp_packet_received_ms_ = last_rtp_packet_received_ms_; + uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(&packet[8]); ReadLockScoped read_lock(*receive_crit_); if (media_type == MediaType::ANY || media_type == MediaType::AUDIO) { auto it = audio_receive_ssrcs_.find(ssrc); if (it != audio_receive_ssrcs_.end()) { + received_audio_bytes_ += length; auto status = it->second->DeliverRtp(packet, length, packet_time) ? DELIVERY_OK : DELIVERY_PACKET_ERROR; @@ -570,6 +714,7 @@ if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) { auto it = video_receive_ssrcs_.find(ssrc); if (it != video_receive_ssrcs_.end()) { + received_video_bytes_ += length; auto status = it->second->DeliverRtp(packet, length, packet_time) ? DELIVERY_OK : DELIVERY_PACKET_ERROR;
diff --git a/webrtc/call/call_perf_tests.cc b/webrtc/call/call_perf_tests.cc index c37b83b..3adcb10 100644 --- a/webrtc/call/call_perf_tests.cc +++ b/webrtc/call/call_perf_tests.cc
@@ -18,8 +18,10 @@ #include "webrtc/base/thread_annotations.h" #include "webrtc/call.h" #include "webrtc/call/transport_adapter.h" -#include "webrtc/modules/audio_coding/main/include/audio_coding_module.h" -#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" +#include "webrtc/common.h" +#include "webrtc/config.h" +#include "webrtc/modules/audio_coding/include/audio_coding_module.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" #include "webrtc/system_wrappers/include/rtp_to_ntp.h" @@ -172,7 +174,7 @@ false); } if (time_since_creation > kMinRunTimeMs) - observation_complete_->Set(); + observation_complete_.Set(); } } @@ -189,6 +191,8 @@ void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) { const char* kSyncGroup = "av_sync"; + const uint32_t kAudioSendSsrc = 1234; + const uint32_t kAudioRecvSsrc = 5678; class AudioPacketReceiver : public PacketReceiver { public: AudioPacketReceiver(int channel, VoENetwork* voe_network) @@ -228,35 +232,45 @@ test::FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(), audio_filename); EXPECT_EQ(0, voe_base->Init(&fake_audio_device, nullptr)); - int channel = voe_base->CreateChannel(); + Config voe_config; + voe_config.Set<VoicePacing>(new VoicePacing(true)); + int send_channel_id = voe_base->CreateChannel(voe_config); + int recv_channel_id = voe_base->CreateChannel(); SyncRtcpObserver audio_observer; + AudioState::Config send_audio_state_config; + send_audio_state_config.voice_engine = voice_engine; + Call::Config sender_config; + sender_config.audio_state = AudioState::Create(send_audio_state_config); Call::Config receiver_config; - receiver_config.voice_engine = voice_engine; - CreateCalls(Call::Config(), receiver_config); + receiver_config.audio_state = sender_config.audio_state; + CreateCalls(sender_config, receiver_config); - CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000}; - EXPECT_EQ(0, voe_codec->SetSendCodec(channel, isac)); - - AudioPacketReceiver voe_packet_receiver(channel, voe_network); + AudioPacketReceiver voe_send_packet_receiver(send_channel_id, voe_network); + AudioPacketReceiver voe_recv_packet_receiver(recv_channel_id, voe_network); FakeNetworkPipe::Config net_config; net_config.queue_delay_ms = 500; net_config.loss_percent = 5; test::PacketTransport audio_send_transport( nullptr, &audio_observer, test::PacketTransport::kSender, net_config); - audio_send_transport.SetReceiver(&voe_packet_receiver); + audio_send_transport.SetReceiver(&voe_recv_packet_receiver); test::PacketTransport audio_receive_transport( nullptr, &audio_observer, test::PacketTransport::kReceiver, net_config); - audio_receive_transport.SetReceiver(&voe_packet_receiver); + audio_receive_transport.SetReceiver(&voe_send_packet_receiver); - internal::TransportAdapter transport_adapter(&audio_send_transport); - transport_adapter.Enable(); - EXPECT_EQ(0, - voe_network->RegisterExternalTransport(channel, transport_adapter)); + internal::TransportAdapter send_transport_adapter(&audio_send_transport); + send_transport_adapter.Enable(); + EXPECT_EQ(0, voe_network->RegisterExternalTransport(send_channel_id, + send_transport_adapter)); - VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(), channel, + internal::TransportAdapter recv_transport_adapter(&audio_receive_transport); + recv_transport_adapter.Enable(); + EXPECT_EQ(0, voe_network->RegisterExternalTransport(recv_channel_id, + recv_transport_adapter)); + + VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(), recv_channel_id, voe_sync, &audio_observer); test::PacketTransport sync_send_transport(sender_call_.get(), &observer, @@ -270,34 +284,45 @@ test::FakeDecoder fake_decoder; - CreateSendConfig(1, &sync_send_transport); + CreateSendConfig(1, 0, &sync_send_transport); CreateMatchingReceiveConfigs(&sync_receive_transport); - send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs; + AudioSendStream::Config audio_send_config(&audio_send_transport); + audio_send_config.voe_channel_id = send_channel_id; + audio_send_config.rtp.ssrc = kAudioSendSsrc; + AudioSendStream* audio_send_stream = + sender_call_->CreateAudioSendStream(audio_send_config); + + CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000}; + EXPECT_EQ(0, voe_codec->SetSendCodec(send_channel_id, isac)); + + video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs; if (fec) { - send_config_.rtp.fec.red_payload_type = kRedPayloadType; - send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType; - receive_configs_[0].rtp.fec.red_payload_type = kRedPayloadType; - receive_configs_[0].rtp.fec.ulpfec_payload_type = kUlpfecPayloadType; + video_send_config_.rtp.fec.red_payload_type = kRedPayloadType; + video_send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType; + video_receive_configs_[0].rtp.fec.red_payload_type = kRedPayloadType; + video_receive_configs_[0].rtp.fec.ulpfec_payload_type = kUlpfecPayloadType; } - receive_configs_[0].rtp.nack.rtp_history_ms = 1000; - receive_configs_[0].renderer = &observer; - receive_configs_[0].sync_group = kSyncGroup; + video_receive_configs_[0].rtp.nack.rtp_history_ms = 1000; + video_receive_configs_[0].renderer = &observer; + video_receive_configs_[0].sync_group = kSyncGroup; - AudioReceiveStream::Config audio_config; - audio_config.voe_channel_id = channel; - audio_config.sync_group = kSyncGroup; + AudioReceiveStream::Config audio_recv_config; + audio_recv_config.rtp.remote_ssrc = kAudioSendSsrc; + audio_recv_config.rtp.local_ssrc = kAudioRecvSsrc; + audio_recv_config.voe_channel_id = recv_channel_id; + audio_recv_config.sync_group = kSyncGroup; - AudioReceiveStream* audio_receive_stream = nullptr; + AudioReceiveStream* audio_receive_stream; if (create_audio_first) { audio_receive_stream = - receiver_call_->CreateAudioReceiveStream(audio_config); - CreateStreams(); + receiver_call_->CreateAudioReceiveStream(audio_recv_config); + CreateVideoStreams(); } else { - CreateStreams(); + CreateVideoStreams(); audio_receive_stream = - receiver_call_->CreateAudioReceiveStream(audio_config); + receiver_call_->CreateAudioReceiveStream(audio_recv_config); } CreateFrameGeneratorCapturer(); @@ -305,16 +330,16 @@ Start(); fake_audio_device.Start(); - EXPECT_EQ(0, voe_base->StartPlayout(channel)); - EXPECT_EQ(0, voe_base->StartReceive(channel)); - EXPECT_EQ(0, voe_base->StartSend(channel)); + EXPECT_EQ(0, voe_base->StartPlayout(recv_channel_id)); + EXPECT_EQ(0, voe_base->StartReceive(recv_channel_id)); + EXPECT_EQ(0, voe_base->StartSend(send_channel_id)); - EXPECT_EQ(kEventSignaled, observer.Wait()) + EXPECT_TRUE(observer.Wait()) << "Timed out while waiting for audio and video to be synchronized."; - EXPECT_EQ(0, voe_base->StopSend(channel)); - EXPECT_EQ(0, voe_base->StopReceive(channel)); - EXPECT_EQ(0, voe_base->StopPlayout(channel)); + EXPECT_EQ(0, voe_base->StopSend(send_channel_id)); + EXPECT_EQ(0, voe_base->StopReceive(recv_channel_id)); + EXPECT_EQ(0, voe_base->StopPlayout(recv_channel_id)); fake_audio_device.Stop(); Stop(); @@ -323,16 +348,18 @@ audio_send_transport.StopSending(); audio_receive_transport.StopSending(); - voe_base->DeleteChannel(channel); + DestroyStreams(); + + sender_call_->DestroyAudioSendStream(audio_send_stream); + receiver_call_->DestroyAudioReceiveStream(audio_receive_stream); + + voe_base->DeleteChannel(send_channel_id); + voe_base->DeleteChannel(recv_channel_id); voe_base->Release(); voe_codec->Release(); voe_network->Release(); voe_sync->Release(); - DestroyStreams(); - - receiver_call_->DestroyAudioReceiveStream(audio_receive_stream); - DestroyCalls(); VoiceEngine::Delete(voice_engine); @@ -357,8 +384,12 @@ class CaptureNtpTimeObserver : public test::EndToEndTest, public VideoRenderer { public: - CaptureNtpTimeObserver(int threshold_ms, int start_time_ms, int run_time_ms) + CaptureNtpTimeObserver(const FakeNetworkPipe::Config& net_config, + int threshold_ms, + int start_time_ms, + int run_time_ms) : EndToEndTest(kLongTimeoutMs), + net_config_(net_config), clock_(Clock::GetRealTimeClock()), threshold_ms_(threshold_ms), start_time_ms_(start_time_ms), @@ -369,6 +400,16 @@ rtp_start_timestamp_(0) {} private: + test::PacketTransport* CreateSendTransport(Call* sender_call) override { + return new test::PacketTransport( + sender_call, this, test::PacketTransport::kSender, net_config_); + } + + test::PacketTransport* CreateReceiveTransport() override { + return new test::PacketTransport( + nullptr, this, test::PacketTransport::kReceiver, net_config_); + } + void RenderFrame(const VideoFrame& video_frame, int time_to_render_ms) override { rtc::CritScope lock(&crit_); @@ -386,7 +427,7 @@ } if (time_since_creation > run_time_ms_) { - observation_complete_->Set(); + observation_complete_.Set(); } FrameCaptureTimeList::iterator iter = @@ -437,21 +478,23 @@ capturer_ = frame_generator_capturer; } - void ModifyConfigs(VideoSendStream::Config* send_config, - std::vector<VideoReceiveStream::Config>* receive_configs, - VideoEncoderConfig* encoder_config) override { + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config) override { (*receive_configs)[0].renderer = this; // Enable the receiver side rtt calculation. (*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true; } void PerformTest() override { - EXPECT_EQ(kEventSignaled, Wait()) << "Timed out while waiting for " - "estimated capture NTP time to be " - "within bounds."; + EXPECT_TRUE(Wait()) << "Timed out while waiting for " + "estimated capture NTP time to be " + "within bounds."; } rtc::CriticalSection crit_; + const FakeNetworkPipe::Config net_config_; Clock* const clock_; int threshold_ms_; int start_time_ms_; @@ -462,9 +505,9 @@ uint32_t rtp_start_timestamp_; typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList; FrameCaptureTimeList capture_time_list_ GUARDED_BY(&crit_); - } test(threshold_ms, start_time_ms, run_time_ms); + } test(net_config, threshold_ms, start_time_ms, run_time_ms); - RunBaseTest(&test, net_config); + RunBaseTest(&test); } TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) { @@ -501,26 +544,26 @@ void OnLoadUpdate(Load load) override { if (load == tested_load_) - observation_complete_->Set(); + observation_complete_.Set(); } - void ModifyConfigs(VideoSendStream::Config* send_config, - std::vector<VideoReceiveStream::Config>* receive_configs, - VideoEncoderConfig* encoder_config) override { + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config) override { send_config->overuse_callback = this; send_config->encoder_settings.encoder = &encoder_; } void PerformTest() override { - EXPECT_EQ(kEventSignaled, Wait()) - << "Timed out before receiving an overuse callback."; + EXPECT_TRUE(Wait()) << "Timed out before receiving an overuse callback."; } LoadObserver::Load tested_load_; test::DelayedEncoder encoder_; } test(tested_load, encode_delay_ms); - RunBaseTest(&test, FakeNetworkPipe::Config()); + RunBaseTest(&test); } TEST_F(CallPerfTest, ReceivesCpuUnderuse) { @@ -581,21 +624,22 @@ } if (num_bitrate_observations_in_range_ == kNumBitrateObservationsInRange) - observation_complete_->Set(); + observation_complete_.Set(); } } return SEND_PACKET; } - void OnStreamsCreated( + void OnVideoStreamsCreated( VideoSendStream* send_stream, const std::vector<VideoReceiveStream*>& receive_streams) override { send_stream_ = send_stream; } - void ModifyConfigs(VideoSendStream::Config* send_config, - std::vector<VideoReceiveStream::Config>* receive_configs, - VideoEncoderConfig* encoder_config) override { + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config) override { if (pad_to_min_bitrate_) { encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps; } else { @@ -604,8 +648,7 @@ } void PerformTest() override { - EXPECT_EQ(kEventSignaled, Wait()) - << "Timeout while waiting for send-bitrate stats."; + EXPECT_TRUE(Wait()) << "Timeout while waiting for send-bitrate stats."; } VideoSendStream* send_stream_; @@ -614,7 +657,7 @@ } test(pad_to_min_bitrate); fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps); - RunBaseTest(&test, FakeNetworkPipe::Config()); + RunBaseTest(&test); } TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); } @@ -633,7 +676,7 @@ BitrateObserver() : EndToEndTest(kDefaultTimeoutMs), FakeEncoder(Clock::GetRealTimeClock()), - time_to_reconfigure_(webrtc::EventWrapper::Create()), + time_to_reconfigure_(false, false), encoder_inits_(0), last_set_bitrate_(0), send_stream_(nullptr) {} @@ -652,7 +695,7 @@ last_set_bitrate_, kPermittedReconfiguredBitrateDiffKbps) << "Encoder reconfigured with bitrate too far away from last set."; - observation_complete_->Set(); + observation_complete_.Set(); } return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size); } @@ -662,7 +705,7 @@ last_set_bitrate_ = new_target_bitrate_kbps; if (encoder_inits_ == 1 && new_target_bitrate_kbps > kReconfigureThresholdKbps) { - time_to_reconfigure_->Set(); + time_to_reconfigure_.Set(); } return FakeEncoder::SetRates(new_target_bitrate_kbps, framerate); } @@ -673,9 +716,10 @@ return config; } - void ModifyConfigs(VideoSendStream::Config* send_config, - std::vector<VideoReceiveStream::Config>* receive_configs, - VideoEncoderConfig* encoder_config) override { + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config) override { send_config->encoder_settings.encoder = this; encoder_config->streams[0].min_bitrate_bps = 50000; encoder_config->streams[0].target_bitrate_bps = @@ -684,32 +728,32 @@ encoder_config_ = *encoder_config; } - void OnStreamsCreated( + void OnVideoStreamsCreated( VideoSendStream* send_stream, const std::vector<VideoReceiveStream*>& receive_streams) override { send_stream_ = send_stream; } void PerformTest() override { - ASSERT_EQ(kEventSignaled, time_to_reconfigure_->Wait(kDefaultTimeoutMs)) + ASSERT_TRUE(time_to_reconfigure_.Wait(kDefaultTimeoutMs)) << "Timed out before receiving an initial high bitrate."; encoder_config_.streams[0].width *= 2; encoder_config_.streams[0].height *= 2; EXPECT_TRUE(send_stream_->ReconfigureVideoEncoder(encoder_config_)); - EXPECT_EQ(kEventSignaled, Wait()) + EXPECT_TRUE(Wait()) << "Timed out while waiting for a couple of high bitrate estimates " "after reconfiguring the send stream."; } private: - rtc::scoped_ptr<webrtc::EventWrapper> time_to_reconfigure_; + rtc::Event time_to_reconfigure_; int encoder_inits_; uint32_t last_set_bitrate_; VideoSendStream* send_stream_; VideoEncoderConfig encoder_config_; } test; - RunBaseTest(&test, FakeNetworkPipe::Config()); + RunBaseTest(&test); } } // namespace webrtc
diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc index 9819b53..75c8238 100644 --- a/webrtc/call/call_unittest.cc +++ b/webrtc/call/call_unittest.cc
@@ -12,22 +12,25 @@ #include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/audio_state.h" #include "webrtc/call.h" -#include "webrtc/test/fake_voice_engine.h" +#include "webrtc/test/mock_voice_engine.h" namespace { struct CallHelper { - CallHelper() : voice_engine_(new webrtc::test::FakeVoiceEngine()) { + CallHelper() { + webrtc::AudioState::Config audio_state_config; + audio_state_config.voice_engine = &voice_engine_; webrtc::Call::Config config; - config.voice_engine = voice_engine_.get(); + config.audio_state = webrtc::AudioState::Create(audio_state_config); call_.reset(webrtc::Call::Create(config)); } webrtc::Call* operator->() { return call_.get(); } private: - rtc::scoped_ptr<webrtc::test::FakeVoiceEngine> voice_engine_; + testing::NiceMock<webrtc::test::MockVoiceEngine> voice_engine_; rtc::scoped_ptr<webrtc::Call> call_; }; } // namespace
diff --git a/webrtc/call/congestion_controller.cc b/webrtc/call/congestion_controller.cc index 1ec361e..c442667 100644 --- a/webrtc/call/congestion_controller.cc +++ b/webrtc/call/congestion_controller.cc
@@ -11,23 +11,24 @@ #include "webrtc/call/congestion_controller.h" #include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/common.h" -#include "webrtc/modules/pacing/include/paced_sender.h" -#include "webrtc/modules/pacing/include/packet_router.h" +#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" +#include "webrtc/modules/pacing/paced_sender.h" +#include "webrtc/modules/pacing/packet_router.h" #include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h" #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h" #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h" #include "webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h" #include "webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h" -#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" -#include "webrtc/modules/utility/interface/process_thread.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" +#include "webrtc/modules/utility/include/process_thread.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" -#include "webrtc/system_wrappers/include/logging.h" -#include "webrtc/video_engine/call_stats.h" -#include "webrtc/video_engine/payload_router.h" -#include "webrtc/video_engine/vie_encoder.h" -#include "webrtc/video_engine/vie_remb.h" +#include "webrtc/video/call_stats.h" +#include "webrtc/video/payload_router.h" +#include "webrtc/video/vie_encoder.h" +#include "webrtc/video/vie_remb.h" #include "webrtc/voice_engine/include/voe_video_sync.h" namespace webrtc { @@ -144,9 +145,9 @@ } // namespace CongestionController::CongestionController(ProcessThread* process_thread, - CallStats* call_stats) - : remb_(new VieRemb()), - bitrate_allocator_(new BitrateAllocator()), + CallStats* call_stats, + BitrateObserver* bitrate_observer) + : remb_(new VieRemb(Clock::GetRealTimeClock())), packet_router_(new PacketRouter()), pacer_(new PacedSender(Clock::GetRealTimeClock(), packet_router_.get(), @@ -166,7 +167,7 @@ // construction. bitrate_controller_( BitrateController::CreateBitrateController(Clock::GetRealTimeClock(), - this)), + bitrate_observer)), min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps) { call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get()); @@ -249,6 +250,12 @@ return transport_feedback_adapter_.get(); } +void CongestionController::UpdatePacerBitrate(int bitrate_kbps, + int max_bitrate_kbps, + int min_bitrate_kbps) { + pacer_->UpdateBitrate(bitrate_kbps, max_bitrate_kbps, min_bitrate_kbps); +} + int64_t CongestionController::GetPacerQueuingDelayMs() const { return pacer_->QueueInMs(); } @@ -278,23 +285,6 @@ } } -// TODO(mflodman): Move this logic out from CongestionController. -void CongestionController::OnNetworkChanged(uint32_t target_bitrate_bps, - uint8_t fraction_loss, - int64_t rtt) { - bitrate_allocator_->OnNetworkChanged(target_bitrate_bps, fraction_loss, rtt); - int pad_up_to_bitrate_bps = 0; - { - rtc::CritScope lock(&encoder_crit_); - for (const auto& encoder : encoders_) - pad_up_to_bitrate_bps += encoder->GetPaddingNeededBps(); - } - pacer_->UpdateBitrate( - target_bitrate_bps / 1000, - PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, - pad_up_to_bitrate_bps / 1000); -} - void CongestionController::OnSentPacket(const rtc::SentPacket& sent_packet) { if (transport_feedback_adapter_) { transport_feedback_adapter_->OnSentPacket(sent_packet.packet_id,
diff --git a/webrtc/call/congestion_controller.h b/webrtc/call/congestion_controller.h index b424234..b77c46f 100644 --- a/webrtc/call/congestion_controller.h +++ b/webrtc/call/congestion_controller.h
@@ -16,12 +16,12 @@ #include "webrtc/base/criticalsection.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/socket.h" -#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" #include "webrtc/stream.h" namespace webrtc { -class BitrateAllocator; +class BitrateController; +class BitrateObserver; class CallStats; class Config; class PacedSender; @@ -32,43 +32,43 @@ class RtpRtcp; class SendStatisticsProxy; class TransportFeedbackAdapter; +class TransportFeedbackObserver; class ViEEncoder; class VieRemb; -class CongestionController : public BitrateObserver { +class CongestionController { public: - CongestionController(ProcessThread* process_thread, CallStats* call_stats); - ~CongestionController(); - void AddEncoder(ViEEncoder* encoder); - void RemoveEncoder(ViEEncoder* encoder); - void SetBweBitrates(int min_bitrate_bps, - int start_bitrate_bps, - int max_bitrate_bps); + CongestionController(ProcessThread* process_thread, CallStats* call_stats, + BitrateObserver* bitrate_observer); + virtual ~CongestionController(); + virtual void AddEncoder(ViEEncoder* encoder); + virtual void RemoveEncoder(ViEEncoder* encoder); + virtual void SetBweBitrates(int min_bitrate_bps, + int start_bitrate_bps, + int max_bitrate_bps); - void SetChannelRembStatus(bool sender, bool receiver, RtpRtcp* rtp_module); + virtual void SetChannelRembStatus(bool sender, + bool receiver, + RtpRtcp* rtp_module); - void SignalNetworkState(NetworkState state); + virtual void SignalNetworkState(NetworkState state); - BitrateController* GetBitrateController() const; - RemoteBitrateEstimator* GetRemoteBitrateEstimator(bool send_side_bwe) const; - int64_t GetPacerQueuingDelayMs() const; - PacedSender* pacer() const { return pacer_.get(); } - PacketRouter* packet_router() const { return packet_router_.get(); } - BitrateAllocator* bitrate_allocator() const { - return bitrate_allocator_.get(); } - TransportFeedbackObserver* GetTransportFeedbackObserver(); + virtual BitrateController* GetBitrateController() const; + virtual RemoteBitrateEstimator* GetRemoteBitrateEstimator( + bool send_side_bwe) const; + virtual int64_t GetPacerQueuingDelayMs() const; + virtual PacedSender* pacer() const { return pacer_.get(); } + virtual PacketRouter* packet_router() const { return packet_router_.get(); } + virtual TransportFeedbackObserver* GetTransportFeedbackObserver(); - // Implements BitrateObserver. - void OnNetworkChanged(uint32_t target_bitrate_bps, - uint8_t fraction_loss, - int64_t rtt) override; + virtual void UpdatePacerBitrate(int bitrate_kbps, + int max_bitrate_kbps, + int min_bitrate_kbps); - void OnSentPacket(const rtc::SentPacket& sent_packet); + virtual void OnSentPacket(const rtc::SentPacket& sent_packet); private: rtc::scoped_ptr<VieRemb> remb_; - // TODO(mflodman): Move bitrate_allocator_ to Call. - rtc::scoped_ptr<BitrateAllocator> bitrate_allocator_; rtc::scoped_ptr<PacketRouter> packet_router_; rtc::scoped_ptr<PacedSender> pacer_; rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_; @@ -86,6 +86,8 @@ rtc::scoped_ptr<BitrateController> bitrate_controller_; rtc::scoped_ptr<TransportFeedbackAdapter> transport_feedback_adapter_; int min_bitrate_bps_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(CongestionController); }; } // namespace webrtc
diff --git a/webrtc/call/mock/mock_congestion_controller.h b/webrtc/call/mock/mock_congestion_controller.h new file mode 100644 index 0000000..54014da --- /dev/null +++ b/webrtc/call/mock/mock_congestion_controller.h
@@ -0,0 +1,52 @@ +/* + * 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_CALL_MOCK_MOCK_CONGESTION_CONTROLLER_H_ +#define WEBRTC_CALL_MOCK_MOCK_CONGESTION_CONTROLLER_H_ + +#include "testing/gmock/include/gmock/gmock.h" +#include "webrtc/call/congestion_controller.h" + +namespace webrtc { +namespace test { + +class MockCongestionController : public CongestionController { + public: + MockCongestionController(ProcessThread* process_thread, + CallStats* call_stats, + BitrateObserver* bitrate_observer) + : CongestionController(process_thread, call_stats, bitrate_observer) {} + MOCK_METHOD1(AddEncoder, void(ViEEncoder* encoder)); + MOCK_METHOD1(RemoveEncoder, void(ViEEncoder* encoder)); + MOCK_METHOD3(SetBweBitrates, + void(int min_bitrate_bps, + int start_bitrate_bps, + int max_bitrate_bps)); + MOCK_METHOD3(SetChannelRembStatus, + void(bool sender, bool receiver, RtpRtcp* rtp_module)); + MOCK_METHOD1(SignalNetworkState, void(NetworkState state)); + MOCK_CONST_METHOD0(GetBitrateController, BitrateController*()); + MOCK_CONST_METHOD1(GetRemoteBitrateEstimator, + RemoteBitrateEstimator*(bool send_side_bwe)); + MOCK_CONST_METHOD0(GetPacerQueuingDelayMs, int64_t()); + MOCK_CONST_METHOD0(pacer, PacedSender*()); + MOCK_CONST_METHOD0(packet_router, PacketRouter*()); + MOCK_METHOD0(GetTransportFeedbackObserver, TransportFeedbackObserver*()); + MOCK_METHOD3(UpdatePacerBitrate, + void(int bitrate_kbps, + int max_bitrate_kbps, + int min_bitrate_kbps)); + MOCK_METHOD1(OnSentPacket, void(const rtc::SentPacket& sent_packet)); + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(MockCongestionController); +}; +} // namespace test +} // namespace webrtc +#endif // WEBRTC_CALL_MOCK_MOCK_CONGESTION_CONTROLLER_H_
diff --git a/webrtc/call/packet_injection_tests.cc b/webrtc/call/packet_injection_tests.cc index 18ca058..277cd3e 100644 --- a/webrtc/call/packet_injection_tests.cc +++ b/webrtc/call/packet_injection_tests.cc
@@ -40,22 +40,22 @@ CreateReceiverCall(Call::Config()); test::NullTransport null_transport; - CreateSendConfig(1, &null_transport); + CreateSendConfig(1, 0, &null_transport); CreateMatchingReceiveConfigs(&null_transport); - receive_configs_[0].decoders[0].payload_type = payload_type; + video_receive_configs_[0].decoders[0].payload_type = payload_type; switch (codec_type) { case CodecType::kVp8: - receive_configs_[0].decoders[0].payload_name = "VP8"; + video_receive_configs_[0].decoders[0].payload_name = "VP8"; break; case CodecType::kH264: - receive_configs_[0].decoders[0].payload_name = "H264"; + video_receive_configs_[0].decoders[0].payload_name = "H264"; break; } - CreateStreams(); + CreateVideoStreams(); RTPHeader header; EXPECT_TRUE(rtp_header_parser_->Parse(packet, length, &header)); - EXPECT_EQ(kSendSsrcs[0], header.ssrc) + EXPECT_EQ(kVideoSendSsrcs[0], header.ssrc) << "Packet should have configured SSRC to not be dropped early."; EXPECT_EQ(payload_type, header.payloadType); Start();
diff --git a/webrtc/call/rampup_tests.cc b/webrtc/call/rampup_tests.cc new file mode 100644 index 0000000..81f1e81 --- /dev/null +++ b/webrtc/call/rampup_tests.cc
@@ -0,0 +1,587 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/call/rampup_tests.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/checks.h" +#include "webrtc/base/platform_thread.h" +#include "webrtc/test/testsupport/perf_test.h" + +namespace webrtc { +namespace { + +static const int64_t kPollIntervalMs = 20; + +std::vector<uint32_t> GenerateSsrcs(size_t num_streams, uint32_t ssrc_offset) { + std::vector<uint32_t> ssrcs; + for (size_t i = 0; i != num_streams; ++i) + ssrcs.push_back(static_cast<uint32_t>(ssrc_offset + i)); + return ssrcs; +} +} // namespace + +RampUpTester::RampUpTester(size_t num_video_streams, + size_t num_audio_streams, + unsigned int start_bitrate_bps, + const std::string& extension_type, + bool rtx, + bool red) + : EndToEndTest(test::CallTest::kLongTimeoutMs), + event_(false, false), + clock_(Clock::GetRealTimeClock()), + num_video_streams_(num_video_streams), + num_audio_streams_(num_audio_streams), + rtx_(rtx), + red_(red), + send_stream_(nullptr), + start_bitrate_bps_(start_bitrate_bps), + start_bitrate_verified_(false), + expected_bitrate_bps_(0), + test_start_ms_(-1), + ramp_up_finished_ms_(-1), + extension_type_(extension_type), + video_ssrcs_(GenerateSsrcs(num_video_streams_, 100)), + video_rtx_ssrcs_(GenerateSsrcs(num_video_streams_, 200)), + audio_ssrcs_(GenerateSsrcs(num_audio_streams_, 300)), + poller_thread_(&BitrateStatsPollingThread, + this, + "BitrateStatsPollingThread"), + sender_call_(nullptr) { + EXPECT_LE(num_audio_streams_, 1u); + if (rtx_) { + for (size_t i = 0; i < video_ssrcs_.size(); ++i) + rtx_ssrc_map_[video_rtx_ssrcs_[i]] = video_ssrcs_[i]; + } +} + +RampUpTester::~RampUpTester() { + event_.Set(); +} + +Call::Config RampUpTester::GetSenderCallConfig() { + Call::Config call_config; + if (start_bitrate_bps_ != 0) { + call_config.bitrate_config.start_bitrate_bps = start_bitrate_bps_; + } + call_config.bitrate_config.min_bitrate_bps = 10000; + return call_config; +} + +void RampUpTester::OnVideoStreamsCreated( + VideoSendStream* send_stream, + const std::vector<VideoReceiveStream*>& receive_streams) { + send_stream_ = send_stream; +} + +test::PacketTransport* RampUpTester::CreateSendTransport(Call* sender_call) { + send_transport_ = new test::PacketTransport(sender_call, this, + test::PacketTransport::kSender, + forward_transport_config_); + return send_transport_; +} + +size_t RampUpTester::GetNumVideoStreams() const { + return num_video_streams_; +} + +size_t RampUpTester::GetNumAudioStreams() const { + return num_audio_streams_; +} + +void RampUpTester::ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config) { + send_config->suspend_below_min_bitrate = true; + + if (num_video_streams_ == 1) { + encoder_config->streams[0].target_bitrate_bps = + encoder_config->streams[0].max_bitrate_bps = 2000000; + // For single stream rampup until 1mbps + expected_bitrate_bps_ = kSingleStreamTargetBps; + } else { + // For multi stream rampup until all streams are being sent. That means + // enough birate to send all the target streams plus the min bitrate of + // the last one. + expected_bitrate_bps_ = encoder_config->streams.back().min_bitrate_bps; + for (size_t i = 0; i < encoder_config->streams.size() - 1; ++i) { + expected_bitrate_bps_ += encoder_config->streams[i].target_bitrate_bps; + } + } + + send_config->rtp.extensions.clear(); + + bool remb; + bool transport_cc; + if (extension_type_ == RtpExtension::kAbsSendTime) { + remb = true; + transport_cc = false; + send_config->rtp.extensions.push_back( + RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId)); + } else if (extension_type_ == RtpExtension::kTransportSequenceNumber) { + remb = false; + transport_cc = true; + send_config->rtp.extensions.push_back(RtpExtension( + extension_type_.c_str(), kTransportSequenceNumberExtensionId)); + } else { + remb = true; + transport_cc = false; + send_config->rtp.extensions.push_back(RtpExtension( + extension_type_.c_str(), kTransmissionTimeOffsetExtensionId)); + } + + send_config->rtp.nack.rtp_history_ms = test::CallTest::kNackRtpHistoryMs; + send_config->rtp.ssrcs = video_ssrcs_; + if (rtx_) { + send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType; + send_config->rtp.rtx.ssrcs = video_rtx_ssrcs_; + } + if (red_) { + send_config->rtp.fec.ulpfec_payload_type = + test::CallTest::kUlpfecPayloadType; + send_config->rtp.fec.red_payload_type = test::CallTest::kRedPayloadType; + } + + size_t i = 0; + for (VideoReceiveStream::Config& recv_config : *receive_configs) { + recv_config.rtp.remb = remb; + recv_config.rtp.transport_cc = transport_cc; + recv_config.rtp.extensions = send_config->rtp.extensions; + + recv_config.rtp.remote_ssrc = video_ssrcs_[i]; + recv_config.rtp.nack.rtp_history_ms = send_config->rtp.nack.rtp_history_ms; + + if (red_) { + recv_config.rtp.fec.red_payload_type = + send_config->rtp.fec.red_payload_type; + recv_config.rtp.fec.ulpfec_payload_type = + send_config->rtp.fec.ulpfec_payload_type; + } + + if (rtx_) { + recv_config.rtp.rtx[send_config->encoder_settings.payload_type].ssrc = + video_rtx_ssrcs_[i]; + recv_config.rtp.rtx[send_config->encoder_settings.payload_type] + .payload_type = send_config->rtp.rtx.payload_type; + } + ++i; + } +} + +void RampUpTester::ModifyAudioConfigs( + AudioSendStream::Config* send_config, + std::vector<AudioReceiveStream::Config>* receive_configs) { + if (num_audio_streams_ == 0) + return; + + EXPECT_NE(RtpExtension::kTOffset, extension_type_) + << "Audio BWE not supported with toffset."; + + send_config->rtp.ssrc = audio_ssrcs_[0]; + send_config->rtp.extensions.clear(); + + bool transport_cc = false; + if (extension_type_ == RtpExtension::kAbsSendTime) { + transport_cc = false; + send_config->rtp.extensions.push_back( + RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId)); + } else if (extension_type_ == RtpExtension::kTransportSequenceNumber) { + transport_cc = true; + send_config->rtp.extensions.push_back(RtpExtension( + extension_type_.c_str(), kTransportSequenceNumberExtensionId)); + } + + for (AudioReceiveStream::Config& recv_config : *receive_configs) { + recv_config.combined_audio_video_bwe = true; + recv_config.rtp.transport_cc = transport_cc; + recv_config.rtp.extensions = send_config->rtp.extensions; + recv_config.rtp.remote_ssrc = send_config->rtp.ssrc; + } +} + +void RampUpTester::OnCallsCreated(Call* sender_call, Call* receiver_call) { + sender_call_ = sender_call; +} + +bool RampUpTester::BitrateStatsPollingThread(void* obj) { + return static_cast<RampUpTester*>(obj)->PollStats(); +} + +bool RampUpTester::PollStats() { + if (sender_call_) { + Call::Stats stats = sender_call_->GetStats(); + + RTC_DCHECK_GT(expected_bitrate_bps_, 0); + if (!start_bitrate_verified_ && start_bitrate_bps_ != 0) { + // For tests with an explicitly set start bitrate, verify the first + // bitrate estimate is close to the start bitrate and lower than the + // test target bitrate. This is to verify a call respects the configured + // start bitrate, but due to the BWE implementation we can't guarantee the + // first estimate really is as high as the start bitrate. + EXPECT_GT(stats.send_bandwidth_bps, 0.9 * start_bitrate_bps_); + start_bitrate_verified_ = true; + } + if (stats.send_bandwidth_bps >= expected_bitrate_bps_) { + ramp_up_finished_ms_ = clock_->TimeInMilliseconds(); + observation_complete_.Set(); + } + } + + return !event_.Wait(kPollIntervalMs); +} + +void RampUpTester::ReportResult(const std::string& measurement, + size_t value, + const std::string& units) const { + webrtc::test::PrintResult( + measurement, "", + ::testing::UnitTest::GetInstance()->current_test_info()->name(), value, + units, false); +} + +void RampUpTester::AccumulateStats(const VideoSendStream::StreamStats& stream, + size_t* total_packets_sent, + size_t* total_sent, + size_t* padding_sent, + size_t* media_sent) const { + *total_packets_sent += stream.rtp_stats.transmitted.packets + + stream.rtp_stats.retransmitted.packets + + stream.rtp_stats.fec.packets; + *total_sent += stream.rtp_stats.transmitted.TotalBytes() + + stream.rtp_stats.retransmitted.TotalBytes() + + stream.rtp_stats.fec.TotalBytes(); + *padding_sent += stream.rtp_stats.transmitted.padding_bytes + + stream.rtp_stats.retransmitted.padding_bytes + + stream.rtp_stats.fec.padding_bytes; + *media_sent += stream.rtp_stats.MediaPayloadBytes(); +} + +void RampUpTester::TriggerTestDone() { + RTC_DCHECK_GE(test_start_ms_, 0); + + // TODO(holmer): Add audio send stats here too when those APIs are available. + VideoSendStream::Stats send_stats = send_stream_->GetStats(); + + size_t total_packets_sent = 0; + size_t total_sent = 0; + size_t padding_sent = 0; + size_t media_sent = 0; + for (uint32_t ssrc : video_ssrcs_) { + AccumulateStats(send_stats.substreams[ssrc], &total_packets_sent, + &total_sent, &padding_sent, &media_sent); + } + + size_t rtx_total_packets_sent = 0; + size_t rtx_total_sent = 0; + size_t rtx_padding_sent = 0; + size_t rtx_media_sent = 0; + for (uint32_t rtx_ssrc : video_rtx_ssrcs_) { + AccumulateStats(send_stats.substreams[rtx_ssrc], &rtx_total_packets_sent, + &rtx_total_sent, &rtx_padding_sent, &rtx_media_sent); + } + + ReportResult("ramp-up-total-packets-sent", total_packets_sent, "packets"); + ReportResult("ramp-up-total-sent", total_sent, "bytes"); + ReportResult("ramp-up-media-sent", media_sent, "bytes"); + ReportResult("ramp-up-padding-sent", padding_sent, "bytes"); + ReportResult("ramp-up-rtx-total-packets-sent", rtx_total_packets_sent, + "packets"); + ReportResult("ramp-up-rtx-total-sent", rtx_total_sent, "bytes"); + ReportResult("ramp-up-rtx-media-sent", rtx_media_sent, "bytes"); + ReportResult("ramp-up-rtx-padding-sent", rtx_padding_sent, "bytes"); + if (ramp_up_finished_ms_ >= 0) { + ReportResult("ramp-up-time", ramp_up_finished_ms_ - test_start_ms_, + "milliseconds"); + } + ReportResult("ramp-up-average-network-latency", + send_transport_->GetAverageDelayMs(), "milliseconds"); +} + +void RampUpTester::PerformTest() { + test_start_ms_ = clock_->TimeInMilliseconds(); + poller_thread_.Start(); + EXPECT_TRUE(Wait()) << "Timed out while waiting for ramp-up to complete."; + TriggerTestDone(); + poller_thread_.Stop(); +} + +RampUpDownUpTester::RampUpDownUpTester(size_t num_video_streams, + size_t num_audio_streams, + unsigned int start_bitrate_bps, + const std::string& extension_type, + bool rtx, + bool red) + : RampUpTester(num_video_streams, + num_audio_streams, + start_bitrate_bps, + extension_type, + rtx, + red), + test_state_(kFirstRampup), + state_start_ms_(clock_->TimeInMilliseconds()), + interval_start_ms_(clock_->TimeInMilliseconds()), + sent_bytes_(0) { + forward_transport_config_.link_capacity_kbps = kHighBandwidthLimitBps / 1000; +} + +RampUpDownUpTester::~RampUpDownUpTester() {} + +bool RampUpDownUpTester::PollStats() { + if (send_stream_) { + webrtc::VideoSendStream::Stats stats = send_stream_->GetStats(); + int transmit_bitrate_bps = 0; + for (auto it : stats.substreams) { + transmit_bitrate_bps += it.second.total_bitrate_bps; + } + + EvolveTestState(transmit_bitrate_bps, stats.suspended); + } + + return !event_.Wait(kPollIntervalMs); +} + +Call::Config RampUpDownUpTester::GetReceiverCallConfig() { + Call::Config config; + config.bitrate_config.min_bitrate_bps = 10000; + return config; +} + +std::string RampUpDownUpTester::GetModifierString() const { + std::string str("_"); + if (num_video_streams_ > 0) { + std::ostringstream s; + s << num_video_streams_; + str += s.str(); + str += "stream"; + str += (num_video_streams_ > 1 ? "s" : ""); + str += "_"; + } + if (num_audio_streams_ > 0) { + std::ostringstream s; + s << num_audio_streams_; + str += s.str(); + str += "stream"; + str += (num_audio_streams_ > 1 ? "s" : ""); + str += "_"; + } + str += (rtx_ ? "" : "no"); + str += "rtx"; + return str; +} + +void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) { + int64_t now = clock_->TimeInMilliseconds(); + switch (test_state_) { + case kFirstRampup: { + EXPECT_FALSE(suspended); + if (bitrate_bps > kExpectedHighBitrateBps) { + // The first ramp-up has reached the target bitrate. Change the + // channel limit, and move to the next test state. + forward_transport_config_.link_capacity_kbps = + kLowBandwidthLimitBps / 1000; + send_transport_->SetConfig(forward_transport_config_); + test_state_ = kLowRate; + webrtc::test::PrintResult("ramp_up_down_up", GetModifierString(), + "first_rampup", now - state_start_ms_, "ms", + false); + state_start_ms_ = now; + interval_start_ms_ = now; + sent_bytes_ = 0; + } + break; + } + case kLowRate: { + if (bitrate_bps < kExpectedLowBitrateBps && suspended) { + // The ramp-down was successful. Change the channel limit back to a + // high value, and move to the next test state. + forward_transport_config_.link_capacity_kbps = + kHighBandwidthLimitBps / 1000; + send_transport_->SetConfig(forward_transport_config_); + test_state_ = kSecondRampup; + webrtc::test::PrintResult("ramp_up_down_up", GetModifierString(), + "rampdown", now - state_start_ms_, "ms", + false); + state_start_ms_ = now; + interval_start_ms_ = now; + sent_bytes_ = 0; + } + break; + } + case kSecondRampup: { + if (bitrate_bps > kExpectedHighBitrateBps && !suspended) { + webrtc::test::PrintResult("ramp_up_down_up", GetModifierString(), + "second_rampup", now - state_start_ms_, "ms", + false); + ReportResult("ramp-up-down-up-average-network-latency", + send_transport_->GetAverageDelayMs(), "milliseconds"); + observation_complete_.Set(); + } + break; + } + } +} + +class RampUpTest : public test::CallTest { + public: + RampUpTest() {} + + virtual ~RampUpTest() { + EXPECT_EQ(nullptr, video_send_stream_); + EXPECT_TRUE(video_receive_streams_.empty()); + } +}; + +TEST_F(RampUpTest, SingleStream) { + RampUpTester test(1, 0, 0, RtpExtension::kTOffset, false, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, Simulcast) { + RampUpTester test(3, 0, 0, RtpExtension::kTOffset, false, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, SimulcastWithRtx) { + RampUpTester test(3, 0, 0, RtpExtension::kTOffset, true, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, SimulcastByRedWithRtx) { + RampUpTester test(3, 0, 0, RtpExtension::kTOffset, true, true); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, SingleStreamWithHighStartBitrate) { + RampUpTester test(1, 0, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset, + false, false); + RunBaseTest(&test); +} + +// Disabled on Mac due to flakiness, see +// https://bugs.chromium.org/p/webrtc/issues/detail?id=5407 +#ifndef WEBRTC_MAC + +static const uint32_t kStartBitrateBps = 60000; + +TEST_F(RampUpTest, UpDownUpOneStream) { + RampUpDownUpTester test(1, 0, kStartBitrateBps, RtpExtension::kAbsSendTime, + false, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, UpDownUpThreeStreams) { + RampUpDownUpTester test(3, 0, kStartBitrateBps, RtpExtension::kAbsSendTime, + false, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, UpDownUpOneStreamRtx) { + RampUpDownUpTester test(1, 0, kStartBitrateBps, RtpExtension::kAbsSendTime, + true, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, UpDownUpThreeStreamsRtx) { + RampUpDownUpTester test(3, 0, kStartBitrateBps, RtpExtension::kAbsSendTime, + true, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, UpDownUpOneStreamByRedRtx) { + RampUpDownUpTester test(1, 0, kStartBitrateBps, RtpExtension::kAbsSendTime, + true, true); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, UpDownUpThreeStreamsByRedRtx) { + RampUpDownUpTester test(3, 0, kStartBitrateBps, RtpExtension::kAbsSendTime, + true, true); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, SendSideVideoUpDownUpRtx) { + RampUpDownUpTester test(3, 0, kStartBitrateBps, + RtpExtension::kTransportSequenceNumber, true, false); + RunBaseTest(&test); +} + +// TODO(holmer): Enable when audio bitrates are included in the bitrate +// allocation. +TEST_F(RampUpTest, DISABLED_SendSideAudioVideoUpDownUpRtx) { + RampUpDownUpTester test(3, 1, kStartBitrateBps, + RtpExtension::kTransportSequenceNumber, true, false); + RunBaseTest(&test); +} + +#endif + +TEST_F(RampUpTest, AbsSendTimeSingleStream) { + RampUpTester test(1, 0, 0, RtpExtension::kAbsSendTime, false, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, AbsSendTimeSimulcast) { + RampUpTester test(3, 0, 0, RtpExtension::kAbsSendTime, false, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, AbsSendTimeSimulcastWithRtx) { + RampUpTester test(3, 0, 0, RtpExtension::kAbsSendTime, true, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, AbsSendTimeSimulcastByRedWithRtx) { + RampUpTester test(3, 0, 0, RtpExtension::kAbsSendTime, true, true); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, AbsSendTimeSingleStreamWithHighStartBitrate) { + RampUpTester test(1, 0, 0.9 * kSingleStreamTargetBps, + RtpExtension::kAbsSendTime, false, false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, TransportSequenceNumberSingleStream) { + RampUpTester test(1, 0, 0, RtpExtension::kTransportSequenceNumber, false, + false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, TransportSequenceNumberSimulcast) { + RampUpTester test(3, 0, 0, RtpExtension::kTransportSequenceNumber, false, + false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, TransportSequenceNumberSimulcastWithRtx) { + RampUpTester test(3, 0, 0, RtpExtension::kTransportSequenceNumber, true, + false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, AudioVideoTransportSequenceNumberSimulcastWithRtx) { + RampUpTester test(3, 1, 0, RtpExtension::kTransportSequenceNumber, true, + false); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, TransportSequenceNumberSimulcastByRedWithRtx) { + RampUpTester test(3, 0, 0, RtpExtension::kTransportSequenceNumber, true, + true); + RunBaseTest(&test); +} + +TEST_F(RampUpTest, TransportSequenceNumberSingleStreamWithHighStartBitrate) { + RampUpTester test(1, 0, 0.9 * kSingleStreamTargetBps, + RtpExtension::kTransportSequenceNumber, false, false); + RunBaseTest(&test); +} +} // namespace webrtc
diff --git a/webrtc/call/rampup_tests.h b/webrtc/call/rampup_tests.h new file mode 100644 index 0000000..31a0a02 --- /dev/null +++ b/webrtc/call/rampup_tests.h
@@ -0,0 +1,137 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_CALL_RAMPUP_TESTS_H_ +#define WEBRTC_CALL_RAMPUP_TESTS_H_ + +#include <map> +#include <string> +#include <vector> + +#include "webrtc/base/event.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/call.h" +#include "webrtc/test/call_test.h" + +namespace webrtc { + +static const int kTransmissionTimeOffsetExtensionId = 6; +static const int kAbsSendTimeExtensionId = 7; +static const int kTransportSequenceNumberExtensionId = 8; +static const unsigned int kSingleStreamTargetBps = 1000000; + +class Clock; + +class RampUpTester : public test::EndToEndTest { + public: + RampUpTester(size_t num_video_streams, + size_t num_audio_streams, + unsigned int start_bitrate_bps, + const std::string& extension_type, + bool rtx, + bool red); + ~RampUpTester() override; + + size_t GetNumVideoStreams() const override; + size_t GetNumAudioStreams() const override; + + void PerformTest() override; + + protected: + virtual bool PollStats(); + + void AccumulateStats(const VideoSendStream::StreamStats& stream, + size_t* total_packets_sent, + size_t* total_sent, + size_t* padding_sent, + size_t* media_sent) const; + + void ReportResult(const std::string& measurement, + size_t value, + const std::string& units) const; + void TriggerTestDone(); + + rtc::Event event_; + Clock* const clock_; + FakeNetworkPipe::Config forward_transport_config_; + const size_t num_video_streams_; + const size_t num_audio_streams_; + const bool rtx_; + const bool red_; + VideoSendStream* send_stream_; + test::PacketTransport* send_transport_; + + private: + typedef std::map<uint32_t, uint32_t> SsrcMap; + + Call::Config GetSenderCallConfig() override; + void OnVideoStreamsCreated( + VideoSendStream* send_stream, + const std::vector<VideoReceiveStream*>& receive_streams) override; + test::PacketTransport* CreateSendTransport(Call* sender_call) override; + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config) override; + void ModifyAudioConfigs( + AudioSendStream::Config* send_config, + std::vector<AudioReceiveStream::Config>* receive_configs) override; + void OnCallsCreated(Call* sender_call, Call* receiver_call) override; + + static bool BitrateStatsPollingThread(void* obj); + + const int start_bitrate_bps_; + bool start_bitrate_verified_; + int expected_bitrate_bps_; + int64_t test_start_ms_; + int64_t ramp_up_finished_ms_; + + const std::string extension_type_; + std::vector<uint32_t> video_ssrcs_; + std::vector<uint32_t> video_rtx_ssrcs_; + std::vector<uint32_t> audio_ssrcs_; + SsrcMap rtx_ssrc_map_; + + rtc::PlatformThread poller_thread_; + Call* sender_call_; +}; + +class RampUpDownUpTester : public RampUpTester { + public: + RampUpDownUpTester(size_t num_video_streams, + size_t num_audio_streams, + unsigned int start_bitrate_bps, + const std::string& extension_type, + bool rtx, + bool red); + ~RampUpDownUpTester() override; + + protected: + bool PollStats() override; + + private: + static const int kHighBandwidthLimitBps = 80000; + static const int kExpectedHighBitrateBps = 60000; + static const int kLowBandwidthLimitBps = 20000; + static const int kExpectedLowBitrateBps = 20000; + enum TestStates { kFirstRampup, kLowRate, kSecondRampup }; + + Call::Config GetReceiverCallConfig() override; + + std::string GetModifierString() const; + void EvolveTestState(int bitrate_bps, bool suspended); + + TestStates test_state_; + int64_t state_start_ms_; + int64_t interval_start_ms_; + int sent_bytes_; +}; +} // namespace webrtc +#endif // WEBRTC_CALL_RAMPUP_TESTS_H_
diff --git a/webrtc/call/rtc_event_log.cc b/webrtc/call/rtc_event_log.cc index 550b556..9f592ce 100644 --- a/webrtc/call/rtc_event_log.cc +++ b/webrtc/call/rtc_event_log.cc
@@ -17,7 +17,9 @@ #include "webrtc/base/criticalsection.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/call.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" #include "webrtc/system_wrappers/include/clock.h" #include "webrtc/system_wrappers/include/file_wrapper.h" @@ -54,6 +56,9 @@ const uint8_t* packet, size_t length) override {} void LogAudioPlayout(uint32_t ssrc) override {} + void LogBwePacketLossEvent(int32_t bitrate, + uint8_t fraction_loss, + int32_t total_packets) override {} }; #else // ENABLE_RTC_EVENT_LOG is defined @@ -78,6 +83,9 @@ const uint8_t* packet, size_t length) override; void LogAudioPlayout(uint32_t ssrc) override; + void LogBwePacketLossEvent(int32_t bitrate, + uint8_t fraction_loss, + int32_t total_packets) override; private: // Starts logging. This function assumes the file_ has been opened succesfully @@ -254,8 +262,7 @@ rtc::CritScope lock(&crit_); rtclog::Event event; - const int64_t timestamp = clock_->TimeInMicroseconds(); - event.set_timestamp_us(timestamp); + event.set_timestamp_us(clock_->TimeInMicroseconds()); event.set_type(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT); rtclog::VideoReceiveConfig* receiver_config = @@ -264,9 +271,6 @@ receiver_config->set_local_ssrc(config.rtp.local_ssrc); receiver_config->set_rtcp_mode(ConvertRtcpMode(config.rtp.rtcp_mode)); - - receiver_config->set_receiver_reference_time_report( - config.rtp.rtcp_xr.receiver_reference_time_report); receiver_config->set_remb(config.rtp.remb); for (const auto& kv : config.rtp.rtx) { @@ -296,8 +300,7 @@ rtc::CritScope lock(&crit_); rtclog::Event event; - const int64_t timestamp = clock_->TimeInMicroseconds(); - event.set_timestamp_us(timestamp); + event.set_timestamp_us(clock_->TimeInMicroseconds()); event.set_type(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT); rtclog::VideoSendConfig* sender_config = event.mutable_video_sender_config(); @@ -318,8 +321,6 @@ } sender_config->set_rtx_payload_type(config.rtp.rtx.payload_type); - sender_config->set_c_name(config.rtp.c_name); - rtclog::EncoderConfig* encoder = sender_config->mutable_encoder(); encoder->set_name(config.encoder_settings.payload_name); encoder->set_payload_type(config.encoder_settings.payload_type); @@ -348,8 +349,7 @@ rtc::CritScope lock(&crit_); rtclog::Event rtp_event; - const int64_t timestamp = clock_->TimeInMicroseconds(); - rtp_event.set_timestamp_us(timestamp); + rtp_event.set_timestamp_us(clock_->TimeInMicroseconds()); rtp_event.set_type(rtclog::Event::RTP_EVENT); rtp_event.mutable_rtp_packet()->set_incoming(incoming); rtp_event.mutable_rtp_packet()->set_type(ConvertMediaType(media_type)); @@ -364,33 +364,89 @@ size_t length) { rtc::CritScope lock(&crit_); rtclog::Event rtcp_event; - const int64_t timestamp = clock_->TimeInMicroseconds(); - rtcp_event.set_timestamp_us(timestamp); + rtcp_event.set_timestamp_us(clock_->TimeInMicroseconds()); rtcp_event.set_type(rtclog::Event::RTCP_EVENT); rtcp_event.mutable_rtcp_packet()->set_incoming(incoming); rtcp_event.mutable_rtcp_packet()->set_type(ConvertMediaType(media_type)); - rtcp_event.mutable_rtcp_packet()->set_packet_data(packet, length); + + RTCPUtility::RtcpCommonHeader header; + const uint8_t* block_begin = packet; + const uint8_t* packet_end = packet + length; + RTC_DCHECK(length <= IP_PACKET_SIZE); + uint8_t buffer[IP_PACKET_SIZE]; + uint32_t buffer_length = 0; + while (block_begin < packet_end) { + if (!RtcpParseCommonHeader(block_begin, packet_end - block_begin, + &header)) { + break; // Incorrect message header. + } + uint32_t block_size = header.BlockSize(); + switch (header.packet_type) { + case RTCPUtility::PT_SR: + FALLTHROUGH(); + case RTCPUtility::PT_RR: + FALLTHROUGH(); + case RTCPUtility::PT_BYE: + FALLTHROUGH(); + case RTCPUtility::PT_IJ: + FALLTHROUGH(); + case RTCPUtility::PT_RTPFB: + FALLTHROUGH(); + case RTCPUtility::PT_PSFB: + FALLTHROUGH(); + case RTCPUtility::PT_XR: + // We log sender reports, receiver reports, bye messages + // inter-arrival jitter, third-party loss reports, payload-specific + // feedback and extended reports. + memcpy(buffer + buffer_length, block_begin, block_size); + buffer_length += block_size; + break; + case RTCPUtility::PT_SDES: + FALLTHROUGH(); + case RTCPUtility::PT_APP: + FALLTHROUGH(); + default: + // We don't log sender descriptions, application defined messages + // or message blocks of unknown type. + break; + } + + block_begin += block_size; + } + rtcp_event.mutable_rtcp_packet()->set_packet_data(buffer, buffer_length); HandleEvent(&rtcp_event); } void RtcEventLogImpl::LogAudioPlayout(uint32_t ssrc) { rtc::CritScope lock(&crit_); rtclog::Event event; - const int64_t timestamp = clock_->TimeInMicroseconds(); - event.set_timestamp_us(timestamp); + event.set_timestamp_us(clock_->TimeInMicroseconds()); event.set_type(rtclog::Event::AUDIO_PLAYOUT_EVENT); auto playout_event = event.mutable_audio_playout_event(); playout_event->set_local_ssrc(ssrc); HandleEvent(&event); } +void RtcEventLogImpl::LogBwePacketLossEvent(int32_t bitrate, + uint8_t fraction_loss, + int32_t total_packets) { + rtc::CritScope lock(&crit_); + rtclog::Event event; + event.set_timestamp_us(clock_->TimeInMicroseconds()); + event.set_type(rtclog::Event::BWE_PACKET_LOSS_EVENT); + auto bwe_event = event.mutable_bwe_packet_loss_event(); + bwe_event->set_bitrate(bitrate); + bwe_event->set_fraction_loss(fraction_loss); + bwe_event->set_total_packets(total_packets); + HandleEvent(&event); +} + void RtcEventLogImpl::StopLoggingLocked() { if (currently_logging_) { currently_logging_ = false; // Create a LogEnd event rtclog::Event event; - int64_t timestamp = clock_->TimeInMicroseconds(); - event.set_timestamp_us(timestamp); + event.set_timestamp_us(clock_->TimeInMicroseconds()); event.set_type(rtclog::Event::LOG_END); // Store the event and close the file RTC_DCHECK(file_->Open());
diff --git a/webrtc/call/rtc_event_log.h b/webrtc/call/rtc_event_log.h index 85d7525..489687a 100644 --- a/webrtc/call/rtc_event_log.h +++ b/webrtc/call/rtc_event_log.h
@@ -77,6 +77,11 @@ // Logs an audio playout event virtual void LogAudioPlayout(uint32_t ssrc) = 0; + // Logs a bitrate update from the bandwidth estimator based on packet loss. + virtual void LogBwePacketLossEvent(int32_t bitrate, + uint8_t fraction_loss, + int32_t total_packets) = 0; + // Reads an RtcEventLog file and returns true when reading was successful. // The result is stored in the given EventStream object. static bool ParseRtcEventLog(const std::string& file_name,
diff --git a/webrtc/call/rtc_event_log.proto b/webrtc/call/rtc_event_log.proto index 6bdea7b..b14306e 100644 --- a/webrtc/call/rtc_event_log.proto +++ b/webrtc/call/rtc_event_log.proto
@@ -34,10 +34,12 @@ RTP_EVENT = 3; RTCP_EVENT = 4; AUDIO_PLAYOUT_EVENT = 5; - VIDEO_RECEIVER_CONFIG_EVENT = 6; - VIDEO_SENDER_CONFIG_EVENT = 7; - AUDIO_RECEIVER_CONFIG_EVENT = 8; - AUDIO_SENDER_CONFIG_EVENT = 9; + BWE_PACKET_LOSS_EVENT = 6; + BWE_PACKET_DELAY_EVENT = 7; + VIDEO_RECEIVER_CONFIG_EVENT = 8; + VIDEO_SENDER_CONFIG_EVENT = 9; + AUDIO_RECEIVER_CONFIG_EVENT = 10; + AUDIO_SENDER_CONFIG_EVENT = 11; } // required - Indicates the type of this event @@ -52,17 +54,20 @@ // optional - but required if type == AUDIO_PLAYOUT_EVENT optional AudioPlayoutEvent audio_playout_event = 5; + // optional - but required if type == BWE_PACKET_LOSS_EVENT + optional BwePacketLossEvent bwe_packet_loss_event = 6; + // optional - but required if type == VIDEO_RECEIVER_CONFIG_EVENT - optional VideoReceiveConfig video_receiver_config = 6; + optional VideoReceiveConfig video_receiver_config = 8; // optional - but required if type == VIDEO_SENDER_CONFIG_EVENT - optional VideoSendConfig video_sender_config = 7; + optional VideoSendConfig video_sender_config = 9; // optional - but required if type == AUDIO_RECEIVER_CONFIG_EVENT - optional AudioReceiveConfig audio_receiver_config = 8; + optional AudioReceiveConfig audio_receiver_config = 10; // optional - but required if type == AUDIO_SENDER_CONFIG_EVENT - optional AudioSendConfig audio_sender_config = 9; + optional AudioSendConfig audio_sender_config = 11; } @@ -99,6 +104,19 @@ optional uint32 local_ssrc = 2; } +message BwePacketLossEvent { + // required - Bandwidth estimate (in bps) after the update. + optional int32 bitrate = 1; + + // required - Fraction of lost packets since last receiver report + // computed as floor( 256 * (#lost_packets / #total_packets) ). + // The possible values range from 0 to 255. + optional uint32 fraction_loss = 2; + + // TODO(terelius): Is this really needed? Remove or make optional? + // required - Total number of packets that the BWE update is based on. + optional int32 total_packets = 3; +} // TODO(terelius): Video and audio streams could in principle share SSRC, // so identifying a stream based only on SSRC might not work. @@ -119,20 +137,17 @@ // required - RTCP mode to use. optional RtcpMode rtcp_mode = 3; - // required - Extended RTCP settings. - optional bool receiver_reference_time_report = 4; - // required - Receiver estimated maximum bandwidth. - optional bool remb = 5; + optional bool remb = 4; // Map from video RTP payload type -> RTX config. - repeated RtxMap rtx_map = 6; + repeated RtxMap rtx_map = 5; // RTP header extensions used for the received stream. - repeated RtpHeaderExtension header_extensions = 7; + repeated RtpHeaderExtension header_extensions = 6; // List of decoders associated with the stream. - repeated DecoderConfig decoders = 8; + repeated DecoderConfig decoders = 7; } @@ -142,7 +157,7 @@ optional string name = 1; // required - optional sint32 payload_type = 2; + optional int32 payload_type = 2; } @@ -152,7 +167,7 @@ optional string name = 1; // required - optional sint32 id = 2; + optional int32 id = 2; } @@ -163,13 +178,13 @@ optional uint32 rtx_ssrc = 1; // required - Payload type to use for the RTX stream. - optional sint32 rtx_payload_type = 2; + optional int32 rtx_payload_type = 2; } message RtxMap { // required - optional sint32 payload_type = 1; + optional int32 payload_type = 1; // required optional RtxConfig config = 2; @@ -189,13 +204,10 @@ repeated uint32 rtx_ssrcs = 3; // required if rtx_ssrcs is used - Payload type for retransmitted packets. - optional sint32 rtx_payload_type = 4; - - // required - Canonical end-point identifier. - optional string c_name = 5; + optional int32 rtx_payload_type = 4; // required - Encoder associated with the stream. - optional EncoderConfig encoder = 6; + optional EncoderConfig encoder = 5; } @@ -205,7 +217,7 @@ optional string name = 1; // required - optional sint32 payload_type = 2; + optional int32 payload_type = 2; }
diff --git a/webrtc/call/rtc_event_log_unittest.cc b/webrtc/call/rtc_event_log_unittest.cc index a4fdd13..f590f66 100644 --- a/webrtc/call/rtc_event_log_unittest.cc +++ b/webrtc/call/rtc_event_log_unittest.cc
@@ -10,22 +10,23 @@ #ifdef ENABLE_RTC_EVENT_LOG -#include <stdio.h> #include <string> +#include <utility> #include <vector> #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/base/buffer.h" #include "webrtc/base/checks.h" +#include "webrtc/base/random.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/thread.h" #include "webrtc/call.h" #include "webrtc/call/rtc_event_log.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h" #include "webrtc/modules/rtp_rtcp/source/rtp_sender.h" #include "webrtc/system_wrappers/include/clock.h" #include "webrtc/test/test_suite.h" #include "webrtc/test/testsupport/fileutils.h" -#include "webrtc/test/testsupport/gtest_disable.h" // Files generated at build-time by the protobuf compiler. #ifdef WEBRTC_ANDROID_PLATFORM_BUILD @@ -138,9 +139,6 @@ else EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE, receiver_config.rtcp_mode()); - ASSERT_TRUE(receiver_config.has_receiver_reference_time_report()); - EXPECT_EQ(config.rtp.rtcp_xr.receiver_reference_time_report, - receiver_config.receiver_reference_time_report()); ASSERT_TRUE(receiver_config.has_remb()); EXPECT_EQ(config.rtp.remb, receiver_config.remb()); // Check RTX map. @@ -214,9 +212,6 @@ ASSERT_TRUE(sender_config.has_rtx_payload_type()); EXPECT_EQ(config.rtp.rtx.payload_type, sender_config.rtx_payload_type()); } - // Check CNAME. - ASSERT_TRUE(sender_config.has_c_name()); - EXPECT_EQ(config.rtp.c_name, sender_config.c_name()); // Check encoder. ASSERT_TRUE(sender_config.has_encoder()); ASSERT_TRUE(sender_config.encoder().has_name()); @@ -230,7 +225,7 @@ void VerifyRtpEvent(const rtclog::Event& event, bool incoming, MediaType media_type, - uint8_t* header, + const uint8_t* header, size_t header_size, size_t total_size) { ASSERT_TRUE(IsValidBasicEvent(event)); @@ -252,7 +247,7 @@ void VerifyRtcpEvent(const rtclog::Event& event, bool incoming, MediaType media_type, - uint8_t* packet, + const uint8_t* packet, size_t total_size) { ASSERT_TRUE(IsValidBasicEvent(event)); ASSERT_EQ(rtclog::Event::RTCP_EVENT, event.type()); @@ -276,6 +271,21 @@ EXPECT_EQ(ssrc, playout_event.local_ssrc()); } +void VerifyBweLossEvent(const rtclog::Event& event, + int32_t bitrate, + uint8_t fraction_loss, + int32_t total_packets) { + ASSERT_TRUE(IsValidBasicEvent(event)); + ASSERT_EQ(rtclog::Event::BWE_PACKET_LOSS_EVENT, event.type()); + const rtclog::BwePacketLossEvent& bwe_event = event.bwe_packet_loss_event(); + ASSERT_TRUE(bwe_event.has_bitrate()); + EXPECT_EQ(bitrate, bwe_event.bitrate()); + ASSERT_TRUE(bwe_event.has_fraction_loss()); + EXPECT_EQ(fraction_loss, bwe_event.fraction_loss()); + ASSERT_TRUE(bwe_event.has_total_packets()); + EXPECT_EQ(total_packets, bwe_event.total_packets()); +} + void VerifyLogStartEvent(const rtclog::Event& event) { ASSERT_TRUE(IsValidBasicEvent(event)); EXPECT_EQ(rtclog::Event::LOG_START, event.type()); @@ -289,7 +299,8 @@ size_t GenerateRtpPacket(uint32_t extensions_bitvector, uint32_t csrcs_count, uint8_t* packet, - size_t packet_size) { + size_t packet_size, + Random* prng) { RTC_CHECK_GE(packet_size, 16 + 4 * csrcs_count + 4 * kNumExtensions); Clock* clock = Clock::GetRealTimeClock(); @@ -306,12 +317,12 @@ std::vector<uint32_t> csrcs; for (unsigned i = 0; i < csrcs_count; i++) { - csrcs.push_back(rand()); + csrcs.push_back(prng->Rand<uint32_t>()); } rtp_sender.SetCsrcs(csrcs); - rtp_sender.SetSSRC(rand()); - rtp_sender.SetStartTimestamp(rand(), true); - rtp_sender.SetSequenceNumber(rand()); + rtp_sender.SetSSRC(prng->Rand<uint32_t>()); + rtp_sender.SetStartTimestamp(prng->Rand<uint32_t>(), true); + rtp_sender.SetSequenceNumber(prng->Rand<uint16_t>()); for (unsigned i = 0; i < kNumExtensions; i++) { if (extensions_bitvector & (1u << i)) { @@ -319,76 +330,84 @@ } } - int8_t payload_type = rand() % 128; - bool marker_bit = (rand() % 2 == 1); - uint32_t capture_timestamp = rand(); - int64_t capture_time_ms = rand(); - bool timestamp_provided = (rand() % 2 == 1); - bool inc_sequence_number = (rand() % 2 == 1); + int8_t payload_type = prng->Rand(0, 127); + bool marker_bit = prng->Rand<bool>(); + uint32_t capture_timestamp = prng->Rand<uint32_t>(); + int64_t capture_time_ms = prng->Rand<uint32_t>(); + bool timestamp_provided = prng->Rand<bool>(); + bool inc_sequence_number = prng->Rand<bool>(); size_t header_size = rtp_sender.BuildRTPheader( packet, payload_type, marker_bit, capture_timestamp, capture_time_ms, timestamp_provided, inc_sequence_number); for (size_t i = header_size; i < packet_size; i++) { - packet[i] = rand(); + packet[i] = prng->Rand<uint8_t>(); } return header_size; } -void GenerateRtcpPacket(uint8_t* packet, size_t packet_size) { - for (size_t i = 0; i < packet_size; i++) { - packet[i] = rand(); - } +rtc::scoped_ptr<rtcp::RawPacket> GenerateRtcpPacket(Random* prng) { + rtcp::ReportBlock report_block; + report_block.To(prng->Rand<uint32_t>()); // Remote SSRC. + report_block.WithFractionLost(prng->Rand(50)); + + rtcp::SenderReport sender_report; + sender_report.From(prng->Rand<uint32_t>()); // Sender SSRC. + sender_report.WithNtpSec(prng->Rand<uint32_t>()); + sender_report.WithNtpFrac(prng->Rand<uint32_t>()); + sender_report.WithPacketCount(prng->Rand<uint32_t>()); + sender_report.WithReportBlock(report_block); + + return sender_report.Build(); } void GenerateVideoReceiveConfig(uint32_t extensions_bitvector, - VideoReceiveStream::Config* config) { + VideoReceiveStream::Config* config, + Random* prng) { // Create a map from a payload type to an encoder name. VideoReceiveStream::Decoder decoder; - decoder.payload_type = rand(); - decoder.payload_name = (rand() % 2 ? "VP8" : "H264"); + decoder.payload_type = prng->Rand(0, 127); + decoder.payload_name = (prng->Rand<bool>() ? "VP8" : "H264"); config->decoders.push_back(decoder); // Add SSRCs for the stream. - config->rtp.remote_ssrc = rand(); - config->rtp.local_ssrc = rand(); + config->rtp.remote_ssrc = prng->Rand<uint32_t>(); + config->rtp.local_ssrc = prng->Rand<uint32_t>(); // Add extensions and settings for RTCP. config->rtp.rtcp_mode = - rand() % 2 ? RtcpMode::kCompound : RtcpMode::kReducedSize; - config->rtp.rtcp_xr.receiver_reference_time_report = (rand() % 2 == 1); - config->rtp.remb = (rand() % 2 == 1); + prng->Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize; + config->rtp.remb = prng->Rand<bool>(); // Add a map from a payload type to a new ssrc and a new payload type for RTX. VideoReceiveStream::Config::Rtp::Rtx rtx_pair; - rtx_pair.ssrc = rand(); - rtx_pair.payload_type = rand(); - config->rtp.rtx.insert(std::make_pair(rand(), rtx_pair)); + rtx_pair.ssrc = prng->Rand<uint32_t>(); + rtx_pair.payload_type = prng->Rand(0, 127); + config->rtp.rtx.insert(std::make_pair(prng->Rand(0, 127), rtx_pair)); // Add header extensions. for (unsigned i = 0; i < kNumExtensions; i++) { if (extensions_bitvector & (1u << i)) { config->rtp.extensions.push_back( - RtpExtension(kExtensionNames[i], rand())); + RtpExtension(kExtensionNames[i], prng->Rand<int>())); } } } void GenerateVideoSendConfig(uint32_t extensions_bitvector, - VideoSendStream::Config* config) { + VideoSendStream::Config* config, + Random* prng) { // Create a map from a payload type to an encoder name. - config->encoder_settings.payload_type = rand(); - config->encoder_settings.payload_name = (rand() % 2 ? "VP8" : "H264"); + config->encoder_settings.payload_type = prng->Rand(0, 127); + config->encoder_settings.payload_name = (prng->Rand<bool>() ? "VP8" : "H264"); // Add SSRCs for the stream. - config->rtp.ssrcs.push_back(rand()); + config->rtp.ssrcs.push_back(prng->Rand<uint32_t>()); // Add a map from a payload type to new ssrcs and a new payload type for RTX. - config->rtp.rtx.ssrcs.push_back(rand()); - config->rtp.rtx.payload_type = rand(); - // Add a CNAME. - config->rtp.c_name = "some.user@some.host"; + config->rtp.rtx.ssrcs.push_back(prng->Rand<uint32_t>()); + config->rtp.rtx.payload_type = prng->Rand(0, 127); // Add header extensions. for (unsigned i = 0; i < kNumExtensions; i++) { if (extensions_bitvector & (1u << i)) { config->rtp.extensions.push_back( - RtpExtension(kExtensionNames[i], rand())); + RtpExtension(kExtensionNames[i], prng->Rand<int>())); } } } @@ -398,42 +417,49 @@ void LogSessionAndReadBack(size_t rtp_count, size_t rtcp_count, size_t playout_count, + size_t bwe_loss_count, uint32_t extensions_bitvector, uint32_t csrcs_count, unsigned int random_seed) { ASSERT_LE(rtcp_count, rtp_count); ASSERT_LE(playout_count, rtp_count); + ASSERT_LE(bwe_loss_count, rtp_count); std::vector<rtc::Buffer> rtp_packets; - std::vector<rtc::Buffer> rtcp_packets; + std::vector<rtc::scoped_ptr<rtcp::RawPacket> > rtcp_packets; std::vector<size_t> rtp_header_sizes; std::vector<uint32_t> playout_ssrcs; + std::vector<std::pair<int32_t, uint8_t> > bwe_loss_updates; VideoReceiveStream::Config receiver_config(nullptr); VideoSendStream::Config sender_config(nullptr); - srand(random_seed); + Random prng(random_seed); // Create rtp_count RTP packets containing random data. for (size_t i = 0; i < rtp_count; i++) { - size_t packet_size = 1000 + rand() % 64; + size_t packet_size = prng.Rand(1000, 1100); rtp_packets.push_back(rtc::Buffer(packet_size)); - size_t header_size = GenerateRtpPacket(extensions_bitvector, csrcs_count, - rtp_packets[i].data(), packet_size); + size_t header_size = + GenerateRtpPacket(extensions_bitvector, csrcs_count, + rtp_packets[i].data(), packet_size, &prng); rtp_header_sizes.push_back(header_size); } // Create rtcp_count RTCP packets containing random data. for (size_t i = 0; i < rtcp_count; i++) { - size_t packet_size = 1000 + rand() % 64; - rtcp_packets.push_back(rtc::Buffer(packet_size)); - GenerateRtcpPacket(rtcp_packets[i].data(), packet_size); + rtcp_packets.push_back(GenerateRtcpPacket(&prng)); } // Create playout_count random SSRCs to use when logging AudioPlayout events. for (size_t i = 0; i < playout_count; i++) { - playout_ssrcs.push_back(static_cast<uint32_t>(rand())); + playout_ssrcs.push_back(prng.Rand<uint32_t>()); + } + // Create bwe_loss_count random bitrate updates for BwePacketLoss. + for (size_t i = 0; i < bwe_loss_count; i++) { + bwe_loss_updates.push_back( + std::make_pair(prng.Rand<int32_t>(), prng.Rand<uint8_t>())); } // Create configurations for the video streams. - GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config); - GenerateVideoSendConfig(extensions_bitvector, &sender_config); + GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config, &prng); + GenerateVideoSendConfig(extensions_bitvector, &sender_config, &prng); const int config_count = 2; // Find the name of the current test, in order to use it as a temporary @@ -448,7 +474,9 @@ rtc::scoped_ptr<RtcEventLog> log_dumper(RtcEventLog::Create()); log_dumper->LogVideoReceiveStreamConfig(receiver_config); log_dumper->LogVideoSendStreamConfig(sender_config); - size_t rtcp_index = 1, playout_index = 1; + size_t rtcp_index = 1; + size_t playout_index = 1; + size_t bwe_loss_index = 1; for (size_t i = 1; i <= rtp_count; i++) { log_dumper->LogRtpHeader( (i % 2 == 0), // Every second packet is incoming. @@ -458,14 +486,20 @@ log_dumper->LogRtcpPacket( rtcp_index % 2 == 0, // Every second packet is incoming rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO, - rtcp_packets[rtcp_index - 1].data(), - rtcp_packets[rtcp_index - 1].size()); + rtcp_packets[rtcp_index - 1]->Buffer(), + rtcp_packets[rtcp_index - 1]->Length()); rtcp_index++; } if (i * playout_count >= playout_index * rtp_count) { log_dumper->LogAudioPlayout(playout_ssrcs[playout_index - 1]); playout_index++; } + if (i * bwe_loss_count >= bwe_loss_index * rtp_count) { + log_dumper->LogBwePacketLossEvent( + bwe_loss_updates[bwe_loss_index - 1].first, + bwe_loss_updates[bwe_loss_index - 1].second, i); + bwe_loss_index++; + } if (i == rtp_count / 2) { log_dumper->StartLogging(temp_filename, 10000000); } @@ -480,12 +514,15 @@ // Verify that what we read back from the event log is the same as // what we wrote down. For RTCP we log the full packets, but for // RTP we should only log the header. - const int event_count = - config_count + playout_count + rtcp_count + rtp_count + 1; + const int event_count = config_count + playout_count + bwe_loss_count + + rtcp_count + rtp_count + 1; EXPECT_EQ(event_count, parsed_stream.stream_size()); VerifyReceiveStreamConfig(parsed_stream.stream(0), receiver_config); VerifySendStreamConfig(parsed_stream.stream(1), sender_config); - size_t event_index = config_count, rtcp_index = 1, playout_index = 1; + size_t event_index = config_count; + size_t rtcp_index = 1; + size_t playout_index = 1; + size_t bwe_loss_index = 1; for (size_t i = 1; i <= rtp_count; i++) { VerifyRtpEvent(parsed_stream.stream(event_index), (i % 2 == 0), // Every second packet is incoming. @@ -497,8 +534,8 @@ VerifyRtcpEvent(parsed_stream.stream(event_index), rtcp_index % 2 == 0, // Every second packet is incoming. rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO, - rtcp_packets[rtcp_index - 1].data(), - rtcp_packets[rtcp_index - 1].size()); + rtcp_packets[rtcp_index - 1]->Buffer(), + rtcp_packets[rtcp_index - 1]->Length()); event_index++; rtcp_index++; } @@ -508,6 +545,13 @@ event_index++; playout_index++; } + if (i * bwe_loss_count >= bwe_loss_index * rtp_count) { + VerifyBweLossEvent(parsed_stream.stream(event_index), + bwe_loss_updates[bwe_loss_index - 1].first, + bwe_loss_updates[bwe_loss_index - 1].second, i); + event_index++; + bwe_loss_index++; + } if (i == rtp_count / 2) { VerifyLogStartEvent(parsed_stream.stream(event_index)); event_index++; @@ -519,10 +563,11 @@ } TEST(RtcEventLogTest, LogSessionAndReadBack) { - // Log 5 RTP, 2 RTCP, and 0 playout events with no header extensions or CSRCS. - LogSessionAndReadBack(5, 2, 0, 0, 0, 321); + // Log 5 RTP, 2 RTCP, 0 playout events and 0 BWE events + // with no header extensions or CSRCS. + LogSessionAndReadBack(5, 2, 0, 0, 0, 0, 321); - // Enable AbsSendTime and TransportSequenceNumbers + // Enable AbsSendTime and TransportSequenceNumbers. uint32_t extensions = 0; for (uint32_t i = 0; i < kNumExtensions; i++) { if (kExtensionTypes[i] == RTPExtensionType::kRtpExtensionAbsoluteSendTime || @@ -531,20 +576,21 @@ extensions |= 1u << i; } } - LogSessionAndReadBack(8, 2, 0, extensions, 0, 3141592653u); + LogSessionAndReadBack(8, 2, 0, 0, extensions, 0, 3141592653u); - extensions = (1u << kNumExtensions) - 1; // Enable all header extensions - LogSessionAndReadBack(9, 2, 3, extensions, 2, 2718281828u); + extensions = (1u << kNumExtensions) - 1; // Enable all header extensions. + LogSessionAndReadBack(9, 2, 3, 2, extensions, 2, 2718281828u); // Try all combinations of header extensions and up to 2 CSRCS. for (extensions = 0; extensions < (1u << kNumExtensions); extensions++) { for (uint32_t csrcs_count = 0; csrcs_count < 3; csrcs_count++) { LogSessionAndReadBack(5 + extensions, // Number of RTP packets. 2 + csrcs_count, // Number of RTCP packets. - 3 + csrcs_count, // Number of playout events - extensions, // Bit vector choosing extensions - csrcs_count, // Number of contributing sources - rand()); + 3 + csrcs_count, // Number of playout events. + 1 + csrcs_count, // Number of BWE loss events. + extensions, // Bit vector choosing extensions. + csrcs_count, // Number of contributing sources. + extensions * 3 + csrcs_count + 1); // Random seed. } } } @@ -556,35 +602,32 @@ unsigned int random_seed) { rtc::Buffer old_rtp_packet; rtc::Buffer recent_rtp_packet; - rtc::Buffer old_rtcp_packet; - rtc::Buffer recent_rtcp_packet; + rtc::scoped_ptr<rtcp::RawPacket> old_rtcp_packet; + rtc::scoped_ptr<rtcp::RawPacket> recent_rtcp_packet; VideoReceiveStream::Config receiver_config(nullptr); VideoSendStream::Config sender_config(nullptr); - srand(random_seed); + Random prng(random_seed); // Create two RTP packets containing random data. - size_t packet_size = 1000 + rand() % 64; + size_t packet_size = prng.Rand(1000, 1100); old_rtp_packet.SetSize(packet_size); GenerateRtpPacket(extensions_bitvector, csrcs_count, old_rtp_packet.data(), - packet_size); - packet_size = 1000 + rand() % 64; + packet_size, &prng); + packet_size = prng.Rand(1000, 1100); recent_rtp_packet.SetSize(packet_size); - size_t recent_header_size = GenerateRtpPacket( - extensions_bitvector, csrcs_count, recent_rtp_packet.data(), packet_size); + size_t recent_header_size = + GenerateRtpPacket(extensions_bitvector, csrcs_count, + recent_rtp_packet.data(), packet_size, &prng); // Create two RTCP packets containing random data. - packet_size = 1000 + rand() % 64; - old_rtcp_packet.SetSize(packet_size); - GenerateRtcpPacket(old_rtcp_packet.data(), packet_size); - packet_size = 1000 + rand() % 64; - recent_rtcp_packet.SetSize(packet_size); - GenerateRtcpPacket(recent_rtcp_packet.data(), packet_size); + old_rtcp_packet = GenerateRtcpPacket(&prng); + recent_rtcp_packet = GenerateRtcpPacket(&prng); // Create configurations for the video streams. - GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config); - GenerateVideoSendConfig(extensions_bitvector, &sender_config); + GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config, &prng); + GenerateVideoSendConfig(extensions_bitvector, &sender_config, &prng); // Find the name of the current test, in order to use it as a temporary // filename. @@ -601,16 +644,16 @@ log_dumper->LogVideoSendStreamConfig(sender_config); log_dumper->LogRtpHeader(false, MediaType::AUDIO, old_rtp_packet.data(), old_rtp_packet.size()); - log_dumper->LogRtcpPacket(true, MediaType::AUDIO, old_rtcp_packet.data(), - old_rtcp_packet.size()); + log_dumper->LogRtcpPacket(true, MediaType::AUDIO, old_rtcp_packet->Buffer(), + old_rtcp_packet->Length()); // Sleep 55 ms to let old events be removed from the queue. rtc::Thread::SleepMs(55); log_dumper->StartLogging(temp_filename, 10000000); log_dumper->LogRtpHeader(true, MediaType::VIDEO, recent_rtp_packet.data(), recent_rtp_packet.size()); log_dumper->LogRtcpPacket(false, MediaType::VIDEO, - recent_rtcp_packet.data(), - recent_rtcp_packet.size()); + recent_rtcp_packet->Buffer(), + recent_rtcp_packet->Length()); } // Read the generated file from disk. @@ -628,7 +671,7 @@ recent_rtp_packet.data(), recent_header_size, recent_rtp_packet.size()); VerifyRtcpEvent(parsed_stream.stream(4), false, MediaType::VIDEO, - recent_rtcp_packet.data(), recent_rtcp_packet.size()); + recent_rtcp_packet->Buffer(), recent_rtcp_packet->Length()); // Clean up temporary file - can be pretty slow. remove(temp_filename.c_str());
diff --git a/webrtc/call/webrtc_call.gypi b/webrtc/call/webrtc_call.gypi index fd70ae8..0c3efff 100644 --- a/webrtc/call/webrtc_call.gypi +++ b/webrtc/call/webrtc_call.gypi
@@ -14,6 +14,7 @@ '<(webrtc_root)/webrtc.gyp:rtc_event_log', ], 'webrtc_call_sources': [ + 'call/bitrate_allocator.cc', 'call/call.cc', 'call/congestion_controller.cc', 'call/transport_adapter.cc',
diff --git a/webrtc/codereview.settings b/webrtc/codereview.settings index 97bee14..c441cc6 100644 --- a/webrtc/codereview.settings +++ b/webrtc/codereview.settings
@@ -1,4 +1,5 @@ -Creating CLs from this location is not supported! -Please create a full WebRTC checkout using 'fetch webrtc' -or by cloning https://chromium.googlesource.com/external/webrtc +Creating CLs from this location is not supported! Please make sure the current +working directory is the parent directory of this directory. +If you're working with a Chromium checkout, you'll have to create a full WebRTC +checkout and upload a CL from that. See http://www.webrtc.org for instructions.
diff --git a/webrtc/common.h b/webrtc/common.h index dda045e..d705d4b 100644 --- a/webrtc/common.h +++ b/webrtc/common.h
@@ -17,6 +17,23 @@ namespace webrtc { +// Only add new values to the end of the enumeration and never remove (only +// deprecate) to maintain binary compatibility. +enum class ConfigOptionID { + kMyExperimentForTest, + kAlgo1CostFunctionForTest, + kTemporalLayersFactory, + kNetEqCapacityConfig, + kNetEqFastAccelerate, + kVoicePacing, + kExtendedFilter, + kDelayAgnostic, + kExperimentalAgc, + kExperimentalNs, + kBeamforming, + kIntelligibility +}; + // Class Config is designed to ease passing a set of options across webrtc code. // Options are identified by typename in order to avoid incorrect casts. // @@ -61,8 +78,6 @@ } private: - typedef void* OptionIdentifier; - struct BaseOption { virtual ~BaseOption() {} }; @@ -76,11 +91,9 @@ T* value; }; - // Own implementation of rtti-subset to avoid depending on rtti and its costs. template<typename T> - static OptionIdentifier identifier() { - static char id_placeholder; - return &id_placeholder; + static ConfigOptionID identifier() { + return T::identifier; } // Used to instantiate a default constructed object that doesn't needs to be @@ -92,7 +105,7 @@ return def; } - typedef std::map<OptionIdentifier, BaseOption*> OptionMap; + typedef std::map<ConfigOptionID, BaseOption*> OptionMap; OptionMap options_; // RTC_DISALLOW_COPY_AND_ASSIGN
diff --git a/webrtc/common_audio/BUILD.gn b/webrtc/common_audio/BUILD.gn index b01b318..b4ec1d7 100644 --- a/webrtc/common_audio/BUILD.gn +++ b/webrtc/common_audio/BUILD.gn
@@ -87,6 +87,7 @@ "signal_processing/vector_scaling_operations.c", "sparse_fir_filter.cc", "sparse_fir_filter.h", + "swap_queue.h", "vad/include/vad.h", "vad/include/webrtc_vad.h", "vad/vad.cc",
diff --git a/webrtc/common_audio/OWNERS b/webrtc/common_audio/OWNERS index 20f6400..208a7c5 100644 --- a/webrtc/common_audio/OWNERS +++ b/webrtc/common_audio/OWNERS
@@ -1,4 +1,3 @@ -andrew@webrtc.org henrik.lundin@webrtc.org jan.skoglund@webrtc.org kwiberg@webrtc.org
diff --git a/webrtc/common_audio/audio_converter.cc b/webrtc/common_audio/audio_converter.cc index f1709ae..9ebfabc 100644 --- a/webrtc/common_audio/audio_converter.cc +++ b/webrtc/common_audio/audio_converter.cc
@@ -11,6 +11,7 @@ #include "webrtc/common_audio/audio_converter.h" #include <cstring> +#include <utility> #include "webrtc/base/checks.h" #include "webrtc/base/safe_conversions.h" @@ -24,7 +25,7 @@ class CopyConverter : public AudioConverter { public: - CopyConverter(int src_channels, size_t src_frames, int dst_channels, + CopyConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} ~CopyConverter() override {}; @@ -33,7 +34,7 @@ size_t dst_capacity) override { CheckSizes(src_size, dst_capacity); if (src != dst) { - for (int i = 0; i < src_channels(); ++i) + for (size_t i = 0; i < src_channels(); ++i) std::memcpy(dst[i], src[i], dst_frames() * sizeof(*dst[i])); } } @@ -41,7 +42,7 @@ class UpmixConverter : public AudioConverter { public: - UpmixConverter(int src_channels, size_t src_frames, int dst_channels, + UpmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} ~UpmixConverter() override {}; @@ -51,7 +52,7 @@ CheckSizes(src_size, dst_capacity); for (size_t i = 0; i < dst_frames(); ++i) { const float value = src[0][i]; - for (int j = 0; j < dst_channels(); ++j) + for (size_t j = 0; j < dst_channels(); ++j) dst[j][i] = value; } } @@ -59,7 +60,7 @@ class DownmixConverter : public AudioConverter { public: - DownmixConverter(int src_channels, size_t src_frames, int dst_channels, + DownmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) { } @@ -71,7 +72,7 @@ float* dst_mono = dst[0]; for (size_t i = 0; i < src_frames(); ++i) { float sum = 0; - for (int j = 0; j < src_channels(); ++j) + for (size_t j = 0; j < src_channels(); ++j) sum += src[j][i]; dst_mono[i] = sum / src_channels(); } @@ -80,11 +81,11 @@ class ResampleConverter : public AudioConverter { public: - ResampleConverter(int src_channels, size_t src_frames, int dst_channels, + ResampleConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) { resamplers_.reserve(src_channels); - for (int i = 0; i < src_channels; ++i) + for (size_t i = 0; i < src_channels; ++i) resamplers_.push_back(new PushSincResampler(src_frames, dst_frames)); } ~ResampleConverter() override {}; @@ -105,7 +106,7 @@ class CompositionConverter : public AudioConverter { public: CompositionConverter(ScopedVector<AudioConverter> converters) - : converters_(converters.Pass()) { + : converters_(std::move(converters)) { RTC_CHECK_GE(converters_.size(), 2u); // We need an intermediate buffer after every converter. for (auto it = converters_.begin(); it != converters_.end() - 1; ++it) @@ -135,9 +136,9 @@ ScopedVector<ChannelBuffer<float>> buffers_; }; -rtc::scoped_ptr<AudioConverter> AudioConverter::Create(int src_channels, +rtc::scoped_ptr<AudioConverter> AudioConverter::Create(size_t src_channels, size_t src_frames, - int dst_channels, + size_t dst_channels, size_t dst_frames) { rtc::scoped_ptr<AudioConverter> sp; if (src_channels > dst_channels) { @@ -147,7 +148,7 @@ dst_channels, src_frames)); converters.push_back(new ResampleConverter(dst_channels, src_frames, dst_channels, dst_frames)); - sp.reset(new CompositionConverter(converters.Pass())); + sp.reset(new CompositionConverter(std::move(converters))); } else { sp.reset(new DownmixConverter(src_channels, src_frames, dst_channels, dst_frames)); @@ -159,7 +160,7 @@ src_channels, dst_frames)); converters.push_back(new UpmixConverter(src_channels, dst_frames, dst_channels, dst_frames)); - sp.reset(new CompositionConverter(converters.Pass())); + sp.reset(new CompositionConverter(std::move(converters))); } else { sp.reset(new UpmixConverter(src_channels, src_frames, dst_channels, dst_frames)); @@ -172,7 +173,7 @@ dst_frames)); } - return sp.Pass(); + return sp; } // For CompositionConverter. @@ -182,8 +183,8 @@ dst_channels_(0), dst_frames_(0) {} -AudioConverter::AudioConverter(int src_channels, size_t src_frames, - int dst_channels, size_t dst_frames) +AudioConverter::AudioConverter(size_t src_channels, size_t src_frames, + size_t dst_channels, size_t dst_frames) : src_channels_(src_channels), src_frames_(src_frames), dst_channels_(dst_channels),
diff --git a/webrtc/common_audio/audio_converter.h b/webrtc/common_audio/audio_converter.h index 7d1513b..c5f08c1 100644 --- a/webrtc/common_audio/audio_converter.h +++ b/webrtc/common_audio/audio_converter.h
@@ -26,9 +26,9 @@ public: // Returns a new AudioConverter, which will use the supplied format for its // lifetime. Caller is responsible for the memory. - static rtc::scoped_ptr<AudioConverter> Create(int src_channels, + static rtc::scoped_ptr<AudioConverter> Create(size_t src_channels, size_t src_frames, - int dst_channels, + size_t dst_channels, size_t dst_frames); virtual ~AudioConverter() {}; @@ -39,23 +39,23 @@ virtual void Convert(const float* const* src, size_t src_size, float* const* dst, size_t dst_capacity) = 0; - int src_channels() const { return src_channels_; } + size_t src_channels() const { return src_channels_; } size_t src_frames() const { return src_frames_; } - int dst_channels() const { return dst_channels_; } + size_t dst_channels() const { return dst_channels_; } size_t dst_frames() const { return dst_frames_; } protected: AudioConverter(); - AudioConverter(int src_channels, size_t src_frames, int dst_channels, + AudioConverter(size_t src_channels, size_t src_frames, size_t dst_channels, size_t dst_frames); // Helper to RTC_CHECK that inputs are correctly sized. void CheckSizes(size_t src_size, size_t dst_capacity) const; private: - const int src_channels_; + const size_t src_channels_; const size_t src_frames_; - const int dst_channels_; + const size_t dst_channels_; const size_t dst_frames_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioConverter);
diff --git a/webrtc/common_audio/audio_converter_unittest.cc b/webrtc/common_audio/audio_converter_unittest.cc index c85b96e..dace0bd 100644 --- a/webrtc/common_audio/audio_converter_unittest.cc +++ b/webrtc/common_audio/audio_converter_unittest.cc
@@ -13,6 +13,7 @@ #include <vector> #include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/arraysize.h" #include "webrtc/base/format_macros.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/common_audio/audio_converter.h" @@ -24,11 +25,11 @@ typedef rtc::scoped_ptr<ChannelBuffer<float>> ScopedBuffer; // Sets the signal value to increase by |data| with every sample. -ScopedBuffer CreateBuffer(const std::vector<float>& data, int frames) { - const int num_channels = static_cast<int>(data.size()); +ScopedBuffer CreateBuffer(const std::vector<float>& data, size_t frames) { + const size_t num_channels = data.size(); ScopedBuffer sb(new ChannelBuffer<float>(frames, num_channels)); - for (int i = 0; i < num_channels; ++i) - for (int j = 0; j < frames; ++j) + for (size_t i = 0; i < num_channels; ++i) + for (size_t j = 0; j < frames; ++j) sb->channels()[i][j] = data[i] * j; return sb; } @@ -56,7 +57,7 @@ float mse = 0; float variance = 0; float mean = 0; - for (int i = 0; i < ref.num_channels(); ++i) { + for (size_t i = 0; i < ref.num_channels(); ++i) { for (size_t j = 0; j < ref.num_frames() - delay; ++j) { float error = ref.channels()[i][j] - test.channels()[i][j + delay]; mse += error * error; @@ -85,9 +86,9 @@ // Sets the source to a linearly increasing signal for which we can easily // generate a reference. Runs the AudioConverter and ensures the output has // sufficiently high SNR relative to the reference. -void RunAudioConverterTest(int src_channels, +void RunAudioConverterTest(size_t src_channels, int src_sample_rate_hz, - int dst_channels, + size_t dst_channels, int dst_sample_rate_hz) { const float kSrcLeft = 0.0002f; const float kSrcRight = 0.0001f; @@ -96,8 +97,8 @@ const float dst_left = resampling_factor * kSrcLeft; const float dst_right = resampling_factor * kSrcRight; const float dst_mono = (dst_left + dst_right) / 2; - const int src_frames = src_sample_rate_hz / 100; - const int dst_frames = dst_sample_rate_hz / 100; + const size_t src_frames = static_cast<size_t>(src_sample_rate_hz / 100); + const size_t dst_frames = static_cast<size_t>(dst_sample_rate_hz / 100); std::vector<float> src_data(1, kSrcLeft); if (src_channels == 2) @@ -127,8 +128,9 @@ static_cast<size_t>( PushSincResampler::AlgorithmicDelaySeconds(src_sample_rate_hz) * dst_sample_rate_hz); - printf("(%d, %d Hz) -> (%d, %d Hz) ", // SNR reported on the same line later. - src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz); + // SNR reported on the same line later. + printf("(%" PRIuS ", %d Hz) -> (%" PRIuS ", %d Hz) ", + src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz); rtc::scoped_ptr<AudioConverter> converter = AudioConverter::Create( src_channels, src_frames, dst_channels, dst_frames); @@ -141,13 +143,13 @@ TEST(AudioConverterTest, ConversionsPassSNRThreshold) { const int kSampleRates[] = {8000, 16000, 32000, 44100, 48000}; - const int kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates); - const int kChannels[] = {1, 2}; - const int kChannelsSize = sizeof(kChannels) / sizeof(*kChannels); - for (int src_rate = 0; src_rate < kSampleRatesSize; ++src_rate) { - for (int dst_rate = 0; dst_rate < kSampleRatesSize; ++dst_rate) { - for (int src_channel = 0; src_channel < kChannelsSize; ++src_channel) { - for (int dst_channel = 0; dst_channel < kChannelsSize; ++dst_channel) { + const size_t kChannels[] = {1, 2}; + for (size_t src_rate = 0; src_rate < arraysize(kSampleRates); ++src_rate) { + for (size_t dst_rate = 0; dst_rate < arraysize(kSampleRates); ++dst_rate) { + for (size_t src_channel = 0; src_channel < arraysize(kChannels); + ++src_channel) { + for (size_t dst_channel = 0; dst_channel < arraysize(kChannels); + ++dst_channel) { RunAudioConverterTest(kChannels[src_channel], kSampleRates[src_rate], kChannels[dst_channel], kSampleRates[dst_rate]); }
diff --git a/webrtc/common_audio/blocker.cc b/webrtc/common_audio/blocker.cc index 0133550..13432f2 100644 --- a/webrtc/common_audio/blocker.cc +++ b/webrtc/common_audio/blocker.cc
@@ -22,10 +22,10 @@ const float* const* b, int b_start_index, size_t num_frames, - int num_channels, + size_t num_channels, float* const* result, size_t result_start_index) { - for (int i = 0; i < num_channels; ++i) { + for (size_t i = 0; i < num_channels; ++i) { for (size_t j = 0; j < num_frames; ++j) { result[i][j + result_start_index] = a[i][j + a_start_index] + b[i][j + b_start_index]; @@ -37,10 +37,10 @@ void CopyFrames(const float* const* src, size_t src_start_index, size_t num_frames, - int num_channels, + size_t num_channels, float* const* dst, size_t dst_start_index) { - for (int i = 0; i < num_channels; ++i) { + for (size_t i = 0; i < num_channels; ++i) { memcpy(&dst[i][dst_start_index], &src[i][src_start_index], num_frames * sizeof(dst[i][dst_start_index])); @@ -51,10 +51,10 @@ void MoveFrames(const float* const* src, size_t src_start_index, size_t num_frames, - int num_channels, + size_t num_channels, float* const* dst, size_t dst_start_index) { - for (int i = 0; i < num_channels; ++i) { + for (size_t i = 0; i < num_channels; ++i) { memmove(&dst[i][dst_start_index], &src[i][src_start_index], num_frames * sizeof(dst[i][dst_start_index])); @@ -64,8 +64,8 @@ void ZeroOut(float* const* buffer, size_t starting_idx, size_t num_frames, - int num_channels) { - for (int i = 0; i < num_channels; ++i) { + size_t num_channels) { + for (size_t i = 0; i < num_channels; ++i) { memset(&buffer[i][starting_idx], 0, num_frames * sizeof(buffer[i][starting_idx])); } @@ -75,9 +75,9 @@ // stored in |frames|. void ApplyWindow(const float* window, size_t num_frames, - int num_channels, + size_t num_channels, float* const* frames) { - for (int i = 0; i < num_channels; ++i) { + for (size_t i = 0; i < num_channels; ++i) { for (size_t j = 0; j < num_frames; ++j) { frames[i][j] = frames[i][j] * window[j]; } @@ -100,8 +100,8 @@ Blocker::Blocker(size_t chunk_size, size_t block_size, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, const float* window, size_t shift_amount, BlockerCallback* callback) @@ -166,8 +166,8 @@ // TODO(claguna): Look at using ring buffers to eliminate some copies. void Blocker::ProcessChunk(const float* const* input, size_t chunk_size, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, float* const* output) { RTC_CHECK_EQ(chunk_size, chunk_size_); RTC_CHECK_EQ(num_input_channels, num_input_channels_);
diff --git a/webrtc/common_audio/blocker.h b/webrtc/common_audio/blocker.h index 025638a..3a67c13 100644 --- a/webrtc/common_audio/blocker.h +++ b/webrtc/common_audio/blocker.h
@@ -26,8 +26,8 @@ virtual void ProcessBlock(const float* const* input, size_t num_frames, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, float* const* output) = 0; }; @@ -65,23 +65,23 @@ public: Blocker(size_t chunk_size, size_t block_size, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, const float* window, size_t shift_amount, BlockerCallback* callback); void ProcessChunk(const float* const* input, size_t chunk_size, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, float* const* output); private: const size_t chunk_size_; const size_t block_size_; - const int num_input_channels_; - const int num_output_channels_; + const size_t num_input_channels_; + const size_t num_output_channels_; // The number of frames of delay to add at the beginning of the first chunk. const size_t initial_delay_;
diff --git a/webrtc/common_audio/blocker_unittest.cc b/webrtc/common_audio/blocker_unittest.cc index 397e269..a5a7b56 100644 --- a/webrtc/common_audio/blocker_unittest.cc +++ b/webrtc/common_audio/blocker_unittest.cc
@@ -11,6 +11,7 @@ #include "webrtc/common_audio/blocker.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/arraysize.h" namespace { @@ -19,10 +20,10 @@ public: void ProcessBlock(const float* const* input, size_t num_frames, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, float* const* output) override { - for (int i = 0; i < num_output_channels; ++i) { + for (size_t i = 0; i < num_output_channels; ++i) { for (size_t j = 0; j < num_frames; ++j) { output[i][j] = input[i][j] + 3; } @@ -35,10 +36,10 @@ public: void ProcessBlock(const float* const* input, size_t num_frames, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, float* const* output) override { - for (int i = 0; i < num_output_channels; ++i) { + for (size_t i = 0; i < num_output_channels; ++i) { for (size_t j = 0; j < num_frames; ++j) { output[i][j] = input[i][j]; } @@ -56,16 +57,16 @@ class BlockerTest : public ::testing::Test { protected: void RunTest(Blocker* blocker, - int chunk_size, - int num_frames, + size_t chunk_size, + size_t num_frames, const float* const* input, float* const* input_chunk, float* const* output, float* const* output_chunk, - int num_input_channels, - int num_output_channels) { - int start = 0; - int end = chunk_size - 1; + size_t num_input_channels, + size_t num_output_channels) { + size_t start = 0; + size_t end = chunk_size - 1; while (end < num_frames) { CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input); blocker->ProcessChunk(input_chunk, @@ -75,28 +76,28 @@ output_chunk); CopyTo(output, start, 0, num_output_channels, chunk_size, output_chunk); - start = start + chunk_size; - end = end + chunk_size; + start += chunk_size; + end += chunk_size; } } void ValidateSignalEquality(const float* const* expected, const float* const* actual, - int num_channels, - int num_frames) { - for (int i = 0; i < num_channels; ++i) { - for (int j = 0; j < num_frames; ++j) { + size_t num_channels, + size_t num_frames) { + for (size_t i = 0; i < num_channels; ++i) { + for (size_t j = 0; j < num_frames; ++j) { EXPECT_FLOAT_EQ(expected[i][j], actual[i][j]); } } } void ValidateInitialDelay(const float* const* output, - int num_channels, - int num_frames, - int initial_delay) { - for (int i = 0; i < num_channels; ++i) { - for (int j = 0; j < num_frames; ++j) { + size_t num_channels, + size_t num_frames, + size_t initial_delay) { + for (size_t i = 0; i < num_channels; ++i) { + for (size_t j = 0; j < num_frames; ++j) { if (j < initial_delay) { EXPECT_FLOAT_EQ(output[i][j], 0.f); } else { @@ -107,12 +108,12 @@ } static void CopyTo(float* const* dst, - int start_index_dst, - int start_index_src, - int num_channels, - int num_frames, + size_t start_index_dst, + size_t start_index_src, + size_t num_channels, + size_t num_frames, const float* const* src) { - for (int i = 0; i < num_channels; ++i) { + for (size_t i = 0; i < num_channels; ++i) { memcpy(&dst[i][start_index_dst], &src[i][start_index_src], num_frames * sizeof(float)); @@ -121,12 +122,12 @@ }; TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) { - const int kNumInputChannels = 3; - const int kNumOutputChannels = 2; - const int kNumFrames = 10; - const int kBlockSize = 4; - const int kChunkSize = 5; - const int kShiftAmount = 2; + const size_t kNumInputChannels = 3; + const size_t kNumOutputChannels = 2; + const size_t kNumFrames = 10; + const size_t kBlockSize = 4; + const size_t kChunkSize = 5; + const size_t kShiftAmount = 2; const float kInput[kNumInputChannels][kNumFrames] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, @@ -174,12 +175,12 @@ } TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) { - const int kNumInputChannels = 3; - const int kNumOutputChannels = 2; - const int kNumFrames = 12; - const int kBlockSize = 4; - const int kChunkSize = 6; - const int kShiftAmount = 3; + const size_t kNumInputChannels = 3; + const size_t kNumOutputChannels = 2; + const size_t kNumFrames = 12; + const size_t kBlockSize = 4; + const size_t kChunkSize = 6; + const size_t kShiftAmount = 3; const float kInput[kNumInputChannels][kNumFrames] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, @@ -227,12 +228,12 @@ } TEST_F(BlockerTest, TestBlockerNoOverlap) { - const int kNumInputChannels = 3; - const int kNumOutputChannels = 2; - const int kNumFrames = 12; - const int kBlockSize = 4; - const int kChunkSize = 4; - const int kShiftAmount = 4; + const size_t kNumInputChannels = 3; + const size_t kNumOutputChannels = 2; + const size_t kNumFrames = 12; + const size_t kBlockSize = 4; + const size_t kChunkSize = 4; + const size_t kShiftAmount = 4; const float kInput[kNumInputChannels][kNumFrames] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, @@ -280,21 +281,21 @@ } TEST_F(BlockerTest, InitialDelaysAreMinimum) { - const int kNumInputChannels = 3; - const int kNumOutputChannels = 2; - const int kNumFrames = 1280; - const int kChunkSize[] = + const size_t kNumInputChannels = 3; + const size_t kNumOutputChannels = 2; + const size_t kNumFrames = 1280; + const size_t kChunkSize[] = {80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160}; - const int kBlockSize[] = + const size_t kBlockSize[] = {64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256}; - const int kShiftAmount[] = + const size_t kShiftAmount[] = {16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256}; - const int kInitialDelay[] = + const size_t kInitialDelay[] = {48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224}; float input[kNumInputChannels][kNumFrames]; - for (int i = 0; i < kNumInputChannels; ++i) { - for (int j = 0; j < kNumFrames; ++j) { + for (size_t i = 0; i < kNumInputChannels; ++i) { + for (size_t j = 0; j < kNumFrames; ++j) { input[i][j] = i + 1; } } @@ -305,9 +306,9 @@ CopyBlockerCallback callback; - for (size_t i = 0; i < (sizeof(kChunkSize) / sizeof(*kChunkSize)); ++i) { + for (size_t i = 0; i < arraysize(kChunkSize); ++i) { rtc::scoped_ptr<float[]> window(new float[kBlockSize[i]]); - for (int j = 0; j < kBlockSize[i]; ++j) { + for (size_t j = 0; j < kBlockSize[i]; ++j) { window[j] = 1.f; }
diff --git a/webrtc/common_audio/channel_buffer.cc b/webrtc/common_audio/channel_buffer.cc index d3dc7c0..44520c6 100644 --- a/webrtc/common_audio/channel_buffer.cc +++ b/webrtc/common_audio/channel_buffer.cc
@@ -13,7 +13,7 @@ namespace webrtc { IFChannelBuffer::IFChannelBuffer(size_t num_frames, - int num_channels, + size_t num_channels, size_t num_bands) : ivalid_(true), ibuf_(num_frames, num_channels, num_bands), @@ -47,7 +47,7 @@ assert(ivalid_); const int16_t* const* int_channels = ibuf_.channels(); float* const* float_channels = fbuf_.channels(); - for (int i = 0; i < ibuf_.num_channels(); ++i) { + for (size_t i = 0; i < ibuf_.num_channels(); ++i) { for (size_t j = 0; j < ibuf_.num_frames(); ++j) { float_channels[i][j] = int_channels[i][j]; } @@ -61,7 +61,7 @@ assert(fvalid_); int16_t* const* int_channels = ibuf_.channels(); const float* const* float_channels = fbuf_.channels(); - for (int i = 0; i < ibuf_.num_channels(); ++i) { + for (size_t i = 0; i < ibuf_.num_channels(); ++i) { FloatS16ToS16(float_channels[i], ibuf_.num_frames(), int_channels[i]);
diff --git a/webrtc/common_audio/channel_buffer.h b/webrtc/common_audio/channel_buffer.h index 6050090..d906916 100644 --- a/webrtc/common_audio/channel_buffer.h +++ b/webrtc/common_audio/channel_buffer.h
@@ -40,7 +40,7 @@ class ChannelBuffer { public: ChannelBuffer(size_t num_frames, - int num_channels, + size_t num_channels, size_t num_bands = 1) : data_(new T[num_frames * num_channels]()), channels_(new T*[num_channels * num_bands]), @@ -49,7 +49,7 @@ num_frames_per_band_(num_frames / num_bands), num_channels_(num_channels), num_bands_(num_bands) { - for (int i = 0; i < num_channels_; ++i) { + for (size_t i = 0; i < num_channels_; ++i) { for (size_t j = 0; j < num_bands_; ++j) { channels_[j * num_channels_ + i] = &data_[i * num_frames_ + j * num_frames_per_band_]; @@ -90,12 +90,12 @@ // 0 <= channel < |num_channels_| // 0 <= band < |num_bands_| // 0 <= sample < |num_frames_per_band_| - const T* const* bands(int channel) const { + const T* const* bands(size_t channel) const { RTC_DCHECK_LT(channel, num_channels_); - RTC_DCHECK_GE(channel, 0); + RTC_DCHECK_GE(channel, 0u); return &bands_[channel * num_bands_]; } - T* const* bands(int channel) { + T* const* bands(size_t channel) { const ChannelBuffer<T>* t = this; return const_cast<T* const*>(t->bands(channel)); } @@ -104,7 +104,7 @@ // Returns |slice| for convenience. const T* const* Slice(T** slice, size_t start_frame) const { RTC_DCHECK_LT(start_frame, num_frames_); - for (int i = 0; i < num_channels_; ++i) + for (size_t i = 0; i < num_channels_; ++i) slice[i] = &channels_[i][start_frame]; return slice; } @@ -115,7 +115,7 @@ size_t num_frames() const { return num_frames_; } size_t num_frames_per_band() const { return num_frames_per_band_; } - int num_channels() const { return num_channels_; } + size_t num_channels() const { return num_channels_; } size_t num_bands() const { return num_bands_; } size_t size() const {return num_frames_ * num_channels_; } @@ -130,7 +130,7 @@ rtc::scoped_ptr<T* []> bands_; const size_t num_frames_; const size_t num_frames_per_band_; - const int num_channels_; + const size_t num_channels_; const size_t num_bands_; }; @@ -142,7 +142,7 @@ // fbuf() until the next call to any of the other functions. class IFChannelBuffer { public: - IFChannelBuffer(size_t num_frames, int num_channels, size_t num_bands = 1); + IFChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1); ChannelBuffer<int16_t>* ibuf(); ChannelBuffer<float>* fbuf(); @@ -151,7 +151,7 @@ size_t num_frames() const { return ibuf_.num_frames(); } size_t num_frames_per_band() const { return ibuf_.num_frames_per_band(); } - int num_channels() const { return ibuf_.num_channels(); } + size_t num_channels() const { return ibuf_.num_channels(); } size_t num_bands() const { return ibuf_.num_bands(); } private:
diff --git a/webrtc/common_audio/common_audio.gyp b/webrtc/common_audio/common_audio.gyp index 884a8af..f0a6fc9 100644 --- a/webrtc/common_audio/common_audio.gyp +++ b/webrtc/common_audio/common_audio.gyp
@@ -101,6 +101,7 @@ 'signal_processing/vector_scaling_operations.c', 'sparse_fir_filter.cc', 'sparse_fir_filter.h', + 'swap_queue.h', 'vad/include/vad.h', 'vad/include/webrtc_vad.h', 'vad/vad.cc', @@ -227,9 +228,10 @@ }, ], # targets }], - ['include_tests==1', { + ['include_tests==1 and OS!="ios"', { 'targets' : [ { + # Does not compile on iOS: webrtc:4755. 'target_name': 'common_audio_unittests', 'type': '<(gtest_target_type)', 'dependencies': [ @@ -256,6 +258,7 @@ 'signal_processing/real_fft_unittest.cc', 'signal_processing/signal_processing_unittest.cc', 'sparse_fir_filter_unittest.cc', + 'swap_queue_unittest.cc', 'vad/vad_core_unittest.cc', 'vad/vad_filterbank_unittest.cc', 'vad/vad_gmm_unittest.cc',
diff --git a/webrtc/common_audio/include/audio_util.h b/webrtc/common_audio/include/audio_util.h index 2c0028c..55dfc06 100644 --- a/webrtc/common_audio/include/audio_util.h +++ b/webrtc/common_audio/include/audio_util.h
@@ -87,11 +87,11 @@ template <typename T> void Deinterleave(const T* interleaved, size_t samples_per_channel, - int num_channels, + size_t num_channels, T* const* deinterleaved) { - for (int i = 0; i < num_channels; ++i) { + for (size_t i = 0; i < num_channels; ++i) { T* channel = deinterleaved[i]; - int interleaved_idx = i; + size_t interleaved_idx = i; for (size_t j = 0; j < samples_per_channel; ++j) { channel[j] = interleaved[interleaved_idx]; interleaved_idx += num_channels; @@ -105,11 +105,11 @@ template <typename T> void Interleave(const T* const* deinterleaved, size_t samples_per_channel, - int num_channels, + size_t num_channels, T* interleaved) { - for (int i = 0; i < num_channels; ++i) { + for (size_t i = 0; i < num_channels; ++i) { const T* channel = deinterleaved[i]; - int interleaved_idx = i; + size_t interleaved_idx = i; for (size_t j = 0; j < samples_per_channel; ++j) { interleaved[interleaved_idx] = channel[j]; interleaved_idx += num_channels;
diff --git a/webrtc/common_audio/lapped_transform.cc b/webrtc/common_audio/lapped_transform.cc index c01f1d9..5ab1db1 100644 --- a/webrtc/common_audio/lapped_transform.cc +++ b/webrtc/common_audio/lapped_transform.cc
@@ -21,14 +21,14 @@ void LappedTransform::BlockThunk::ProcessBlock(const float* const* input, size_t num_frames, - int num_input_channels, - int num_output_channels, + size_t num_input_channels, + size_t num_output_channels, float* const* output) { RTC_CHECK_EQ(num_input_channels, parent_->num_in_channels_); RTC_CHECK_EQ(num_output_channels, parent_->num_out_channels_); RTC_CHECK_EQ(parent_->block_length_, num_frames); - for (int i = 0; i < num_input_channels; ++i) { + for (size_t i = 0; i < num_input_channels; ++i) { memcpy(parent_->real_buf_.Row(i), input[i], num_frames * sizeof(*input[0])); parent_->fft_->Forward(parent_->real_buf_.Row(i), @@ -44,7 +44,7 @@ num_output_channels, parent_->cplx_post_.Array()); - for (int i = 0; i < num_output_channels; ++i) { + for (size_t i = 0; i < num_output_channels; ++i) { parent_->fft_->Inverse(parent_->cplx_post_.Row(i), parent_->real_buf_.Row(i)); memcpy(output[i], parent_->real_buf_.Row(i), @@ -52,8 +52,8 @@ } } -LappedTransform::LappedTransform(int num_in_channels, - int num_out_channels, +LappedTransform::LappedTransform(size_t num_in_channels, + size_t num_out_channels, size_t chunk_length, const float* window, size_t block_length,
diff --git a/webrtc/common_audio/lapped_transform.h b/webrtc/common_audio/lapped_transform.h index 21e10e3..1373ca1 100644 --- a/webrtc/common_audio/lapped_transform.h +++ b/webrtc/common_audio/lapped_transform.h
@@ -35,8 +35,8 @@ virtual ~Callback() {} virtual void ProcessAudioBlock(const std::complex<float>* const* in_block, - int num_in_channels, size_t frames, - int num_out_channels, + size_t num_in_channels, size_t frames, + size_t num_out_channels, std::complex<float>* const* out_block) = 0; }; @@ -46,8 +46,8 @@ // |block_length| defines the length of a block, in samples. // |shift_amount| is in samples. |callback| is the caller-owned audio // processing function called for each block of the input chunk. - LappedTransform(int num_in_channels, - int num_out_channels, + LappedTransform(size_t num_in_channels, + size_t num_out_channels, size_t chunk_length, const float* window, size_t block_length, @@ -75,7 +75,7 @@ // in_chunk. // // Returns the same num_in_channels passed to the LappedTransform constructor. - int num_in_channels() const { return num_in_channels_; } + size_t num_in_channels() const { return num_in_channels_; } // Get the number of output channels. // @@ -84,7 +84,7 @@ // // Returns the same num_out_channels passed to the LappedTransform // constructor. - int num_out_channels() const { return num_out_channels_; } + size_t num_out_channels() const { return num_out_channels_; } private: // Internal middleware callback, given to the blocker. Transforms each block @@ -93,16 +93,18 @@ public: explicit BlockThunk(LappedTransform* parent) : parent_(parent) {} - virtual void ProcessBlock(const float* const* input, size_t num_frames, - int num_input_channels, int num_output_channels, + virtual void ProcessBlock(const float* const* input, + size_t num_frames, + size_t num_input_channels, + size_t num_output_channels, float* const* output); private: LappedTransform* const parent_; } blocker_callback_; - const int num_in_channels_; - const int num_out_channels_; + const size_t num_in_channels_; + const size_t num_out_channels_; const size_t block_length_; const size_t chunk_length_;
diff --git a/webrtc/common_audio/lapped_transform_unittest.cc b/webrtc/common_audio/lapped_transform_unittest.cc index f688cc2..a78488e 100644 --- a/webrtc/common_audio/lapped_transform_unittest.cc +++ b/webrtc/common_audio/lapped_transform_unittest.cc
@@ -25,23 +25,23 @@ NoopCallback() : block_num_(0) {} virtual void ProcessAudioBlock(const complex<float>* const* in_block, - int in_channels, + size_t in_channels, size_t frames, - int out_channels, + size_t out_channels, complex<float>* const* out_block) { RTC_CHECK_EQ(in_channels, out_channels); - for (int i = 0; i < out_channels; ++i) { + for (size_t i = 0; i < out_channels; ++i) { memcpy(out_block[i], in_block[i], sizeof(**in_block) * frames); } ++block_num_; } - int block_num() { + size_t block_num() { return block_num_; } private: - int block_num_; + size_t block_num_; }; class FftCheckerCallback : public webrtc::LappedTransform::Callback { @@ -49,9 +49,9 @@ FftCheckerCallback() : block_num_(0) {} virtual void ProcessAudioBlock(const complex<float>* const* in_block, - int in_channels, + size_t in_channels, size_t frames, - int out_channels, + size_t out_channels, complex<float>* const* out_block) { RTC_CHECK_EQ(in_channels, out_channels); @@ -69,12 +69,12 @@ } } - int block_num() { + size_t block_num() { return block_num_; } private: - int block_num_; + size_t block_num_; }; void SetFloatArray(float value, int rows, int cols, float* const* array) { @@ -90,10 +90,10 @@ namespace webrtc { TEST(LappedTransformTest, Windowless) { - const int kChannels = 3; - const int kChunkLength = 512; - const int kBlockLength = 64; - const int kShiftAmount = 64; + const size_t kChannels = 3; + const size_t kChunkLength = 512; + const size_t kBlockLength = 64; + const size_t kShiftAmount = 64; NoopCallback noop; // Rectangular window. @@ -118,8 +118,8 @@ trans.ProcessChunk(in_chunk, out_chunk); - for (int i = 0; i < kChannels; ++i) { - for (int j = 0; j < kChunkLength; ++j) { + for (size_t i = 0; i < kChannels; ++i) { + for (size_t j = 0; j < kChunkLength; ++j) { ASSERT_NEAR(out_chunk[i][j], 2.0f, 1e-5f); } } @@ -128,9 +128,9 @@ } TEST(LappedTransformTest, IdentityProcessor) { - const int kChunkLength = 512; - const int kBlockLength = 64; - const int kShiftAmount = 32; + const size_t kChunkLength = 512; + const size_t kBlockLength = 64; + const size_t kShiftAmount = 32; NoopCallback noop; // Identity window for |overlap = block_size / 2|. @@ -149,7 +149,7 @@ trans.ProcessChunk(&in_chunk, &out_chunk); - for (int i = 0; i < kChunkLength; ++i) { + for (size_t i = 0; i < kChunkLength; ++i) { ASSERT_NEAR(out_chunk[i], (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f, 1e-5f); @@ -159,8 +159,8 @@ } TEST(LappedTransformTest, Callbacks) { - const int kChunkLength = 512; - const int kBlockLength = 64; + const size_t kChunkLength = 512; + const size_t kBlockLength = 64; FftCheckerCallback call; // Rectangular window. @@ -183,7 +183,7 @@ } TEST(LappedTransformTest, chunk_length) { - const int kBlockLength = 64; + const size_t kBlockLength = 64; FftCheckerCallback call; const float window[kBlockLength] = {};
diff --git a/webrtc/common_audio/real_fourier.cc b/webrtc/common_audio/real_fourier.cc index fef3c60..55ec49c 100644 --- a/webrtc/common_audio/real_fourier.cc +++ b/webrtc/common_audio/real_fourier.cc
@@ -19,7 +19,7 @@ using std::complex; -const int RealFourier::kFftBufferAlignment = 32; +const size_t RealFourier::kFftBufferAlignment = 32; rtc::scoped_ptr<RealFourier> RealFourier::Create(int fft_order) { #if defined(RTC_USE_OPENMAX_DL)
diff --git a/webrtc/common_audio/real_fourier.h b/webrtc/common_audio/real_fourier.h index ce3bbff..0be56a5 100644 --- a/webrtc/common_audio/real_fourier.h +++ b/webrtc/common_audio/real_fourier.h
@@ -30,7 +30,7 @@ fft_cplx_scoper; // The alignment required for all input and output buffers, in bytes. - static const int kFftBufferAlignment; + static const size_t kFftBufferAlignment; // Construct a wrapper instance for the given input order, which must be // between 1 and kMaxFftOrder, inclusively.
diff --git a/webrtc/common_audio/real_fourier_unittest.cc b/webrtc/common_audio/real_fourier_unittest.cc index 5c85421..eb5880e 100644 --- a/webrtc/common_audio/real_fourier_unittest.cc +++ b/webrtc/common_audio/real_fourier_unittest.cc
@@ -26,15 +26,15 @@ RealFourier::fft_real_scoper real; real = RealFourier::AllocRealBuffer(3); ASSERT_TRUE(real.get() != nullptr); - int64_t ptr_value = reinterpret_cast<int64_t>(real.get()); - EXPECT_EQ(0, ptr_value % RealFourier::kFftBufferAlignment); + uintptr_t ptr_value = reinterpret_cast<uintptr_t>(real.get()); + EXPECT_EQ(0u, ptr_value % RealFourier::kFftBufferAlignment); } { RealFourier::fft_cplx_scoper cplx; cplx = RealFourier::AllocCplxBuffer(3); ASSERT_TRUE(cplx.get() != nullptr); - int64_t ptr_value = reinterpret_cast<int64_t>(cplx.get()); - EXPECT_EQ(0, ptr_value % RealFourier::kFftBufferAlignment); + uintptr_t ptr_value = reinterpret_cast<uintptr_t>(cplx.get()); + EXPECT_EQ(0u, ptr_value % RealFourier::kFftBufferAlignment); } }
diff --git a/webrtc/common_audio/resampler/include/push_resampler.h b/webrtc/common_audio/resampler/include/push_resampler.h index b5c0003..eeda790 100644 --- a/webrtc/common_audio/resampler/include/push_resampler.h +++ b/webrtc/common_audio/resampler/include/push_resampler.h
@@ -29,7 +29,7 @@ // Must be called whenever the parameters change. Free to be called at any // time as it is a no-op if parameters have not changed since the last call. int InitializeIfNeeded(int src_sample_rate_hz, int dst_sample_rate_hz, - int num_channels); + size_t num_channels); // Returns the total number of samples provided in destination (e.g. 32 kHz, // 2 channel audio gives 640 samples). @@ -40,7 +40,7 @@ rtc::scoped_ptr<PushSincResampler> sinc_resampler_right_; int src_sample_rate_hz_; int dst_sample_rate_hz_; - int num_channels_; + size_t num_channels_; rtc::scoped_ptr<T[]> src_left_; rtc::scoped_ptr<T[]> src_right_; rtc::scoped_ptr<T[]> dst_left_;
diff --git a/webrtc/common_audio/resampler/include/resampler.h b/webrtc/common_audio/resampler/include/resampler.h index 0d4c1af..e26ac90 100644 --- a/webrtc/common_audio/resampler/include/resampler.h +++ b/webrtc/common_audio/resampler/include/resampler.h
@@ -28,14 +28,14 @@ public: Resampler(); - Resampler(int inFreq, int outFreq, int num_channels); + Resampler(int inFreq, int outFreq, size_t num_channels); ~Resampler(); // Reset all states - int Reset(int inFreq, int outFreq, int num_channels); + int Reset(int inFreq, int outFreq, size_t num_channels); // Reset all states if any parameter has changed - int ResetIfNeeded(int inFreq, int outFreq, int num_channels); + int ResetIfNeeded(int inFreq, int outFreq, size_t num_channels); // Resample samplesIn to samplesOut. int Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut, @@ -83,7 +83,7 @@ int my_in_frequency_khz_; int my_out_frequency_khz_; ResamplerMode my_mode_; - int num_channels_; + size_t num_channels_; // Extra instance for stereo Resampler* slave_left_;
diff --git a/webrtc/common_audio/resampler/push_resampler.cc b/webrtc/common_audio/resampler/push_resampler.cc index 566acde..f654e9a 100644 --- a/webrtc/common_audio/resampler/push_resampler.cc +++ b/webrtc/common_audio/resampler/push_resampler.cc
@@ -32,7 +32,7 @@ template <typename T> int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz, int dst_sample_rate_hz, - int num_channels) { + size_t num_channels) { if (src_sample_rate_hz == src_sample_rate_hz_ && dst_sample_rate_hz == dst_sample_rate_hz_ && num_channels == num_channels_) @@ -68,10 +68,8 @@ template <typename T> int PushResampler<T>::Resample(const T* src, size_t src_length, T* dst, size_t dst_capacity) { - const size_t src_size_10ms = - static_cast<size_t>(src_sample_rate_hz_ * num_channels_ / 100); - const size_t dst_size_10ms = - static_cast<size_t>(dst_sample_rate_hz_ * num_channels_ / 100); + const size_t src_size_10ms = src_sample_rate_hz_ * num_channels_ / 100; + const size_t dst_size_10ms = dst_sample_rate_hz_ * num_channels_ / 100; if (src_length != src_size_10ms || dst_capacity < dst_size_10ms) return -1;
diff --git a/webrtc/common_audio/resampler/resampler.cc b/webrtc/common_audio/resampler/resampler.cc index c9e7a1f..7c690fc 100644 --- a/webrtc/common_audio/resampler/resampler.cc +++ b/webrtc/common_audio/resampler/resampler.cc
@@ -39,7 +39,7 @@ slave_right_(nullptr) { } -Resampler::Resampler(int inFreq, int outFreq, int num_channels) +Resampler::Resampler(int inFreq, int outFreq, size_t num_channels) : Resampler() { Reset(inFreq, outFreq, num_channels); } @@ -76,7 +76,7 @@ } } -int Resampler::ResetIfNeeded(int inFreq, int outFreq, int num_channels) +int Resampler::ResetIfNeeded(int inFreq, int outFreq, size_t num_channels) { int tmpInFreq_kHz = inFreq / 1000; int tmpOutFreq_kHz = outFreq / 1000; @@ -91,7 +91,7 @@ } } -int Resampler::Reset(int inFreq, int outFreq, int num_channels) +int Resampler::Reset(int inFreq, int outFreq, size_t num_channels) { if (num_channels != 1 && num_channels != 2) { return -1;
diff --git a/webrtc/common_audio/signal_processing/real_fft_unittest.cc b/webrtc/common_audio/signal_processing/real_fft_unittest.cc index 9bd35cd..fa98836 100644 --- a/webrtc/common_audio/signal_processing/real_fft_unittest.cc +++ b/webrtc/common_audio/signal_processing/real_fft_unittest.cc
@@ -10,7 +10,6 @@ #include "webrtc/common_audio/signal_processing/include/real_fft.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" -#include "webrtc/test/testsupport/gtest_disable.h" #include "webrtc/typedefs.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/webrtc/common_audio/swap_queue.h b/webrtc/common_audio/swap_queue.h new file mode 100644 index 0000000..d8bb5c0 --- /dev/null +++ b/webrtc/common_audio/swap_queue.h
@@ -0,0 +1,210 @@ +/* + * 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_COMMON_AUDIO_SWAP_QUEUE_H_ +#define WEBRTC_COMMON_AUDIO_SWAP_QUEUE_H_ + +#include <algorithm> +#include <utility> +#include <vector> + +#include "webrtc/base/checks.h" +#include "webrtc/base/criticalsection.h" + +namespace webrtc { + +namespace internal { + +// (Internal; please don't use outside this file.) +template <typename T> +bool NoopSwapQueueItemVerifierFunction(const T&) { + return true; +} + +} // namespace internal + +// Functor to use when supplying a verifier function for the queue. +template <typename T, + bool (*QueueItemVerifierFunction)(const T&) = + internal::NoopSwapQueueItemVerifierFunction> +class SwapQueueItemVerifier { + public: + bool operator()(const T& t) const { return QueueItemVerifierFunction(t); } +}; + +// This class is a fixed-size queue. A producer calls Insert() to insert +// an element of type T at the back of the queue, and a consumer calls +// Remove() to remove an element from the front of the queue. It's safe +// for the producer(s) and the consumer(s) to access the queue +// concurrently, from different threads. +// +// To avoid the construction, copying, and destruction of Ts that a naive +// queue implementation would require, for each "full" T passed from +// producer to consumer, SwapQueue<T> passes an "empty" T in the other +// direction (an "empty" T is one that contains nothing of value for the +// consumer). This bidirectional movement is implemented with swap(). +// +// // Create queue: +// Bottle proto(568); // Prepare an empty Bottle. Heap allocates space for +// // 568 ml. +// SwapQueue<Bottle> q(N, proto); // Init queue with N copies of proto. +// // Each copy allocates on the heap. +// // Producer pseudo-code: +// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml. +// loop { +// b.Fill(amount); // Where amount <= 568 ml. +// q.Insert(&b); // Swap our full Bottle for an empty one from q. +// } +// +// // Consumer pseudo-code: +// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml. +// loop { +// q.Remove(&b); // Swap our empty Bottle for the next-in-line full Bottle. +// Drink(&b); +// } +// +// For a well-behaved Bottle class, there are no allocations in the +// producer, since it just fills an empty Bottle that's already large +// enough; no deallocations in the consumer, since it returns each empty +// Bottle to the queue after having drunk it; and no copies along the +// way, since the queue uses swap() everywhere to move full Bottles in +// one direction and empty ones in the other. +template <typename T, typename QueueItemVerifier = SwapQueueItemVerifier<T>> +class SwapQueue { + public: + // Creates a queue of size size and fills it with default constructed Ts. + explicit SwapQueue(size_t size) : queue_(size) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Same as above and accepts an item verification functor. + SwapQueue(size_t size, const QueueItemVerifier& queue_item_verifier) + : queue_item_verifier_(queue_item_verifier), queue_(size) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Creates a queue of size size and fills it with copies of prototype. + SwapQueue(size_t size, const T& prototype) : queue_(size, prototype) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Same as above and accepts an item verification functor. + SwapQueue(size_t size, + const T& prototype, + const QueueItemVerifier& queue_item_verifier) + : queue_item_verifier_(queue_item_verifier), queue_(size, prototype) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Resets the queue to have zero content wile maintaining the queue size. + void Clear() { + rtc::CritScope cs(&crit_queue_); + next_write_index_ = 0; + next_read_index_ = 0; + num_elements_ = 0; + } + + // Inserts a "full" T at the back of the queue by swapping *input with an + // "empty" T from the queue. + // Returns true if the item was inserted or false if not (the queue was full). + // When specified, the T given in *input must pass the ItemVerifier() test. + // The contents of *input after the call are then also guaranteed to pass the + // ItemVerifier() test. + bool Insert(T* input) WARN_UNUSED_RESULT { + RTC_DCHECK(input); + + rtc::CritScope cs(&crit_queue_); + + RTC_DCHECK(queue_item_verifier_(*input)); + + if (num_elements_ == queue_.size()) { + return false; + } + + using std::swap; + swap(*input, queue_[next_write_index_]); + + ++next_write_index_; + if (next_write_index_ == queue_.size()) { + next_write_index_ = 0; + } + + ++num_elements_; + + RTC_DCHECK_LT(next_write_index_, queue_.size()); + RTC_DCHECK_LE(num_elements_, queue_.size()); + + return true; + } + + // Removes the frontmost "full" T from the queue by swapping it with + // the "empty" T in *output. + // Returns true if an item could be removed or false if not (the queue was + // empty). When specified, The T given in *output must pass the ItemVerifier() + // test and the contents of *output after the call are then also guaranteed to + // pass the ItemVerifier() test. + bool Remove(T* output) WARN_UNUSED_RESULT { + RTC_DCHECK(output); + + rtc::CritScope cs(&crit_queue_); + + RTC_DCHECK(queue_item_verifier_(*output)); + + if (num_elements_ == 0) { + return false; + } + + using std::swap; + swap(*output, queue_[next_read_index_]); + + ++next_read_index_; + if (next_read_index_ == queue_.size()) { + next_read_index_ = 0; + } + + --num_elements_; + + RTC_DCHECK_LT(next_read_index_, queue_.size()); + RTC_DCHECK_LE(num_elements_, queue_.size()); + + return true; + } + + private: + // Verify that the queue slots complies with the ItemVerifier test. + bool VerifyQueueSlots() { + rtc::CritScope cs(&crit_queue_); + for (const auto& v : queue_) { + RTC_DCHECK(queue_item_verifier_(v)); + } + return true; + } + + rtc::CriticalSection crit_queue_; + + // TODO(peah): Change this to use std::function() once we can use C++11 std + // lib. + QueueItemVerifier queue_item_verifier_ GUARDED_BY(crit_queue_); + + // (next_read_index_ + num_elements_) % queue_.size() = + // next_write_index_ + size_t next_write_index_ GUARDED_BY(crit_queue_) = 0; + size_t next_read_index_ GUARDED_BY(crit_queue_) = 0; + size_t num_elements_ GUARDED_BY(crit_queue_) = 0; + + // queue_.size() is constant. + std::vector<T> queue_ GUARDED_BY(crit_queue_); + + RTC_DISALLOW_COPY_AND_ASSIGN(SwapQueue); +}; + +} // namespace webrtc + +#endif // WEBRTC_COMMON_AUDIO_SWAP_QUEUE_H_
diff --git a/webrtc/common_audio/swap_queue_unittest.cc b/webrtc/common_audio/swap_queue_unittest.cc new file mode 100644 index 0000000..104e494 --- /dev/null +++ b/webrtc/common_audio/swap_queue_unittest.cc
@@ -0,0 +1,225 @@ +/* + * 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/common_audio/swap_queue.h" + +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace webrtc { + +namespace { + +// Test parameter for the basic sample based SwapQueue Tests. +const size_t kChunkSize = 3; + +// Queue item verification function for the vector test. +bool LengthVerifierFunction(const std::vector<int>& v) { + return v.size() == kChunkSize; +} + +// Queue item verifier for the vector test. +class LengthVerifierFunctor { + public: + explicit LengthVerifierFunctor(size_t length) : length_(length) {} + + bool operator()(const std::vector<int>& v) const { + return v.size() == length_; + } + + private: + size_t length_; +}; + +} // anonymous namespace + +TEST(SwapQueueTest, BasicOperation) { + std::vector<int> i(kChunkSize, 0); + SwapQueue<std::vector<int>> queue(2, i); + + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_EQ(i.size(), kChunkSize); + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_EQ(i.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i.size(), kChunkSize); +} + +TEST(SwapQueueTest, FullQueue) { + SwapQueue<int> queue(2); + + // Fill the queue. + int i = 0; + EXPECT_TRUE(queue.Insert(&i)); + i = 1; + EXPECT_TRUE(queue.Insert(&i)); + + // Ensure that the value is not swapped when doing an Insert + // on a full queue. + i = 2; + EXPECT_FALSE(queue.Insert(&i)); + EXPECT_EQ(i, 2); + + // Ensure that the Insert didn't overwrite anything in the queue. + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i, 0); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i, 1); +} + +TEST(SwapQueueTest, EmptyQueue) { + SwapQueue<int> queue(2); + int i = 0; + EXPECT_FALSE(queue.Remove(&i)); + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_FALSE(queue.Remove(&i)); +} + +TEST(SwapQueueTest, Clear) { + SwapQueue<int> queue(2); + int i = 0; + + // Fill the queue. + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_TRUE(queue.Insert(&i)); + + // Ensure full queue. + EXPECT_FALSE(queue.Insert(&i)); + + // Empty the queue. + queue.Clear(); + + // Ensure that the queue is empty + EXPECT_FALSE(queue.Remove(&i)); + + // Ensure that the queue is no longer full. + EXPECT_TRUE(queue.Insert(&i)); +} + +TEST(SwapQueueTest, SuccessfulItemVerifyFunction) { + std::vector<int> template_element(kChunkSize); + SwapQueue<std::vector<int>, + SwapQueueItemVerifier<std::vector<int>, LengthVerifierFunction>> + queue(2, template_element); + std::vector<int> valid_chunk(kChunkSize, 0); + + EXPECT_TRUE(queue.Insert(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); +} + +TEST(SwapQueueTest, SuccessfulItemVerifyFunctor) { + std::vector<int> template_element(kChunkSize); + LengthVerifierFunctor verifier(kChunkSize); + SwapQueue<std::vector<int>, LengthVerifierFunctor> queue(2, template_element, + verifier); + std::vector<int> valid_chunk(kChunkSize, 0); + + EXPECT_TRUE(queue.Insert(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(SwapQueueTest, UnsuccessfulItemVerifyFunctor) { + // Queue item verifier for the test. + auto minus_2_verifier = [](const int& i) { return i > -2; }; + SwapQueue<int, decltype(minus_2_verifier)> queue(2, minus_2_verifier); + + int valid_value = 1; + int invalid_value = -4; + EXPECT_TRUE(queue.Insert(&valid_value)); + EXPECT_TRUE(queue.Remove(&valid_value)); + bool result; + EXPECT_DEATH(result = queue.Insert(&invalid_value), ""); +} + +TEST(SwapQueueTest, UnSuccessfulItemVerifyInsert) { + std::vector<int> template_element(kChunkSize); + SwapQueue<std::vector<int>, + SwapQueueItemVerifier<std::vector<int>, &LengthVerifierFunction>> + queue(2, template_element); + std::vector<int> invalid_chunk(kChunkSize - 1, 0); + bool result; + EXPECT_DEATH(result = queue.Insert(&invalid_chunk), ""); +} + +TEST(SwapQueueTest, UnSuccessfulItemVerifyRemove) { + std::vector<int> template_element(kChunkSize); + SwapQueue<std::vector<int>, + SwapQueueItemVerifier<std::vector<int>, &LengthVerifierFunction>> + queue(2, template_element); + std::vector<int> invalid_chunk(kChunkSize - 1, 0); + std::vector<int> valid_chunk(kChunkSize, 0); + EXPECT_TRUE(queue.Insert(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); + bool result; + EXPECT_DEATH(result = queue.Remove(&invalid_chunk), ""); +} +#endif + +TEST(SwapQueueTest, VectorContentTest) { + const size_t kQueueSize = 10; + const size_t kFrameLength = 160; + const size_t kDataLength = kQueueSize * kFrameLength; + std::vector<int16_t> buffer_reader(kFrameLength, 0); + std::vector<int16_t> buffer_writer(kFrameLength, 0); + SwapQueue<std::vector<int16_t>> queue(kQueueSize, + std::vector<int16_t>(kFrameLength)); + std::vector<int16_t> samples(kDataLength); + + for (size_t k = 0; k < kDataLength; k++) { + samples[k] = k % 9; + } + + for (size_t k = 0; k < kQueueSize; k++) { + buffer_writer.clear(); + buffer_writer.insert(buffer_writer.end(), &samples[0] + k * kFrameLength, + &samples[0] + (k + 1) * kFrameLength); + + EXPECT_TRUE(queue.Insert(&buffer_writer)); + } + + for (size_t k = 0; k < kQueueSize; k++) { + EXPECT_TRUE(queue.Remove(&buffer_reader)); + + for (size_t j = 0; j < buffer_reader.size(); j++) { + EXPECT_EQ(buffer_reader[j], samples[k * kFrameLength + j]); + } + } +} + +TEST(SwapQueueTest, ZeroSlotQueue) { + SwapQueue<int> queue(0); + int i = 42; + EXPECT_FALSE(queue.Insert(&i)); + EXPECT_FALSE(queue.Remove(&i)); + EXPECT_EQ(i, 42); +} + +TEST(SwapQueueTest, OneSlotQueue) { + SwapQueue<int> queue(1); + int i = 42; + EXPECT_TRUE(queue.Insert(&i)); + i = 43; + EXPECT_FALSE(queue.Insert(&i)); + EXPECT_EQ(i, 43); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i, 42); + EXPECT_FALSE(queue.Remove(&i)); +} + +} // namespace webrtc
diff --git a/webrtc/common_audio/wav_file.cc b/webrtc/common_audio/wav_file.cc index 8dae7d6..94b7a3c 100644 --- a/webrtc/common_audio/wav_file.cc +++ b/webrtc/common_audio/wav_file.cc
@@ -13,6 +13,7 @@ #include <algorithm> #include <cstdio> #include <limits> +#include <sstream> #include "webrtc/base/checks.h" #include "webrtc/base/safe_conversions.h" @@ -23,7 +24,7 @@ // We write 16-bit PCM WAV files. static const WavFormat kWavFormat = kWavFormatPcm; -static const int kBytesPerSample = 2; +static const size_t kBytesPerSample = 2; // Doesn't take ownership of the file handle and won't close it. class ReadableWavFile : public ReadableWav { @@ -37,13 +38,21 @@ FILE* file_; }; +std::string WavFile::FormatAsString() const { + std::ostringstream s; + s << "Sample rate: " << sample_rate() << " Hz, Channels: " << num_channels() + << ", Duration: " + << (1.f * num_samples()) / (num_channels() * sample_rate()) << " s"; + return s.str(); +} + WavReader::WavReader(const std::string& filename) : file_handle_(fopen(filename.c_str(), "rb")) { - RTC_CHECK(file_handle_ && "Could not open wav file for reading."); + RTC_CHECK(file_handle_) << "Could not open wav file for reading."; ReadableWavFile readable(file_handle_); WavFormat format; - int bytes_per_sample; + size_t bytes_per_sample; RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format, &bytes_per_sample, &num_samples_)); num_samples_remaining_ = num_samples_; @@ -60,14 +69,13 @@ #error "Need to convert samples to big-endian when reading from WAV file" #endif // There could be metadata after the audio; ensure we don't read it. - num_samples = std::min(rtc::checked_cast<uint32_t>(num_samples), - num_samples_remaining_); + num_samples = std::min(num_samples, num_samples_remaining_); const size_t read = fread(samples, sizeof(*samples), num_samples, file_handle_); // If we didn't read what was requested, ensure we've reached the EOF. RTC_CHECK(read == num_samples || feof(file_handle_)); RTC_CHECK_LE(read, num_samples_remaining_); - num_samples_remaining_ -= rtc::checked_cast<uint32_t>(read); + num_samples_remaining_ -= read; return read; } @@ -91,12 +99,12 @@ } WavWriter::WavWriter(const std::string& filename, int sample_rate, - int num_channels) + size_t num_channels) : sample_rate_(sample_rate), num_channels_(num_channels), num_samples_(0), file_handle_(fopen(filename.c_str(), "wb")) { - RTC_CHECK(file_handle_ && "Could not open wav file for writing."); + RTC_CHECK(file_handle_) << "Could not open wav file for writing."; RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, kWavFormat, kBytesPerSample, num_samples_)); @@ -117,9 +125,8 @@ const size_t written = fwrite(samples, sizeof(*samples), num_samples, file_handle_); RTC_CHECK_EQ(num_samples, written); - num_samples_ += static_cast<uint32_t>(written); - RTC_CHECK(written <= std::numeric_limits<uint32_t>::max() || - num_samples_ >= written); // detect uint32_t overflow + num_samples_ += written; + RTC_CHECK(num_samples_ >= written); // detect size_t overflow } void WavWriter::WriteSamples(const float* samples, size_t num_samples) { @@ -146,7 +153,7 @@ rtc_WavWriter* rtc_WavOpen(const char* filename, int sample_rate, - int num_channels) { + size_t num_channels) { return reinterpret_cast<rtc_WavWriter*>( new webrtc::WavWriter(filename, sample_rate, num_channels)); } @@ -165,10 +172,10 @@ return reinterpret_cast<const webrtc::WavWriter*>(wf)->sample_rate(); } -int rtc_WavNumChannels(const rtc_WavWriter* wf) { +size_t rtc_WavNumChannels(const rtc_WavWriter* wf) { return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_channels(); } -uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf) { +size_t rtc_WavNumSamples(const rtc_WavWriter* wf) { return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_samples(); }
diff --git a/webrtc/common_audio/wav_file.h b/webrtc/common_audio/wav_file.h index 2eadd3f..e656eb8 100644 --- a/webrtc/common_audio/wav_file.h +++ b/webrtc/common_audio/wav_file.h
@@ -27,8 +27,11 @@ virtual ~WavFile() {} virtual int sample_rate() const = 0; - virtual int num_channels() const = 0; - virtual uint32_t num_samples() const = 0; + virtual size_t num_channels() const = 0; + virtual size_t num_samples() const = 0; + + // Returns a human-readable string containing the audio format. + std::string FormatAsString() const; }; // Simple C++ class for writing 16-bit PCM WAV files. All error handling is @@ -36,7 +39,7 @@ class WavWriter final : public WavFile { public: // Open a new WAV file for writing. - WavWriter(const std::string& filename, int sample_rate, int num_channels); + WavWriter(const std::string& filename, int sample_rate, size_t num_channels); // Close the WAV file, after writing its header. ~WavWriter(); @@ -48,14 +51,14 @@ void WriteSamples(const int16_t* samples, size_t num_samples); int sample_rate() const override { return sample_rate_; } - int num_channels() const override { return num_channels_; } - uint32_t num_samples() const override { return num_samples_; } + size_t num_channels() const override { return num_channels_; } + size_t num_samples() const override { return num_samples_; } private: void Close(); const int sample_rate_; - const int num_channels_; - uint32_t num_samples_; // Total number of samples written to file. + const size_t num_channels_; + size_t num_samples_; // Total number of samples written to file. FILE* file_handle_; // Output file, owned by this class RTC_DISALLOW_COPY_AND_ASSIGN(WavWriter); @@ -76,15 +79,15 @@ size_t ReadSamples(size_t num_samples, int16_t* samples); int sample_rate() const override { return sample_rate_; } - int num_channels() const override { return num_channels_; } - uint32_t num_samples() const override { return num_samples_; } + size_t num_channels() const override { return num_channels_; } + size_t num_samples() const override { return num_samples_; } private: void Close(); int sample_rate_; - int num_channels_; - uint32_t num_samples_; // Total number of samples in the file. - uint32_t num_samples_remaining_; + size_t num_channels_; + size_t num_samples_; // Total number of samples in the file. + size_t num_samples_remaining_; FILE* file_handle_; // Input file, owned by this class. RTC_DISALLOW_COPY_AND_ASSIGN(WavReader); @@ -99,14 +102,14 @@ typedef struct rtc_WavWriter rtc_WavWriter; rtc_WavWriter* rtc_WavOpen(const char* filename, int sample_rate, - int num_channels); + size_t num_channels); void rtc_WavClose(rtc_WavWriter* wf); void rtc_WavWriteSamples(rtc_WavWriter* wf, const float* samples, size_t num_samples); int rtc_WavSampleRate(const rtc_WavWriter* wf); -int rtc_WavNumChannels(const rtc_WavWriter* wf); -uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf); +size_t rtc_WavNumChannels(const rtc_WavWriter* wf); +size_t rtc_WavNumSamples(const rtc_WavWriter* wf); #ifdef __cplusplus } // extern "C"
diff --git a/webrtc/common_audio/wav_file_unittest.cc b/webrtc/common_audio/wav_file_unittest.cc index 78b0a34..ba1db1c 100644 --- a/webrtc/common_audio/wav_file_unittest.cc +++ b/webrtc/common_audio/wav_file_unittest.cc
@@ -26,11 +26,11 @@ // Write a tiny WAV file with the C++ interface and verify the result. TEST(WavWriterTest, CPP) { const std::string outfile = test::OutputPath() + "wavtest1.wav"; - static const uint32_t kNumSamples = 3; + static const size_t kNumSamples = 3; { WavWriter w(outfile, 14099, 1); EXPECT_EQ(14099, w.sample_rate()); - EXPECT_EQ(1, w.num_channels()); + EXPECT_EQ(1u, w.num_channels()); EXPECT_EQ(0u, w.num_samples()); w.WriteSamples(kSamples, kNumSamples); EXPECT_EQ(kNumSamples, w.num_samples()); @@ -64,10 +64,10 @@ 0xff, 0x7f, // third sample: 4e4 (saturated) kMetadata[0], kMetadata[1], }; - static const int kContentSize = + static const size_t kContentSize = kWavHeaderSize + kNumSamples * sizeof(int16_t) + sizeof(kMetadata); static_assert(sizeof(kExpectedContents) == kContentSize, "content size"); - EXPECT_EQ(size_t(kContentSize), test::GetFileSize(outfile)); + EXPECT_EQ(kContentSize, test::GetFileSize(outfile)); FILE* f = fopen(outfile.c_str(), "rb"); ASSERT_TRUE(f); uint8_t contents[kContentSize]; @@ -78,7 +78,7 @@ { WavReader r(outfile); EXPECT_EQ(14099, r.sample_rate()); - EXPECT_EQ(1, r.num_channels()); + EXPECT_EQ(1u, r.num_channels()); EXPECT_EQ(kNumSamples, r.num_samples()); static const float kTruncatedSamples[] = {0.0, 10.0, 32767.0}; float samples[kNumSamples]; @@ -93,9 +93,9 @@ const std::string outfile = test::OutputPath() + "wavtest2.wav"; rtc_WavWriter* w = rtc_WavOpen(outfile.c_str(), 11904, 2); EXPECT_EQ(11904, rtc_WavSampleRate(w)); - EXPECT_EQ(2, rtc_WavNumChannels(w)); + EXPECT_EQ(2u, rtc_WavNumChannels(w)); EXPECT_EQ(0u, rtc_WavNumSamples(w)); - static const uint32_t kNumSamples = 4; + static const size_t kNumSamples = 4; rtc_WavWriteSamples(w, &kSamples[0], 2); EXPECT_EQ(2u, rtc_WavNumSamples(w)); rtc_WavWriteSamples(w, &kSamples[2], kNumSamples - 2); @@ -120,10 +120,10 @@ 0xff, 0x7f, // third sample: 4e4 (saturated) 0, 0x80, // fourth sample: -1e9 (saturated) }; - static const int kContentSize = + static const size_t kContentSize = kWavHeaderSize + kNumSamples * sizeof(int16_t); static_assert(sizeof(kExpectedContents) == kContentSize, "content size"); - EXPECT_EQ(size_t(kContentSize), test::GetFileSize(outfile)); + EXPECT_EQ(kContentSize, test::GetFileSize(outfile)); FILE* f = fopen(outfile.c_str(), "rb"); ASSERT_TRUE(f); uint8_t contents[kContentSize]; @@ -136,10 +136,10 @@ TEST(WavWriterTest, LargeFile) { std::string outfile = test::OutputPath() + "wavtest3.wav"; static const int kSampleRate = 8000; - static const int kNumChannels = 2; - static const uint32_t kNumSamples = 3 * kSampleRate * kNumChannels; + static const size_t kNumChannels = 2; + static const size_t kNumSamples = 3 * kSampleRate * kNumChannels; float samples[kNumSamples]; - for (uint32_t i = 0; i < kNumSamples; i += kNumChannels) { + for (size_t i = 0; i < kNumSamples; i += kNumChannels) { // A nice periodic beeping sound. static const double kToneHz = 440; const double t = static_cast<double>(i) / (kNumChannels * kSampleRate);
diff --git a/webrtc/common_audio/wav_header.cc b/webrtc/common_audio/wav_header.cc index 61cfffe..402ea17 100644 --- a/webrtc/common_audio/wav_header.cc +++ b/webrtc/common_audio/wav_header.cc
@@ -59,20 +59,19 @@ } // namespace -bool CheckWavParameters(int num_channels, +bool CheckWavParameters(size_t num_channels, int sample_rate, WavFormat format, - int bytes_per_sample, - uint32_t num_samples) { + size_t bytes_per_sample, + size_t num_samples) { // num_channels, sample_rate, and bytes_per_sample must be positive, must fit // in their respective fields, and their product must fit in the 32-bit // ByteRate field. - if (num_channels <= 0 || sample_rate <= 0 || bytes_per_sample <= 0) + if (num_channels == 0 || sample_rate <= 0 || bytes_per_sample == 0) return false; if (static_cast<uint64_t>(sample_rate) > std::numeric_limits<uint32_t>::max()) return false; - if (static_cast<uint64_t>(num_channels) > - std::numeric_limits<uint16_t>::max()) + if (num_channels > std::numeric_limits<uint16_t>::max()) return false; if (static_cast<uint64_t>(bytes_per_sample) * 8 > std::numeric_limits<uint16_t>::max()) @@ -99,10 +98,9 @@ // The number of bytes in the file, not counting the first ChunkHeader, must // be less than 2^32; otherwise, the ChunkSize field overflows. - const uint32_t max_samples = - (std::numeric_limits<uint32_t>::max() - - (kWavHeaderSize - sizeof(ChunkHeader))) / - bytes_per_sample; + const size_t header_size = kWavHeaderSize - sizeof(ChunkHeader); + const size_t max_samples = + (std::numeric_limits<uint32_t>::max() - header_size) / bytes_per_sample; if (num_samples > max_samples) return false; @@ -132,30 +130,32 @@ #error "Write be-to-le conversion functions" #endif -static inline uint32_t RiffChunkSize(uint32_t bytes_in_payload) { - return bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader); +static inline uint32_t RiffChunkSize(size_t bytes_in_payload) { + return static_cast<uint32_t>( + bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader)); } -static inline uint32_t ByteRate(int num_channels, int sample_rate, - int bytes_per_sample) { - return static_cast<uint32_t>(num_channels) * sample_rate * bytes_per_sample; +static inline uint32_t ByteRate(size_t num_channels, int sample_rate, + size_t bytes_per_sample) { + return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample); } -static inline uint16_t BlockAlign(int num_channels, int bytes_per_sample) { - return num_channels * bytes_per_sample; +static inline uint16_t BlockAlign(size_t num_channels, + size_t bytes_per_sample) { + return static_cast<uint16_t>(num_channels * bytes_per_sample); } void WriteWavHeader(uint8_t* buf, - int num_channels, + size_t num_channels, int sample_rate, WavFormat format, - int bytes_per_sample, - uint32_t num_samples) { + size_t bytes_per_sample, + size_t num_samples) { RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format, bytes_per_sample, num_samples)); WavHeader header; - const uint32_t bytes_in_payload = bytes_per_sample * num_samples; + const size_t bytes_in_payload = bytes_per_sample * num_samples; WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F'); WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload)); @@ -164,15 +164,16 @@ WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' '); WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize); WriteLE16(&header.fmt.AudioFormat, format); - WriteLE16(&header.fmt.NumChannels, num_channels); + WriteLE16(&header.fmt.NumChannels, static_cast<uint16_t>(num_channels)); WriteLE32(&header.fmt.SampleRate, sample_rate); WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate, bytes_per_sample)); WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample)); - WriteLE16(&header.fmt.BitsPerSample, 8 * bytes_per_sample); + WriteLE16(&header.fmt.BitsPerSample, + static_cast<uint16_t>(8 * bytes_per_sample)); WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a'); - WriteLE32(&header.data.header.Size, bytes_in_payload); + WriteLE32(&header.data.header.Size, static_cast<uint32_t>(bytes_in_payload)); // Do an extra copy rather than writing everything to buf directly, since buf // might not be correctly aligned. @@ -180,11 +181,11 @@ } bool ReadWavHeader(ReadableWav* readable, - int* num_channels, + size_t* num_channels, int* sample_rate, WavFormat* format, - int* bytes_per_sample, - uint32_t* num_samples) { + size_t* bytes_per_sample, + size_t* num_samples) { WavHeader header; if (readable->Read(&header, kWavHeaderSize - sizeof(header.data)) != kWavHeaderSize - sizeof(header.data)) @@ -210,8 +211,8 @@ *num_channels = ReadLE16(header.fmt.NumChannels); *sample_rate = ReadLE32(header.fmt.SampleRate); *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8; - const uint32_t bytes_in_payload = ReadLE32(header.data.header.Size); - if (*bytes_per_sample <= 0) + const size_t bytes_in_payload = ReadLE32(header.data.header.Size); + if (*bytes_per_sample == 0) return false; *num_samples = bytes_in_payload / *bytes_per_sample;
diff --git a/webrtc/common_audio/wav_header.h b/webrtc/common_audio/wav_header.h index 1a0fd7c..6844306 100644 --- a/webrtc/common_audio/wav_header.h +++ b/webrtc/common_audio/wav_header.h
@@ -32,32 +32,32 @@ }; // Return true if the given parameters will make a well-formed WAV header. -bool CheckWavParameters(int num_channels, +bool CheckWavParameters(size_t num_channels, int sample_rate, WavFormat format, - int bytes_per_sample, - uint32_t num_samples); + size_t bytes_per_sample, + size_t num_samples); // Write a kWavHeaderSize bytes long WAV header to buf. The payload that // follows the header is supposed to have the specified number of interleaved // channels and contain the specified total number of samples of the specified // type. CHECKs the input parameters for validity. void WriteWavHeader(uint8_t* buf, - int num_channels, + size_t num_channels, int sample_rate, WavFormat format, - int bytes_per_sample, - uint32_t num_samples); + size_t bytes_per_sample, + size_t num_samples); // Read a WAV header from an implemented ReadableWav and parse the values into // the provided output parameters. ReadableWav is used because the header can // be variably sized. Returns false if the header is invalid. bool ReadWavHeader(ReadableWav* readable, - int* num_channels, + size_t* num_channels, int* sample_rate, WavFormat* format, - int* bytes_per_sample, - uint32_t* num_samples); + size_t* bytes_per_sample, + size_t* num_samples); } // namespace webrtc
diff --git a/webrtc/common_audio/wav_header_unittest.cc b/webrtc/common_audio/wav_header_unittest.cc index e03cb30..8527939 100644 --- a/webrtc/common_audio/wav_header_unittest.cc +++ b/webrtc/common_audio/wav_header_unittest.cc
@@ -70,7 +70,7 @@ // Try some really stupid values for one parameter at a time. EXPECT_TRUE(CheckWavParameters(1, 8000, kWavFormatPcm, 1, 0)); EXPECT_FALSE(CheckWavParameters(0, 8000, kWavFormatPcm, 1, 0)); - EXPECT_FALSE(CheckWavParameters(-1, 8000, kWavFormatPcm, 1, 0)); + EXPECT_FALSE(CheckWavParameters(0x10000, 8000, kWavFormatPcm, 1, 0)); EXPECT_FALSE(CheckWavParameters(1, 0, kWavFormatPcm, 1, 0)); EXPECT_FALSE(CheckWavParameters(1, 8000, WavFormat(0), 1, 0)); EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 0, 0)); @@ -91,11 +91,11 @@ } TEST(WavHeaderTest, ReadWavHeaderWithErrors) { - int num_channels = 0; + size_t num_channels = 0; int sample_rate = 0; WavFormat format = kWavFormatPcm; - int bytes_per_sample = 0; - uint32_t num_samples = 0; + size_t bytes_per_sample = 0; + size_t num_samples = 0; // Test a few ways the header can be invalid. We start with the valid header // used in WriteAndReadWavHeader, and invalidate one field per test. The @@ -268,19 +268,19 @@ static_assert(sizeof(kExpectedBuf) == kSize, "buffer size"); EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize)); - int num_channels = 0; + size_t num_channels = 0; int sample_rate = 0; WavFormat format = kWavFormatPcm; - int bytes_per_sample = 0; - uint32_t num_samples = 0; + size_t bytes_per_sample = 0; + size_t num_samples = 0; ReadableWavBuffer r(buf + 4, sizeof(buf) - 8); EXPECT_TRUE( ReadWavHeader(&r, &num_channels, &sample_rate, &format, &bytes_per_sample, &num_samples)); - EXPECT_EQ(17, num_channels); + EXPECT_EQ(17u, num_channels); EXPECT_EQ(12345, sample_rate); EXPECT_EQ(kWavFormatALaw, format); - EXPECT_EQ(1, bytes_per_sample); + EXPECT_EQ(1u, bytes_per_sample); EXPECT_EQ(123457689u, num_samples); } @@ -304,19 +304,19 @@ 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 }; - int num_channels = 0; + size_t num_channels = 0; int sample_rate = 0; WavFormat format = kWavFormatPcm; - int bytes_per_sample = 0; - uint32_t num_samples = 0; + size_t bytes_per_sample = 0; + size_t num_samples = 0; ReadableWavBuffer r(kBuf, sizeof(kBuf)); EXPECT_TRUE( ReadWavHeader(&r, &num_channels, &sample_rate, &format, &bytes_per_sample, &num_samples)); - EXPECT_EQ(17, num_channels); + EXPECT_EQ(17u, num_channels); EXPECT_EQ(12345, sample_rate); EXPECT_EQ(kWavFormatALaw, format); - EXPECT_EQ(1, bytes_per_sample); + EXPECT_EQ(1u, bytes_per_sample); EXPECT_EQ(123457689u, num_samples); }
diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 07faf6a..444ef92 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h
@@ -291,7 +291,7 @@ char plname[RTP_PAYLOAD_NAME_SIZE]; int plfreq; int pacsize; - int channels; + size_t channels; int rate; // bits/sec unlike {start,min,max}Bitrate elsewhere in this file! bool operator==(const CodecInst& other) const { @@ -311,12 +311,6 @@ // RTP enum {kRtpCsrcSize = 15}; // RFC 3550 page 13 -enum RTPDirections -{ - kRtpIncoming = 0, - kRtpOutgoing -}; - enum PayloadFrequencies { kFreq8000Hz = 8000, @@ -547,6 +541,7 @@ enum { kConfigParameterSize = 128}; enum { kPayloadNameSize = 32}; enum { kMaxSimulcastStreams = 4}; +enum { kMaxSpatialLayers = 5 }; enum { kMaxTemporalStreams = 4}; enum VideoCodecComplexity @@ -676,6 +671,13 @@ } }; +struct SpatialLayer { + int scaling_factor_num; + int scaling_factor_den; + int target_bitrate_bps; + // TODO(ivica): Add max_quantizer and min_quantizer? +}; + enum VideoCodecMode { kRealtimeVideo, kScreensharing @@ -702,6 +704,7 @@ unsigned int qpMax; unsigned char numberOfSimulcastStreams; SimulcastStream simulcastStream[kMaxSimulcastStreams]; + SpatialLayer spatialLayers[kMaxSpatialLayers]; VideoCodecMode mode;
diff --git a/webrtc/common_video/BUILD.gn b/webrtc/common_video/BUILD.gn index 473c757..4ef968d 100644 --- a/webrtc/common_video/BUILD.gn +++ b/webrtc/common_video/BUILD.gn
@@ -10,7 +10,7 @@ config("common_video_config") { include_dirs = [ - "interface", + "include", "libyuv/include", ] } @@ -18,10 +18,10 @@ source_set("common_video") { sources = [ "i420_buffer_pool.cc", + "include/i420_buffer_pool.h", + "include/incoming_video_stream.h", + "include/video_frame_buffer.h", "incoming_video_stream.cc", - "interface/i420_buffer_pool.h", - "interface/incoming_video_stream.h", - "interface/video_frame_buffer.h", "libyuv/include/scaler.h", "libyuv/include/webrtc_libyuv.h", "libyuv/scaler.cc",
diff --git a/webrtc/common_video/common_video.gyp b/webrtc/common_video/common_video.gyp index 5c0ecb8..fe14da1 100644 --- a/webrtc/common_video/common_video.gyp +++ b/webrtc/common_video/common_video.gyp
@@ -14,7 +14,7 @@ 'type': 'static_library', 'include_dirs': [ '<(webrtc_root)/modules/interface/', - 'interface', + 'include', 'libyuv/include', ], 'dependencies': [ @@ -23,7 +23,7 @@ ], 'direct_dependent_settings': { 'include_dirs': [ - 'interface', + 'include', 'libyuv/include', ], }, @@ -42,9 +42,9 @@ 'i420_buffer_pool.cc', 'video_frame.cc', 'incoming_video_stream.cc', - 'interface/i420_buffer_pool.h', - 'interface/incoming_video_stream.h', - 'interface/video_frame_buffer.h', + 'include/i420_buffer_pool.h', + 'include/incoming_video_stream.h', + 'include/video_frame_buffer.h', 'libyuv/include/scaler.h', 'libyuv/include/webrtc_libyuv.h', 'libyuv/scaler.cc',
diff --git a/webrtc/common_video/common_video_unittests.gyp b/webrtc/common_video/common_video_unittests.gyp index beeab5d..b5e892c 100644 --- a/webrtc/common_video/common_video_unittests.gyp +++ b/webrtc/common_video/common_video_unittests.gyp
@@ -17,6 +17,7 @@ '<(DEPTH)/testing/gtest.gyp:gtest', '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers', '<(webrtc_root)/test/test.gyp:test_support_main', + '<(webrtc_root)/test/test.gyp:fake_video_frames', ], 'sources': [ 'i420_buffer_pool_unittest.cc',
diff --git a/webrtc/common_video/i420_buffer_pool.cc b/webrtc/common_video/i420_buffer_pool.cc index c746666..98daec9 100644 --- a/webrtc/common_video/i420_buffer_pool.cc +++ b/webrtc/common_video/i420_buffer_pool.cc
@@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/common_video/interface/i420_buffer_pool.h" +#include "webrtc/common_video/include/i420_buffer_pool.h" #include "webrtc/base/checks.h"
diff --git a/webrtc/common_video/i420_buffer_pool_unittest.cc b/webrtc/common_video/i420_buffer_pool_unittest.cc index a1596eb..b030ee7 100644 --- a/webrtc/common_video/i420_buffer_pool_unittest.cc +++ b/webrtc/common_video/i420_buffer_pool_unittest.cc
@@ -11,7 +11,7 @@ #include <string> #include "testing/gtest/include/gtest/gtest.h" -#include "webrtc/common_video/interface/i420_buffer_pool.h" +#include "webrtc/common_video/include/i420_buffer_pool.h" namespace webrtc {
diff --git a/webrtc/common_video/i420_video_frame_unittest.cc b/webrtc/common_video/i420_video_frame_unittest.cc index da3996b..1ec451c 100644 --- a/webrtc/common_video/i420_video_frame_unittest.cc +++ b/webrtc/common_video/i420_video_frame_unittest.cc
@@ -8,8 +8,6 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/video_frame.h" - #include <math.h> #include <string.h> @@ -17,6 +15,7 @@ #include "webrtc/base/bind.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/test/fake_texture_frame.h" +#include "webrtc/video_frame.h" namespace webrtc { @@ -25,7 +24,6 @@ int stride, int width, int height); -bool EqualFrames(const VideoFrame& frame1, const VideoFrame& frame2); int ExpectedSize(int plane_stride, int image_height, PlaneType type); TEST(TestVideoFrame, InitialValues) { @@ -103,7 +101,7 @@ stride_u, stride_v, kRotation)); // Frame of smaller dimensions. EXPECT_EQ(0, small_frame.CopyFrame(big_frame)); - EXPECT_TRUE(EqualFrames(small_frame, big_frame)); + EXPECT_TRUE(small_frame.EqualsFrame(big_frame)); EXPECT_EQ(kRotation, small_frame.rotation()); // Frame of larger dimensions. @@ -113,7 +111,7 @@ memset(small_frame.buffer(kUPlane), 2, small_frame.allocated_size(kUPlane)); memset(small_frame.buffer(kVPlane), 3, small_frame.allocated_size(kVPlane)); EXPECT_EQ(0, big_frame.CopyFrame(small_frame)); - EXPECT_TRUE(EqualFrames(small_frame, big_frame)); + EXPECT_TRUE(small_frame.EqualsFrame(big_frame)); } TEST(TestVideoFrame, ShallowCopy) { @@ -174,7 +172,7 @@ TEST(TestVideoFrame, Reset) { VideoFrame frame; - ASSERT_TRUE(frame.CreateEmptyFrame(5, 5, 5, 5, 5) == 0); + ASSERT_EQ(frame.CreateEmptyFrame(5, 5, 5, 5, 5), 0); frame.set_ntp_time_ms(1); frame.set_timestamp(2); frame.set_render_time_ms(3); @@ -244,7 +242,7 @@ TEST(TestVideoFrame, TextureInitialValues) { test::FakeNativeHandle* handle = new test::FakeNativeHandle(); - VideoFrame frame = test::CreateFakeNativeHandleFrame( + VideoFrame frame = test::FakeNativeHandle::CreateFrame( handle, 640, 480, 100, 10, webrtc::kVideoRotation_0); EXPECT_EQ(640, frame.width()); EXPECT_EQ(480, frame.height()); @@ -258,48 +256,4 @@ EXPECT_EQ(20, frame.render_time_ms()); } -bool EqualPlane(const uint8_t* data1, - const uint8_t* data2, - int stride, - int width, - int height) { - for (int y = 0; y < height; ++y) { - if (memcmp(data1, data2, width) != 0) - return false; - data1 += stride; - data2 += stride; - } - return true; -} - -bool EqualFrames(const VideoFrame& frame1, const VideoFrame& frame2) { - if ((frame1.width() != frame2.width()) || - (frame1.height() != frame2.height()) || - (frame1.stride(kYPlane) != frame2.stride(kYPlane)) || - (frame1.stride(kUPlane) != frame2.stride(kUPlane)) || - (frame1.stride(kVPlane) != frame2.stride(kVPlane)) || - (frame1.timestamp() != frame2.timestamp()) || - (frame1.ntp_time_ms() != frame2.ntp_time_ms()) || - (frame1.render_time_ms() != frame2.render_time_ms())) { - return false; - } - const int half_width = (frame1.width() + 1) / 2; - const int half_height = (frame1.height() + 1) / 2; - return EqualPlane(frame1.buffer(kYPlane), frame2.buffer(kYPlane), - frame1.stride(kYPlane), frame1.width(), frame1.height()) && - EqualPlane(frame1.buffer(kUPlane), frame2.buffer(kUPlane), - frame1.stride(kUPlane), half_width, half_height) && - EqualPlane(frame1.buffer(kVPlane), frame2.buffer(kVPlane), - frame1.stride(kVPlane), half_width, half_height); -} - -int ExpectedSize(int plane_stride, int image_height, PlaneType type) { - if (type == kYPlane) { - return (plane_stride * image_height); - } else { - int half_height = (image_height + 1) / 2; - return (plane_stride * half_height); - } -} - } // namespace webrtc
diff --git a/webrtc/common_video/include/i420_buffer_pool.h b/webrtc/common_video/include/i420_buffer_pool.h new file mode 100644 index 0000000..5ab1510 --- /dev/null +++ b/webrtc/common_video/include/i420_buffer_pool.h
@@ -0,0 +1,43 @@ +/* + * 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_COMMON_VIDEO_INCLUDE_I420_BUFFER_POOL_H_ +#define WEBRTC_COMMON_VIDEO_INCLUDE_I420_BUFFER_POOL_H_ + +#include <list> + +#include "webrtc/base/thread_checker.h" +#include "webrtc/common_video/include/video_frame_buffer.h" + +namespace webrtc { + +// Simple buffer pool to avoid unnecessary allocations of I420Buffer objects. +// The pool manages the memory of the I420Buffer returned from CreateBuffer. +// When the I420Buffer is destructed, the memory is returned to the pool for use +// by subsequent calls to CreateBuffer. If the resolution passed to CreateBuffer +// changes, old buffers will be purged from the pool. +class I420BufferPool { + public: + I420BufferPool(); + // Returns a buffer from the pool, or creates a new buffer if no suitable + // buffer exists in the pool. + rtc::scoped_refptr<VideoFrameBuffer> CreateBuffer(int width, int height); + // Clears buffers_ and detaches the thread checker so that it can be reused + // later from another thread. + void Release(); + + private: + rtc::ThreadChecker thread_checker_; + std::list<rtc::scoped_refptr<I420Buffer>> buffers_; +}; + +} // namespace webrtc + +#endif // WEBRTC_COMMON_VIDEO_INCLUDE_I420_BUFFER_POOL_H_
diff --git a/webrtc/common_video/include/incoming_video_stream.h b/webrtc/common_video/include/incoming_video_stream.h new file mode 100644 index 0000000..e3147eb --- /dev/null +++ b/webrtc/common_video/include/incoming_video_stream.h
@@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_COMMON_VIDEO_INCLUDE_INCOMING_VIDEO_STREAM_H_ +#define WEBRTC_COMMON_VIDEO_INCLUDE_INCOMING_VIDEO_STREAM_H_ + +#include "webrtc/base/platform_thread.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/thread_annotations.h" +#include "webrtc/common_video/video_render_frames.h" + +namespace webrtc { +class CriticalSectionWrapper; +class EventTimerWrapper; + +class VideoRenderCallback { + public: + virtual int32_t RenderFrame(const uint32_t streamId, + const VideoFrame& videoFrame) = 0; + + protected: + virtual ~VideoRenderCallback() {} +}; + +class IncomingVideoStream : public VideoRenderCallback { + public: + IncomingVideoStream(uint32_t stream_id, bool disable_prerenderer_smoothing); + ~IncomingVideoStream(); + + // Get callback to deliver frames to the module. + VideoRenderCallback* ModuleCallback(); + virtual int32_t RenderFrame(const uint32_t stream_id, + const VideoFrame& video_frame); + + // Set callback to the platform dependent code. + void SetRenderCallback(VideoRenderCallback* render_callback); + + // Callback for file recording, snapshot, ... + void SetExternalCallback(VideoRenderCallback* render_object); + + // Start/Stop. + int32_t Start(); + int32_t Stop(); + + // Clear all buffers. + int32_t Reset(); + + // Properties. + uint32_t StreamId() const; + uint32_t IncomingRate() const; + + int32_t SetStartImage(const VideoFrame& video_frame); + + int32_t SetTimeoutImage(const VideoFrame& video_frame, + const uint32_t timeout); + + int32_t SetExpectedRenderDelay(int32_t delay_ms); + + protected: + static bool IncomingVideoStreamThreadFun(void* obj); + bool IncomingVideoStreamProcess(); + + private: + enum { kEventStartupTimeMs = 10 }; + enum { kEventMaxWaitTimeMs = 100 }; + enum { kFrameRatePeriodMs = 1000 }; + + void DeliverFrame(const VideoFrame& video_frame); + + uint32_t const stream_id_; + const bool disable_prerenderer_smoothing_; + // Critsects in allowed to enter order. + const rtc::scoped_ptr<CriticalSectionWrapper> stream_critsect_; + const rtc::scoped_ptr<CriticalSectionWrapper> thread_critsect_; + const rtc::scoped_ptr<CriticalSectionWrapper> buffer_critsect_; + // TODO(pbos): Make plain member and stop resetting this thread, just + // start/stoping it is enough. + rtc::scoped_ptr<rtc::PlatformThread> incoming_render_thread_ + GUARDED_BY(thread_critsect_); + rtc::scoped_ptr<EventTimerWrapper> deliver_buffer_event_; + + bool running_ GUARDED_BY(stream_critsect_); + VideoRenderCallback* external_callback_ GUARDED_BY(thread_critsect_); + VideoRenderCallback* render_callback_ GUARDED_BY(thread_critsect_); + const rtc::scoped_ptr<VideoRenderFrames> render_buffers_ + GUARDED_BY(buffer_critsect_); + + uint32_t incoming_rate_ GUARDED_BY(stream_critsect_); + int64_t last_rate_calculation_time_ms_ GUARDED_BY(stream_critsect_); + uint16_t num_frames_since_last_calculation_ GUARDED_BY(stream_critsect_); + int64_t last_render_time_ms_ GUARDED_BY(thread_critsect_); + VideoFrame temp_frame_ GUARDED_BY(thread_critsect_); + VideoFrame start_image_ GUARDED_BY(thread_critsect_); + VideoFrame timeout_image_ GUARDED_BY(thread_critsect_); + uint32_t timeout_time_ GUARDED_BY(thread_critsect_); +}; + +} // namespace webrtc + +#endif // WEBRTC_COMMON_VIDEO_INCLUDE_INCOMING_VIDEO_STREAM_H_
diff --git a/webrtc/common_video/include/video_frame_buffer.h b/webrtc/common_video/include/video_frame_buffer.h new file mode 100644 index 0000000..710d286 --- /dev/null +++ b/webrtc/common_video/include/video_frame_buffer.h
@@ -0,0 +1,157 @@ +/* + * 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_COMMON_VIDEO_INCLUDE_VIDEO_FRAME_BUFFER_H_ +#define WEBRTC_COMMON_VIDEO_INCLUDE_VIDEO_FRAME_BUFFER_H_ + +#include "webrtc/base/callback.h" +#include "webrtc/base/refcount.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/system_wrappers/include/aligned_malloc.h" + +namespace webrtc { + +enum PlaneType { + kYPlane = 0, + kUPlane = 1, + kVPlane = 2, + kNumOfPlanes = 3, +}; + +// Interface of a simple frame buffer containing pixel data. This interface does +// not contain any frame metadata such as rotation, timestamp, pixel_width, etc. +class VideoFrameBuffer : public rtc::RefCountInterface { + public: + // Returns true if this buffer has a single exclusive owner. + virtual bool HasOneRef() const = 0; + + // The resolution of the frame in pixels. For formats where some planes are + // subsampled, this is the highest-resolution plane. + virtual int width() const = 0; + virtual int height() const = 0; + + // Returns pointer to the pixel data for a given plane. The memory is owned by + // the VideoFrameBuffer object and must not be freed by the caller. + virtual const uint8_t* data(PlaneType type) const = 0; + + // Non-const data access is disallowed by default. You need to make sure you + // have exclusive access and a writable buffer before calling this function. + virtual uint8_t* MutableData(PlaneType type); + + // Returns the number of bytes between successive rows for a given plane. + virtual int stride(PlaneType type) const = 0; + + // Return the handle of the underlying video frame. This is used when the + // frame is backed by a texture. + virtual void* native_handle() const = 0; + + // Returns a new memory-backed frame buffer converted from this buffer's + // native handle. + virtual rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() = 0; + + protected: + virtual ~VideoFrameBuffer(); +}; + +// Plain I420 buffer in standard memory. +class I420Buffer : public VideoFrameBuffer { + public: + I420Buffer(int width, int height); + I420Buffer(int width, int height, int stride_y, int stride_u, int stride_v); + + int width() const override; + int height() const override; + const uint8_t* data(PlaneType type) const override; + // Non-const data access is only allowed if HasOneRef() is true to protect + // against unexpected overwrites. + uint8_t* MutableData(PlaneType type) override; + int stride(PlaneType type) const override; + void* native_handle() const override; + rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() override; + + protected: + ~I420Buffer() override; + + private: + const int width_; + const int height_; + const int stride_y_; + const int stride_u_; + const int stride_v_; + const rtc::scoped_ptr<uint8_t, AlignedFreeDeleter> data_; +}; + +// Base class for native-handle buffer is a wrapper around a |native_handle|. +// This is used for convenience as most native-handle implementations can share +// many VideoFrame implementations, but need to implement a few others (such +// as their own destructors or conversion methods back to software I420). +class NativeHandleBuffer : public VideoFrameBuffer { + public: + NativeHandleBuffer(void* native_handle, int width, int height); + + int width() const override; + int height() const override; + const uint8_t* data(PlaneType type) const override; + int stride(PlaneType type) const override; + void* native_handle() const override; + + protected: + void* native_handle_; + const int width_; + const int height_; +}; + +class WrappedI420Buffer : public webrtc::VideoFrameBuffer { + public: + WrappedI420Buffer(int width, + int height, + const uint8_t* y_plane, + int y_stride, + const uint8_t* u_plane, + int u_stride, + const uint8_t* v_plane, + int v_stride, + const rtc::Callback0<void>& no_longer_used); + int width() const override; + int height() const override; + + const uint8_t* data(PlaneType type) const override; + + int stride(PlaneType type) const override; + void* native_handle() const override; + + rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() override; + + private: + friend class rtc::RefCountedObject<WrappedI420Buffer>; + ~WrappedI420Buffer() override; + + const int width_; + const int height_; + const uint8_t* const y_plane_; + const uint8_t* const u_plane_; + const uint8_t* const v_plane_; + const int y_stride_; + const int u_stride_; + const int v_stride_; + rtc::Callback0<void> no_longer_used_cb_; +}; + +// Helper function to crop |buffer| without making a deep copy. May only be used +// for non-native frames. +rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop( + const rtc::scoped_refptr<VideoFrameBuffer>& buffer, + int cropped_width, + int cropped_height); + +} // namespace webrtc + +#endif // WEBRTC_COMMON_VIDEO_INCLUDE_VIDEO_FRAME_BUFFER_H_
diff --git a/webrtc/common_video/include/video_image.h b/webrtc/common_video/include/video_image.h new file mode 100644 index 0000000..4a6e451 --- /dev/null +++ b/webrtc/common_video/include/video_image.h
@@ -0,0 +1,17 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_COMMON_VIDEO_INCLUDE_VIDEO_IMAGE_H_ +#define WEBRTC_COMMON_VIDEO_INCLUDE_VIDEO_IMAGE_H_ + +// TODO(pbos): Remove this file and include webrtc/video_frame.h instead. +#include "webrtc/video_frame.h" + +#endif // WEBRTC_COMMON_VIDEO_INCLUDE_VIDEO_IMAGE_H_
diff --git a/webrtc/common_video/incoming_video_stream.cc b/webrtc/common_video/incoming_video_stream.cc index 79bbb8a..1272ecc 100644 --- a/webrtc/common_video/incoming_video_stream.cc +++ b/webrtc/common_video/incoming_video_stream.cc
@@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/common_video/interface/incoming_video_stream.h" +#include "webrtc/common_video/include/incoming_video_stream.h" #include <assert.h> @@ -21,18 +21,21 @@ #include <sys/time.h> #endif +#include "webrtc/base/platform_thread.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/common_video/video_render_frames.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" #include "webrtc/system_wrappers/include/event_wrapper.h" -#include "webrtc/system_wrappers/include/thread_wrapper.h" #include "webrtc/system_wrappers/include/tick_util.h" #include "webrtc/system_wrappers/include/trace.h" +#include "webrtc/video_renderer.h" namespace webrtc { -IncomingVideoStream::IncomingVideoStream(uint32_t stream_id) +IncomingVideoStream::IncomingVideoStream(uint32_t stream_id, + bool disable_prerenderer_smoothing) : stream_id_(stream_id), + disable_prerenderer_smoothing_(disable_prerenderer_smoothing), stream_critsect_(CriticalSectionWrapper::CreateCriticalSection()), thread_critsect_(CriticalSectionWrapper::CreateCriticalSection()), buffer_critsect_(CriticalSectionWrapper::CreateCriticalSection()), @@ -49,8 +52,7 @@ temp_frame_(), start_image_(), timeout_image_(), - timeout_time_() { -} + timeout_time_() {} IncomingVideoStream::~IncomingVideoStream() { Stop(); @@ -80,11 +82,15 @@ last_rate_calculation_time_ms_ = now_ms; } - // Insert frame. - CriticalSectionScoped csB(buffer_critsect_.get()); - if (render_buffers_->AddFrame(video_frame) == 1) - deliver_buffer_event_->Set(); - + // Hand over or insert frame. + if (disable_prerenderer_smoothing_) { + DeliverFrame(video_frame); + } else { + CriticalSectionScoped csB(buffer_critsect_.get()); + if (render_buffers_->AddFrame(video_frame) == 1) { + deliver_buffer_event_->Set(); + } + } return 0; } @@ -128,21 +134,20 @@ return 0; } - CriticalSectionScoped csT(thread_critsect_.get()); - assert(incoming_render_thread_ == NULL); + if (!disable_prerenderer_smoothing_) { + CriticalSectionScoped csT(thread_critsect_.get()); + assert(incoming_render_thread_ == NULL); - incoming_render_thread_ = ThreadWrapper::CreateThread( - IncomingVideoStreamThreadFun, this, "IncomingVideoStreamThread"); - if (!incoming_render_thread_) { - return -1; - } + incoming_render_thread_.reset(new rtc::PlatformThread( + IncomingVideoStreamThreadFun, this, "IncomingVideoStreamThread")); + if (!incoming_render_thread_) { + return -1; + } - if (incoming_render_thread_->Start()) { - } else { - return -1; + incoming_render_thread_->Start(); + incoming_render_thread_->SetPriority(rtc::kRealtimePriority); + deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs); } - incoming_render_thread_->SetPriority(kRealtimePriority); - deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs); running_ = true; return 0; @@ -155,7 +160,7 @@ return 0; } - ThreadWrapper* thread = NULL; + rtc::PlatformThread* thread = NULL; { CriticalSectionScoped cs_thread(thread_critsect_.get()); if (incoming_render_thread_) { @@ -169,11 +174,8 @@ } } if (thread) { - if (thread->Stop()) { - delete thread; - } else { - assert(false); - } + thread->Stop(); + delete thread; } running_ = false; return 0; @@ -205,6 +207,7 @@ // Terminating return false; } + // Get a new frame to render and the time for the frame after this one. VideoFrame frame_to_render; uint32_t wait_time; @@ -220,37 +223,41 @@ } deliver_buffer_event_->StartTimer(false, wait_time); - if (frame_to_render.IsZeroSize()) { - if (render_callback_) { - if (last_render_time_ms_ == 0 && !start_image_.IsZeroSize()) { - // We have not rendered anything and have a start image. - temp_frame_.CopyFrame(start_image_); - render_callback_->RenderFrame(stream_id_, temp_frame_); - } else if (!timeout_image_.IsZeroSize() && - last_render_time_ms_ + timeout_time_ < - TickTime::MillisecondTimestamp()) { - // Render a timeout image. - temp_frame_.CopyFrame(timeout_image_); - render_callback_->RenderFrame(stream_id_, temp_frame_); - } - } - - // No frame. - return true; - } - - // Send frame for rendering. - if (external_callback_) { - external_callback_->RenderFrame(stream_id_, frame_to_render); - } else if (render_callback_) { - render_callback_->RenderFrame(stream_id_, frame_to_render); - } - - // We're done with this frame. - if (!frame_to_render.IsZeroSize()) - last_render_time_ms_ = frame_to_render.render_time_ms(); + DeliverFrame(frame_to_render); } return true; } +void IncomingVideoStream::DeliverFrame(const VideoFrame& video_frame) { + CriticalSectionScoped cs(thread_critsect_.get()); + if (video_frame.IsZeroSize()) { + if (render_callback_) { + if (last_render_time_ms_ == 0 && !start_image_.IsZeroSize()) { + // We have not rendered anything and have a start image. + temp_frame_.CopyFrame(start_image_); + render_callback_->RenderFrame(stream_id_, temp_frame_); + } else if (!timeout_image_.IsZeroSize() && + last_render_time_ms_ + timeout_time_ < + TickTime::MillisecondTimestamp()) { + // Render a timeout image. + temp_frame_.CopyFrame(timeout_image_); + render_callback_->RenderFrame(stream_id_, temp_frame_); + } + } + + // No frame. + return; + } + + // Send frame for rendering. + if (external_callback_) { + external_callback_->RenderFrame(stream_id_, video_frame); + } else if (render_callback_) { + render_callback_->RenderFrame(stream_id_, video_frame); + } + + // We're done with this frame. + last_render_time_ms_ = video_frame.render_time_ms(); +} + } // namespace webrtc
diff --git a/webrtc/common_video/interface/i420_buffer_pool.h b/webrtc/common_video/interface/i420_buffer_pool.h deleted file mode 100644 index df862cd..0000000 --- a/webrtc/common_video/interface/i420_buffer_pool.h +++ /dev/null
@@ -1,43 +0,0 @@ -/* - * 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_COMMON_VIDEO_INTERFACE_I420_BUFFER_POOL_H_ -#define WEBRTC_COMMON_VIDEO_INTERFACE_I420_BUFFER_POOL_H_ - -#include <list> - -#include "webrtc/base/thread_checker.h" -#include "webrtc/common_video/interface/video_frame_buffer.h" - -namespace webrtc { - -// Simple buffer pool to avoid unnecessary allocations of I420Buffer objects. -// The pool manages the memory of the I420Buffer returned from CreateBuffer. -// When the I420Buffer is destructed, the memory is returned to the pool for use -// by subsequent calls to CreateBuffer. If the resolution passed to CreateBuffer -// changes, old buffers will be purged from the pool. -class I420BufferPool { - public: - I420BufferPool(); - // Returns a buffer from the pool, or creates a new buffer if no suitable - // buffer exists in the pool. - rtc::scoped_refptr<VideoFrameBuffer> CreateBuffer(int width, int height); - // Clears buffers_ and detaches the thread checker so that it can be reused - // later from another thread. - void Release(); - - private: - rtc::ThreadChecker thread_checker_; - std::list<rtc::scoped_refptr<I420Buffer>> buffers_; -}; - -} // namespace webrtc - -#endif // WEBRTC_COMMON_VIDEO_INTERFACE_I420_BUFFER_POOL_H_
diff --git a/webrtc/common_video/interface/incoming_video_stream.h b/webrtc/common_video/interface/incoming_video_stream.h deleted file mode 100644 index 74ecc4e..0000000 --- a/webrtc/common_video/interface/incoming_video_stream.h +++ /dev/null
@@ -1,102 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_COMMON_VIDEO_INTERFACE_INCOMING_VIDEO_STREAM_H_ -#define WEBRTC_COMMON_VIDEO_INTERFACE_INCOMING_VIDEO_STREAM_H_ - -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/thread_annotations.h" -#include "webrtc/common_video/video_render_frames.h" - -namespace webrtc { -class CriticalSectionWrapper; -class EventTimerWrapper; -class ThreadWrapper; - -class VideoRenderCallback { - public: - virtual int32_t RenderFrame(const uint32_t streamId, - const VideoFrame& videoFrame) = 0; - - protected: - virtual ~VideoRenderCallback() {} -}; - -class IncomingVideoStream : public VideoRenderCallback { - public: - explicit IncomingVideoStream(uint32_t stream_id); - ~IncomingVideoStream(); - - // Get callback to deliver frames to the module. - VideoRenderCallback* ModuleCallback(); - virtual int32_t RenderFrame(const uint32_t stream_id, - const VideoFrame& video_frame); - - // Set callback to the platform dependent code. - void SetRenderCallback(VideoRenderCallback* render_callback); - - // Callback for file recording, snapshot, ... - void SetExternalCallback(VideoRenderCallback* render_object); - - // Start/Stop. - int32_t Start(); - int32_t Stop(); - - // Clear all buffers. - int32_t Reset(); - - // Properties. - uint32_t StreamId() const; - uint32_t IncomingRate() const; - - int32_t SetStartImage(const VideoFrame& video_frame); - - int32_t SetTimeoutImage(const VideoFrame& video_frame, - const uint32_t timeout); - - int32_t SetExpectedRenderDelay(int32_t delay_ms); - - protected: - static bool IncomingVideoStreamThreadFun(void* obj); - bool IncomingVideoStreamProcess(); - - private: - enum { kEventStartupTimeMs = 10 }; - enum { kEventMaxWaitTimeMs = 100 }; - enum { kFrameRatePeriodMs = 1000 }; - - uint32_t const stream_id_; - // Critsects in allowed to enter order. - const rtc::scoped_ptr<CriticalSectionWrapper> stream_critsect_; - const rtc::scoped_ptr<CriticalSectionWrapper> thread_critsect_; - const rtc::scoped_ptr<CriticalSectionWrapper> buffer_critsect_; - rtc::scoped_ptr<ThreadWrapper> incoming_render_thread_ - GUARDED_BY(thread_critsect_); - rtc::scoped_ptr<EventTimerWrapper> deliver_buffer_event_; - - bool running_ GUARDED_BY(stream_critsect_); - VideoRenderCallback* external_callback_ GUARDED_BY(thread_critsect_); - VideoRenderCallback* render_callback_ GUARDED_BY(thread_critsect_); - const rtc::scoped_ptr<VideoRenderFrames> render_buffers_ - GUARDED_BY(buffer_critsect_); - - uint32_t incoming_rate_ GUARDED_BY(stream_critsect_); - int64_t last_rate_calculation_time_ms_ GUARDED_BY(stream_critsect_); - uint16_t num_frames_since_last_calculation_ GUARDED_BY(stream_critsect_); - int64_t last_render_time_ms_ GUARDED_BY(thread_critsect_); - VideoFrame temp_frame_ GUARDED_BY(thread_critsect_); - VideoFrame start_image_ GUARDED_BY(thread_critsect_); - VideoFrame timeout_image_ GUARDED_BY(thread_critsect_); - uint32_t timeout_time_ GUARDED_BY(thread_critsect_); -}; - -} // namespace webrtc - -#endif // WEBRTC_COMMON_VIDEO_INTERFACE_INCOMING_VIDEO_STREAM_H_
diff --git a/webrtc/common_video/interface/video_frame_buffer.h b/webrtc/common_video/interface/video_frame_buffer.h deleted file mode 100644 index 1062165..0000000 --- a/webrtc/common_video/interface/video_frame_buffer.h +++ /dev/null
@@ -1,157 +0,0 @@ -/* - * 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_VIDEO_FRAME_BUFFER_H_ -#define WEBRTC_VIDEO_FRAME_BUFFER_H_ - -#include "webrtc/base/callback.h" -#include "webrtc/base/refcount.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/scoped_ref_ptr.h" -#include "webrtc/system_wrappers/include/aligned_malloc.h" - -namespace webrtc { - -enum PlaneType { - kYPlane = 0, - kUPlane = 1, - kVPlane = 2, - kNumOfPlanes = 3, -}; - -// Interface of a simple frame buffer containing pixel data. This interface does -// not contain any frame metadata such as rotation, timestamp, pixel_width, etc. -class VideoFrameBuffer : public rtc::RefCountInterface { - public: - // Returns true if this buffer has a single exclusive owner. - virtual bool HasOneRef() const = 0; - - // The resolution of the frame in pixels. For formats where some planes are - // subsampled, this is the highest-resolution plane. - virtual int width() const = 0; - virtual int height() const = 0; - - // Returns pointer to the pixel data for a given plane. The memory is owned by - // the VideoFrameBuffer object and must not be freed by the caller. - virtual const uint8_t* data(PlaneType type) const = 0; - - // Non-const data access is disallowed by default. You need to make sure you - // have exclusive access and a writable buffer before calling this function. - virtual uint8_t* MutableData(PlaneType type); - - // Returns the number of bytes between successive rows for a given plane. - virtual int stride(PlaneType type) const = 0; - - // Return the handle of the underlying video frame. This is used when the - // frame is backed by a texture. - virtual void* native_handle() const = 0; - - // Returns a new memory-backed frame buffer converted from this buffer's - // native handle. - virtual rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() = 0; - - protected: - virtual ~VideoFrameBuffer(); -}; - -// Plain I420 buffer in standard memory. -class I420Buffer : public VideoFrameBuffer { - public: - I420Buffer(int width, int height); - I420Buffer(int width, int height, int stride_y, int stride_u, int stride_v); - - int width() const override; - int height() const override; - const uint8_t* data(PlaneType type) const override; - // Non-const data access is only allowed if HasOneRef() is true to protect - // against unexpected overwrites. - uint8_t* MutableData(PlaneType type) override; - int stride(PlaneType type) const override; - void* native_handle() const override; - rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() override; - - protected: - ~I420Buffer() override; - - private: - const int width_; - const int height_; - const int stride_y_; - const int stride_u_; - const int stride_v_; - const rtc::scoped_ptr<uint8_t, AlignedFreeDeleter> data_; -}; - -// Base class for native-handle buffer is a wrapper around a |native_handle|. -// This is used for convenience as most native-handle implementations can share -// many VideoFrame implementations, but need to implement a few others (such -// as their own destructors or conversion methods back to software I420). -class NativeHandleBuffer : public VideoFrameBuffer { - public: - NativeHandleBuffer(void* native_handle, int width, int height); - - int width() const override; - int height() const override; - const uint8_t* data(PlaneType type) const override; - int stride(PlaneType type) const override; - void* native_handle() const override; - - protected: - void* native_handle_; - const int width_; - const int height_; -}; - -class WrappedI420Buffer : public webrtc::VideoFrameBuffer { - public: - WrappedI420Buffer(int width, - int height, - const uint8_t* y_plane, - int y_stride, - const uint8_t* u_plane, - int u_stride, - const uint8_t* v_plane, - int v_stride, - const rtc::Callback0<void>& no_longer_used); - int width() const override; - int height() const override; - - const uint8_t* data(PlaneType type) const override; - - int stride(PlaneType type) const override; - void* native_handle() const override; - - rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() override; - - private: - friend class rtc::RefCountedObject<WrappedI420Buffer>; - ~WrappedI420Buffer() override; - - const int width_; - const int height_; - const uint8_t* const y_plane_; - const uint8_t* const u_plane_; - const uint8_t* const v_plane_; - const int y_stride_; - const int u_stride_; - const int v_stride_; - rtc::Callback0<void> no_longer_used_cb_; -}; - -// Helper function to crop |buffer| without making a deep copy. May only be used -// for non-native frames. -rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop( - const rtc::scoped_refptr<VideoFrameBuffer>& buffer, - int cropped_width, - int cropped_height); - -} // namespace webrtc - -#endif // WEBRTC_VIDEO_FRAME_BUFFER_H_
diff --git a/webrtc/common_video/interface/video_image.h b/webrtc/common_video/interface/video_image.h deleted file mode 100644 index 4cbf23f..0000000 --- a/webrtc/common_video/interface/video_image.h +++ /dev/null
@@ -1,17 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef COMMON_VIDEO_INTERFACE_VIDEO_IMAGE_H -#define COMMON_VIDEO_INTERFACE_VIDEO_IMAGE_H - -// TODO(pbos): Remove this file and include webrtc/video_frame.h instead. -#include "webrtc/video_frame.h" - -#endif // COMMON_VIDEO_INTERFACE_VIDEO_IMAGE_H
diff --git a/webrtc/common_video/libyuv/include/scaler.h b/webrtc/common_video/libyuv/include/scaler.h index c04d01f..2b92f81 100644 --- a/webrtc/common_video/libyuv/include/scaler.h +++ b/webrtc/common_video/libyuv/include/scaler.h
@@ -15,7 +15,7 @@ #ifndef WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_SCALER_H_ #define WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_SCALER_H_ -#include "webrtc/common_video/interface/i420_buffer_pool.h" +#include "webrtc/common_video/include/i420_buffer_pool.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/typedefs.h" #include "webrtc/video_frame.h"
diff --git a/webrtc/common_video/libyuv/include/webrtc_libyuv.h b/webrtc/common_video/libyuv/include/webrtc_libyuv.h index baf8c17..d66736f 100644 --- a/webrtc/common_video/libyuv/include/webrtc_libyuv.h +++ b/webrtc/common_video/libyuv/include/webrtc_libyuv.h
@@ -152,6 +152,7 @@ double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame); // Compute SSIM for an I420 frame (all planes). double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame); -} + +} // namespace webrtc #endif // WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_WEBRTC_LIBYUV_H_
diff --git a/webrtc/common_video/libyuv/libyuv_unittest.cc b/webrtc/common_video/libyuv/libyuv_unittest.cc index b674b51..e7cf075 100644 --- a/webrtc/common_video/libyuv/libyuv_unittest.cc +++ b/webrtc/common_video/libyuv/libyuv_unittest.cc
@@ -97,7 +97,7 @@ width_(352), height_(288), size_y_(width_ * height_), - size_uv_(((width_ + 1 ) / 2) * ((height_ + 1) / 2)), + size_uv_(((width_ + 1) / 2) * ((height_ + 1) / 2)), frame_length_(CalcBufferSize(kI420, 352, 288)) { orig_buffer_.reset(new uint8_t[frame_length_]); } @@ -142,9 +142,9 @@ double psnr = 0.0; VideoFrame res_i420_frame; - EXPECT_EQ(0,res_i420_frame.CreateEmptyFrame(width_, height_, width_, - (width_ + 1) / 2, - (width_ + 1) / 2)); + EXPECT_EQ(0, res_i420_frame.CreateEmptyFrame(width_, height_, width_, + (width_ + 1) / 2, + (width_ + 1) / 2)); printf("\nConvert #%d I420 <-> I420 \n", j); rtc::scoped_ptr<uint8_t[]> out_i420_buffer(new uint8_t[frame_length_]); EXPECT_EQ(0, ConvertFromI420(orig_frame_, kI420, 0, @@ -281,8 +281,8 @@ int stride_y = 0; int stride_uv = 0; Calc16ByteAlignedStride(width_, &stride_y, &stride_uv); - EXPECT_EQ(0,res_i420_frame.CreateEmptyFrame(width_, height_, - stride_y, stride_uv, stride_uv)); + EXPECT_EQ(0, res_i420_frame.CreateEmptyFrame(width_, height_, + stride_y, stride_uv, stride_uv)); rtc::scoped_ptr<uint8_t[]> out_i420_buffer(new uint8_t[frame_length_]); EXPECT_EQ(0, ConvertFromI420(orig_frame_, kI420, 0, out_i420_buffer.get())); @@ -303,27 +303,27 @@ VideoFrame rotated_res_i420_frame; int rotated_width = height_; int rotated_height = width_; - int stride_y ; + int stride_y; int stride_uv; Calc16ByteAlignedStride(rotated_width, &stride_y, &stride_uv); - EXPECT_EQ(0,rotated_res_i420_frame.CreateEmptyFrame(rotated_width, - rotated_height, - stride_y, - stride_uv, - stride_uv)); + EXPECT_EQ(0, rotated_res_i420_frame.CreateEmptyFrame(rotated_width, + rotated_height, + stride_y, + stride_uv, + stride_uv)); EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_, 0, kVideoRotation_90, &rotated_res_i420_frame)); EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_, 0, kVideoRotation_270, &rotated_res_i420_frame)); - EXPECT_EQ(0,rotated_res_i420_frame.CreateEmptyFrame(width_, height_, - width_, (width_ + 1) / 2, - (width_ + 1) / 2)); + EXPECT_EQ(0, rotated_res_i420_frame.CreateEmptyFrame(width_, height_, + width_, (width_ + 1) / 2, + (width_ + 1) / 2)); EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_, 0, kVideoRotation_180, &rotated_res_i420_frame)); } TEST_F(TestLibYuv, alignment) { - int value = 0x3FF; // 1023 + int value = 0x3FF; // 1023 EXPECT_EQ(0x400, AlignInt(value, 128)); // Low 7 bits are zero. EXPECT_EQ(0x400, AlignInt(value, 64)); // Low 6 bits are zero. EXPECT_EQ(0x400, AlignInt(value, 32)); // Low 5 bits are zero. @@ -346,4 +346,4 @@ EXPECT_EQ(64, stride_uv); } -} // namespace +} // namespace webrtc
diff --git a/webrtc/common_video/libyuv/scaler_unittest.cc b/webrtc/common_video/libyuv/scaler_unittest.cc index 568311b..6d02638 100644 --- a/webrtc/common_video/libyuv/scaler_unittest.cc +++ b/webrtc/common_video/libyuv/scaler_unittest.cc
@@ -15,7 +15,6 @@ #include "webrtc/common_video/libyuv/include/scaler.h" #include "webrtc/system_wrappers/include/tick_util.h" #include "webrtc/test/testsupport/fileutils.h" -#include "webrtc/test/testsupport/gtest_disable.h" namespace webrtc { @@ -114,8 +113,13 @@ EXPECT_EQ(half_height_, test_frame2.height()); } -//TODO (mikhal): Converge the test into one function that accepts the method. -TEST_F(TestScaler, DISABLED_ON_ANDROID(PointScaleTest)) { +// TODO(mikhal): Converge the test into one function that accepts the method. +#if defined(WEBRTC_ANDROID) +#define MAYBE_PointScaleTest DISABLED_PointScaleTest +#else +#define MAYBE_PointScaleTest PointScaleTest +#endif +TEST_F(TestScaler, MAYBE_PointScaleTest) { double avg_psnr; FILE* source_file2; ScaleMethod method = kScalePoint; @@ -182,7 +186,12 @@ ASSERT_EQ(0, fclose(source_file2)); } -TEST_F(TestScaler, DISABLED_ON_ANDROID(BiLinearScaleTest)) { +#if defined(WEBRTC_ANDROID) +#define MAYBE_BilinearScaleTest DISABLED_BiLinearScaleTest +#else +#define MAYBE_BilinearScaleTest BiLinearScaleTest +#endif +TEST_F(TestScaler, MAYBE_BiLinearScaleTest) { double avg_psnr; FILE* source_file2; ScaleMethod method = kScaleBilinear; @@ -234,7 +243,12 @@ 400, 300); } -TEST_F(TestScaler, DISABLED_ON_ANDROID(BoxScaleTest)) { +#if defined(WEBRTC_ANDROID) +#define MAYBE_BoxScaleTest DISABLED_BoxScaleTest +#else +#define MAYBE_BoxScaleTest BoxScaleTest +#endif +TEST_F(TestScaler, MAYBE_BoxScaleTest) { double avg_psnr; FILE* source_file2; ScaleMethod method = kScaleBox; @@ -322,7 +336,7 @@ return avg_psnr; } -// TODO (mikhal): Move part to a separate scale test. +// TODO(mikhal): Move part to a separate scale test. void TestScaler::ScaleSequence(ScaleMethod method, FILE* source_file, std::string out_name, int src_width, int src_height,
diff --git a/webrtc/common_video/libyuv/webrtc_libyuv.cc b/webrtc/common_video/libyuv/webrtc_libyuv.cc index bf95624..48f5c20 100644 --- a/webrtc/common_video/libyuv/webrtc_libyuv.cc +++ b/webrtc/common_video/libyuv/webrtc_libyuv.cc
@@ -58,7 +58,7 @@ int AlignInt(int value, int alignment) { assert(!((alignment - 1) & alignment)); - return ((value + alignment - 1) & ~ (alignment - 1)); + return ((value + alignment - 1) & ~(alignment - 1)); } void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv) { @@ -119,8 +119,8 @@ } plane_buffer += frame.stride(plane_type); } - } - return 0; + } + return 0; } int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) { @@ -176,7 +176,7 @@ } libyuv::RotationMode ConvertRotationMode(VideoRotation rotation) { - switch(rotation) { + switch (rotation) { case kVideoRotation_0: return libyuv::kRotate0; case kVideoRotation_90: @@ -191,7 +191,7 @@ } int ConvertVideoType(VideoType video_type) { - switch(video_type) { + switch (video_type) { case kUnknown: return libyuv::FOURCC_ANY; case kI420: @@ -243,7 +243,7 @@ // Stride values should correspond to the destination values. if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) { dst_width = dst_frame->height(); - dst_height =dst_frame->width(); + dst_height = dst_frame->width(); } return libyuv::ConvertToI420(src_frame, sample_size, dst_frame->buffer(kYPlane),
diff --git a/webrtc/common_video/plane.cc b/webrtc/common_video/plane.cc deleted file mode 100644 index e0bbba1..0000000 --- a/webrtc/common_video/plane.cc +++ /dev/null
@@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/common_video/plane.h" - -#include <string.h> // memcpy - -#include <algorithm> // swap - -namespace webrtc { - -// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. -static const int kBufferAlignment = 64; - -Plane::Plane() - : allocated_size_(0), - plane_size_(0), - stride_(0) {} - -Plane::~Plane() {} - -int Plane::CreateEmptyPlane(int allocated_size, int stride, int plane_size) { - if (allocated_size < 1 || stride < 1 || plane_size < 1) - return -1; - stride_ = stride; - if (MaybeResize(allocated_size) < 0) - return -1; - plane_size_ = plane_size; - return 0; -} - -int Plane::MaybeResize(int new_size) { - if (new_size <= 0) - return -1; - if (new_size <= allocated_size_) - return 0; - rtc::scoped_ptr<uint8_t, AlignedFreeDeleter> new_buffer( - static_cast<uint8_t*>(AlignedMalloc(new_size, kBufferAlignment))); - if (buffer_.get()) { - memcpy(new_buffer.get(), buffer_.get(), plane_size_); - } - buffer_.reset(new_buffer.release()); - allocated_size_ = new_size; - return 0; -} - -int Plane::Copy(const Plane& plane) { - if (MaybeResize(plane.allocated_size_) < 0) - return -1; - if (plane.buffer_.get()) - memcpy(buffer_.get(), plane.buffer_.get(), plane.plane_size_); - stride_ = plane.stride_; - plane_size_ = plane.plane_size_; - return 0; -} - -int Plane::Copy(int size, int stride, const uint8_t* buffer) { - if (MaybeResize(size) < 0) - return -1; - memcpy(buffer_.get(), buffer, size); - plane_size_ = size; - stride_ = stride; - return 0; -} - -void Plane::Swap(Plane& plane) { - std::swap(stride_, plane.stride_); - std::swap(allocated_size_, plane.allocated_size_); - std::swap(plane_size_, plane.plane_size_); - buffer_.swap(plane.buffer_); -} - -} // namespace webrtc
diff --git a/webrtc/common_video/plane.h b/webrtc/common_video/plane.h deleted file mode 100644 index 3ef949a..0000000 --- a/webrtc/common_video/plane.h +++ /dev/null
@@ -1,75 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef COMMON_VIDEO_PLANE_H -#define COMMON_VIDEO_PLANE_H - -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/system_wrappers/include/aligned_malloc.h" -#include "webrtc/typedefs.h" - -namespace webrtc { - -// Helper class for VideoFrame: Store plane data and perform basic plane -// operations. -class Plane { - public: - Plane(); - ~Plane(); - // CreateEmptyPlane - set allocated size, actual plane size and stride: - // If current size is smaller than current size, then a buffer of sufficient - // size will be allocated. - // Return value: 0 on success ,-1 on error. - int CreateEmptyPlane(int allocated_size, int stride, int plane_size); - - // Copy the entire plane data. - // Return value: 0 on success ,-1 on error. - int Copy(const Plane& plane); - - // Copy buffer: If current size is smaller - // than current size, then a buffer of sufficient size will be allocated. - // Return value: 0 on success ,-1 on error. - int Copy(int size, int stride, const uint8_t* buffer); - - // Swap plane data. - void Swap(Plane& plane); - - // Get allocated size. - int allocated_size() const {return allocated_size_;} - - // Set actual size. - void ResetSize() {plane_size_ = 0;} - - // Return true is plane size is zero, false if not. - bool IsZeroSize() const {return plane_size_ == 0;} - - // Get stride value. - int stride() const {return stride_;} - - // Return data pointer. - const uint8_t* buffer() const {return buffer_.get();} - // Overloading with non-const. - uint8_t* buffer() {return buffer_.get();} - - private: - // Resize when needed: If current allocated size is less than new_size, buffer - // will be updated. Old data will be copied to new buffer. - // Return value: 0 on success ,-1 on error. - int MaybeResize(int new_size); - - rtc::scoped_ptr<uint8_t, AlignedFreeDeleter> buffer_; - int allocated_size_; - int plane_size_; - int stride_; -}; // Plane - -} // namespace webrtc - -#endif // COMMON_VIDEO_PLANE_H
diff --git a/webrtc/common_video/video_frame.cc b/webrtc/common_video/video_frame.cc index 7cdbd53..8ccd821 100644 --- a/webrtc/common_video/video_frame.cc +++ b/webrtc/common_video/video_frame.cc
@@ -19,6 +19,26 @@ namespace webrtc { +bool EqualPlane(const uint8_t* data1, + const uint8_t* data2, + int stride, + int width, + int height) { + for (int y = 0; y < height; ++y) { + if (memcmp(data1, data2, width) != 0) + return false; + data1 += stride; + data2 += stride; + } + return true; +} + +int ExpectedSize(int plane_stride, int image_height, PlaneType type) { + if (type == kYPlane) + return plane_stride * image_height; + return plane_stride * ((image_height + 1) / 2); +} + VideoFrame::VideoFrame() { // Intentionally using Reset instead of initializer list so that any missed // fields in Reset will be caught by memory checkers. @@ -202,4 +222,24 @@ return frame; } +bool VideoFrame::EqualsFrame(const VideoFrame& frame) const { + if (width() != frame.width() || height() != frame.height() || + stride(kYPlane) != frame.stride(kYPlane) || + stride(kUPlane) != frame.stride(kUPlane) || + stride(kVPlane) != frame.stride(kVPlane) || + timestamp() != frame.timestamp() || + ntp_time_ms() != frame.ntp_time_ms() || + render_time_ms() != frame.render_time_ms()) { + return false; + } + const int half_width = (width() + 1) / 2; + const int half_height = (height() + 1) / 2; + return EqualPlane(buffer(kYPlane), frame.buffer(kYPlane), + stride(kYPlane), width(), height()) && + EqualPlane(buffer(kUPlane), frame.buffer(kUPlane), + stride(kUPlane), half_width, half_height) && + EqualPlane(buffer(kVPlane), frame.buffer(kVPlane), + stride(kVPlane), half_width, half_height); +} + } // namespace webrtc
diff --git a/webrtc/common_video/video_frame_buffer.cc b/webrtc/common_video/video_frame_buffer.cc index 36ee14a..492bc49 100644 --- a/webrtc/common_video/video_frame_buffer.cc +++ b/webrtc/common_video/video_frame_buffer.cc
@@ -8,21 +8,15 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/common_video/interface/video_frame_buffer.h" +#include "webrtc/common_video/include/video_frame_buffer.h" -#include "webrtc/base/bind.h" #include "webrtc/base/checks.h" +#include "webrtc/base/keep_ref_until_done.h" // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. static const int kBufferAlignment = 64; namespace webrtc { -namespace { - -// Used in rtc::Bind to keep a buffer alive until destructor is called. -static void NoLongerUsedCallback(rtc::scoped_refptr<VideoFrameBuffer> dummy) {} - -} // anonymous namespace uint8_t* VideoFrameBuffer::MutableData(PlaneType type) { RTC_NOTREACHED(); @@ -238,7 +232,7 @@ y_plane, buffer->stride(kYPlane), u_plane, buffer->stride(kUPlane), v_plane, buffer->stride(kVPlane), - rtc::Bind(&NoLongerUsedCallback, buffer)); + rtc::KeepRefUntilDone(buffer)); } } // namespace webrtc
diff --git a/webrtc/common_video/video_render_frames.cc b/webrtc/common_video/video_render_frames.cc index f4ece5e..8b447cb 100644 --- a/webrtc/common_video/video_render_frames.cc +++ b/webrtc/common_video/video_render_frames.cc
@@ -12,7 +12,7 @@ #include <assert.h> -#include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/modules/include/module_common_types.h" #include "webrtc/system_wrappers/include/tick_util.h" #include "webrtc/system_wrappers/include/trace.h" @@ -20,7 +20,7 @@ const uint32_t KEventMaxWaitTimeMs = 200; const uint32_t kMinRenderDelayMs = 10; -const uint32_t kMaxRenderDelayMs= 500; +const uint32_t kMaxRenderDelayMs = 500; VideoRenderFrames::VideoRenderFrames() : render_delay_ms_(10) {
diff --git a/webrtc/config.h b/webrtc/config.h index 5271163..06460ae 100644 --- a/webrtc/config.h +++ b/webrtc/config.h
@@ -16,6 +16,7 @@ #include <string> #include <vector> +#include "webrtc/common.h" #include "webrtc/common_types.h" #include "webrtc/typedefs.h" @@ -49,10 +50,13 @@ int red_rtx_payload_type; }; -// RTP header extension to use for the video stream, see RFC 5285. +// RTP header extension, see RFC 5285. struct RtpExtension { RtpExtension(const std::string& name, int id) : name(name), id(id) {} std::string ToString() const; + bool operator==(const RtpExtension& rhs) const { + return name == rhs.name && id == rhs.id; + } static bool IsSupportedForAudio(const std::string& name); static bool IsSupportedForVideo(const std::string& name); @@ -104,6 +108,7 @@ std::string ToString() const; std::vector<VideoStream> streams; + std::vector<SpatialLayer> spatial_layers; ContentType content_type; void* encoder_specific_settings; @@ -124,6 +129,7 @@ struct NetEqCapacityConfig { NetEqCapacityConfig() : enabled(false), capacity(0) {} explicit NetEqCapacityConfig(int value) : enabled(true), capacity(value) {} + static const ConfigOptionID identifier = ConfigOptionID::kNetEqCapacityConfig; bool enabled; int capacity; }; @@ -131,6 +137,14 @@ struct NetEqFastAccelerate { NetEqFastAccelerate() : enabled(false) {} explicit NetEqFastAccelerate(bool value) : enabled(value) {} + static const ConfigOptionID identifier = ConfigOptionID::kNetEqFastAccelerate; + bool enabled; +}; + +struct VoicePacing { + VoicePacing() : enabled(false) {} + explicit VoicePacing(bool value) : enabled(value) {} + static const ConfigOptionID identifier = ConfigOptionID::kVoicePacing; bool enabled; };
diff --git a/webrtc/engine_configurations.h b/webrtc/engine_configurations.h index c832d9a..42b1816 100644 --- a/webrtc/engine_configurations.h +++ b/webrtc/engine_configurations.h
@@ -14,19 +14,6 @@ #include "webrtc/typedefs.h" // ============================================================================ -// Voice and Video -// ============================================================================ - -// ---------------------------------------------------------------------------- -// [Video] Codec settings -// ---------------------------------------------------------------------------- - -#define VIDEOCODEC_I420 -#define VIDEOCODEC_VP8 -#define VIDEOCODEC_VP9 -#define VIDEOCODEC_H264 - -// ============================================================================ // VoiceEngine // ============================================================================
diff --git a/webrtc/examples/android/media_demo/AndroidManifest.xml b/webrtc/examples/android/media_demo/AndroidManifest.xml deleted file mode 100644 index 62bf460..0000000 --- a/webrtc/examples/android/media_demo/AndroidManifest.xml +++ /dev/null
@@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - android:versionCode="1" package="org.webrtc.webrtcdemo" android:versionName="1.07"> - <application android:icon="@drawable/logo" - android:label="@string/appName" - android:debuggable="true"> - <activity android:name=".WebRTCDemo" - android:theme="@android:style/Theme.Holo" - android:label="@string/appName" - android:screenOrientation="landscape" - > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - <action android:name="android.intent.action.HEADSET_PLUG"/> - </intent-filter> - </activity> - </application> - - <uses-sdk android:minSdkVersion="14" /> - <uses-permission android:name="android.permission.CAMERA"></uses-permission> - <uses-feature android:name="android.hardware.camera" /> - <uses-feature android:name="android.hardware.camera.autofocus" /> - <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> - <uses-permission android:name="android.permission.RECORD_AUDIO" /> - <uses-permission android:name="android.permission.INTERNET" /> - <uses-permission android:name="android.permission.WAKE_LOCK" /> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> -</manifest> \ No newline at end of file
diff --git a/webrtc/examples/android/media_demo/README b/webrtc/examples/android/media_demo/README deleted file mode 100644 index af71f38..0000000 --- a/webrtc/examples/android/media_demo/README +++ /dev/null
@@ -1,24 +0,0 @@ -This directory contains a sample app for sending and receiving audio -on Android. It further lets you enable and disable some call quality -enhancements such as echo cancellation, noise suppression etc. - -Prerequisites: -- Make sure gclient is checking out tools necessary to target Android: your - .gclient file should contain a line like: - target_os = ['android'] - Make sure to re-run gclient sync after adding this to download the tools. -- Env vars need to be set up to target Android; easiest way to do this is to run - (from the libjingle trunk directory): - . ./build/android/envsetup.sh - Note that this clobbers any previously-set $GYP_DEFINES so it must be done - before the next item. -- Set up webrtc-related GYP variables: - export GYP_DEFINES="$GYP_DEFINES java_home=</path/to/JDK>" -- Finally, run "gclient runhooks" to generate Android-targeting .ninja files. - -Example of building the app: -cd <path/to/repository>/trunk -ninja -C out/Debug WebRTCDemo - -It can then be installed and run on the device: -adb install -r out/Debug/WebRTCDemo-debug.apk
diff --git a/webrtc/examples/android/media_demo/build.xml b/webrtc/examples/android/media_demo/build.xml deleted file mode 100644 index 1773488..0000000 --- a/webrtc/examples/android/media_demo/build.xml +++ /dev/null
@@ -1,92 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project name="WebRTCDemo" default="help"> - - <!-- The local.properties file is created and updated by the 'android' tool. - It contains the path to the SDK. It should *NOT* be checked into - Version Control Systems. --> - <property file="local.properties" /> - - <!-- The ant.properties file can be created by you. It is only edited by the - 'android' tool to add properties to it. - This is the place to change some Ant specific build properties. - Here are some properties you may want to change/update: - - source.dir - The name of the source directory. Default is 'src'. - out.dir - The name of the output directory. Default is 'bin'. - - For other overridable properties, look at the beginning of the rules - files in the SDK, at tools/ant/build.xml - - Properties related to the SDK location or the project target should - be updated using the 'android' tool with the 'update' action. - - This file is an integral part of the build system for your - application and should be checked into Version Control Systems. - - --> - <property file="ant.properties" /> - - <!-- if sdk.dir was not set from one of the property file, then - get it from the ANDROID_HOME env var. - This must be done before we load project.properties since - the proguard config can use sdk.dir --> - <property environment="env" /> - <condition property="sdk.dir" value="${env.ANDROID_SDK_ROOT}"> - <isset property="env.ANDROID_SDK_ROOT" /> - </condition> - - <!-- The project.properties file is created and updated by the 'android' - tool, as well as ADT. - - This contains project specific properties such as project target, and library - dependencies. Lower level build properties are stored in ant.properties - (or in .classpath for Eclipse projects). - - This file is an integral part of the build system for your - application and should be checked into Version Control Systems. --> - <loadproperties srcFile="project.properties" /> - - <!-- quick check on sdk.dir --> - <fail - message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_SDK_ROOT environment variable." - unless="sdk.dir" - /> - - <!-- - Import per project custom build rules if present at the root of the project. - This is the place to put custom intermediary targets such as: - -pre-build - -pre-compile - -post-compile (This is typically used for code obfuscation. - Compiled code location: ${out.classes.absolute.dir} - If this is not done in place, override ${out.dex.input.absolute.dir}) - -post-package - -post-build - -pre-clean - --> - <import file="custom_rules.xml" optional="true" /> - - <!-- Import the actual build file. - - To customize existing targets, there are two options: - - Customize only one target: - - copy/paste the target into this file, *before* the - <import> task. - - customize it to your needs. - - Customize the whole content of build.xml - - copy/paste the content of the rules files (minus the top node) - into this file, replacing the <import> task. - - customize to your needs. - - *********************** - ****** IMPORTANT ****** - *********************** - In all cases you must update the value of version-tag below to read 'custom' instead of an integer, - in order to avoid having your file be overridden by tools such as "android update project" - --> - <!-- version-tag: 1 --> - <import file="${sdk.dir}/tools/ant/build.xml" /> - -</project>
diff --git a/webrtc/examples/android/media_demo/jni/jni_helpers.cc b/webrtc/examples/android/media_demo/jni/jni_helpers.cc deleted file mode 100644 index b0d1a74..0000000 --- a/webrtc/examples/android/media_demo/jni/jni_helpers.cc +++ /dev/null
@@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/examples/android/media_demo/jni/jni_helpers.h" - -#include <limits> - -#include "unicode/unistr.h" - -using icu::UnicodeString; - -jmethodID GetMethodID(JNIEnv* jni, jclass c, const std::string& name, - const char* signature) { - jmethodID m = jni->GetMethodID(c, name.c_str(), signature); - CHECK_JNI_EXCEPTION(jni, "error during GetMethodID"); - return m; -} - -jlong jlongFromPointer(void* ptr) { - CHECK(sizeof(intptr_t) <= sizeof(jlong), "Time to rethink the use of jlongs"); - // Going through intptr_t to be obvious about the definedness of the - // conversion from pointer to integral type. intptr_t to jlong is a standard - // widening by the COMPILE_ASSERT above. - jlong ret = reinterpret_cast<intptr_t>(ptr); - CHECK(reinterpret_cast<void*>(ret) == ptr, - "jlong does not convert back to pointer"); - return ret; -} - -// Given a (UTF-16) jstring return a new UTF-8 native string. -std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) { - const jchar* jchars = jni->GetStringChars(j_string, NULL); - CHECK_JNI_EXCEPTION(jni, "Error during GetStringChars"); - UnicodeString ustr(jchars, jni->GetStringLength(j_string)); - CHECK_JNI_EXCEPTION(jni, "Error during GetStringLength"); - jni->ReleaseStringChars(j_string, jchars); - CHECK_JNI_EXCEPTION(jni, "Error during ReleaseStringChars"); - std::string ret; - return ustr.toUTF8String(ret); -} - -ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni, const char** classes, - int size) { - for (int i = 0; i < size; ++i) { - LoadClass(jni, classes[i]); - } -} -ClassReferenceHolder::~ClassReferenceHolder() { - CHECK(classes_.empty(), "Must call FreeReferences() before dtor!"); -} - -void ClassReferenceHolder::FreeReferences(JNIEnv* jni) { - for (std::map<std::string, jclass>::const_iterator it = classes_.begin(); - it != classes_.end(); ++it) { - jni->DeleteGlobalRef(it->second); - } - classes_.clear(); -} - -jclass ClassReferenceHolder::GetClass(const std::string& name) { - std::map<std::string, jclass>::iterator it = classes_.find(name); - CHECK(it != classes_.end(), "Could not find class"); - return it->second; -} - -void ClassReferenceHolder::LoadClass(JNIEnv* jni, const std::string& name) { - jclass localRef = jni->FindClass(name.c_str()); - CHECK_JNI_EXCEPTION(jni, "Could not load class"); - CHECK(localRef, name.c_str()); - jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef)); - CHECK_JNI_EXCEPTION(jni, "error during NewGlobalRef"); - CHECK(globalRef, name.c_str()); - bool inserted = classes_.insert(std::make_pair(name, globalRef)).second; - CHECK(inserted, "Duplicate class name"); -}
diff --git a/webrtc/examples/android/media_demo/jni/jni_helpers.h b/webrtc/examples/android/media_demo/jni/jni_helpers.h deleted file mode 100644 index 3d8ff48..0000000 --- a/webrtc/examples/android/media_demo/jni/jni_helpers.h +++ /dev/null
@@ -1,79 +0,0 @@ -/* - * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_EXAMPLES_ANDROID_MEDIA_DEMO_JNI_JNI_HELPERS_H_ -#define WEBRTC_EXAMPLES_ANDROID_MEDIA_DEMO_JNI_JNI_HELPERS_H_ - -// TODO(henrike): this file contains duplication with regards to -// talk/app/webrtc/java/jni/peerconnection_jni.cc. When/if code can be shared -// between trunk/talk and trunk/webrtc remove the duplication. - -#include <android/log.h> -#include <jni.h> - -#include <assert.h> -#include <map> -#include <string> - -#define TAG "WEBRTC-NATIVE" - -// Abort the process if |x| is false, emitting |msg| to logcat. -#define CHECK(x, msg) \ - if (x) { \ - } else { \ - __android_log_print(ANDROID_LOG_ERROR, TAG, "%s:%d: %s", __FILE__, \ - __LINE__, msg); \ - assert(false); \ - } - -// Abort the process if |jni| has a Java exception pending, emitting |msg| to -// logcat. -#define CHECK_JNI_EXCEPTION(jni, msg) \ - if (0) { \ - } else { \ - if (jni->ExceptionCheck()) { \ - jni->ExceptionDescribe(); \ - jni->ExceptionClear(); \ - CHECK(0, msg); \ - } \ - } - -// JNIEnv-helper methods that CHECK success: no Java exception thrown and found -// object/class/method/field is non-null. -jmethodID GetMethodID(JNIEnv* jni, jclass c, const std::string& name, - const char* signature); - -// Return a |jlong| that will automatically convert back to |ptr| when assigned -// to a |uint64_t| -jlong jlongFromPointer(void* ptr); - -// Given a (UTF-16) jstring return a new UTF-8 native string. -std::string JavaToStdString(JNIEnv* jni, const jstring& j_string); - -// Android's FindClass() is trickier than usual because the app-specific -// ClassLoader is not consulted when there is no app-specific frame on the -// stack. Consequently, we only look up classes once in JNI_OnLoad. -// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass -class ClassReferenceHolder { - public: - ClassReferenceHolder(JNIEnv* jni, const char** classes, int size); - ~ClassReferenceHolder(); - - void FreeReferences(JNIEnv* jni); - - jclass GetClass(const std::string& name); - - private: - void LoadClass(JNIEnv* jni, const std::string& name); - - std::map<std::string, jclass> classes_; -}; - -#endif // WEBRTC_EXAMPLES_ANDROID_MEDIA_DEMO_JNI_JNI_HELPERS_H_
diff --git a/webrtc/examples/android/media_demo/jni/on_load.cc b/webrtc/examples/android/media_demo/jni/on_load.cc deleted file mode 100644 index 5827ee8..0000000 --- a/webrtc/examples/android/media_demo/jni/on_load.cc +++ /dev/null
@@ -1,48 +0,0 @@ -/* - * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include <jni.h> - -#include <assert.h> - -#include "webrtc/examples/android/media_demo/jni/jni_helpers.h" -#include "webrtc/examples/android/media_demo/jni/voice_engine_jni.h" -#include "webrtc/voice_engine/include/voe_base.h" - -// Macro for native functions that can be found by way of jni-auto discovery. -// Note extern "C" is needed for "discovery" of native methods to work. -#define JOWW(rettype, name) \ - extern "C" rettype JNIEXPORT JNICALL Java_org_webrtc_webrtcdemo_##name - -static JavaVM* g_vm = NULL; - -extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { - // Only called once. - CHECK(!g_vm, "OnLoad called more than once"); - g_vm = vm; - return JNI_VERSION_1_4; -} - -JOWW(void, NativeWebRtcContextRegistry_register)( - JNIEnv* jni, - jclass, - jobject context) { - webrtc_examples::SetVoeDeviceObjects(g_vm); - CHECK(webrtc::VoiceEngine::SetAndroidObjects(g_vm, context) == 0, - "Failed to register android objects to voice engine"); -} - -JOWW(void, NativeWebRtcContextRegistry_unRegister)( - JNIEnv* jni, - jclass) { - CHECK(webrtc::VoiceEngine::SetAndroidObjects(NULL, NULL) == 0, - "Failed to unregister android objects from voice engine"); - webrtc_examples::ClearVoeDeviceObjects(); -}
diff --git a/webrtc/examples/android/media_demo/jni/voice_engine_jni.cc b/webrtc/examples/android/media_demo/jni/voice_engine_jni.cc deleted file mode 100644 index 79d6cbc..0000000 --- a/webrtc/examples/android/media_demo/jni/voice_engine_jni.cc +++ /dev/null
@@ -1,423 +0,0 @@ -/* - * 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. - */ - -// This file contains JNI for the voice engine interfaces. -// The native functions are found using jni's auto discovery. - -#include "webrtc/examples/android/media_demo/jni/voice_engine_jni.h" -