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 @@
                  &parameters_.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(&params)) {
-    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(
-      &parameters_.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, &param) == 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, &param) != 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, &param) != 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"
-
-#include <map>
-#include <string>
-
-#include "webrtc/base/arraysize.h"
-#include "webrtc/examples/android/media_demo/jni/jni_helpers.h"
-#include "webrtc/modules/utility/interface/helpers_android.h"
-#include "webrtc/test/channel_transport/include/channel_transport.h"
-#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_file.h"
-#include "webrtc/voice_engine/include/voe_hardware.h"
-#include "webrtc/voice_engine/include/voe_network.h"
-#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
-#include "webrtc/voice_engine/include/voe_volume_control.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
-
-namespace {
-
-static JavaVM* g_vm = NULL;
-static ClassReferenceHolder* g_class_reference_holder = NULL;
-
-jclass GetClass(JNIEnv* jni, const char* name) {
-  CHECK(g_class_reference_holder, "Class reference holder NULL");
-  return g_class_reference_holder->GetClass(name);
-}
-
-static const char* g_classes[] = {"org/webrtc/webrtcdemo/CodecInst"};
-
-template<typename T>
-void ReleaseSubApi(T instance) {
-  CHECK(instance->Release() >= 0, "failed to release instance")
-}
-
-class VoiceEngineData {
- public:
-  VoiceEngineData()
-      : ve(webrtc::VoiceEngine::Create()),
-        base(webrtc::VoEBase::GetInterface(ve)),
-        codec(webrtc::VoECodec::GetInterface(ve)),
-        file(webrtc::VoEFile::GetInterface(ve)),
-        netw(webrtc::VoENetwork::GetInterface(ve)),
-        apm(webrtc::VoEAudioProcessing::GetInterface(ve)),
-        volume(webrtc::VoEVolumeControl::GetInterface(ve)),
-        hardware(webrtc::VoEHardware::GetInterface(ve)),
-        rtp(webrtc::VoERTP_RTCP::GetInterface(ve)) {
-    CHECK(ve != NULL, "Voice engine instance failed to be created");
-    CHECK(base != NULL, "Failed to acquire base interface");
-    CHECK(codec != NULL, "Failed to acquire codec interface");
-    CHECK(file != NULL, "Failed to acquire file interface");
-    CHECK(netw != NULL, "Failed to acquire netw interface");
-    CHECK(apm != NULL, "Failed to acquire apm interface");
-    CHECK(volume != NULL, "Failed to acquire volume interface");
-    CHECK(hardware != NULL, "Failed to acquire hardware interface");
-    CHECK(rtp != NULL, "Failed to acquire rtp interface");
-  }
-
-  ~VoiceEngineData() {
-    CHECK(channel_transports_.empty(),
-          "VoE transports must be deleted before terminating");
-    CHECK(base->Terminate() == 0, "VoE failed to terminate");
-    ReleaseSubApi(base);
-    ReleaseSubApi(codec);
-    ReleaseSubApi(file);
-    ReleaseSubApi(netw);
-    ReleaseSubApi(apm);
-    ReleaseSubApi(volume);
-    ReleaseSubApi(hardware);
-    ReleaseSubApi(rtp);
-    webrtc::VoiceEngine* ve_instance = ve;
-    CHECK(webrtc::VoiceEngine::Delete(ve_instance), "VoE failed to be deleted