Merge from Chromium at DEPS revision db3f05efe0f9

This commit was generated by merge_to_master.py.

Change-Id: Ibb07e7633f0f96e925c9bd5cdcb91747ad656b6e
diff --git a/BUILD.gn b/BUILD.gn
index 9d2fa6a..157be6f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -120,6 +120,10 @@
     }
   }
 
+  if (cpu_arch == "arm64") {
+    defines += [ "WEBRTC_ARCH_ARM" ]
+  }
+
   if (cpu_arch == "arm") {
     defines += [ "WEBRTC_ARCH_ARM" ]
     if (arm_version == 7) {
diff --git a/base/BUILD.gn b/base/BUILD.gn
index be53e40..1c2527a 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -40,7 +40,7 @@
   ]
 }
 
-config("no_openssl_config") {
+config("nss_config") {
   defines = [
     "SSL_USE_NSS",
     "HAVE_NSS_SSL_H",
@@ -465,24 +465,30 @@
       "opensslstreamadapter.h",
     ]
   } else {
-    public_configs += [ ":no_openssl_config" ]
+    public_configs += [ ":nss_config" ]
+    if (rtc_build_ssl) {
+      if (build_with_chromium) {
+        deps += [ "//crypto:platform" ]
+      } else {
+        deps += [ "//net/third_party/nss/ssl:libssl" ]
+        if (is_linux) {
+          deps += [ ":linux_system_ssl" ]
+        } else {
+          deps += [
+            "//third_party/nss:nspr",
+            "//third_party/nss:nss",
+          ]
+        }
+      }
+    } else {
+      configs += [ "external_ssl_library" ]
+    }
     sources += [
       "nssidentity.cc",
       "nssidentity.h",
       "nssstreamadapter.cc",
       "nssstreamadapter.h",
     ]
-    if (is_mac || is_ios || is_win) {
-      if (rtc_build_ssl) {
-        deps += [
-          "//net/third_party/nss/ssl:libssl",
-          "//third_party/nss:nspr",
-          "//third_party/nss:nss",
-        ]
-      } else {
-        configs += [ "external_ssl_library" ]
-      }
-    }
   }
 
   if (is_android) {
@@ -518,13 +524,9 @@
 
   if (is_linux) {
     libs += [
-      "crypto",
       "dl",
       "rt",
     ]
-    if (rtc_build_ssl) {
-      configs += [ "//third_party/nss:system_nss_no_ssl_config" ]
-    }
   }
 
   if (is_mac) {
@@ -595,16 +597,4 @@
       "linux.h",
     ]
   }
-
-  if (is_posix && !is_mac && !is_ios && !is_android) {
-    if (build_with_chromium) {
-      deps += [ "//crypto:platform" ]
-    } else {
-      if (rtc_build_ssl) {
-        deps += [ ":linux_system_ssl" ]
-      } else {
-        configs += [ "external_ssl_library" ]
-      }
-    }
-  }
 }
diff --git a/base/base.gyp b/base/base.gyp
index 569db74..2fd64ba 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -539,32 +539,31 @@
                 ],
               },
             }],
-            ['OS=="mac" or OS=="ios" or OS=="win"', {
+            ['build_ssl==1', {
               'conditions': [
-                ['build_ssl==1', {
+                # On some platforms, the rest of NSS is bundled. On others,
+                # it's pulled from the system.
+                ['OS == "mac" or OS == "ios" or OS == "win"', {
                   'dependencies': [
                     '<(DEPTH)/net/third_party/nss/ssl.gyp:libssl',
                     '<(DEPTH)/third_party/nss/nss.gyp:nspr',
                     '<(DEPTH)/third_party/nss/nss.gyp:nss',
                   ],
-                }, {
-                  'include_dirs': [
-                    '<(ssl_root)',
+                }],
+                ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
+                  'dependencies': [
+                    '<(DEPTH)/build/linux/system.gyp:ssl',
                   ],
                 }],
               ],
+            }, {
+              'include_dirs': [
+                '<(ssl_root)',
+              ],
             }],
           ],
         }],
         ['OS == "android"', {
-          'defines': [
-            'HAVE_OPENSSL_SSL_H'
-          ],
-          'direct_dependent_settings': {
-            'defines': [
-              'HAVE_OPENSSL_SSL_H'
-            ],
-          },
           'link_settings': {
             'libraries': [
               '-llog',
@@ -572,20 +571,6 @@
             ],
           },
         }, {
-          'conditions': [
-            ['use_legacy_ssl_defaults!=1', {
-              'defines': [
-                'HAVE_NSS_SSL_H',
-                'SSL_USE_NSS_RNG',
-              ],
-              'direct_dependent_settings': {
-                'defines': [
-                  'HAVE_NSS_SSL_H',
-                  'SSL_USE_NSS_RNG',
-                ],
-              },
-            }],
-          ],
           'sources!': [
             'ifaddrs-android.cc',
             'ifaddrs-android.h',
@@ -627,21 +612,6 @@
               '-lrt',
             ],
           },
-          'conditions': [
-            ['build_ssl==1', {
-              'link_settings': {
-                'libraries': [
-                  '<!@(<(pkg-config) --libs-only-l nss | sed -e "s/-lssl3//")',
-                ],
-              },
-              'cflags': [
-                '<!@(<(pkg-config) --cflags nss)',
-              ],
-              'ldflags': [
-                '<!@(<(pkg-config) --libs-only-L --libs-only-other nss)',
-              ],
-            }],
-          ],
         }, {
           'sources!': [
             'dbus.cc',
@@ -757,19 +727,6 @@
             'linux.h',
           ],
         }],
-        ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
-          'conditions': [
-            ['build_ssl==1', {
-              'dependencies': [
-                '<(DEPTH)/build/linux/system.gyp:ssl',
-              ],
-            }, {
-              'include_dirs': [
-                '<(ssl_root)',
-              ],
-            }],
-          ],
-        }],
       ],
     },
   ],
diff --git a/base/rtc_base.target.darwin-arm.mk b/base/rtc_base.target.darwin-arm.mk
index c352b2b..5c7018c 100644
--- a/base/rtc_base.target.darwin-arm.mk
+++ b/base/rtc_base.target.darwin-arm.mk
@@ -145,11 +145,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -171,6 +173,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -265,11 +268,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -291,6 +296,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.darwin-arm64.mk b/base/rtc_base.target.darwin-arm64.mk
index f9dd503..6633e54 100644
--- a/base/rtc_base.target.darwin-arm64.mk
+++ b/base/rtc_base.target.darwin-arm64.mk
@@ -134,11 +134,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -147,6 +149,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -157,6 +160,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -239,11 +243,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -252,6 +258,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -262,6 +269,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.darwin-mips.mk b/base/rtc_base.target.darwin-mips.mk
index 5b11cbf..049b1ef 100644
--- a/base/rtc_base.target.darwin-mips.mk
+++ b/base/rtc_base.target.darwin-mips.mk
@@ -138,11 +138,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -163,6 +165,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -250,11 +253,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -275,6 +280,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.darwin-mips64.mk b/base/rtc_base.target.darwin-mips64.mk
new file mode 100644
index 0000000..b83453d
--- /dev/null
+++ b/base/rtc_base.target.darwin-mips64.mk
@@ -0,0 +1,336 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_base_rtc_base_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/base/asyncfile.cc \
+	third_party/webrtc/base/asynchttprequest.cc \
+	third_party/webrtc/base/asyncsocket.cc \
+	third_party/webrtc/base/asynctcpsocket.cc \
+	third_party/webrtc/base/asyncudpsocket.cc \
+	third_party/webrtc/base/autodetectproxy.cc \
+	third_party/webrtc/base/base64.cc \
+	third_party/webrtc/base/bytebuffer.cc \
+	third_party/webrtc/base/common.cc \
+	third_party/webrtc/base/cpumonitor.cc \
+	third_party/webrtc/base/crc32.cc \
+	third_party/webrtc/base/diskcache.cc \
+	third_party/webrtc/base/event.cc \
+	third_party/webrtc/base/fileutils.cc \
+	third_party/webrtc/base/firewallsocketserver.cc \
+	third_party/webrtc/base/flags.cc \
+	third_party/webrtc/base/helpers.cc \
+	third_party/webrtc/base/httpbase.cc \
+	third_party/webrtc/base/httpclient.cc \
+	third_party/webrtc/base/httpcommon.cc \
+	third_party/webrtc/base/httprequest.cc \
+	third_party/webrtc/base/ifaddrs-android.cc \
+	third_party/webrtc/base/ipaddress.cc \
+	third_party/webrtc/base/linux.cc \
+	third_party/webrtc/base/messagedigest.cc \
+	third_party/webrtc/base/messagehandler.cc \
+	third_party/webrtc/base/messagequeue.cc \
+	third_party/webrtc/base/nethelpers.cc \
+	third_party/webrtc/base/network.cc \
+	third_party/webrtc/base/pathutils.cc \
+	third_party/webrtc/base/physicalsocketserver.cc \
+	third_party/webrtc/base/proxydetect.cc \
+	third_party/webrtc/base/proxyinfo.cc \
+	third_party/webrtc/base/ratelimiter.cc \
+	third_party/webrtc/base/ratetracker.cc \
+	third_party/webrtc/base/sha1.cc \
+	third_party/webrtc/base/signalthread.cc \
+	third_party/webrtc/base/socketadapters.cc \
+	third_party/webrtc/base/socketaddress.cc \
+	third_party/webrtc/base/socketaddresspair.cc \
+	third_party/webrtc/base/socketpool.cc \
+	third_party/webrtc/base/socketstream.cc \
+	third_party/webrtc/base/ssladapter.cc \
+	third_party/webrtc/base/sslfingerprint.cc \
+	third_party/webrtc/base/sslidentity.cc \
+	third_party/webrtc/base/sslsocketfactory.cc \
+	third_party/webrtc/base/sslstreamadapter.cc \
+	third_party/webrtc/base/sslstreamadapterhelper.cc \
+	third_party/webrtc/base/stream.cc \
+	third_party/webrtc/base/systeminfo.cc \
+	third_party/webrtc/base/task.cc \
+	third_party/webrtc/base/taskparent.cc \
+	third_party/webrtc/base/taskrunner.cc \
+	third_party/webrtc/base/thread.cc \
+	third_party/webrtc/base/thread_checker_impl.cc \
+	third_party/webrtc/base/timing.cc \
+	third_party/webrtc/base/unixfilesystem.cc \
+	third_party/webrtc/base/urlencode.cc \
+	third_party/webrtc/base/worker.cc \
+	third_party/webrtc/overrides/webrtc/base/logging.cc \
+	third_party/webrtc/base/openssladapter.cc \
+	third_party/webrtc/base/openssldigest.cc \
+	third_party/webrtc/base/opensslidentity.cc \
+	third_party/webrtc/base/opensslstreamadapter.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DLOGGING=1' \
+	'-DUSE_WEBRTC_DEV_BRANCH' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/overrides/include \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/source/include \
+	$(LOCAL_PATH)/third_party/boringssl/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DLOGGING=1' \
+	'-DUSE_WEBRTC_DEV_BRANCH' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/overrides/include \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/source/include \
+	$(LOCAL_PATH)/third_party/boringssl/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_base_rtc_base_gyp
+
+# Alias gyp target name.
+.PHONY: rtc_base
+rtc_base: third_party_webrtc_base_rtc_base_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/rtc_base.target.darwin-x86.mk b/base/rtc_base.target.darwin-x86.mk
index fff4716..50f5234 100644
--- a/base/rtc_base.target.darwin-x86.mk
+++ b/base/rtc_base.target.darwin-x86.mk
@@ -140,11 +140,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -163,6 +165,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -251,11 +254,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -274,6 +279,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.darwin-x86_64.mk b/base/rtc_base.target.darwin-x86_64.mk
index e6932f4..fbb7d54 100644
--- a/base/rtc_base.target.darwin-x86_64.mk
+++ b/base/rtc_base.target.darwin-x86_64.mk
@@ -139,11 +139,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -162,6 +164,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -249,11 +252,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -272,6 +277,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.linux-arm.mk b/base/rtc_base.target.linux-arm.mk
index c352b2b..5c7018c 100644
--- a/base/rtc_base.target.linux-arm.mk
+++ b/base/rtc_base.target.linux-arm.mk
@@ -145,11 +145,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -171,6 +173,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -265,11 +268,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -291,6 +296,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.linux-arm64.mk b/base/rtc_base.target.linux-arm64.mk
index f9dd503..6633e54 100644
--- a/base/rtc_base.target.linux-arm64.mk
+++ b/base/rtc_base.target.linux-arm64.mk
@@ -134,11 +134,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -147,6 +149,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -157,6 +160,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -239,11 +243,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -252,6 +258,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -262,6 +269,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.linux-mips.mk b/base/rtc_base.target.linux-mips.mk
index 5b11cbf..049b1ef 100644
--- a/base/rtc_base.target.linux-mips.mk
+++ b/base/rtc_base.target.linux-mips.mk
@@ -138,11 +138,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -163,6 +165,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -250,11 +253,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -275,6 +280,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.linux-mips64.mk b/base/rtc_base.target.linux-mips64.mk
new file mode 100644
index 0000000..b83453d
--- /dev/null
+++ b/base/rtc_base.target.linux-mips64.mk
@@ -0,0 +1,336 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_base_rtc_base_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/base/asyncfile.cc \
+	third_party/webrtc/base/asynchttprequest.cc \
+	third_party/webrtc/base/asyncsocket.cc \
+	third_party/webrtc/base/asynctcpsocket.cc \
+	third_party/webrtc/base/asyncudpsocket.cc \
+	third_party/webrtc/base/autodetectproxy.cc \
+	third_party/webrtc/base/base64.cc \
+	third_party/webrtc/base/bytebuffer.cc \
+	third_party/webrtc/base/common.cc \
+	third_party/webrtc/base/cpumonitor.cc \
+	third_party/webrtc/base/crc32.cc \
+	third_party/webrtc/base/diskcache.cc \
+	third_party/webrtc/base/event.cc \
+	third_party/webrtc/base/fileutils.cc \
+	third_party/webrtc/base/firewallsocketserver.cc \
+	third_party/webrtc/base/flags.cc \
+	third_party/webrtc/base/helpers.cc \
+	third_party/webrtc/base/httpbase.cc \
+	third_party/webrtc/base/httpclient.cc \
+	third_party/webrtc/base/httpcommon.cc \
+	third_party/webrtc/base/httprequest.cc \
+	third_party/webrtc/base/ifaddrs-android.cc \
+	third_party/webrtc/base/ipaddress.cc \
+	third_party/webrtc/base/linux.cc \
+	third_party/webrtc/base/messagedigest.cc \
+	third_party/webrtc/base/messagehandler.cc \
+	third_party/webrtc/base/messagequeue.cc \
+	third_party/webrtc/base/nethelpers.cc \
+	third_party/webrtc/base/network.cc \
+	third_party/webrtc/base/pathutils.cc \
+	third_party/webrtc/base/physicalsocketserver.cc \
+	third_party/webrtc/base/proxydetect.cc \
+	third_party/webrtc/base/proxyinfo.cc \
+	third_party/webrtc/base/ratelimiter.cc \
+	third_party/webrtc/base/ratetracker.cc \
+	third_party/webrtc/base/sha1.cc \
+	third_party/webrtc/base/signalthread.cc \
+	third_party/webrtc/base/socketadapters.cc \
+	third_party/webrtc/base/socketaddress.cc \
+	third_party/webrtc/base/socketaddresspair.cc \
+	third_party/webrtc/base/socketpool.cc \
+	third_party/webrtc/base/socketstream.cc \
+	third_party/webrtc/base/ssladapter.cc \
+	third_party/webrtc/base/sslfingerprint.cc \
+	third_party/webrtc/base/sslidentity.cc \
+	third_party/webrtc/base/sslsocketfactory.cc \
+	third_party/webrtc/base/sslstreamadapter.cc \
+	third_party/webrtc/base/sslstreamadapterhelper.cc \
+	third_party/webrtc/base/stream.cc \
+	third_party/webrtc/base/systeminfo.cc \
+	third_party/webrtc/base/task.cc \
+	third_party/webrtc/base/taskparent.cc \
+	third_party/webrtc/base/taskrunner.cc \
+	third_party/webrtc/base/thread.cc \
+	third_party/webrtc/base/thread_checker_impl.cc \
+	third_party/webrtc/base/timing.cc \
+	third_party/webrtc/base/unixfilesystem.cc \
+	third_party/webrtc/base/urlencode.cc \
+	third_party/webrtc/base/worker.cc \
+	third_party/webrtc/overrides/webrtc/base/logging.cc \
+	third_party/webrtc/base/openssladapter.cc \
+	third_party/webrtc/base/openssldigest.cc \
+	third_party/webrtc/base/opensslidentity.cc \
+	third_party/webrtc/base/opensslstreamadapter.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DLOGGING=1' \
+	'-DUSE_WEBRTC_DEV_BRANCH' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/overrides/include \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/source/include \
+	$(LOCAL_PATH)/third_party/boringssl/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DLOGGING=1' \
+	'-DUSE_WEBRTC_DEV_BRANCH' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/overrides/include \
+	$(LOCAL_PATH)/third_party/third_party/jsoncpp/source/include \
+	$(LOCAL_PATH)/third_party/boringssl/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_base_rtc_base_gyp
+
+# Alias gyp target name.
+.PHONY: rtc_base
+rtc_base: third_party_webrtc_base_rtc_base_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/rtc_base.target.linux-x86.mk b/base/rtc_base.target.linux-x86.mk
index fff4716..50f5234 100644
--- a/base/rtc_base.target.linux-x86.mk
+++ b/base/rtc_base.target.linux-x86.mk
@@ -140,11 +140,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -163,6 +165,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -251,11 +254,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -274,6 +279,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base.target.linux-x86_64.mk b/base/rtc_base.target.linux-x86_64.mk
index e6932f4..fbb7d54 100644
--- a/base/rtc_base.target.linux-x86_64.mk
+++ b/base/rtc_base.target.linux-x86_64.mk
@@ -139,11 +139,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -162,6 +164,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -249,11 +252,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -272,6 +277,7 @@
 	'-DNO_MAIN_THREAD_WRAPPING' \
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.darwin-arm.mk b/base/rtc_base_approved.target.darwin-arm.mk
index a8b08fe..3ea72cf 100644
--- a/base/rtc_base_approved.target.darwin-arm.mk
+++ b/base/rtc_base_approved.target.darwin-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +204,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.darwin-arm64.mk b/base/rtc_base_approved.target.darwin-arm64.mk
index f836ae0..3bd58bf 100644
--- a/base/rtc_base_approved.target.darwin-arm64.mk
+++ b/base/rtc_base_approved.target.darwin-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -175,11 +179,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -188,10 +194,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.darwin-mips.mk b/base/rtc_base_approved.target.darwin-mips.mk
index bf55d2e..cf2a6c0 100644
--- a/base/rtc_base_approved.target.darwin-mips.mk
+++ b/base/rtc_base_approved.target.darwin-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -186,11 +189,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.darwin-mips64.mk b/base/rtc_base_approved.target.darwin-mips64.mk
new file mode 100644
index 0000000..060a226
--- /dev/null
+++ b/base/rtc_base_approved.target.darwin-mips64.mk
@@ -0,0 +1,263 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_base_rtc_base_approved_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/base/checks.cc \
+	third_party/webrtc/base/exp_filter.cc \
+	third_party/webrtc/base/md5.cc \
+	third_party/webrtc/base/platform_file.cc \
+	third_party/webrtc/base/stringencode.cc \
+	third_party/webrtc/base/stringutils.cc \
+	third_party/webrtc/base/timeutils.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_base_rtc_base_approved_gyp
+
+# Alias gyp target name.
+.PHONY: rtc_base_approved
+rtc_base_approved: third_party_webrtc_base_rtc_base_approved_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/rtc_base_approved.target.darwin-x86.mk b/base/rtc_base_approved.target.darwin-x86.mk
index ef5db5d..e71ccfb 100644
--- a/base/rtc_base_approved.target.darwin-x86.mk
+++ b/base/rtc_base_approved.target.darwin-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.darwin-x86_64.mk b/base/rtc_base_approved.target.darwin-x86_64.mk
index 1b39de1..44ac3b0 100644
--- a/base/rtc_base_approved.target.darwin-x86_64.mk
+++ b/base/rtc_base_approved.target.darwin-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -185,11 +188,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -202,6 +207,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.linux-arm.mk b/base/rtc_base_approved.target.linux-arm.mk
index a8b08fe..3ea72cf 100644
--- a/base/rtc_base_approved.target.linux-arm.mk
+++ b/base/rtc_base_approved.target.linux-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +204,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.linux-arm64.mk b/base/rtc_base_approved.target.linux-arm64.mk
index f836ae0..3bd58bf 100644
--- a/base/rtc_base_approved.target.linux-arm64.mk
+++ b/base/rtc_base_approved.target.linux-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -175,11 +179,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -188,10 +194,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.linux-mips.mk b/base/rtc_base_approved.target.linux-mips.mk
index bf55d2e..cf2a6c0 100644
--- a/base/rtc_base_approved.target.linux-mips.mk
+++ b/base/rtc_base_approved.target.linux-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -186,11 +189,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.linux-mips64.mk b/base/rtc_base_approved.target.linux-mips64.mk
new file mode 100644
index 0000000..060a226
--- /dev/null
+++ b/base/rtc_base_approved.target.linux-mips64.mk
@@ -0,0 +1,263 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_base_rtc_base_approved_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/base/checks.cc \
+	third_party/webrtc/base/exp_filter.cc \
+	third_party/webrtc/base/md5.cc \
+	third_party/webrtc/base/platform_file.cc \
+	third_party/webrtc/base/stringencode.cc \
+	third_party/webrtc/base/stringutils.cc \
+	third_party/webrtc/base/timeutils.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_base_rtc_base_approved_gyp
+
+# Alias gyp target name.
+.PHONY: rtc_base_approved
+rtc_base_approved: third_party_webrtc_base_rtc_base_approved_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/rtc_base_approved.target.linux-x86.mk b/base/rtc_base_approved.target.linux-x86.mk
index ef5db5d..e71ccfb 100644
--- a/base/rtc_base_approved.target.linux-x86.mk
+++ b/base/rtc_base_approved.target.linux-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/rtc_base_approved.target.linux-x86_64.mk b/base/rtc_base_approved.target.linux-x86_64.mk
index 1b39de1..44ac3b0 100644
--- a/base/rtc_base_approved.target.linux-x86_64.mk
+++ b/base/rtc_base_approved.target.linux-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -185,11 +188,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -202,6 +207,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/base/webrtc_base.target.darwin-mips64.mk b/base/webrtc_base.target.darwin-mips64.mk
new file mode 100644
index 0000000..3ec755a
--- /dev/null
+++ b/base/webrtc_base.target.darwin-mips64.mk
@@ -0,0 +1,47 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := GYP
+LOCAL_MODULE := third_party_webrtc_base_webrtc_base_gyp
+LOCAL_MODULE_STEM := webrtc_base
+LOCAL_MODULE_SUFFIX := .stamp
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_webrtc_base_rtc_base_gyp,,,$(GYP_VAR_PREFIX))/third_party_webrtc_base_rtc_base_gyp.a
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_base_webrtc_base_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_base
+webrtc_base: third_party_webrtc_base_webrtc_base_gyp
+
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_VAR_PREFIX)
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
+	$(hide) echo "Gyp timestamp: $@"
+	$(hide) mkdir -p $(dir $@)
+	$(hide) touch $@
+
+LOCAL_2ND_ARCH_VAR_PREFIX :=
diff --git a/base/webrtc_base.target.linux-mips64.mk b/base/webrtc_base.target.linux-mips64.mk
new file mode 100644
index 0000000..3ec755a
--- /dev/null
+++ b/base/webrtc_base.target.linux-mips64.mk
@@ -0,0 +1,47 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := GYP
+LOCAL_MODULE := third_party_webrtc_base_webrtc_base_gyp
+LOCAL_MODULE_STEM := webrtc_base
+LOCAL_MODULE_SUFFIX := .stamp
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_webrtc_base_rtc_base_gyp,,,$(GYP_VAR_PREFIX))/third_party_webrtc_base_rtc_base_gyp.a
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_base_webrtc_base_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_base
+webrtc_base: third_party_webrtc_base_webrtc_base_gyp
+
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_VAR_PREFIX)
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
+	$(hide) echo "Gyp timestamp: $@"
+	$(hide) mkdir -p $(dir $@)
+	$(hide) touch $@
+
+LOCAL_2ND_ARCH_VAR_PREFIX :=
diff --git a/build/common.gypi b/build/common.gypi
index 18b3383..366e7e9 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -42,6 +42,7 @@
       'modules_java_gyp_path%': '<(modules_java_gyp_path)',
       'gen_core_neon_offsets_gyp%': '<(gen_core_neon_offsets_gyp)',
       'webrtc_vp8_dir%': '<(webrtc_root)/modules/video_coding/codecs/vp8',
+      'webrtc_vp9_dir%': '<(webrtc_root)/modules/video_coding/codecs/vp9',
       'rbe_components_path%': '<(webrtc_root)/modules/remote_bitrate_estimator',
       'include_opus%': 1,
     },
@@ -52,6 +53,7 @@
     'modules_java_gyp_path%': '<(modules_java_gyp_path)',
     'gen_core_neon_offsets_gyp%': '<(gen_core_neon_offsets_gyp)',
     'webrtc_vp8_dir%': '<(webrtc_vp8_dir)',
+    'webrtc_vp9_dir%': '<(webrtc_vp9_dir)',
     'include_opus%': '<(include_opus)',
     'rtc_relative_path%': 1,
     'rbe_components_path%': '<(rbe_components_path)',
@@ -250,6 +252,11 @@
           }],
         ],
       }],
+      ['target_arch=="arm64"', {
+        'defines': [
+          'WEBRTC_ARCH_ARM',
+        ],
+      }],
       ['target_arch=="arm" or target_arch=="armv7"', {
         'defines': [
           'WEBRTC_ARCH_ARM',
@@ -267,7 +274,7 @@
           }],
         ],
       }],
-      ['target_arch=="mipsel"', {
+      ['target_arch=="mipsel" and mips_arch_variant!="r6"', {
         'defines': [
           'MIPS32_LE',
         ],
diff --git a/build/isolate.gypi b/build/isolate.gypi
index 2e86020..86169fd 100644
--- a/build/isolate.gypi
+++ b/build/isolate.gypi
@@ -62,18 +62,6 @@
         # Files that are known to be involved in this step.
         '<(DEPTH)/tools/swarming_client/isolate.py',
         '<(DEPTH)/tools/swarming_client/run_isolated.py',
-
-        # Disable file tracking by the build driver for now. This means the
-        # project must have the proper build-time dependency for their runtime
-        # dependency. This improves the runtime of the build driver since it
-        # doesn't have to stat() all these files.
-        #
-        # More importantly, it means that even if a isolate_dependency_tracked
-        # file is missing, for example if a file was deleted and the .isolate
-        # file was not updated, that won't break the build, especially in the
-        # case where foo_tests_run is not built! This should be reenabled once
-        # the switch-over to running tests on Swarm is completed.
-        #'<@(isolate_dependency_tracked)',
       ],
       'outputs': [
         '<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated',
diff --git a/build/merge_libs.gyp b/build/merge_libs.gyp
index d661002..d28d71b 100644
--- a/build/merge_libs.gyp
+++ b/build/merge_libs.gyp
@@ -21,6 +21,8 @@
         '../webrtc.gyp:webrtc',
         '../sound/sound.gyp:rtc_sound',
         '../libjingle/xmllite/xmllite.gyp:rtc_xmllite',
+        '../libjingle/xmpp/xmpp.gyp:rtc_xmpp',
+        '../p2p/p2p.gyp:rtc_p2p',
       ],
       'sources': ['no_op.cc',],
     },
diff --git a/build/tsan_suppressions_webrtc.cc b/build/tsan_suppressions_webrtc.cc
index 723e62a..01658ed 100644
--- a/build/tsan_suppressions_webrtc.cc
+++ b/build/tsan_suppressions_webrtc.cc
@@ -27,6 +27,7 @@
 "race:rtc::MessageQueue::Quit\n"
 "race:FileVideoCapturerTest::VideoCapturerListener::OnFrameCaptured\n"
 "race:vp8cx_remove_encoder_threads\n"
+"race:third_party/libvpx/source/libvpx/vp9/common/vp9_scan.h\n"
 
 // Usage of trace callback and trace level is racy in libjingle_media_unittests.
 // https://code.google.com/p/webrtc/issues/detail?id=3372
diff --git a/common_audio/BUILD.gn b/common_audio/BUILD.gn
index 455e527..ba1d179 100644
--- a/common_audio/BUILD.gn
+++ b/common_audio/BUILD.gn
@@ -19,6 +19,8 @@
 
 source_set("common_audio") {
   sources = [
+    "audio_converter.cc",
+    "audio_converter.h",
     "audio_util.cc",
     "blocker.cc",
     "blocker.h",
@@ -69,7 +71,9 @@
     "signal_processing/splitting_filter.c",
     "signal_processing/sqrt_of_one_minus_x_squared.c",
     "signal_processing/vector_scaling_operations.c",
+    "vad/include/vad.h",
     "vad/include/webrtc_vad.h",
+    "vad/vad.cc",
     "vad/webrtc_vad.c",
     "vad/vad_core.c",
     "vad/vad_core.h",
@@ -81,8 +85,8 @@
     "vad/vad_sp.h",
     "wav_header.cc",
     "wav_header.h",
-    "wav_writer.cc",
-    "wav_writer.h",
+    "wav_file.cc",
+    "wav_file.h",
     "window_generator.cc",
     "window_generator.h",
   ]
diff --git a/common_audio/audio_converter.cc b/common_audio/audio_converter.cc
new file mode 100644
index 0000000..f085ff1
--- /dev/null
+++ b/common_audio/audio_converter.cc
@@ -0,0 +1,110 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/audio_converter.h"
+#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
+
+namespace webrtc {
+namespace {
+
+void DownmixToMono(const float* const* src,
+                   int src_channels,
+                   int frames,
+                   float* dst) {
+  DCHECK_GT(src_channels, 0);
+  for (int i = 0; i < frames; ++i) {
+    float sum = 0;
+    for (int j = 0; j < src_channels; ++j)
+      sum += src[j][i];
+    dst[i] = sum / src_channels;
+  }
+}
+
+void UpmixFromMono(const float* src,
+                   int dst_channels,
+                   int frames,
+                   float* const* dst) {
+  DCHECK_GT(dst_channels, 0);
+  for (int i = 0; i < frames; ++i) {
+    float value = src[i];
+    for (int j = 0; j < dst_channels; ++j)
+      dst[j][i] = value;
+  }
+}
+
+}  // namespace
+
+AudioConverter::AudioConverter(int src_channels, int src_frames,
+                               int dst_channels, int dst_frames)
+    : src_channels_(src_channels),
+      src_frames_(src_frames),
+      dst_channels_(dst_channels),
+      dst_frames_(dst_frames) {
+  CHECK(dst_channels == src_channels || dst_channels == 1 || src_channels == 1);
+  const int resample_channels = std::min(src_channels, dst_channels);
+
+  // Prepare buffers as needed for intermediate stages.
+  if (dst_channels < src_channels)
+    downmix_buffer_.reset(new ChannelBuffer<float>(src_frames,
+                                                   resample_channels));
+
+  if (src_frames != dst_frames) {
+    resamplers_.reserve(resample_channels);
+    for (int i = 0; i < resample_channels; ++i)
+      resamplers_.push_back(new PushSincResampler(src_frames, dst_frames));
+  }
+}
+
+void AudioConverter::Convert(const float* const* src,
+                             int src_channels,
+                             int src_frames,
+                             int dst_channels,
+                             int dst_frames,
+                             float* const* dst) {
+  DCHECK_EQ(src_channels_, src_channels);
+  DCHECK_EQ(src_frames_, src_frames);
+  DCHECK_EQ(dst_channels_, dst_channels);
+  DCHECK_EQ(dst_frames_, dst_frames);;
+
+  if (src_channels == dst_channels && src_frames == dst_frames) {
+    // Shortcut copy.
+    if (src != dst) {
+      for (int i = 0; i < src_channels; ++i)
+        memcpy(dst[i], src[i], dst_frames * sizeof(*dst[i]));
+    }
+    return;
+  }
+
+  const float* const* src_ptr = src;
+  if (dst_channels < src_channels) {
+    float* const* dst_ptr = dst;
+    if (src_frames != dst_frames) {
+      // Downmix to a buffer for subsequent resampling.
+      DCHECK_EQ(downmix_buffer_->num_channels(), dst_channels);
+      DCHECK_EQ(downmix_buffer_->samples_per_channel(), src_frames);
+      dst_ptr = downmix_buffer_->channels();
+    }
+
+    DownmixToMono(src, src_channels, src_frames, dst_ptr[0]);
+    src_ptr = dst_ptr;
+  }
+
+  if (src_frames != dst_frames) {
+    for (size_t i = 0; i < resamplers_.size(); ++i)
+      resamplers_[i]->Resample(src_ptr[i], src_frames, dst[i], dst_frames);
+    src_ptr = dst;
+  }
+
+  if (dst_channels > src_channels)
+    UpmixFromMono(src_ptr[0], dst_channels, dst_frames, dst);
+}
+
+}  // namespace webrtc
diff --git a/common_audio/audio_converter.h b/common_audio/audio_converter.h
new file mode 100644
index 0000000..6365f58
--- /dev/null
+++ b/common_audio/audio_converter.h
@@ -0,0 +1,55 @@
+/*
+ *  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_COMMON_AUDIO_AUDIO_CONVERTER_H_
+#define WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
+
+// TODO(ajm): Move channel buffer to common_audio.
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/modules/audio_processing/common.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/system_wrappers/interface/scoped_vector.h"
+
+namespace webrtc {
+
+class PushSincResampler;
+
+// Format conversion (remixing and resampling) for audio. Only simple remixing
+// conversions are supported: downmix to mono (i.e. |dst_channels| == 1) or
+// upmix from mono (i.e. |src_channels == 1|).
+//
+// The source and destination chunks have the same duration in time; specifying
+// the number of frames is equivalent to specifying the sample rates.
+class AudioConverter {
+ public:
+  AudioConverter(int src_channels, int src_frames,
+                 int dst_channels, int dst_frames);
+
+  void Convert(const float* const* src,
+               int src_channels,
+               int src_frames,
+               int dst_channels,
+               int dst_frames,
+               float* const* dest);
+
+ private:
+  const int src_channels_;
+  const int src_frames_;
+  const int dst_channels_;
+  const int dst_frames_;
+  scoped_ptr<ChannelBuffer<float>> downmix_buffer_;
+  ScopedVector<PushSincResampler> resamplers_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioConverter);
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
diff --git a/common_audio/audio_converter_unittest.cc b/common_audio/audio_converter_unittest.cc
new file mode 100644
index 0000000..91836f9
--- /dev/null
+++ b/common_audio/audio_converter_unittest.cc
@@ -0,0 +1,155 @@
+/*
+ *  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.
+ */
+
+#include <math.h>
+#include <algorithm>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/audio_converter.h"
+#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
+#include "webrtc/modules/audio_processing/common.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+
+typedef 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 sb(new ChannelBuffer<float>(frames, num_channels));
+  for (int i = 0; i < num_channels; ++i)
+    for (int j = 0; j < frames; ++j)
+      sb->channel(i)[j] = data[i] * j;
+  return sb;
+}
+
+void VerifyParams(const ChannelBuffer<float>& ref,
+                  const ChannelBuffer<float>& test) {
+  EXPECT_EQ(ref.num_channels(), test.num_channels());
+  EXPECT_EQ(ref.samples_per_channel(), test.samples_per_channel());
+}
+
+// Computes the best SNR based on the error between |ref_frame| and
+// |test_frame|. It searches around |expected_delay| in samples between the
+// signals to compensate for the resampling delay.
+float ComputeSNR(const ChannelBuffer<float>& ref,
+                 const ChannelBuffer<float>& test,
+                 int expected_delay) {
+  VerifyParams(ref, test);
+  float best_snr = 0;
+  int best_delay = 0;
+
+  // Search within one sample of the expected delay.
+  for (int delay = std::max(expected_delay - 1, 0);
+       delay <= std::min(expected_delay + 1, ref.samples_per_channel());
+       ++delay) {
+    float mse = 0;
+    float variance = 0;
+    float mean = 0;
+    for (int i = 0; i < ref.num_channels(); ++i) {
+      for (int j = 0; j < ref.samples_per_channel() - delay; ++j) {
+        float error = ref.channel(i)[j] - test.channel(i)[j + delay];
+        mse += error * error;
+        variance += ref.channel(i)[j] * ref.channel(i)[j];
+        mean += ref.channel(i)[j];
+      }
+    }
+    const int length = ref.num_channels() * (ref.samples_per_channel() - delay);
+    mse /= length;
+    variance /= length;
+    mean /= length;
+    variance -= mean * mean;
+    float snr = 100;  // We assign 100 dB to the zero-error case.
+    if (mse > 0)
+      snr = 10 * log10(variance / mse);
+    if (snr > best_snr) {
+      best_snr = snr;
+      best_delay = delay;
+    }
+  }
+  printf("SNR=%.1f dB at delay=%d\n", best_snr, best_delay);
+  return best_snr;
+}
+
+// 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,
+                           int src_sample_rate_hz,
+                           int dst_channels,
+                           int dst_sample_rate_hz) {
+  const float kSrcLeft = 0.0002f;
+  const float kSrcRight = 0.0001f;
+  const float resampling_factor = (1.f * src_sample_rate_hz) /
+      dst_sample_rate_hz;
+  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;
+
+  std::vector<float> src_data(1, kSrcLeft);
+  if (src_channels == 2)
+    src_data.push_back(kSrcRight);
+  ScopedBuffer src_buffer = CreateBuffer(src_data, src_frames);
+
+  std::vector<float> dst_data(1, 0);
+  std::vector<float> ref_data;
+  if (dst_channels == 1) {
+    if (src_channels == 1)
+      ref_data.push_back(dst_left);
+    else
+      ref_data.push_back(dst_mono);
+  } else {
+    dst_data.push_back(0);
+    ref_data.push_back(dst_left);
+    if (src_channels == 1)
+      ref_data.push_back(dst_left);
+    else
+      ref_data.push_back(dst_right);
+  }
+  ScopedBuffer dst_buffer = CreateBuffer(dst_data, dst_frames);
+  ScopedBuffer ref_buffer = CreateBuffer(ref_data, dst_frames);
+
+  // The sinc resampler has a known delay, which we compute here.
+  const int delay_frames = src_sample_rate_hz == dst_sample_rate_hz ? 0 :
+      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);
+
+  AudioConverter converter(src_channels, src_frames, dst_channels, dst_frames);
+  converter.Convert(src_buffer->channels(), src_channels, src_frames,
+                    dst_channels, dst_frames, dst_buffer->channels());
+
+  EXPECT_LT(43.f,
+            ComputeSNR(*ref_buffer.get(), *dst_buffer.get(), delay_frames));
+}
+
+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) {
+          RunAudioConverterTest(kChannels[src_channel], kSampleRates[src_rate],
+                                kChannels[dst_channel], kSampleRates[dst_rate]);
+        }
+      }
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/common_audio/audio_util.cc b/common_audio/audio_util.cc
index f2936b0..2047295 100644
--- a/common_audio/audio_util.cc
+++ b/common_audio/audio_util.cc
@@ -14,19 +14,29 @@
 
 namespace webrtc {
 
-void RoundToInt16(const float* src, size_t size, int16_t* dest) {
+void FloatToS16(const float* src, size_t size, int16_t* dest) {
   for (size_t i = 0; i < size; ++i)
-    dest[i] = RoundToInt16(src[i]);
+    dest[i] = FloatToS16(src[i]);
 }
 
-void ScaleAndRoundToInt16(const float* src, size_t size, int16_t* dest) {
+void S16ToFloat(const int16_t* src, size_t size, float* dest) {
   for (size_t i = 0; i < size; ++i)
-    dest[i] = ScaleAndRoundToInt16(src[i]);
+    dest[i] = S16ToFloat(src[i]);
 }
 
-void ScaleToFloat(const int16_t* src, size_t size, float* dest) {
+void FloatS16ToS16(const float* src, size_t size, int16_t* dest) {
   for (size_t i = 0; i < size; ++i)
-    dest[i] = ScaleToFloat(src[i]);
+    dest[i] = FloatS16ToS16(src[i]);
+}
+
+void FloatToFloatS16(const float* src, size_t size, float* dest) {
+  for (size_t i = 0; i < size; ++i)
+    dest[i] = FloatToFloatS16(src[i]);
+}
+
+void FloatS16ToFloat(const float* src, size_t size, float* dest) {
+  for (size_t i = 0; i < size; ++i)
+    dest[i] = FloatS16ToFloat(src[i]);
 }
 
 }  // namespace webrtc
diff --git a/common_audio/audio_util_unittest.cc b/common_audio/audio_util_unittest.cc
index bf9ad81..2cdf538 100644
--- a/common_audio/audio_util_unittest.cc
+++ b/common_audio/audio_util_unittest.cc
@@ -26,17 +26,7 @@
   }
 }
 
-TEST(AudioUtilTest, RoundToInt16) {
-  const int kSize = 7;
-  const float kInput[kSize] = {
-      0.f, 0.4f, 0.5f, -0.4f, -0.5f, 32768.f, -32769.f};
-  const int16_t kReference[kSize] = {0, 0, 1, 0, -1, 32767, -32768};
-  int16_t output[kSize];
-  RoundToInt16(kInput, kSize, output);
-  ExpectArraysEq(kReference, output, kSize);
-}
-
-TEST(AudioUtilTest, ScaleAndRoundToInt16) {
+TEST(AudioUtilTest, FloatToS16) {
   const int kSize = 9;
   const float kInput[kSize] = {
       0.f, 0.4f / 32767.f, 0.6f / 32767.f, -0.4f / 32768.f, -0.6f / 32768.f,
@@ -44,17 +34,51 @@
   const int16_t kReference[kSize] = {
     0, 0, 1, 0, -1, 32767, -32768, 32767, -32768};
   int16_t output[kSize];
-  ScaleAndRoundToInt16(kInput, kSize, output);
+  FloatToS16(kInput, kSize, output);
   ExpectArraysEq(kReference, output, kSize);
 }
 
-TEST(AudioUtilTest, ScaleToFloat) {
+TEST(AudioUtilTest, S16ToFloat) {
   const int kSize = 7;
   const int16_t kInput[kSize] = {0, 1, -1, 16384, -16384, 32767, -32768};
   const float kReference[kSize] = {
       0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f};
   float output[kSize];
-  ScaleToFloat(kInput, kSize, output);
+  S16ToFloat(kInput, kSize, output);
+  ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, FloatS16ToS16) {
+  const int kSize = 7;
+  const float kInput[kSize] = {
+      0.f, 0.4f, 0.5f, -0.4f, -0.5f, 32768.f, -32769.f};
+  const int16_t kReference[kSize] = {0, 0, 1, 0, -1, 32767, -32768};
+  int16_t output[kSize];
+  FloatS16ToS16(kInput, kSize, output);
+  ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, FloatToFloatS16) {
+  const int kSize = 9;
+  const float kInput[kSize] = {
+      0.f, 0.4f / 32767.f, 0.6f / 32767.f, -0.4f / 32768.f, -0.6f / 32768.f,
+      1.f, -1.f, 1.1f, -1.1f};
+  const float kReference[kSize] = {
+    0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f};
+  float output[kSize];
+  FloatToFloatS16(kInput, kSize, output);
+  ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, FloatS16ToFloat) {
+  const int kSize = 9;
+  const float kInput[kSize] = {
+    0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f};
+  const float kReference[kSize] = {
+      0.f, 0.4f / 32767.f, 0.6f / 32767.f, -0.4f / 32768.f, -0.6f / 32768.f,
+      1.f, -1.f, 1.1f, -1.1f};
+  float output[kSize];
+  FloatS16ToFloat(kInput, kSize, output);
   ExpectArraysEq(kReference, output, kSize);
 }
 
diff --git a/common_audio/common_audio.gyp b/common_audio/common_audio.gyp
index 66ab777..8f96674 100644
--- a/common_audio/common_audio.gyp
+++ b/common_audio/common_audio.gyp
@@ -29,6 +29,8 @@
         ],
       },
       'sources': [
+        'audio_converter.cc',
+        'audio_converter.h',
         'audio_util.cc',
         'blocker.cc',
         'blocker.h',
@@ -83,7 +85,9 @@
         'signal_processing/splitting_filter.c',
         'signal_processing/sqrt_of_one_minus_x_squared.c',
         'signal_processing/vector_scaling_operations.c',
+        'vad/include/vad.h',
         'vad/include/webrtc_vad.h',
+        'vad/vad.cc',
         'vad/webrtc_vad.c',
         'vad/vad_core.c',
         'vad/vad_core.h',
@@ -95,8 +99,8 @@
         'vad/vad_sp.h',
         'wav_header.cc',
         'wav_header.h',
-        'wav_writer.cc',
-        'wav_writer.h',
+        'wav_file.cc',
+        'wav_file.h',
         'window_generator.cc',
         'window_generator.h',
       ],
@@ -136,7 +140,7 @@
             }],
           ],  # conditions
         }],
-        ['target_arch=="mipsel"', {
+        ['target_arch=="mipsel" and mips_arch_variant!="r6"', {
           'sources': [
             'signal_processing/include/spl_inl_mips.h',
             'signal_processing/complex_bit_reverse_mips.c',
@@ -222,6 +226,7 @@
             '<(DEPTH)/testing/gtest.gyp:gtest',
           ],
           'sources': [
+            'audio_converter_unittest.cc',
             'audio_util_unittest.cc',
             'blocker_unittest.cc',
             'fir_filter_unittest.cc',
@@ -240,7 +245,7 @@
             'vad/vad_unittest.cc',
             'vad/vad_unittest.h',
             'wav_header_unittest.cc',
-            'wav_writer_unittest.cc',
+            'wav_file_unittest.cc',
             'window_generator_unittest.cc',
           ],
           'conditions': [
@@ -280,7 +285,6 @@
               ],
               'includes': [
                 '../build/isolate.gypi',
-                'common_audio_unittests.isolate',
               ],
               'sources': [
                 'common_audio_unittests.isolate',
diff --git a/common_audio/common_audio.target.darwin-arm.mk b/common_audio/common_audio.target.darwin-arm.mk
index 4d28e2e..1ee1df1 100644
--- a/common_audio/common_audio.target.darwin-arm.mk
+++ b/common_audio/common_audio.target.darwin-arm.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -61,13 +62,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc \
@@ -132,11 +134,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -153,6 +157,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON_OPTIONAL' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -249,11 +254,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -270,6 +277,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON_OPTIONAL' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.darwin-arm64.mk b/common_audio/common_audio.target.darwin-arm64.mk
index fabeaf1..27d0e13 100644
--- a/common_audio/common_audio.target.darwin-arm64.mk
+++ b/common_audio/common_audio.target.darwin-arm64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -64,13 +65,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc
@@ -121,11 +123,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -134,11 +138,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -223,11 +229,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -236,11 +244,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.darwin-mips.mk b/common_audio/common_audio.target.darwin-mips.mk
index fe76cba..c1396e4 100644
--- a/common_audio/common_audio.target.darwin-mips.mk
+++ b/common_audio/common_audio.target.darwin-mips.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -60,13 +61,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc \
@@ -129,11 +131,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -148,6 +152,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -237,11 +242,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -256,6 +263,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.darwin-mips64.mk b/common_audio/common_audio.target.darwin-mips64.mk
new file mode 100644
index 0000000..2893a03
--- /dev/null
+++ b/common_audio/common_audio.target.darwin-mips64.mk
@@ -0,0 +1,316 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_common_audio_common_audio_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
+	third_party/webrtc/common_audio/audio_util.cc \
+	third_party/webrtc/common_audio/blocker.cc \
+	third_party/webrtc/common_audio/fir_filter.cc \
+	third_party/webrtc/common_audio/resampler/push_resampler.cc \
+	third_party/webrtc/common_audio/resampler/push_sinc_resampler.cc \
+	third_party/webrtc/common_audio/resampler/resampler.cc \
+	third_party/webrtc/common_audio/resampler/sinc_resampler.cc \
+	third_party/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c \
+	third_party/webrtc/common_audio/signal_processing/auto_correlation.c \
+	third_party/webrtc/common_audio/signal_processing/complex_fft.c \
+	third_party/webrtc/common_audio/signal_processing/complex_bit_reverse.c \
+	third_party/webrtc/common_audio/signal_processing/copy_set_operations.c \
+	third_party/webrtc/common_audio/signal_processing/cross_correlation.c \
+	third_party/webrtc/common_audio/signal_processing/division_operations.c \
+	third_party/webrtc/common_audio/signal_processing/dot_product_with_scale.c \
+	third_party/webrtc/common_audio/signal_processing/downsample_fast.c \
+	third_party/webrtc/common_audio/signal_processing/energy.c \
+	third_party/webrtc/common_audio/signal_processing/filter_ar.c \
+	third_party/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c \
+	third_party/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c \
+	third_party/webrtc/common_audio/signal_processing/get_hanning_window.c \
+	third_party/webrtc/common_audio/signal_processing/get_scaling_square.c \
+	third_party/webrtc/common_audio/signal_processing/ilbc_specific_functions.c \
+	third_party/webrtc/common_audio/signal_processing/levinson_durbin.c \
+	third_party/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c \
+	third_party/webrtc/common_audio/signal_processing/min_max_operations.c \
+	third_party/webrtc/common_audio/signal_processing/randomization_functions.c \
+	third_party/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c \
+	third_party/webrtc/common_audio/signal_processing/real_fft.c \
+	third_party/webrtc/common_audio/signal_processing/resample.c \
+	third_party/webrtc/common_audio/signal_processing/resample_48khz.c \
+	third_party/webrtc/common_audio/signal_processing/resample_by_2.c \
+	third_party/webrtc/common_audio/signal_processing/resample_by_2_internal.c \
+	third_party/webrtc/common_audio/signal_processing/resample_fractional.c \
+	third_party/webrtc/common_audio/signal_processing/spl_init.c \
+	third_party/webrtc/common_audio/signal_processing/spl_sqrt.c \
+	third_party/webrtc/common_audio/signal_processing/spl_sqrt_floor.c \
+	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
+	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
+	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
+	third_party/webrtc/common_audio/vad/webrtc_vad.c \
+	third_party/webrtc/common_audio/vad/vad_core.c \
+	third_party/webrtc/common_audio/vad/vad_filterbank.c \
+	third_party/webrtc/common_audio/vad/vad_gmm.c \
+	third_party/webrtc/common_audio/vad/vad_sp.c \
+	third_party/webrtc/common_audio/wav_header.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
+	third_party/webrtc/common_audio/window_generator.cc \
+	third_party/webrtc/common_audio/lapped_transform.cc \
+	third_party/webrtc/common_audio/real_fourier.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/openmax_dl
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/openmax_dl
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_common_audio_common_audio_gyp
+
+# Alias gyp target name.
+.PHONY: common_audio
+common_audio: third_party_webrtc_common_audio_common_audio_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/common_audio/common_audio.target.darwin-x86.mk b/common_audio/common_audio.target.darwin-x86.mk
index 5358eb3..afd5529 100644
--- a/common_audio/common_audio.target.darwin-x86.mk
+++ b/common_audio/common_audio.target.darwin-x86.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -64,13 +65,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc
@@ -127,11 +129,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -144,6 +148,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -234,11 +239,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -251,6 +258,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.darwin-x86_64.mk b/common_audio/common_audio.target.darwin-x86_64.mk
index 1a99a3a..90b4dd0 100644
--- a/common_audio/common_audio.target.darwin-x86_64.mk
+++ b/common_audio/common_audio.target.darwin-x86_64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -64,13 +65,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc
@@ -126,11 +128,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -143,6 +147,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -232,11 +237,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -249,6 +256,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.linux-arm.mk b/common_audio/common_audio.target.linux-arm.mk
index 4d28e2e..1ee1df1 100644
--- a/common_audio/common_audio.target.linux-arm.mk
+++ b/common_audio/common_audio.target.linux-arm.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -61,13 +62,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc \
@@ -132,11 +134,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -153,6 +157,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON_OPTIONAL' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -249,11 +254,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -270,6 +277,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON_OPTIONAL' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.linux-arm64.mk b/common_audio/common_audio.target.linux-arm64.mk
index fabeaf1..27d0e13 100644
--- a/common_audio/common_audio.target.linux-arm64.mk
+++ b/common_audio/common_audio.target.linux-arm64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -64,13 +65,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc
@@ -121,11 +123,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -134,11 +138,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -223,11 +229,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -236,11 +244,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DDL_ARM_NEON' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.linux-mips.mk b/common_audio/common_audio.target.linux-mips.mk
index fe76cba..c1396e4 100644
--- a/common_audio/common_audio.target.linux-mips.mk
+++ b/common_audio/common_audio.target.linux-mips.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -60,13 +61,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc \
@@ -129,11 +131,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -148,6 +152,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -237,11 +242,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -256,6 +263,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.linux-mips64.mk b/common_audio/common_audio.target.linux-mips64.mk
new file mode 100644
index 0000000..2893a03
--- /dev/null
+++ b/common_audio/common_audio.target.linux-mips64.mk
@@ -0,0 +1,316 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_common_audio_common_audio_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
+	third_party/webrtc/common_audio/audio_util.cc \
+	third_party/webrtc/common_audio/blocker.cc \
+	third_party/webrtc/common_audio/fir_filter.cc \
+	third_party/webrtc/common_audio/resampler/push_resampler.cc \
+	third_party/webrtc/common_audio/resampler/push_sinc_resampler.cc \
+	third_party/webrtc/common_audio/resampler/resampler.cc \
+	third_party/webrtc/common_audio/resampler/sinc_resampler.cc \
+	third_party/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c \
+	third_party/webrtc/common_audio/signal_processing/auto_correlation.c \
+	third_party/webrtc/common_audio/signal_processing/complex_fft.c \
+	third_party/webrtc/common_audio/signal_processing/complex_bit_reverse.c \
+	third_party/webrtc/common_audio/signal_processing/copy_set_operations.c \
+	third_party/webrtc/common_audio/signal_processing/cross_correlation.c \
+	third_party/webrtc/common_audio/signal_processing/division_operations.c \
+	third_party/webrtc/common_audio/signal_processing/dot_product_with_scale.c \
+	third_party/webrtc/common_audio/signal_processing/downsample_fast.c \
+	third_party/webrtc/common_audio/signal_processing/energy.c \
+	third_party/webrtc/common_audio/signal_processing/filter_ar.c \
+	third_party/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c \
+	third_party/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c \
+	third_party/webrtc/common_audio/signal_processing/get_hanning_window.c \
+	third_party/webrtc/common_audio/signal_processing/get_scaling_square.c \
+	third_party/webrtc/common_audio/signal_processing/ilbc_specific_functions.c \
+	third_party/webrtc/common_audio/signal_processing/levinson_durbin.c \
+	third_party/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c \
+	third_party/webrtc/common_audio/signal_processing/min_max_operations.c \
+	third_party/webrtc/common_audio/signal_processing/randomization_functions.c \
+	third_party/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c \
+	third_party/webrtc/common_audio/signal_processing/real_fft.c \
+	third_party/webrtc/common_audio/signal_processing/resample.c \
+	third_party/webrtc/common_audio/signal_processing/resample_48khz.c \
+	third_party/webrtc/common_audio/signal_processing/resample_by_2.c \
+	third_party/webrtc/common_audio/signal_processing/resample_by_2_internal.c \
+	third_party/webrtc/common_audio/signal_processing/resample_fractional.c \
+	third_party/webrtc/common_audio/signal_processing/spl_init.c \
+	third_party/webrtc/common_audio/signal_processing/spl_sqrt.c \
+	third_party/webrtc/common_audio/signal_processing/spl_sqrt_floor.c \
+	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
+	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
+	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
+	third_party/webrtc/common_audio/vad/webrtc_vad.c \
+	third_party/webrtc/common_audio/vad/vad_core.c \
+	third_party/webrtc/common_audio/vad/vad_filterbank.c \
+	third_party/webrtc/common_audio/vad/vad_gmm.c \
+	third_party/webrtc/common_audio/vad/vad_sp.c \
+	third_party/webrtc/common_audio/wav_header.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
+	third_party/webrtc/common_audio/window_generator.cc \
+	third_party/webrtc/common_audio/lapped_transform.cc \
+	third_party/webrtc/common_audio/real_fourier.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/openmax_dl
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/openmax_dl
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_common_audio_common_audio_gyp
+
+# Alias gyp target name.
+.PHONY: common_audio
+common_audio: third_party_webrtc_common_audio_common_audio_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/common_audio/common_audio.target.linux-x86.mk b/common_audio/common_audio.target.linux-x86.mk
index 5358eb3..afd5529 100644
--- a/common_audio/common_audio.target.linux-x86.mk
+++ b/common_audio/common_audio.target.linux-x86.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -64,13 +65,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc
@@ -127,11 +129,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -144,6 +148,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -234,11 +239,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -251,6 +258,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio.target.linux-x86_64.mk b/common_audio/common_audio.target.linux-x86_64.mk
index 1a99a3a..90b4dd0 100644
--- a/common_audio/common_audio.target.linux-x86_64.mk
+++ b/common_audio/common_audio.target.linux-x86_64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/common_audio/audio_converter.cc \
 	third_party/webrtc/common_audio/audio_util.cc \
 	third_party/webrtc/common_audio/blocker.cc \
 	third_party/webrtc/common_audio/fir_filter.cc \
@@ -64,13 +65,14 @@
 	third_party/webrtc/common_audio/signal_processing/splitting_filter.c \
 	third_party/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
 	third_party/webrtc/common_audio/signal_processing/vector_scaling_operations.c \
+	third_party/webrtc/common_audio/vad/vad.cc \
 	third_party/webrtc/common_audio/vad/webrtc_vad.c \
 	third_party/webrtc/common_audio/vad/vad_core.c \
 	third_party/webrtc/common_audio/vad/vad_filterbank.c \
 	third_party/webrtc/common_audio/vad/vad_gmm.c \
 	third_party/webrtc/common_audio/vad/vad_sp.c \
 	third_party/webrtc/common_audio/wav_header.cc \
-	third_party/webrtc/common_audio/wav_writer.cc \
+	third_party/webrtc/common_audio/wav_file.cc \
 	third_party/webrtc/common_audio/window_generator.cc \
 	third_party/webrtc/common_audio/lapped_transform.cc \
 	third_party/webrtc/common_audio/real_fourier.cc
@@ -126,11 +128,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -143,6 +147,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -232,11 +237,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -249,6 +256,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio_neon.target.darwin-arm.mk b/common_audio/common_audio_neon.target.darwin-arm.mk
index f8ab09f..f00da32 100644
--- a/common_audio/common_audio_neon.target.darwin-arm.mk
+++ b/common_audio/common_audio_neon.target.darwin-arm.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -110,6 +112,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio_neon.target.linux-arm.mk b/common_audio/common_audio_neon.target.linux-arm.mk
index f8ab09f..f00da32 100644
--- a/common_audio/common_audio_neon.target.linux-arm.mk
+++ b/common_audio/common_audio_neon.target.linux-arm.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -110,6 +112,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio_sse2.target.darwin-x86.mk b/common_audio/common_audio_sse2.target.darwin-x86.mk
index 6c6158c..70af2b1 100644
--- a/common_audio/common_audio_sse2.target.darwin-x86.mk
+++ b/common_audio/common_audio_sse2.target.darwin-x86.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -184,11 +187,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -201,6 +206,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio_sse2.target.darwin-x86_64.mk b/common_audio/common_audio_sse2.target.darwin-x86_64.mk
index 552a99f..7f82d7e 100644
--- a/common_audio/common_audio_sse2.target.darwin-x86_64.mk
+++ b/common_audio/common_audio_sse2.target.darwin-x86_64.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -199,6 +204,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio_sse2.target.linux-x86.mk b/common_audio/common_audio_sse2.target.linux-x86.mk
index 6c6158c..70af2b1 100644
--- a/common_audio/common_audio_sse2.target.linux-x86.mk
+++ b/common_audio/common_audio_sse2.target.linux-x86.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -184,11 +187,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -201,6 +206,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio_sse2.target.linux-x86_64.mk b/common_audio/common_audio_sse2.target.linux-x86_64.mk
index 552a99f..7f82d7e 100644
--- a/common_audio/common_audio_sse2.target.linux-x86_64.mk
+++ b/common_audio/common_audio_sse2.target.linux-x86_64.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -199,6 +204,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_audio/common_audio_unittests.isolate b/common_audio/common_audio_unittests.isolate
index cc5e6ab..80eb0fc 100644
--- a/common_audio/common_audio_unittests.isolate
+++ b/common_audio/common_audio_unittests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,13 +21,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/common_audio/include/audio_util.h b/common_audio/include/audio_util.h
index 0ce034b..767b21c 100644
--- a/common_audio/include/audio_util.h
+++ b/common_audio/include/audio_util.h
@@ -20,18 +20,11 @@
 
 typedef std::numeric_limits<int16_t> limits_int16;
 
-static inline int16_t RoundToInt16(float v) {
-  const float kMaxRound = limits_int16::max() - 0.5f;
-  const float kMinRound = limits_int16::min() + 0.5f;
-  if (v > 0)
-    return v >= kMaxRound ? limits_int16::max() :
-                            static_cast<int16_t>(v + 0.5f);
-  return v <= kMinRound ? limits_int16::min() :
-                          static_cast<int16_t>(v - 0.5f);
-}
-
-// Scale (from [-1, 1]) and round to full-range int16 with clamping.
-static inline int16_t ScaleAndRoundToInt16(float v) {
+// The conversion functions use the following naming convention:
+// S16:      int16_t [-32768, 32767]
+// Float:    float   [-1.0, 1.0]
+// FloatS16: float   [-32768.0, 32767.0]
+static inline int16_t FloatToS16(float v) {
   if (v > 0)
     return v >= 1 ? limits_int16::max() :
                     static_cast<int16_t>(v * limits_int16::max() + 0.5f);
@@ -39,22 +32,37 @@
                    static_cast<int16_t>(-v * limits_int16::min() - 0.5f);
 }
 
-// Scale to float [-1, 1].
-static inline float ScaleToFloat(int16_t v) {
-  const float kMaxInt16Inverse = 1.f / limits_int16::max();
-  const float kMinInt16Inverse = 1.f / limits_int16::min();
+static inline float S16ToFloat(int16_t v) {
+  static const float kMaxInt16Inverse = 1.f / limits_int16::max();
+  static const float kMinInt16Inverse = 1.f / limits_int16::min();
   return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
 }
 
-// Round |size| elements of |src| to int16 with clamping and write to |dest|.
-void RoundToInt16(const float* src, size_t size, int16_t* dest);
+static inline int16_t FloatS16ToS16(float v) {
+  static const float kMaxRound = limits_int16::max() - 0.5f;
+  static const float kMinRound = limits_int16::min() + 0.5f;
+  if (v > 0)
+    return v >= kMaxRound ? limits_int16::max() :
+                            static_cast<int16_t>(v + 0.5f);
+  return v <= kMinRound ? limits_int16::min() :
+                          static_cast<int16_t>(v - 0.5f);
+}
 
-// Scale (from [-1, 1]) and round |size| elements of |src| to full-range int16
-// with clamping and write to |dest|.
-void ScaleAndRoundToInt16(const float* src, size_t size, int16_t* dest);
+static inline float FloatToFloatS16(float v) {
+  return v * (v > 0 ? limits_int16::max() : -limits_int16::min());
+}
 
-// Scale |size| elements of |src| to float [-1, 1] and write to |dest|.
-void ScaleToFloat(const int16_t* src, size_t size, float* dest);
+static inline float FloatS16ToFloat(float v) {
+  static const float kMaxInt16Inverse = 1.f / limits_int16::max();
+  static const float kMinInt16Inverse = 1.f / limits_int16::min();
+  return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
+}
+
+void FloatToS16(const float* src, size_t size, int16_t* dest);
+void S16ToFloat(const int16_t* src, size_t size, float* dest);
+void FloatS16ToS16(const float* src, size_t size, int16_t* dest);
+void FloatToFloatS16(const float* src, size_t size, float* dest);
+void FloatS16ToFloat(const float* src, size_t size, float* dest);
 
 // Deinterleave audio from |interleaved| to the channel buffers pointed to
 // by |deinterleaved|. There must be sufficient space allocated in the
diff --git a/common_audio/resampler/push_sinc_resampler.cc b/common_audio/resampler/push_sinc_resampler.cc
index 0275559..49e2e12 100644
--- a/common_audio/resampler/push_sinc_resampler.cc
+++ b/common_audio/resampler/push_sinc_resampler.cc
@@ -40,7 +40,7 @@
   source_ptr_int_ = source;
   // Pass NULL as the float source to have Run() read from the int16 source.
   Resample(NULL, source_length, float_buffer_.get(), destination_frames_);
-  RoundToInt16(float_buffer_.get(), destination_frames_, destination);
+  FloatS16ToS16(float_buffer_.get(), destination_frames_, destination);
   source_ptr_int_ = NULL;
   return destination_frames_;
 }
diff --git a/common_audio/resampler/push_sinc_resampler_unittest.cc b/common_audio/resampler/push_sinc_resampler_unittest.cc
index 1ca4fdf..90ac0cf 100644
--- a/common_audio/resampler/push_sinc_resampler_unittest.cc
+++ b/common_audio/resampler/push_sinc_resampler_unittest.cc
@@ -160,16 +160,15 @@
   resampler_source.Run(input_samples, source.get());
   if (int_format) {
     for (int i = 0; i < kNumBlocks; ++i) {
-      ScaleAndRoundToInt16(
-          &source[i * input_block_size], input_block_size, source_int.get());
+      FloatToS16(&source[i * input_block_size], input_block_size,
+               source_int.get());
       EXPECT_EQ(output_block_size,
                 resampler.Resample(source_int.get(),
                                    input_block_size,
                                    destination_int.get(),
                                    output_block_size));
-      ScaleToFloat(destination_int.get(),
-                   output_block_size,
-                   &resampled_destination[i * output_block_size]);
+      S16ToFloat(destination_int.get(), output_block_size,
+               &resampled_destination[i * output_block_size]);
     }
   } else {
     for (int i = 0; i < kNumBlocks; ++i) {
diff --git a/common_audio/signal_processing/complex_fft.c b/common_audio/signal_processing/complex_fft.c
index c823064..74b4258 100644
--- a/common_audio/signal_processing/complex_fft.c
+++ b/common_audio/signal_processing/complex_fft.c
@@ -65,18 +65,16 @@
                 {
                     j = i + l;
 
-                    tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
-                            - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1])), 15);
+                    tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
 
-                    ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
-                            + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j])), 15);
+                    ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
 
                     qr32 = (int32_t)frfi[2 * i];
                     qi32 = (int32_t)frfi[2 * i + 1];
-                    frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, 1);
-                    frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, 1);
-                    frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, 1);
-                    frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, 1);
+                    frfi[2 * j] = (int16_t)((qr32 - tr32) >> 1);
+                    frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> 1);
+                    frfi[2 * i] = (int16_t)((qr32 + tr32) >> 1);
+                    frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> 1);
                 }
             }
 
@@ -135,20 +133,20 @@
                             + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND;
 #endif
 
-                    tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CFFTSFT);
-                    ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CFFTSFT);
+                    tr32 >>= 15 - CFFTSFT;
+                    ti32 >>= 15 - CFFTSFT;
 
                     qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
                     qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
 
-                    frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
-                            (qr32 - tr32 + CFFTRND2), 1 + CFFTSFT);
-                    frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
-                            (qi32 - ti32 + CFFTRND2), 1 + CFFTSFT);
-                    frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
-                            (qr32 + tr32 + CFFTRND2), 1 + CFFTSFT);
-                    frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
-                            (qi32 + ti32 + CFFTRND2), 1 + CFFTSFT);
+                    frfi[2 * j] = (int16_t)(
+                        (qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT));
+                    frfi[2 * j + 1] = (int16_t)(
+                        (qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT));
+                    frfi[2 * i] = (int16_t)(
+                        (qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT));
+                    frfi[2 * i + 1] = (int16_t)(
+                        (qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT));
                 }
             }
 
@@ -219,19 +217,16 @@
                 {
                     j = i + l;
 
-                    tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0)
-                            - WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15);
+                    tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
 
-                    ti32 = WEBRTC_SPL_RSHIFT_W32(
-                            (WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0)
-                                    + WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15);
+                    ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
 
                     qr32 = (int32_t)frfi[2 * i];
                     qi32 = (int32_t)frfi[2 * i + 1];
-                    frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift);
-                    frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift);
-                    frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift);
-                    frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift);
+                    frfi[2 * j] = (int16_t)((qr32 - tr32) >> shift);
+                    frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> shift);
+                    frfi[2 * i] = (int16_t)((qr32 + tr32) >> shift);
+                    frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> shift);
                 }
             }
         } else
@@ -281,20 +276,20 @@
                     ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
                             + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CIFFTRND;
 #endif
-                    tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CIFFTSFT);
-                    ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CIFFTSFT);
+                    tr32 >>= 15 - CIFFTSFT;
+                    ti32 >>= 15 - CIFFTSFT;
 
                     qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
                     qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
 
-                    frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2),
-                                                                       shift+CIFFTSFT);
-                    frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
-                            (qi32 - ti32 + round2), shift + CIFFTSFT);
-                    frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2),
-                                                                       shift + CIFFTSFT);
-                    frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
-                            (qi32 + ti32 + round2), shift + CIFFTSFT);
+                    frfi[2 * j] = (int16_t)(
+                        (qr32 - tr32 + round2) >> (shift + CIFFTSFT));
+                    frfi[2 * j + 1] = (int16_t)(
+                        (qi32 - ti32 + round2) >> (shift + CIFFTSFT));
+                    frfi[2 * i] = (int16_t)(
+                        (qr32 + tr32 + round2) >> (shift + CIFFTSFT));
+                    frfi[2 * i + 1] = (int16_t)(
+                        (qi32 + ti32 + round2) >> (shift + CIFFTSFT));
                 }
             }
 
diff --git a/common_audio/signal_processing/division_operations.c b/common_audio/signal_processing/division_operations.c
index e9554f4..6aeb0fb 100644
--- a/common_audio/signal_processing/division_operations.c
+++ b/common_audio/signal_processing/division_operations.c
@@ -113,23 +113,20 @@
     tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
 
     // Store tmpW32 in hi and low format
-    tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
-    tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32
-            - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+    tmp_hi = (int16_t)(tmpW32 >> 16);
+    tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
 
     // tmpW32 = 1/den in Q29
     tmpW32 = ((WEBRTC_SPL_MUL_16_16(tmp_hi, approx) + (WEBRTC_SPL_MUL_16_16(tmp_low, approx)
             >> 15)) << 1);
 
     // 1/den in hi and low format
-    tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
-    tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32
-            - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+    tmp_hi = (int16_t)(tmpW32 >> 16);
+    tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
 
     // Store num in hi and low format
-    num_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(num, 16);
-    num_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((num
-            - WEBRTC_SPL_LSHIFT_W32((int32_t)num_hi, 16)), 1);
+    num_hi = (int16_t)(num >> 16);
+    num_low = (int16_t)((num - ((int32_t)num_hi << 16)) >> 1);
 
     // num * (1/den) by 32 bit multiplication (result in Q28)
 
diff --git a/common_audio/signal_processing/include/signal_processing_library.h b/common_audio/signal_processing/include/signal_processing_library.h
index e3a29ae..2bdfc23 100644
--- a/common_audio/signal_processing/include/signal_processing_library.h
+++ b/common_audio/signal_processing/include/signal_processing_library.h
@@ -40,8 +40,6 @@
     ((int32_t) ((int32_t)(a) * (int32_t)(b)))
 #define WEBRTC_SPL_UMUL(a, b) \
     ((uint32_t) ((uint32_t)(a) * (uint32_t)(b)))
-#define WEBRTC_SPL_UMUL_16_16(a, b) \
-    ((uint32_t) (uint16_t)(a) * (uint16_t)(b))
 #define WEBRTC_SPL_UMUL_32_16(a, b) \
     ((uint32_t) ((uint32_t)(a) * (uint16_t)(b)))
 #define WEBRTC_SPL_MUL_16_U16(a, b) \
@@ -89,7 +87,6 @@
 
 // Shifting with negative numbers not allowed
 // We cannot do casting here due to signed/unsigned problem
-#define WEBRTC_SPL_RSHIFT_W32(x, c)     ((x) >> (c))
 #define WEBRTC_SPL_LSHIFT_W32(x, c)     ((x) << (c))
 
 #define WEBRTC_SPL_RSHIFT_U32(x, c)     ((uint32_t)(x) >> (c))
diff --git a/common_audio/signal_processing/levinson_durbin.c b/common_audio/signal_processing/levinson_durbin.c
index 5c5d224..29f2398 100644
--- a/common_audio/signal_processing/levinson_durbin.c
+++ b/common_audio/signal_processing/levinson_durbin.c
@@ -45,9 +45,8 @@
     {
         temp1W32 = WEBRTC_SPL_LSHIFT_W32(R[i], norm);
         // Put R in hi and low format
-        R_hi[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-        R_low[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-                - WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[i], 16)), 1);
+        R_hi[i] = (int16_t)(temp1W32 >> 16);
+        R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] << 16)) >> 1);
     }
 
     // K = A[1] = -R[1] / R[0]
@@ -63,19 +62,17 @@
     }
 
     // Put K in hi and low format
-    K_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-    K_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-            - WEBRTC_SPL_LSHIFT_W32((int32_t)K_hi, 16)), 1);
+    K_hi = (int16_t)(temp1W32 >> 16);
+    K_low = (int16_t)((temp1W32 - ((int32_t)K_hi << 16)) >> 1);
 
     // Store first reflection coefficient
     K[0] = K_hi;
 
-    temp1W32 = WEBRTC_SPL_RSHIFT_W32(temp1W32, 4); // A[1] in Q27
+    temp1W32 >>= 4;  // A[1] in Q27.
 
     // Put A[1] in hi and low format
-    A_hi[1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-    A_low[1] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-            - WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[1], 16)), 1);
+    A_hi[1] = (int16_t)(temp1W32 >> 16);
+    A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] << 16)) >> 1);
 
     // Alpha = R[0] * (1-K^2)
 
@@ -86,9 +83,8 @@
     temp1W32 = (int32_t)0x7fffffffL - temp1W32; // temp1W32 = (1 - K[0]*K[0]) in Q31
 
     // Store temp1W32 = 1 - K[0]*K[0] on hi and low format
-    tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-    tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-            - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+    tmp_hi = (int16_t)(temp1W32 >> 16);
+    tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
 
     // Calculate Alpha in Q31
     temp1W32 = ((WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_hi)
@@ -99,9 +95,8 @@
 
     Alpha_exp = WebRtcSpl_NormW32(temp1W32);
     temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp);
-    Alpha_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-    Alpha_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-            - WEBRTC_SPL_LSHIFT_W32((int32_t)Alpha_hi, 16)), 1);
+    Alpha_hi = (int16_t)(temp1W32 >> 16);
+    Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
 
     // Perform the iterative calculations in the Levinson-Durbin algorithm
 
@@ -155,9 +150,8 @@
         }
 
         // Put K on hi and low format
-        K_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp3W32, 16);
-        K_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp3W32
-                - WEBRTC_SPL_LSHIFT_W32((int32_t)K_hi, 16)), 1);
+        K_hi = (int16_t)(temp3W32 >> 16);
+        K_low = (int16_t)((temp3W32 - ((int32_t)K_hi << 16)) >> 1);
 
         // Store Reflection coefficient in Q15
         K[i - 1] = K_hi;
@@ -188,18 +182,18 @@
                     + (WEBRTC_SPL_MUL_16_16(K_low, A_hi[i-j]) >> 15)) << 1);
 
             // Put Anew in hi and low format
-            A_upd_hi[j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-            A_upd_low[j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-                    - WEBRTC_SPL_LSHIFT_W32((int32_t)A_upd_hi[j], 16)), 1);
+            A_upd_hi[j] = (int16_t)(temp1W32 >> 16);
+            A_upd_low[j] = (int16_t)(
+                (temp1W32 - ((int32_t)A_upd_hi[j] << 16)) >> 1);
         }
 
         // temp3W32 = K in Q27 (Convert from Q31 to Q27)
-        temp3W32 = WEBRTC_SPL_RSHIFT_W32(temp3W32, 4);
+        temp3W32 >>= 4;
 
         // Store Anew in hi and low format
-        A_upd_hi[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp3W32, 16);
-        A_upd_low[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp3W32
-                - WEBRTC_SPL_LSHIFT_W32((int32_t)A_upd_hi[i], 16)), 1);
+        A_upd_hi[i] = (int16_t)(temp3W32 >> 16);
+        A_upd_low[i] = (int16_t)(
+            (temp3W32 - ((int32_t)A_upd_hi[i] << 16)) >> 1);
 
         // Alpha = Alpha * (1-K^2)
 
@@ -210,9 +204,8 @@
         temp1W32 = (int32_t)0x7fffffffL - temp1W32; // 1 - K*K  in Q31
 
         // Convert 1- K^2 in hi and low format
-        tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-        tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-                - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+        tmp_hi = (int16_t)(temp1W32 >> 16);
+        tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
 
         // Calculate Alpha = Alpha * (1-K^2) in Q31
         temp1W32 = ((WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_hi)
@@ -224,9 +217,8 @@
         norm = WebRtcSpl_NormW32(temp1W32);
         temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm);
 
-        Alpha_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-        Alpha_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
-                - WEBRTC_SPL_LSHIFT_W32((int32_t)Alpha_hi, 16)), 1);
+        Alpha_hi = (int16_t)(temp1W32 >> 16);
+        Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
 
         // Update the total normalization of Alpha
         Alpha_exp = Alpha_exp + norm;
@@ -253,7 +245,7 @@
         temp1W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[i], 16)
                 + WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1);
         // Round and store upper word
-        A[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32<<1)+(int32_t)32768, 16);
+        A[i] = (int16_t)(((temp1W32 << 1) + 32768) >> 16);
     }
     return 1; // Stable filters
 }
diff --git a/common_audio/signal_processing/lpc_to_refl_coef.c b/common_audio/signal_processing/lpc_to_refl_coef.c
index b1a34d4..5fb4d85 100644
--- a/common_audio/signal_processing/lpc_to_refl_coef.c
+++ b/common_audio/signal_processing/lpc_to_refl_coef.c
@@ -32,7 +32,7 @@
         // (1 - k^2) in Q30
         tmp_inv_denom32 = ((int32_t)1073741823) - WEBRTC_SPL_MUL_16_16(k16[m], k16[m]);
         // (1 - k^2) in Q15
-        tmp_inv_denom16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp_inv_denom32, 15);
+        tmp_inv_denom16 = (int16_t)(tmp_inv_denom32 >> 15);
 
         for (k = 1; k <= m; k++)
         {
@@ -47,7 +47,7 @@
 
         for (k = 1; k < m; k++)
         {
-            a16[k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32[k], 1); //Q13>>1 => Q12
+            a16[k] = (int16_t)(tmp32[k] >> 1);  // Q13>>1 => Q12
         }
 
         tmp32[m] = WEBRTC_SPL_SAT(8191, tmp32[m], -8191);
diff --git a/common_audio/signal_processing/min_max_operations_neon.S b/common_audio/signal_processing/min_max_operations_neon.S
index c84307f..f427e68 100644
--- a/common_audio/signal_processing/min_max_operations_neon.S
+++ b/common_audio/signal_processing/min_max_operations_neon.S
@@ -209,7 +209,7 @@
   cmp r1, #0
   ble END_MIN_VALUE_W16
 
-  vmov.i16 q12, #0x7FFF
+  vdup.16 q12, r2
   cmp r1, #8
   blt LOOP_MIN_VALUE_W16
 
diff --git a/common_audio/signal_processing/signal_processing_unittest.cc b/common_audio/signal_processing/signal_processing_unittest.cc
index 3d9f605..611d2bf 100644
--- a/common_audio/signal_processing/signal_processing_unittest.cc
+++ b/common_audio/signal_processing/signal_processing_unittest.cc
@@ -41,7 +41,6 @@
     EXPECT_EQ(-2147483645, WEBRTC_SPL_MUL(a, b));
     EXPECT_EQ(2147483651u, WEBRTC_SPL_UMUL(a, b));
     b = WEBRTC_SPL_WORD16_MAX >> 1;
-    EXPECT_EQ(1073627139u, WEBRTC_SPL_UMUL_16_16(a, b));
     EXPECT_EQ(4294918147u, WEBRTC_SPL_UMUL_32_16(a, b));
     EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_U16(a, b));
 
@@ -66,7 +65,6 @@
 
     // Shifting with negative numbers not allowed
     // We cannot do casting here due to signed/unsigned problem
-    EXPECT_EQ(8191, WEBRTC_SPL_RSHIFT_W32(a, 1));
     EXPECT_EQ(32766, WEBRTC_SPL_LSHIFT_W32(a, 1));
 
     EXPECT_EQ(8191u, WEBRTC_SPL_RSHIFT_U32(a, 1));
diff --git a/common_audio/signal_processing/spl_sqrt.c b/common_audio/signal_processing/spl_sqrt.c
index fff73c0..1de6ccd 100644
--- a/common_audio/signal_processing/spl_sqrt.c
+++ b/common_audio/signal_processing/spl_sqrt.c
@@ -35,11 +35,10 @@
          + 0.875*((x_half)^5)
      */
 
-    B = in;
+    B = in / 2;
 
-    B = WEBRTC_SPL_RSHIFT_W32(B, 1); // B = in/2
     B = B - ((int32_t)0x40000000); // B = in/2 - 1/2
-    x_half = (int16_t)WEBRTC_SPL_RSHIFT_W32(B, 16);// x_half = x/2 = (in-1)/2
+    x_half = (int16_t)(B >> 16);  // x_half = x/2 = (in-1)/2
     B = B + ((int32_t)0x40000000); // B = 1 + x/2
     B = B + ((int32_t)0x40000000); // Add 0.5 twice (since 1.0 does not exist in Q31)
 
@@ -47,19 +46,18 @@
     A = -x2; // A = -(x/2)^2
     B = B + (A >> 1); // B = 1 + x/2 - 0.5*(x/2)^2
 
-    A = WEBRTC_SPL_RSHIFT_W32(A, 16);
+    A >>= 16;
     A = A * A * 2; // A = (x/2)^4
-    t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
+    t16 = (int16_t)(A >> 16);
     B = B + WEBRTC_SPL_MUL_16_16(-20480, t16) * 2; // B = B - 0.625*A
     // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4
 
-    t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
     A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = (x/2)^5
-    t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
+    t16 = (int16_t)(A >> 16);
     B = B + WEBRTC_SPL_MUL_16_16(28672, t16) * 2; // B = B + 0.875*A
     // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + 0.875*(x/2)^5
 
-    t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(x2, 16);
+    t16 = (int16_t)(x2 >> 16);
     A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = x/2^3
 
     B = B + (A >> 1); // B = B + 0.5*A
@@ -154,7 +152,7 @@
         A = WEBRTC_SPL_WORD32_MAX;
     }
 
-    x_norm = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16); // x_norm = AH
+    x_norm = (int16_t)(A >> 16);  // x_norm = AH
 
     nshift = (sh / 2);
     assert(nshift >= 0);
@@ -166,17 +164,17 @@
     if (2 * nshift == sh) {
         // Even shift value case
 
-        t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16); // t16 = AH
+        t16 = (int16_t)(A >> 16);  // t16 = AH
 
         A = WEBRTC_SPL_MUL_16_16(k_sqrt_2, t16) * 2; // A = 1/sqrt(2)*t16
         A = A + ((int32_t)32768); // Round off
         A = A & ((int32_t)0x7fff0000); // Round off
 
-        A = WEBRTC_SPL_RSHIFT_W32(A, 15); // A = A>>16
+        A >>= 15;  // A = A>>16
 
     } else
     {
-        A = WEBRTC_SPL_RSHIFT_W32(A, 16); // A = A>>16
+        A >>= 16;  // A = A>>16
     }
 
     A = A & ((int32_t)0x0000ffff);
diff --git a/common_audio/signal_processing/splitting_filter.c b/common_audio/signal_processing/splitting_filter.c
index 4f6430c..15c3724 100644
--- a/common_audio/signal_processing/splitting_filter.c
+++ b/common_audio/signal_processing/splitting_filter.c
@@ -156,12 +156,10 @@
     // branches to get upper & lower band.
     for (i = 0; i < band_length; i++)
     {
-        tmp = filter1[i] + filter2[i] + 1024;
-        tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11);
+        tmp = (filter1[i] + filter2[i] + 1024) >> 11;
         low_band[i] = WebRtcSpl_SatW32ToW16(tmp);
 
-        tmp = filter1[i] - filter2[i] + 1024;
-        tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11);
+        tmp = (filter1[i] - filter2[i] + 1024) >> 11;
         high_band[i] = WebRtcSpl_SatW32ToW16(tmp);
     }
 }
@@ -200,10 +198,10 @@
     // saturation.
     for (i = 0, k = 0; i < band_length; i++)
     {
-        tmp = WEBRTC_SPL_RSHIFT_W32(filter2[i] + 512, 10);
+        tmp = (filter2[i] + 512) >> 10;
         out_data[k++] = WebRtcSpl_SatW32ToW16(tmp);
 
-        tmp = WEBRTC_SPL_RSHIFT_W32(filter1[i] + 512, 10);
+        tmp = (filter1[i] + 512) >> 10;
         out_data[k++] = WebRtcSpl_SatW32ToW16(tmp);
     }
 
diff --git a/common_audio/vad/include/vad.h b/common_audio/vad/include/vad.h
new file mode 100644
index 0000000..f1d1212
--- /dev/null
+++ b/common_audio/vad/include/vad.h
@@ -0,0 +1,45 @@
+/*
+ *  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_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/vad/include/webrtc_vad.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+// This is a C++ wrapper class for WebRtcVad.
+class Vad {
+ public:
+  enum Aggressiveness {
+    kVadNormal = 0,
+    kVadLowBitrate = 1,
+    kVadAggressive = 2,
+    kVadVeryAggressive = 3
+  };
+
+  enum Activity { kPassive = 0, kActive = 1, kError = -1 };
+
+  explicit Vad(enum Aggressiveness mode);
+
+  virtual ~Vad();
+
+  enum Activity VoiceActivity(const int16_t* audio,
+                              size_t num_samples,
+                              int sample_rate_hz);
+
+ private:
+  VadInst* handle_;
+};
+
+}  // namespace webrtc
+#endif  // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
diff --git a/common_audio/vad/mock/mock_vad.h b/common_audio/vad/mock/mock_vad.h
new file mode 100644
index 0000000..f1d8c22
--- /dev/null
+++ b/common_audio/vad/mock/mock_vad.h
@@ -0,0 +1,34 @@
+/*
+ *  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_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
+#define WEBRTC_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
+
+#include "webrtc/common_audio/vad/include/vad.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace webrtc {
+
+class MockVad : public Vad {
+ public:
+  explicit MockVad(enum Aggressiveness mode) {}
+  virtual ~MockVad() { Die(); }
+  MOCK_METHOD0(Die, void());
+
+  MOCK_METHOD3(VoiceActivity,
+               enum Activity(const int16_t* audio,
+                             size_t num_samples,
+                             int sample_rate_hz));
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
diff --git a/common_audio/vad/vad.cc b/common_audio/vad/vad.cc
new file mode 100644
index 0000000..9cc0c19
--- /dev/null
+++ b/common_audio/vad/vad.cc
@@ -0,0 +1,43 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/common_audio/vad/include/vad.h"
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+Vad::Vad(enum Aggressiveness mode) {
+  CHECK_EQ(WebRtcVad_Create(&handle_), 0);
+  CHECK_EQ(WebRtcVad_Init(handle_), 0);
+  CHECK_EQ(WebRtcVad_set_mode(handle_, mode), 0);
+}
+
+Vad::~Vad() {
+  WebRtcVad_Free(handle_);
+}
+
+enum Vad::Activity Vad::VoiceActivity(const int16_t* audio,
+                                      size_t num_samples,
+                                      int sample_rate_hz) {
+  int ret = WebRtcVad_Process(
+      handle_, sample_rate_hz, audio, static_cast<int>(num_samples));
+  switch (ret) {
+    case 0:
+      return kPassive;
+    case 1:
+      return kActive;
+    default:
+      DCHECK(false) << "WebRtcVad_Process returned an error.";
+      return kError;
+  }
+}
+
+}  // namespace webrtc
diff --git a/common_audio/wav_file.cc b/common_audio/wav_file.cc
new file mode 100644
index 0000000..880e1ec
--- /dev/null
+++ b/common_audio/wav_file.cc
@@ -0,0 +1,166 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/common_audio/wav_file.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <limits>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/include/audio_util.h"
+#include "webrtc/common_audio/wav_header.h"
+
+namespace webrtc {
+
+// We write 16-bit PCM WAV files.
+static const WavFormat kWavFormat = kWavFormatPcm;
+static const int kBytesPerSample = 2;
+
+WavReader::WavReader(const std::string& filename)
+    : file_handle_(fopen(filename.c_str(), "rb")) {
+  CHECK(file_handle_);
+  uint8_t header[kWavHeaderSize];
+  const size_t read =
+      fread(header, sizeof(*header), kWavHeaderSize, file_handle_);
+  CHECK_EQ(kWavHeaderSize, read);
+
+  WavFormat format;
+  int bytes_per_sample;
+  CHECK(ReadWavHeader(header, &num_channels_, &sample_rate_, &format,
+                      &bytes_per_sample, &num_samples_));
+  CHECK_EQ(kWavFormat, format);
+  CHECK_EQ(kBytesPerSample, bytes_per_sample);
+}
+
+WavReader::~WavReader() {
+  Close();
+}
+
+size_t WavReader::ReadSamples(size_t num_samples, int16_t* samples) {
+#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
+#error "Need to convert samples to big-endian when reading from WAV file"
+#endif
+  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.
+  CHECK(read == num_samples || feof(file_handle_));
+  return read;
+}
+
+size_t WavReader::ReadSamples(size_t num_samples, float* samples) {
+  static const size_t kChunksize = 4096 / sizeof(uint16_t);
+  size_t read = 0;
+  for (size_t i = 0; i < num_samples; i += kChunksize) {
+    int16_t isamples[kChunksize];
+    size_t chunk = std::min(kChunksize, num_samples - i);
+    chunk = ReadSamples(chunk, isamples);
+    for (size_t j = 0; j < chunk; ++j)
+      samples[i + j] = isamples[j];
+    read += chunk;
+  }
+  return read;
+}
+
+void WavReader::Close() {
+  CHECK_EQ(0, fclose(file_handle_));
+  file_handle_ = NULL;
+}
+
+WavWriter::WavWriter(const std::string& filename, int sample_rate,
+                     int num_channels)
+    : sample_rate_(sample_rate),
+      num_channels_(num_channels),
+      num_samples_(0),
+      file_handle_(fopen(filename.c_str(), "wb")) {
+  CHECK(file_handle_);
+  CHECK(CheckWavParameters(num_channels_,
+                           sample_rate_,
+                           kWavFormat,
+                           kBytesPerSample,
+                           num_samples_));
+
+  // Write a blank placeholder header, since we need to know the total number
+  // of samples before we can fill in the real data.
+  static const uint8_t blank_header[kWavHeaderSize] = {0};
+  CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
+}
+
+WavWriter::~WavWriter() {
+  Close();
+}
+
+void WavWriter::WriteSamples(const int16_t* samples, size_t num_samples) {
+#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
+#error "Need to convert samples to little-endian when writing to WAV file"
+#endif
+  const size_t written =
+      fwrite(samples, sizeof(*samples), num_samples, file_handle_);
+  CHECK_EQ(num_samples, written);
+  num_samples_ += static_cast<uint32_t>(written);
+  CHECK(written <= std::numeric_limits<uint32_t>::max() ||
+        num_samples_ >= written);  // detect uint32_t overflow
+  CHECK(CheckWavParameters(num_channels_,
+                           sample_rate_,
+                           kWavFormat,
+                           kBytesPerSample,
+                           num_samples_));
+}
+
+void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
+  static const size_t kChunksize = 4096 / sizeof(uint16_t);
+  for (size_t i = 0; i < num_samples; i += kChunksize) {
+    int16_t isamples[kChunksize];
+    const size_t chunk = std::min(kChunksize, num_samples - i);
+    FloatS16ToS16(samples + i, chunk, isamples);
+    WriteSamples(isamples, chunk);
+  }
+}
+
+void WavWriter::Close() {
+  CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
+  uint8_t header[kWavHeaderSize];
+  WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
+                 kBytesPerSample, num_samples_);
+  CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
+  CHECK_EQ(0, fclose(file_handle_));
+  file_handle_ = NULL;
+}
+
+}  // namespace webrtc
+
+rtc_WavWriter* rtc_WavOpen(const char* filename,
+                           int sample_rate,
+                           int num_channels) {
+  return reinterpret_cast<rtc_WavWriter*>(
+      new webrtc::WavWriter(filename, sample_rate, num_channels));
+}
+
+void rtc_WavClose(rtc_WavWriter* wf) {
+  delete reinterpret_cast<webrtc::WavWriter*>(wf);
+}
+
+void rtc_WavWriteSamples(rtc_WavWriter* wf,
+                         const float* samples,
+                         size_t num_samples) {
+  reinterpret_cast<webrtc::WavWriter*>(wf)->WriteSamples(samples, num_samples);
+}
+
+int rtc_WavSampleRate(const rtc_WavWriter* wf) {
+  return reinterpret_cast<const webrtc::WavWriter*>(wf)->sample_rate();
+}
+
+int rtc_WavNumChannels(const rtc_WavWriter* wf) {
+  return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_channels();
+}
+
+uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf) {
+  return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_samples();
+}
diff --git a/common_audio/wav_file.h b/common_audio/wav_file.h
new file mode 100644
index 0000000..c6c5d6b
--- /dev/null
+++ b/common_audio/wav_file.h
@@ -0,0 +1,98 @@
+/*
+ *  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_COMMON_AUDIO_WAV_FILE_H_
+#define WEBRTC_COMMON_AUDIO_WAV_FILE_H_
+
+#ifdef __cplusplus
+
+#include <stdint.h>
+#include <cstddef>
+#include <string>
+
+namespace webrtc {
+
+// Simple C++ class for writing 16-bit PCM WAV files. All error handling is
+// by calls to CHECK(), making it unsuitable for anything but debug code.
+class WavWriter {
+ public:
+  // Open a new WAV file for writing.
+  WavWriter(const std::string& filename, int sample_rate, int num_channels);
+
+  // Close the WAV file, after writing its header.
+  ~WavWriter();
+
+  // Write additional samples to the file. Each sample is in the range
+  // [-32768,32767], and there must be the previously specified number of
+  // interleaved channels.
+  void WriteSamples(const float* samples, size_t num_samples);
+  void WriteSamples(const int16_t* samples, size_t num_samples);
+
+  int sample_rate() const { return sample_rate_; }
+  int num_channels() const { return num_channels_; }
+  uint32_t num_samples() const { 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.
+  FILE* file_handle_;  // Output file, owned by this class
+};
+
+// Follows the conventions of WavWriter.
+class WavReader {
+ public:
+  // Opens an existing WAV file for reading.
+  explicit WavReader(const std::string& filename);
+
+  // Close the WAV file.
+  ~WavReader();
+
+  // Returns the number of samples read. If this is less than requested,
+  // verifies that the end of the file was reached.
+  size_t ReadSamples(size_t num_samples, float* samples);
+  size_t ReadSamples(size_t num_samples, int16_t* samples);
+
+  int sample_rate() const { return sample_rate_; }
+  int num_channels() const { return num_channels_; }
+  uint32_t num_samples() const { return num_samples_; }
+
+ private:
+  void Close();
+  int sample_rate_;
+  int num_channels_;
+  uint32_t num_samples_;  // Total number of samples in the file.
+  FILE* file_handle_;  // Input file, owned by this class.
+};
+
+}  // namespace webrtc
+
+extern "C" {
+#endif  // __cplusplus
+
+// C wrappers for the WavWriter class.
+typedef struct rtc_WavWriter rtc_WavWriter;
+rtc_WavWriter* rtc_WavOpen(const char* filename,
+                           int sample_rate,
+                           int 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);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // WEBRTC_COMMON_AUDIO_WAV_FILE_H_
diff --git a/common_audio/wav_writer_unittest.cc b/common_audio/wav_file_unittest.cc
similarity index 82%
rename from common_audio/wav_writer_unittest.cc
rename to common_audio/wav_file_unittest.cc
index 9c593be..1bdb655 100644
--- a/common_audio/wav_writer_unittest.cc
+++ b/common_audio/wav_file_unittest.cc
@@ -17,7 +17,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/base/compile_assert.h"
 #include "webrtc/common_audio/wav_header.h"
-#include "webrtc/common_audio/wav_writer.h"
+#include "webrtc/common_audio/wav_file.h"
 #include "webrtc/test/testsupport/fileutils.h"
 
 static const float kSamples[] = {0.0, 10.0, 4e4, -1e9};
@@ -27,7 +27,7 @@
   const std::string outfile = webrtc::test::OutputPath() + "wavtest1.wav";
   static const uint32_t kNumSamples = 3;
   {
-    webrtc::WavFile w(outfile, 14099, 1);
+    webrtc::WavWriter w(outfile, 14099, 1);
     EXPECT_EQ(14099, w.sample_rate());
     EXPECT_EQ(1, w.num_channels());
     EXPECT_EQ(0u, w.num_samples());
@@ -62,12 +62,24 @@
   ASSERT_EQ(1u, fread(contents, kContentSize, 1, f));
   EXPECT_EQ(0, fclose(f));
   EXPECT_EQ(0, memcmp(kExpectedContents, contents, kContentSize));
+
+  {
+    webrtc::WavReader r(outfile);
+    EXPECT_EQ(14099, r.sample_rate());
+    EXPECT_EQ(1, r.num_channels());
+    EXPECT_EQ(kNumSamples, r.num_samples());
+    static const float kTruncatedSamples[] = {0.0, 10.0, 32767.0};
+    float samples[kNumSamples];
+    EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, samples));
+    EXPECT_EQ(0, memcmp(kTruncatedSamples, samples, sizeof(samples)));
+    EXPECT_EQ(0u, r.ReadSamples(kNumSamples, samples));
+  }
 }
 
 // Write a tiny WAV file with the C interface and verify the result.
 TEST(WavWriterTest, C) {
   const std::string outfile = webrtc::test::OutputPath() + "wavtest2.wav";
-  rtc_WavFile *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
+  rtc_WavWriter *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
   EXPECT_EQ(11904, rtc_WavSampleRate(w));
   EXPECT_EQ(2, rtc_WavNumChannels(w));
   EXPECT_EQ(0u, rtc_WavNumSamples(w));
@@ -125,7 +137,7 @@
     samples[i + 1] = std::pow(std::cos(t * 2 * 2 * M_PI), 10) * x;
   }
   {
-    webrtc::WavFile w(outfile, kSampleRate, kNumChannels);
+    webrtc::WavWriter w(outfile, kSampleRate, kNumChannels);
     EXPECT_EQ(kSampleRate, w.sample_rate());
     EXPECT_EQ(kNumChannels, w.num_channels());
     EXPECT_EQ(0u, w.num_samples());
@@ -134,4 +146,18 @@
   }
   EXPECT_EQ(sizeof(int16_t) * kNumSamples + webrtc::kWavHeaderSize,
             webrtc::test::GetFileSize(outfile));
+
+  {
+    webrtc::WavReader r(outfile);
+    EXPECT_EQ(kSampleRate, r.sample_rate());
+    EXPECT_EQ(kNumChannels, r.num_channels());
+    EXPECT_EQ(kNumSamples, r.num_samples());
+
+    float read_samples[kNumSamples];
+    EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, read_samples));
+    for (size_t i = 0; i < kNumSamples; ++i)
+      EXPECT_NEAR(samples[i], read_samples[i], 1);
+
+    EXPECT_EQ(0u, r.ReadSamples(kNumSamples, read_samples));
+  }
 }
diff --git a/common_audio/wav_header.cc b/common_audio/wav_header.cc
index ce43896..8c781fb 100644
--- a/common_audio/wav_header.cc
+++ b/common_audio/wav_header.cc
@@ -18,9 +18,11 @@
 #include <cstring>
 #include <limits>
 
+#include "webrtc/base/checks.h"
 #include "webrtc/common_audio/include/audio_util.h"
 
 namespace webrtc {
+namespace {
 
 struct ChunkHeader {
   uint32_t ID;
@@ -28,6 +30,34 @@
 };
 COMPILE_ASSERT(sizeof(ChunkHeader) == 8, chunk_header_size);
 
+// We can't nest this definition in WavHeader, because VS2013 gives an error
+// on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand".
+struct FmtSubchunk {
+  ChunkHeader header;
+  uint16_t AudioFormat;
+  uint16_t NumChannels;
+  uint32_t SampleRate;
+  uint32_t ByteRate;
+  uint16_t BlockAlign;
+  uint16_t BitsPerSample;
+};
+COMPILE_ASSERT(sizeof(FmtSubchunk) == 24, fmt_subchunk_size);
+const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader);
+
+struct WavHeader {
+  struct {
+    ChunkHeader header;
+    uint32_t Format;
+  } riff;
+  FmtSubchunk fmt;
+  struct {
+    ChunkHeader header;
+  } data;
+};
+COMPILE_ASSERT(sizeof(WavHeader) == kWavHeaderSize, no_padding_in_header);
+
+}  // namespace
+
 bool CheckWavParameters(int num_channels,
                         int sample_rate,
                         WavFormat format,
@@ -91,54 +121,53 @@
       | static_cast<uint32_t>(c) << 16
       | static_cast<uint32_t>(d) << 24;
 }
+
+static inline uint16_t ReadLE16(uint16_t x) { return x; }
+static inline uint32_t ReadLE32(uint32_t x) { return x; }
+static inline std::string ReadFourCC(uint32_t x) {
+  return std::string(reinterpret_cast<char*>(&x), 4);
+}
 #else
 #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 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 uint16_t BlockAlign(int num_channels, int bytes_per_sample) {
+  return num_channels * bytes_per_sample;
+}
+
 void WriteWavHeader(uint8_t* buf,
                     int num_channels,
                     int sample_rate,
                     WavFormat format,
                     int bytes_per_sample,
                     uint32_t num_samples) {
-  assert(CheckWavParameters(num_channels, sample_rate, format,
-                            bytes_per_sample, num_samples));
+  CHECK(CheckWavParameters(num_channels, sample_rate, format,
+                           bytes_per_sample, num_samples));
 
-  struct {
-    struct {
-      ChunkHeader header;
-      uint32_t Format;
-    } riff;
-    struct {
-      ChunkHeader header;
-      uint16_t AudioFormat;
-      uint16_t NumChannels;
-      uint32_t SampleRate;
-      uint32_t ByteRate;
-      uint16_t BlockAlign;
-      uint16_t BitsPerSample;
-    } fmt;
-    struct {
-      ChunkHeader header;
-    } data;
-  } header;
-  COMPILE_ASSERT(sizeof(header) == kWavHeaderSize, no_padding_in_header);
-
+  WavHeader header;
   const uint32_t bytes_in_payload = bytes_per_sample * num_samples;
 
   WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F');
-  WriteLE32(&header.riff.header.Size,
-            bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader));
+  WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload));
   WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E');
 
   WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' ');
-  WriteLE32(&header.fmt.header.Size, sizeof(header.fmt) - sizeof(ChunkHeader));
+  WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize);
   WriteLE16(&header.fmt.AudioFormat, format);
   WriteLE16(&header.fmt.NumChannels, num_channels);
   WriteLE32(&header.fmt.SampleRate, sample_rate);
-  WriteLE32(&header.fmt.ByteRate, (static_cast<uint32_t>(num_channels)
-                                   * sample_rate * bytes_per_sample));
-  WriteLE16(&header.fmt.BlockAlign, num_channels * bytes_per_sample);
+  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);
 
   WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a');
@@ -149,4 +178,49 @@
   memcpy(buf, &header, kWavHeaderSize);
 }
 
+bool ReadWavHeader(const uint8_t* buf,
+                   int* num_channels,
+                   int* sample_rate,
+                   WavFormat* format,
+                   int* bytes_per_sample,
+                   uint32_t* num_samples) {
+  WavHeader header;
+  memcpy(&header, buf, kWavHeaderSize);
+
+  // Parse needed fields.
+  *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
+  *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)
+    return false;
+  *num_samples = bytes_in_payload / *bytes_per_sample;
+
+  // Sanity check remaining fields.
+  if (ReadFourCC(header.riff.header.ID) != "RIFF")
+    return false;
+  if (ReadFourCC(header.riff.Format) != "WAVE")
+    return false;
+  if (ReadFourCC(header.fmt.header.ID) != "fmt ")
+    return false;
+  if (ReadFourCC(header.data.header.ID) != "data")
+    return false;
+
+  if (ReadLE32(header.riff.header.Size) != RiffChunkSize(bytes_in_payload))
+    return false;
+  if (ReadLE32(header.fmt.header.Size) != kFmtSubchunkSize)
+    return false;
+  if (ReadLE32(header.fmt.ByteRate) !=
+      ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
+    return false;
+  if (ReadLE16(header.fmt.BlockAlign) !=
+      BlockAlign(*num_channels, *bytes_per_sample))
+    return false;
+
+  return CheckWavParameters(*num_channels, *sample_rate, *format,
+                            *bytes_per_sample, *num_samples);
+}
+
+
 }  // namespace webrtc
diff --git a/common_audio/wav_header.h b/common_audio/wav_header.h
index f9ed8a5..37f78a6 100644
--- a/common_audio/wav_header.h
+++ b/common_audio/wav_header.h
@@ -11,11 +11,12 @@
 #ifndef WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
 #define WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
 namespace webrtc {
 
-static const int kWavHeaderSize = 44;
+static const size_t kWavHeaderSize = 44;
 
 enum WavFormat {
   kWavFormatPcm   = 1,  // PCM, each sample of size bytes_per_sample
@@ -33,7 +34,7 @@
 // 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.
+// type. CHECKs the input parameters for validity.
 void WriteWavHeader(uint8_t* buf,
                     int num_channels,
                     int sample_rate,
@@ -41,6 +42,15 @@
                     int bytes_per_sample,
                     uint32_t num_samples);
 
+// Read a kWavHeaderSize bytes long WAV header from buf and parse the values
+// into the provided output parameters. Returns false if the header is invalid.
+bool ReadWavHeader(const uint8_t* buf,
+                   int* num_channels,
+                   int* sample_rate,
+                   WavFormat* format,
+                   int* bytes_per_sample,
+                   uint32_t* num_samples);
+
 }  // namespace webrtc
 
 #endif  // WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
diff --git a/common_audio/wav_header_unittest.cc b/common_audio/wav_header_unittest.cc
index f05160e..677affa 100644
--- a/common_audio/wav_header_unittest.cc
+++ b/common_audio/wav_header_unittest.cc
@@ -48,8 +48,80 @@
       webrtc::CheckWavParameters(3, 8000, webrtc::kWavFormatPcm, 1, 5));
 }
 
-// Try writing a WAV header and make sure it looks OK.
-TEST(WavHeaderTest, WriteWavHeader) {
+TEST(WavHeaderTest, ReadWavHeaderWithErrors) {
+  int num_channels = 0;
+  int sample_rate = 0;
+  webrtc::WavFormat format = webrtc::kWavFormatPcm;
+  int bytes_per_sample = 0;
+  uint32_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
+  // invalid field is indicated in the array name, and in the comments with
+  // *BAD*.
+  static const uint8_t kBadRiffID[] = {
+    'R', 'i', 'f', 'f',  // *BAD*
+    0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
+    'W', 'A', 'V', 'E',
+    'f', 'm', 't', ' ',
+    16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
+    6, 0,  // format: A-law (6)
+    17, 0,  // channels: 17
+    0x39, 0x30, 0, 0,  // sample rate: 12345
+    0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
+    17, 0,  // block align: NumChannels * BytesPerSample
+    8, 0,  // bits per sample: 1 * 8
+    'd', 'a', 't', 'a',
+    0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+    0xa4, 0xa4, 0xa4, 0xa4,  // untouched bytes after header
+  };
+  EXPECT_FALSE(
+      webrtc::ReadWavHeader(kBadRiffID, &num_channels, &sample_rate,
+                            &format, &bytes_per_sample, &num_samples));
+
+  static const uint8_t kBadBitsPerSample[] = {
+    'R', 'I', 'F', 'F',
+    0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
+    'W', 'A', 'V', 'E',
+    'f', 'm', 't', ' ',
+    16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
+    6, 0,  // format: A-law (6)
+    17, 0,  // channels: 17
+    0x39, 0x30, 0, 0,  // sample rate: 12345
+    0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
+    17, 0,  // block align: NumChannels * BytesPerSample
+    1, 0,  // bits per sample: *BAD*
+    'd', 'a', 't', 'a',
+    0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+    0xa4, 0xa4, 0xa4, 0xa4,  // untouched bytes after header
+  };
+  EXPECT_FALSE(
+      webrtc::ReadWavHeader(kBadBitsPerSample, &num_channels, &sample_rate,
+                            &format, &bytes_per_sample, &num_samples));
+
+  static const uint8_t kBadByteRate[] = {
+    'R', 'I', 'F', 'F',
+    0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
+    'W', 'A', 'V', 'E',
+    'f', 'm', 't', ' ',
+    16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
+    6, 0,  // format: A-law (6)
+    17, 0,  // channels: 17
+    0x39, 0x30, 0, 0,  // sample rate: 12345
+    0x00, 0x33, 0x03, 0,  // byte rate: *BAD*
+    17, 0,  // block align: NumChannels * BytesPerSample
+    8, 0,  // bits per sample: 1 * 8
+    'd', 'a', 't', 'a',
+    0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+    0xa4, 0xa4, 0xa4, 0xa4,  // untouched bytes after header
+  };
+  EXPECT_FALSE(
+      webrtc::ReadWavHeader(kBadByteRate, &num_channels, &sample_rate,
+                            &format, &bytes_per_sample, &num_samples));
+}
+
+// Try writing and reading a valid WAV header and make sure it looks OK.
+TEST(WavHeaderTest, WriteAndReadWavHeader) {
   static const int kSize = 4 + webrtc::kWavHeaderSize + 4;
   uint8_t buf[kSize];
   memset(buf, 0xa4, sizeof(buf));
@@ -74,4 +146,18 @@
   };
   COMPILE_ASSERT(sizeof(kExpectedBuf) == kSize, buf_size);
   EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
+
+  int num_channels = 0;
+  int sample_rate = 0;
+  webrtc::WavFormat format = webrtc::kWavFormatPcm;
+  int bytes_per_sample = 0;
+  uint32_t num_samples = 0;
+  EXPECT_TRUE(
+      webrtc::ReadWavHeader(buf + 4, &num_channels, &sample_rate, &format,
+                            &bytes_per_sample, &num_samples));
+  EXPECT_EQ(17, num_channels);
+  EXPECT_EQ(12345, sample_rate);
+  EXPECT_EQ(webrtc::kWavFormatALaw, format);
+  EXPECT_EQ(1, bytes_per_sample);
+  EXPECT_EQ(123457689u, num_samples);
 }
diff --git a/common_audio/wav_writer.cc b/common_audio/wav_writer.cc
deleted file mode 100644
index 30a220c..0000000
--- a/common_audio/wav_writer.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- *  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.
- */
-
-#include "webrtc/common_audio/wav_writer.h"
-
-#include <algorithm>
-#include <cstdio>
-#include <limits>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/wav_header.h"
-
-namespace webrtc {
-
-// We write 16-bit PCM WAV files.
-static const WavFormat kWavFormat = kWavFormatPcm;
-static const int kBytesPerSample = 2;
-
-WavFile::WavFile(const std::string& filename, int sample_rate, int num_channels)
-    : sample_rate_(sample_rate),
-      num_channels_(num_channels),
-      num_samples_(0),
-      file_handle_(fopen(filename.c_str(), "wb")) {
-  CHECK(file_handle_);
-  CHECK(CheckWavParameters(num_channels_,
-                           sample_rate_,
-                           kWavFormat,
-                           kBytesPerSample,
-                           num_samples_));
-
-  // Write a blank placeholder header, since we need to know the total number
-  // of samples before we can fill in the real data.
-  static const uint8_t blank_header[kWavHeaderSize] = {0};
-  CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
-}
-
-WavFile::~WavFile() {
-  Close();
-}
-
-void WavFile::WriteSamples(const int16_t* samples, size_t num_samples) {
-#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
-#error "Need to convert samples to little-endian when writing to WAV file"
-#endif
-  const size_t written =
-      fwrite(samples, sizeof(*samples), num_samples, file_handle_);
-  CHECK_EQ(num_samples, written);
-  num_samples_ += static_cast<uint32_t>(written);
-  CHECK(written <= std::numeric_limits<uint32_t>::max() ||
-        num_samples_ >= written);  // detect uint32_t overflow
-  CHECK(CheckWavParameters(num_channels_,
-                           sample_rate_,
-                           kWavFormat,
-                           kBytesPerSample,
-                           num_samples_));
-}
-
-void WavFile::WriteSamples(const float* samples, size_t num_samples) {
-  static const size_t kChunksize = 4096 / sizeof(uint16_t);
-  for (size_t i = 0; i < num_samples; i += kChunksize) {
-    int16_t isamples[kChunksize];
-    const size_t chunk = std::min(kChunksize, num_samples - i);
-    RoundToInt16(samples + i, chunk, isamples);
-    WriteSamples(isamples, chunk);
-  }
-}
-
-void WavFile::Close() {
-  CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
-  uint8_t header[kWavHeaderSize];
-  WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
-                 kBytesPerSample, num_samples_);
-  CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
-  CHECK_EQ(0, fclose(file_handle_));
-  file_handle_ = NULL;
-}
-
-}  // namespace webrtc
-
-rtc_WavFile* rtc_WavOpen(const char* filename,
-                         int sample_rate,
-                         int num_channels) {
-  return reinterpret_cast<rtc_WavFile*>(
-      new webrtc::WavFile(filename, sample_rate, num_channels));
-}
-
-void rtc_WavClose(rtc_WavFile* wf) {
-  delete reinterpret_cast<webrtc::WavFile*>(wf);
-}
-
-void rtc_WavWriteSamples(rtc_WavFile* wf,
-                         const float* samples,
-                         size_t num_samples) {
-  reinterpret_cast<webrtc::WavFile*>(wf)->WriteSamples(samples, num_samples);
-}
-
-int rtc_WavSampleRate(const rtc_WavFile* wf) {
-  return reinterpret_cast<const webrtc::WavFile*>(wf)->sample_rate();
-}
-
-int rtc_WavNumChannels(const rtc_WavFile* wf) {
-  return reinterpret_cast<const webrtc::WavFile*>(wf)->num_channels();
-}
-
-uint32_t rtc_WavNumSamples(const rtc_WavFile* wf) {
-  return reinterpret_cast<const webrtc::WavFile*>(wf)->num_samples();
-}
diff --git a/common_audio/wav_writer.h b/common_audio/wav_writer.h
deleted file mode 100644
index 0966727..0000000
--- a/common_audio/wav_writer.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  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_COMMON_AUDIO_WAV_WRITER_H_
-#define WEBRTC_COMMON_AUDIO_WAV_WRITER_H_
-
-#ifdef __cplusplus
-
-#include <stdint.h>
-#include <cstddef>
-#include <string>
-
-namespace webrtc {
-
-// Simple C++ class for writing 16-bit PCM WAV files. All error handling is
-// by calls to CHECK(), making it unsuitable for anything but debug code.
-class WavFile {
- public:
-  // Open a new WAV file for writing.
-  WavFile(const std::string& filename, int sample_rate, int num_channels);
-
-  // Close the WAV file, after writing its header.
-  ~WavFile();
-
-  // Write additional samples to the file. Each sample is in the range
-  // [-32768,32767], and there must be the previously specified number of
-  // interleaved channels.
-  void WriteSamples(const float* samples, size_t num_samples);
-  void WriteSamples(const int16_t* samples, size_t num_samples);
-
-  int sample_rate() const { return sample_rate_; }
-  int num_channels() const { return num_channels_; }
-  uint32_t num_samples() const { 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
-  FILE* file_handle_;  // output file, owned by this class
-};
-
-}  // namespace webrtc
-
-extern "C" {
-#endif  // __cplusplus
-
-// C wrappers for the WavFile class.
-typedef struct rtc_WavFile rtc_WavFile;
-rtc_WavFile* rtc_WavOpen(const char* filename,
-                         int sample_rate,
-                         int num_channels);
-void rtc_WavClose(rtc_WavFile* wf);
-void rtc_WavWriteSamples(rtc_WavFile* wf,
-                         const float* samples,
-                         size_t num_samples);
-int rtc_WavSampleRate(const rtc_WavFile* wf);
-int rtc_WavNumChannels(const rtc_WavFile* wf);
-uint32_t rtc_WavNumSamples(const rtc_WavFile* wf);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // WEBRTC_COMMON_AUDIO_WAV_WRITER_H_
diff --git a/common_types.h b/common_types.h
index e607ddc..7bcfd6d 100644
--- a/common_types.h
+++ b/common_types.h
@@ -202,17 +202,31 @@
   RtcpPacketTypeCounter()
     : nack_packets(0),
       fir_packets(0),
-      pli_packets(0) {}
+      pli_packets(0),
+      nack_requests(0),
+      unique_nack_requests(0) {}
 
   void Add(const RtcpPacketTypeCounter& other) {
     nack_packets += other.nack_packets;
     fir_packets += other.fir_packets;
     pli_packets += other.pli_packets;
+    nack_requests += other.nack_requests;
+    unique_nack_requests += other.unique_nack_requests;
   }
 
-  uint32_t nack_packets;
-  uint32_t fir_packets;
-  uint32_t pli_packets;
+  int UniqueNackRequestsInPercent() const {
+    if (nack_requests == 0) {
+      return 0;
+    }
+    return static_cast<int>(
+        (unique_nack_requests * 100.0f / nack_requests) + 0.5f);
+  }
+
+  uint32_t nack_packets;          // Number of RTCP NACK packets.
+  uint32_t fir_packets;           // Number of RTCP FIR packets.
+  uint32_t pli_packets;           // Number of RTCP PLI packets.
+  uint32_t nack_requests;         // Number of NACKed RTP packets.
+  uint32_t unique_nack_requests;  // Number of unique NACKed RTP packets.
 };
 
 // Data usage statistics for a (rtp) stream
@@ -597,35 +611,45 @@
   }
 };
 
+// VP9 specific
+struct VideoCodecVP9 {
+  VideoCodecComplexity complexity;
+  int                  resilience;
+  unsigned char        numberOfTemporalLayers;
+  bool                 denoisingOn;
+  bool                 frameDroppingOn;
+  int                  keyFrameInterval;
+  bool                 adaptiveQpMode;
+};
+
 // H264 specific.
-struct VideoCodecH264
-{
-    VideoCodecProfile profile;
-    bool           frameDroppingOn;
-    int            keyFrameInterval;
-    // These are NULL/0 if not externally negotiated.
-    const uint8_t* spsData;
-    size_t         spsLen;
-    const uint8_t* ppsData;
-    size_t         ppsLen;
+struct VideoCodecH264 {
+  VideoCodecProfile profile;
+  bool           frameDroppingOn;
+  int            keyFrameInterval;
+  // These are NULL/0 if not externally negotiated.
+  const uint8_t* spsData;
+  size_t         spsLen;
+  const uint8_t* ppsData;
+  size_t         ppsLen;
 };
 
 // Video codec types
-enum VideoCodecType
-{
-    kVideoCodecVP8,
-    kVideoCodecH264,
-    kVideoCodecI420,
-    kVideoCodecRED,
-    kVideoCodecULPFEC,
-    kVideoCodecGeneric,
-    kVideoCodecUnknown
+enum VideoCodecType {
+  kVideoCodecVP8,
+  kVideoCodecVP9,
+  kVideoCodecH264,
+  kVideoCodecI420,
+  kVideoCodecRED,
+  kVideoCodecULPFEC,
+  kVideoCodecGeneric,
+  kVideoCodecUnknown
 };
 
-union VideoCodecUnion
-{
-    VideoCodecVP8       VP8;
-    VideoCodecH264      H264;
+union VideoCodecUnion {
+  VideoCodecVP8       VP8;
+  VideoCodecVP9       VP9;
+  VideoCodecH264      H264;
 };
 
 
diff --git a/common_video/common_video.target.darwin-arm.mk b/common_video/common_video.target.darwin-arm.mk
index f896804..d9bdd3c 100644
--- a/common_video/common_video.target.darwin-arm.mk
+++ b/common_video/common_video.target.darwin-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -225,6 +230,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.darwin-arm64.mk b/common_video/common_video.target.darwin-arm64.mk
index 79d074e..b84c5e7 100644
--- a/common_video/common_video.target.darwin-arm64.mk
+++ b/common_video/common_video.target.darwin-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -192,10 +198,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.darwin-mips.mk b/common_video/common_video.target.darwin-mips.mk
index c2afbeb..0df9250 100644
--- a/common_video/common_video.target.darwin-mips.mk
+++ b/common_video/common_video.target.darwin-mips.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.darwin-mips64.mk b/common_video/common_video.target.darwin-mips64.mk
new file mode 100644
index 0000000..a7ba725
--- /dev/null
+++ b/common_video/common_video.target.darwin-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_common_video_common_video_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/common_video/i420_video_frame.cc \
+	third_party/webrtc/common_video/libyuv/webrtc_libyuv.cc \
+	third_party/webrtc/common_video/libyuv/scaler.cc \
+	third_party/webrtc/common_video/plane.cc \
+	third_party/webrtc/common_video/texture_video_frame.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libyuv/include \
+	$(LOCAL_PATH)/third_party/libyuv
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libyuv/include \
+	$(LOCAL_PATH)/third_party/libyuv
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_common_video_common_video_gyp
+
+# Alias gyp target name.
+.PHONY: common_video
+common_video: third_party_webrtc_common_video_common_video_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/common_video/common_video.target.darwin-x86.mk b/common_video/common_video.target.darwin-x86.mk
index 137d960..642d181 100644
--- a/common_video/common_video.target.darwin-x86.mk
+++ b/common_video/common_video.target.darwin-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.darwin-x86_64.mk b/common_video/common_video.target.darwin-x86_64.mk
index 7d6c591..a169d9c 100644
--- a/common_video/common_video.target.darwin-x86_64.mk
+++ b/common_video/common_video.target.darwin-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.linux-arm.mk b/common_video/common_video.target.linux-arm.mk
index f896804..d9bdd3c 100644
--- a/common_video/common_video.target.linux-arm.mk
+++ b/common_video/common_video.target.linux-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -225,6 +230,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.linux-arm64.mk b/common_video/common_video.target.linux-arm64.mk
index 79d074e..b84c5e7 100644
--- a/common_video/common_video.target.linux-arm64.mk
+++ b/common_video/common_video.target.linux-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -192,10 +198,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.linux-mips.mk b/common_video/common_video.target.linux-mips.mk
index c2afbeb..0df9250 100644
--- a/common_video/common_video.target.linux-mips.mk
+++ b/common_video/common_video.target.linux-mips.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.linux-mips64.mk b/common_video/common_video.target.linux-mips64.mk
new file mode 100644
index 0000000..a7ba725
--- /dev/null
+++ b/common_video/common_video.target.linux-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_common_video_common_video_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/common_video/i420_video_frame.cc \
+	third_party/webrtc/common_video/libyuv/webrtc_libyuv.cc \
+	third_party/webrtc/common_video/libyuv/scaler.cc \
+	third_party/webrtc/common_video/plane.cc \
+	third_party/webrtc/common_video/texture_video_frame.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libyuv/include \
+	$(LOCAL_PATH)/third_party/libyuv
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libyuv/include \
+	$(LOCAL_PATH)/third_party/libyuv
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_common_video_common_video_gyp
+
+# Alias gyp target name.
+.PHONY: common_video
+common_video: third_party_webrtc_common_video_common_video_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/common_video/common_video.target.linux-x86.mk b/common_video/common_video.target.linux-x86.mk
index 137d960..642d181 100644
--- a/common_video/common_video.target.linux-x86.mk
+++ b/common_video/common_video.target.linux-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video.target.linux-x86_64.mk b/common_video/common_video.target.linux-x86_64.mk
index 7d6c591..a169d9c 100644
--- a/common_video/common_video.target.linux-x86_64.mk
+++ b/common_video/common_video.target.linux-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/common_video/common_video_unittests.gyp b/common_video/common_video_unittests.gyp
index 0405ba0..9189991 100644
--- a/common_video/common_video_unittests.gyp
+++ b/common_video/common_video_unittests.gyp
@@ -60,7 +60,6 @@
           ],
           'includes': [
             '../build/isolate.gypi',
-            'common_video_unittests.isolate',
           ],
           'sources': [
             'common_video_unittests.isolate',
diff --git a/common_video/common_video_unittests.isolate b/common_video/common_video_unittests.isolate
index d33366c..7082365 100644
--- a/common_video/common_video_unittests.isolate
+++ b/common_video/common_video_unittests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,15 +21,12 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/common_video_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/DEPS',
           '<(DEPTH)/resources/foreman_cif.yuv',
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/common_video_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/config.cc b/config.cc
index e0324b9..70bd870 100644
--- a/config.cc
+++ b/config.cc
@@ -39,10 +39,10 @@
   ss << ", max_bitrate_bps:" << max_bitrate_bps;
   ss << ", max_qp: " << max_qp;
 
-  ss << ", temporal_layers: {";
-  for (size_t i = 0; i < temporal_layers.size(); ++i) {
-    ss << temporal_layers[i];
-    if (i != temporal_layers.size() - 1)
+  ss << ", temporal_layer_thresholds_bps: {";
+  for (size_t i = 0; i < temporal_layer_thresholds_bps.size(); ++i) {
+    ss << temporal_layer_thresholds_bps[i];
+    if (i != temporal_layer_thresholds_bps.size() - 1)
       ss << "}, {";
   }
   ss << '}';
@@ -50,4 +50,32 @@
   ss << '}';
   return ss.str();
 }
+
+std::string VideoEncoderConfig::ToString() const {
+  std::stringstream ss;
+
+  ss << "{streams: {";
+  for (size_t i = 0; i < streams.size(); ++i) {
+    ss << streams[i].ToString();
+    if (i != streams.size() - 1)
+      ss << "}, {";
+  }
+  ss << '}';
+  ss << ", content_type: ";
+  switch (content_type) {
+    case kRealtimeVideo:
+      ss << "kRealtimeVideo";
+      break;
+    case kScreenshare:
+      ss << "kScreenshare";
+      break;
+  }
+  ss << ", encoder_specific_settings: ";
+  ss << (encoder_specific_settings != NULL ? "(ptr)" : "NULL");
+
+  ss << ", min_transmit_bitrate_bps: " << min_transmit_bitrate_bps;
+  ss << '}';
+  return ss.str();
+}
+
 }  // namespace webrtc
diff --git a/config.h b/config.h
index 6f3fb1d..8ea2828 100644
--- a/config.h
+++ b/config.h
@@ -104,8 +104,17 @@
 
   int max_qp;
 
-  // Bitrate thresholds for enabling additional temporal layers.
-  std::vector<int> temporal_layers;
+  // Bitrate thresholds for enabling additional temporal layers. Since these are
+  // thresholds in between layers, we have one additional layer. One threshold
+  // gives two temporal layers, one below the threshold and one above, two give
+  // three, and so on.
+  // The VideoEncoder may redistribute bitrates over the temporal layers so a
+  // bitrate threshold of 100k and an estimate of 105k does not imply that we
+  // get 100k in one temporal layer and 5k in the other, just that the bitrate
+  // in the first temporal layer should not exceed 100k.
+  // TODO(pbos): Apart from a special case for two-layer screencast these
+  // thresholds are not propagated to the VideoEncoder. To be implemented.
+  std::vector<int> temporal_layer_thresholds_bps;
 };
 
 struct VideoEncoderConfig {
@@ -115,11 +124,21 @@
   };
 
   VideoEncoderConfig()
-      : content_type(kRealtimeVideo), encoder_specific_settings(NULL) {}
+      : content_type(kRealtimeVideo),
+        encoder_specific_settings(NULL),
+        min_transmit_bitrate_bps(0) {}
+
+  std::string ToString() const;
 
   std::vector<VideoStream> streams;
   ContentType content_type;
   void* encoder_specific_settings;
+
+  // Padding will be used up to this bitrate regardless of the bitrate produced
+  // by the encoder. Padding above what's actually produced by the encoder helps
+  // maintaining a higher bitrate estimate. Padding will however not be sent
+  // unless the estimated bandwidth indicates that the link can handle it.
+  int min_transmit_bitrate_bps;
 };
 
 }  // namespace webrtc
diff --git a/engine_configurations.h b/engine_configurations.h
index e9f2309..5b093e5 100644
--- a/engine_configurations.h
+++ b/engine_configurations.h
@@ -21,13 +21,14 @@
 //  [Voice] Codec settings
 // ----------------------------------------------------------------------------
 
-// iSAC is not included in the Mozilla build, but in all other builds.
+// iSAC and G722 are not included in the Mozilla build, but in all other builds.
 #ifndef WEBRTC_MOZILLA_BUILD
 #ifdef WEBRTC_ARCH_ARM
 #define WEBRTC_CODEC_ISACFX  // Fix-point iSAC implementation.
 #else
 #define WEBRTC_CODEC_ISAC  // Floating-point iSAC implementation (default).
 #endif  // WEBRTC_ARCH_ARM
+#define WEBRTC_CODEC_G722
 #endif  // !WEBRTC_MOZILLA_BUILD
 
 // AVT is included in all builds, along with G.711, NetEQ and CNG
@@ -37,11 +38,10 @@
 // PCM16 is useful for testing and incurs only a small binary size cost.
 #define WEBRTC_CODEC_PCM16
 
-// iLBC, G.722, and Redundancy coding are excluded from Chromium and Mozilla
+// iLBC and Redundancy coding are excluded from Chromium and Mozilla
 // builds to reduce binary size.
 #if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_MOZILLA_BUILD)
 #define WEBRTC_CODEC_ILBC
-#define WEBRTC_CODEC_G722
 #define WEBRTC_CODEC_RED
 #endif  // !WEBRTC_CHROMIUM_BUILD && !WEBRTC_MOZILLA_BUILD
 
@@ -51,6 +51,7 @@
 
 #define VIDEOCODEC_I420
 #define VIDEOCODEC_VP8
+#define VIDEOCODEC_VP9
 #define VIDEOCODEC_H264
 
 // ============================================================================
diff --git a/examples/android/media_demo/build.xml b/examples/android/media_demo/build.xml
index c8a51dd..1773488 100644
--- a/examples/android/media_demo/build.xml
+++ b/examples/android/media_demo/build.xml
@@ -1,15 +1,92 @@
 <?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/examples/android/media_demo/project.properties b/examples/android/media_demo/project.properties
index 162fe60..8ee39b9 100644
--- a/examples/android/media_demo/project.properties
+++ b/examples/android/media_demo/project.properties
@@ -11,4 +11,4 @@
 #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
 
 # Project target.
-target=android-19
+target=android-21
diff --git a/examples/android/opensl_loopback/project.properties b/examples/android/opensl_loopback/project.properties
index 8459f9b..47b7078 100644
--- a/examples/android/opensl_loopback/project.properties
+++ b/examples/android/opensl_loopback/project.properties
@@ -11,6 +11,6 @@
 #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
 
 # Project target.
-target=android-19
+target=android-21
 
 java.compilerargs=-Xlint:all -Werror
diff --git a/libjingle/xmllite/rtc_xmllite.target.darwin-arm.mk b/libjingle/xmllite/rtc_xmllite.target.darwin-arm.mk
index b7f2f9c..92f43a7 100644
--- a/libjingle/xmllite/rtc_xmllite.target.darwin-arm.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.darwin-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,6 +116,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -207,11 +210,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -232,6 +237,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.darwin-arm64.mk b/libjingle/xmllite/rtc_xmllite.target.darwin-arm64.mk
index d443071..1042bec 100644
--- a/libjingle/xmllite/rtc_xmllite.target.darwin-arm64.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.darwin-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,6 +93,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -100,6 +103,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -194,6 +200,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -203,6 +210,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.darwin-mips.mk b/libjingle/xmllite/rtc_xmllite.target.darwin-mips.mk
index e1e9f6e..d7f0305 100644
--- a/libjingle/xmllite/rtc_xmllite.target.darwin-mips.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.darwin-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -216,6 +221,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.darwin-mips64.mk b/libjingle/xmllite/rtc_xmllite.target.darwin-mips64.mk
new file mode 100644
index 0000000..106a5e0
--- /dev/null
+++ b/libjingle/xmllite/rtc_xmllite.target.darwin-mips64.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_libjingle_xmllite_rtc_xmllite_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/libjingle/xmllite/qname.cc \
+	third_party/webrtc/libjingle/xmllite/xmlbuilder.cc \
+	third_party/webrtc/libjingle/xmllite/xmlconstants.cc \
+	third_party/webrtc/libjingle/xmllite/xmlelement.cc \
+	third_party/webrtc/libjingle/xmllite/xmlnsstack.cc \
+	third_party/webrtc/libjingle/xmllite/xmlparser.cc \
+	third_party/webrtc/libjingle/xmllite/xmlprinter.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/expat/files/lib
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/expat/files/lib
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_libjingle_xmllite_rtc_xmllite_gyp
+
+# Alias gyp target name.
+.PHONY: rtc_xmllite
+rtc_xmllite: third_party_webrtc_libjingle_xmllite_rtc_xmllite_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libjingle/xmllite/rtc_xmllite.target.darwin-x86.mk b/libjingle/xmllite/rtc_xmllite.target.darwin-x86.mk
index 3064430..7d9225c 100644
--- a/libjingle/xmllite/rtc_xmllite.target.darwin-x86.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.darwin-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.darwin-x86_64.mk b/libjingle/xmllite/rtc_xmllite.target.darwin-x86_64.mk
index f7426fe..dc3674d 100644
--- a/libjingle/xmllite/rtc_xmllite.target.darwin-x86_64.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.darwin-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -105,6 +107,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -213,6 +218,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.linux-arm.mk b/libjingle/xmllite/rtc_xmllite.target.linux-arm.mk
index b7f2f9c..92f43a7 100644
--- a/libjingle/xmllite/rtc_xmllite.target.linux-arm.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.linux-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,6 +116,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -207,11 +210,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -232,6 +237,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.linux-arm64.mk b/libjingle/xmllite/rtc_xmllite.target.linux-arm64.mk
index d443071..1042bec 100644
--- a/libjingle/xmllite/rtc_xmllite.target.linux-arm64.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.linux-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,6 +93,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -100,6 +103,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -194,6 +200,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -203,6 +210,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.linux-mips.mk b/libjingle/xmllite/rtc_xmllite.target.linux-mips.mk
index e1e9f6e..d7f0305 100644
--- a/libjingle/xmllite/rtc_xmllite.target.linux-mips.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.linux-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -216,6 +221,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.linux-mips64.mk b/libjingle/xmllite/rtc_xmllite.target.linux-mips64.mk
new file mode 100644
index 0000000..106a5e0
--- /dev/null
+++ b/libjingle/xmllite/rtc_xmllite.target.linux-mips64.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_libjingle_xmllite_rtc_xmllite_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/libjingle/xmllite/qname.cc \
+	third_party/webrtc/libjingle/xmllite/xmlbuilder.cc \
+	third_party/webrtc/libjingle/xmllite/xmlconstants.cc \
+	third_party/webrtc/libjingle/xmllite/xmlelement.cc \
+	third_party/webrtc/libjingle/xmllite/xmlnsstack.cc \
+	third_party/webrtc/libjingle/xmllite/xmlparser.cc \
+	third_party/webrtc/libjingle/xmllite/xmlprinter.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/expat/files/lib
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DFEATURE_ENABLE_SSL' \
+	'-DNO_MAIN_THREAD_WRAPPING' \
+	'-DSSL_USE_OPENSSL' \
+	'-DHAVE_OPENSSL_SSL_H' \
+	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/expat/files/lib
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_libjingle_xmllite_rtc_xmllite_gyp
+
+# Alias gyp target name.
+.PHONY: rtc_xmllite
+rtc_xmllite: third_party_webrtc_libjingle_xmllite_rtc_xmllite_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libjingle/xmllite/rtc_xmllite.target.linux-x86.mk b/libjingle/xmllite/rtc_xmllite.target.linux-x86.mk
index 3064430..7d9225c 100644
--- a/libjingle/xmllite/rtc_xmllite.target.linux-x86.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.linux-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmllite/rtc_xmllite.target.linux-x86_64.mk b/libjingle/xmllite/rtc_xmllite.target.linux-x86_64.mk
index f7426fe..dc3674d 100644
--- a/libjingle/xmllite/rtc_xmllite.target.linux-x86_64.mk
+++ b/libjingle/xmllite/rtc_xmllite.target.linux-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -105,6 +107,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -213,6 +218,7 @@
 	'-DSSL_USE_OPENSSL' \
 	'-DHAVE_OPENSSL_SSL_H' \
 	'-DXML_STATIC' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/libjingle/xmpp/OWNERS b/libjingle/xmpp/OWNERS
new file mode 100644
index 0000000..1a24a6a
--- /dev/null
+++ b/libjingle/xmpp/OWNERS
@@ -0,0 +1,13 @@
+henrika@webrtc.org
+henrike@webrtc.org
+henrikg@webrtc.org
+hta@webrtc.org
+jiayl@webrtc.org
+juberti@webrtc.org
+mflodman@webrtc.org
+perkj@webrtc.org
+pthatcher@webrtc.org
+sergeyu@chromium.org
+tommi@webrtc.org
+
+per-file BUILD.gn=kjellander@webrtc.org
diff --git a/libjingle/xmpp/asyncsocket.h b/libjingle/xmpp/asyncsocket.h
new file mode 100644
index 0000000..6d77ce0
--- /dev/null
+++ b/libjingle/xmpp/asyncsocket.h
@@ -0,0 +1,72 @@
+/*
+ *  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_LIBJINGLE_XMPP_ASYNCSOCKET_H_
+#define WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
+
+#include <string>
+
+#include "webrtc/base/sigslot.h"
+
+namespace rtc {
+  class SocketAddress;
+}
+
+namespace buzz {
+
+class AsyncSocket {
+public:
+  enum State {
+    STATE_CLOSED = 0,      //!< Socket is not open.
+    STATE_CLOSING,         //!< Socket is closing but can have buffered data
+    STATE_CONNECTING,      //!< In the process of
+    STATE_OPEN,            //!< Socket is connected
+#if defined(FEATURE_ENABLE_SSL)
+    STATE_TLS_CONNECTING,  //!< Establishing TLS connection
+    STATE_TLS_OPEN,        //!< TLS connected
+#endif
+  };
+
+  enum Error {
+    ERROR_NONE = 0,         //!< No error
+    ERROR_WINSOCK,          //!< Winsock error
+    ERROR_DNS,              //!< Couldn't resolve host name
+    ERROR_WRONGSTATE,       //!< Call made while socket is in the wrong state
+#if defined(FEATURE_ENABLE_SSL)
+    ERROR_SSL,              //!< Something went wrong with OpenSSL
+#endif
+  };
+
+  virtual ~AsyncSocket() {}
+  virtual State state() = 0;
+  virtual Error error() = 0;
+  virtual int GetError() = 0;    // winsock error code
+
+  virtual bool Connect(const rtc::SocketAddress& addr) = 0;
+  virtual bool Read(char * data, size_t len, size_t* len_read) = 0;
+  virtual bool Write(const char * data, size_t len) = 0;
+  virtual bool Close() = 0;
+#if defined(FEATURE_ENABLE_SSL)
+  // We allow matching any passed domain.  This allows us to avoid
+  // handling the valuable certificates for logins into proxies.  If
+  // both names are passed as empty, we do not require a match.
+  virtual bool StartTls(const std::string & domainname) = 0;
+#endif
+
+  sigslot::signal0<> SignalConnected;
+  sigslot::signal0<> SignalSSLConnected;
+  sigslot::signal0<> SignalClosed;
+  sigslot::signal0<> SignalRead;
+  sigslot::signal0<> SignalError;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
diff --git a/libjingle/xmpp/chatroommodule.h b/libjingle/xmpp/chatroommodule.h
new file mode 100644
index 0000000..a68f82b
--- /dev/null
+++ b/libjingle/xmpp/chatroommodule.h
@@ -0,0 +1,253 @@
+/*
+ *  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_LIBJINGLE_XMPP_CHATROOMMODULE_H_
+#define WEBRTC_LIBJINGLE_XMPP_CHATROOMMODULE_H_
+
+#include "webrtc/libjingle/xmpp/module.h"
+#include "webrtc/libjingle/xmpp/rostermodule.h"
+
+namespace buzz {
+
+// forward declarations
+class XmppChatroomModule;
+class XmppChatroomHandler;
+class XmppChatroomMember;
+class XmppChatroomMemberEnumerator;
+
+enum XmppChatroomState {
+  XMPP_CHATROOM_STATE_NOT_IN_ROOM      = 0,
+  XMPP_CHATROOM_STATE_REQUESTED_ENTER  = 1,
+  XMPP_CHATROOM_STATE_IN_ROOM          = 2,
+  XMPP_CHATROOM_STATE_REQUESTED_EXIT   = 3,
+};
+
+//! Module that encapsulates a chatroom.
+class XmppChatroomModule : public XmppModule {
+public:
+
+  //! Creates a new XmppChatroomModule
+  static XmppChatroomModule* Create();
+  virtual ~XmppChatroomModule() {}
+
+  //! Sets the chatroom handler (callbacks) for the chatroom
+  virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler) = 0;
+
+  //! Gets the chatroom handler for the module
+  virtual XmppChatroomHandler* chatroom_handler() = 0;
+
+  //! Sets the jid of the chatroom.
+  //! Has to be set before entering the chatroom and can't be changed
+  //! while in the chatroom
+  virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid) = 0;
+
+  //! The jid for the chatroom
+  virtual const Jid& chatroom_jid() const = 0;
+
+  //! Sets the nickname of the member
+  //! Has to be set before entering the chatroom and can't be changed
+  //! while in the chatroom
+  virtual XmppReturnStatus set_nickname(const std::string& nickname) = 0;
+
+  //! The nickname of the member in the chatroom
+  virtual const std::string& nickname() const = 0;
+
+  //! Returns the jid of the member (this is the chatroom_jid plus the
+  //! nickname as the resource name)
+  virtual const Jid member_jid() const = 0;
+
+  //! Requests that the user enter a chatroom
+  //! The EnterChatroom callback will be called when the request is complete.
+  //! Password should be empty for a room that doesn't require a password
+  //! If the room doesn't exist, the server will create an "Instant Room" if the
+  //! server policy supports this action.
+  //! There will be different methods for creating/configuring a "Reserved Room"
+  //! Async callback for this method is ChatroomEnteredStatus
+  virtual XmppReturnStatus RequestEnterChatroom(const std::string& password,
+      const std::string& client_version,
+      const std::string& locale) = 0;
+
+  //! Requests that the user exit a chatroom
+  //! Async callback for this method is ChatroomExitedStatus
+  virtual XmppReturnStatus RequestExitChatroom() = 0;
+
+  //! Requests a status change
+  //! status is the standard XMPP status code
+  //! extended_status is the extended status when status is XMPP_PRESENCE_XA
+  virtual XmppReturnStatus RequestConnectionStatusChange(
+      XmppPresenceConnectionStatus connection_status) = 0;
+
+  //! Returns the number of members in the room
+  virtual size_t GetChatroomMemberCount() = 0;
+
+  //! Gets an enumerator for the members in the chatroom
+  //! The caller must delete the enumerator when the caller is finished with it.
+  //! The caller must also ensure that the lifetime of the enumerator is
+  //! scoped by the XmppChatRoomModule that created it.
+  virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) = 0;
+
+  //! Gets the subject of the chatroom
+  virtual const std::string subject() = 0;
+
+  //! Returns the current state of the user with respect to the chatroom
+  virtual XmppChatroomState state() = 0;
+
+  virtual XmppReturnStatus SendMessage(const XmlElement& message) = 0;
+};
+
+//! Class for enumerating participatns
+class XmppChatroomMemberEnumerator {
+public:
+  virtual ~XmppChatroomMemberEnumerator() { }
+  //! Returns the member at the current position
+  //! Returns null if the enumerator is before the beginning
+  //! or after the end of the collection
+  virtual XmppChatroomMember* current() = 0;
+
+  //! Returns whether the enumerator is valid
+  //! This returns true if the collection has changed
+  //! since the enumerator was created
+  virtual bool IsValid() = 0;
+
+  //! Returns whether the enumerator is before the beginning
+  //! This is the initial state of the enumerator
+  virtual bool IsBeforeBeginning() = 0;
+
+  //! Returns whether the enumerator is after the end
+  virtual bool IsAfterEnd() = 0;
+
+  //! Advances the enumerator to the next position
+  //! Returns false is the enumerator is advanced
+  //! off the end of the collection
+  virtual bool Next() = 0;
+
+  //! Advances the enumerator to the previous position
+  //! Returns false is the enumerator is advanced
+  //! off the end of the collection
+  virtual bool Prev() = 0;
+};
+
+
+//! Represents a single member in a chatroom
+class XmppChatroomMember {
+public:
+  virtual ~XmppChatroomMember() { }
+
+  //! The jid for the member in the chatroom
+  virtual const Jid member_jid() const = 0;
+
+  //! The full jid for the member
+  //! This is only available in non-anonymous rooms.
+  //! If the room is anonymous, this returns JID_EMPTY
+  virtual const Jid full_jid() const = 0;
+
+   //! Returns the backing presence for this member
+  virtual const XmppPresence* presence() const = 0;
+
+  //! The nickname for this member
+  virtual const std::string name() const = 0;
+};
+
+//! Status codes for ChatroomEnteredStatus callback
+enum XmppChatroomEnteredStatus
+{
+  //! User successfully entered the room
+  XMPP_CHATROOM_ENTERED_SUCCESS                    = 0,
+  //! The nickname confliced with somebody already in the room
+  XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT  = 1,
+  //! A password is required to enter the room
+  XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED  = 2,
+  //! The specified password was incorrect
+  XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_INCORRECT = 3,
+  //! The user is not a member of a member-only room
+  XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER       = 4,
+  //! The user cannot enter because the user has been banned
+  XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED      = 5,
+  //! The room has the maximum number of users already
+  XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS          = 6,
+  //! The room has been locked by an administrator
+  XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED        = 7,
+  //! Someone in the room has blocked you
+  XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED     = 8,
+  //! You have blocked someone in the room
+  XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING    = 9,
+  //! Client is old. User must upgrade to a more recent version for
+  // hangouts to work.
+  XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT    = 10,
+  //! Some other reason
+  XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED        = 2000,
+};
+
+//! Status codes for ChatroomExitedStatus callback
+enum XmppChatroomExitedStatus
+{
+  //! The user requested to exit and did so
+  XMPP_CHATROOM_EXITED_REQUESTED                   = 0,
+  //! The user was banned from the room
+  XMPP_CHATROOM_EXITED_BANNED                      = 1,
+  //! The user has been kicked out of the room
+  XMPP_CHATROOM_EXITED_KICKED                      = 2,
+  //! The user has been removed from the room because the
+  //! user is no longer a member of a member-only room
+  //! or the room has changed to membership-only
+  XMPP_CHATROOM_EXITED_NOT_A_MEMBER                = 3,
+  //! The system is shutting down
+  XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN             = 4,
+  //! For some other reason
+  XMPP_CHATROOM_EXITED_UNSPECIFIED                 = 5,
+};
+
+//! The XmppChatroomHandler is the interface for callbacks from the
+//! the chatroom
+class XmppChatroomHandler {
+public:
+  virtual ~XmppChatroomHandler() {}
+
+  //! Indicates the response to RequestEnterChatroom method
+  //! XMPP_CHATROOM_SUCCESS represents success.
+  //! Other status codes are for errors
+  virtual void ChatroomEnteredStatus(XmppChatroomModule* room,
+                                     const XmppPresence* presence,
+                                     XmppChatroomEnteredStatus status) = 0;
+
+
+  //! Indicates that the user has exited the chatroom, either due to
+  //! a call to RequestExitChatroom or for some other reason.
+  //! status indicates the reason the user exited
+  virtual void ChatroomExitedStatus(XmppChatroomModule* room,
+                                    XmppChatroomExitedStatus status) = 0;
+
+  //! Indicates a member entered the room.
+  //! It can be called before ChatroomEnteredStatus.
+  virtual void MemberEntered(XmppChatroomModule* room,
+                                  const XmppChatroomMember* entered_member) = 0;
+
+  //! Indicates that a member exited the room.
+  virtual void MemberExited(XmppChatroomModule* room,
+                              const XmppChatroomMember* exited_member) = 0;
+
+  //! Indicates that the data for the member has changed
+  //! (such as the nickname or presence)
+  virtual void MemberChanged(XmppChatroomModule* room,
+                             const XmppChatroomMember* changed_member) = 0;
+
+  //! Indicates a new message has been received
+  //! message is the message -
+  // $TODO - message should be changed
+  //! to a strongly-typed message class that contains info
+  //! such as the sender, message bodies, etc.,
+  virtual void MessageReceived(XmppChatroomModule* room,
+                               const XmlElement& message) = 0;
+};
+
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_CHATROOMMODULE_H_
diff --git a/libjingle/xmpp/chatroommodule_unittest.cc b/libjingle/xmpp/chatroommodule_unittest.cc
new file mode 100644
index 0000000..27b5211
--- /dev/null
+++ b/libjingle/xmpp/chatroommodule_unittest.cc
@@ -0,0 +1,280 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "buzz/chatroommodule.h"
+#include "buzz/constants.h"
+#include "buzz/xmlelement.h"
+#include "buzz/xmppengine.h"
+#include "common/common.h"
+#include "engine/util_unittest.h"
+#include "test/unittest-inl.h"
+#include "test/unittest.h"
+
+#define TEST_OK(x) TEST_EQ((x),XMPP_RETURN_OK)
+#define TEST_BADARGUMENT(x) TEST_EQ((x),XMPP_RETURN_BADARGUMENT)
+
+namespace buzz {
+
+class MultiUserChatModuleTest;
+
+static void
+WriteEnteredStatus(std::ostream& os, XmppChatroomEnteredStatus status) {
+  switch(status) {
+    case XMPP_CHATROOM_ENTERED_SUCCESS:
+      os<<"success";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT:
+      os<<"failure(nickname conflict)";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED:
+      os<<"failure(password required)";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_INCORRECT:
+      os<<"failure(password incorrect)";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER:
+      os<<"failure(not a member)";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED:
+      os<<"failure(member banned)";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS:
+      os<<"failure(max users)";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED:
+      os<<"failure(room locked)";
+      break;
+    case XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED:
+      os<<"failure(unspecified)";
+      break;
+    default:
+      os<<"unknown";
+      break;
+  } 
+}
+
+static void
+WriteExitedStatus(std::ostream& os, XmppChatroomExitedStatus status) {
+  switch (status) {
+    case XMPP_CHATROOM_EXITED_REQUESTED:
+      os<<"requested";
+      break;
+    case XMPP_CHATROOM_EXITED_BANNED:
+      os<<"banned";
+      break;
+    case XMPP_CHATROOM_EXITED_KICKED:
+      os<<"kicked";
+      break;
+    case XMPP_CHATROOM_EXITED_NOT_A_MEMBER:
+      os<<"not member";
+      break;
+    case XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN:
+      os<<"system shutdown";
+      break;
+    case XMPP_CHATROOM_EXITED_UNSPECIFIED:
+      os<<"unspecified";
+      break;
+    default:
+      os<<"unknown";
+      break;
+  }
+}
+
+//! This session handler saves all calls to a string.  These are events and
+//! data delivered form the engine to application code.
+class XmppTestChatroomHandler : public XmppChatroomHandler {
+public:
+  XmppTestChatroomHandler() {}
+  virtual ~XmppTestChatroomHandler() {}
+
+  void ChatroomEnteredStatus(XmppChatroomModule* room,
+                             XmppChatroomEnteredStatus status) {
+    RTC_UNUSED(room);
+    ss_ <<"[ChatroomEnteredStatus status: ";
+    WriteEnteredStatus(ss_, status);
+    ss_ <<"]";
+  }
+
+
+  void ChatroomExitedStatus(XmppChatroomModule* room,
+                            XmppChatroomExitedStatus status) {
+    RTC_UNUSED(room);
+    ss_ <<"[ChatroomExitedStatus status: ";
+    WriteExitedStatus(ss_, status);
+    ss_ <<"]";
+  }
+
+  void MemberEntered(XmppChatroomModule* room, 
+                          const XmppChatroomMember* entered_member) {
+    RTC_UNUSED(room);
+    ss_ << "[MemberEntered " << entered_member->member_jid().Str() << "]";
+  }
+
+  void MemberExited(XmppChatroomModule* room,
+                         const XmppChatroomMember* exited_member) {
+    RTC_UNUSED(room);
+    ss_ << "[MemberExited " << exited_member->member_jid().Str() << "]";
+  }
+
+  void MemberChanged(XmppChatroomModule* room,
+      const XmppChatroomMember* changed_member) {
+    RTC_UNUSED(room);
+    ss_ << "[MemberChanged " << changed_member->member_jid().Str() << "]";
+  }
+
+  virtual void MessageReceived(XmppChatroomModule* room, const XmlElement& message) {
+    RTC_UNUSED2(room, message);
+  }
+
+ 
+  std::string Str() {
+    return ss_.str();
+  }
+
+  std::string StrClear() {
+    std::string result = ss_.str();
+    ss_.str("");
+    return result;
+  }
+
+private:
+  std::stringstream ss_;
+};
+
+//! This is the class that holds all of the unit test code for the
+//! roster module
+class XmppChatroomModuleTest : public UnitTest {
+public:
+  XmppChatroomModuleTest() {}
+
+  void TestEnterExitChatroom() {
+    std::stringstream dump;
+
+    // Configure the engine
+    scoped_ptr<XmppEngine> engine(XmppEngine::Create());
+    XmppTestHandler handler(engine.get());
+
+    // Configure the module and handler
+    scoped_ptr<XmppChatroomModule> chatroom(XmppChatroomModule::Create());
+
+    // Configure the module handler
+    chatroom->RegisterEngine(engine.get());
+
+    // Set up callbacks
+    engine->SetOutputHandler(&handler);
+    engine->AddStanzaHandler(&handler);
+    engine->SetSessionHandler(&handler);
+
+    // Set up minimal login info
+    engine->SetUser(Jid("david@my-server"));
+    engine->SetPassword("david");
+
+    // Do the whole login handshake
+    RunLogin(this, engine.get(), &handler);
+    TEST_EQ("", handler.OutputActivity());
+
+    // Get the chatroom and set the handler
+    XmppTestChatroomHandler chatroom_handler;
+    chatroom->set_chatroom_handler(static_cast<XmppChatroomHandler*>(&chatroom_handler));
+
+    // try to enter the chatroom
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_NOT_IN_ROOM);
+    chatroom->set_nickname("thirdwitch");
+    chatroom->set_chatroom_jid(Jid("darkcave@my-server"));
+    chatroom->RequestEnterChatroom("", XMPP_CONNECTION_STATUS_UNKNOWN, "en");
+    TEST_EQ(chatroom_handler.StrClear(), "");
+    TEST_EQ(handler.OutputActivity(),
+      "<presence to=\"darkcave@my-server/thirdwitch\">"
+        "<muc:x xmlns:muc=\"http://jabber.org/protocol/muc\"/>"
+      "</presence>");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER);
+
+    // simulate the server and test the client
+    std::string input;
+    input = "<presence from=\"darkcave@my-server/firstwitch\" to=\"david@my-server\">"
+             "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
+              "<item affiliation=\"owner\" role=\"participant\"/>"
+             "</x>"
+            "</presence>";
+    TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+    TEST_EQ(chatroom_handler.StrClear(), "");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER);
+
+    input = "<presence from=\"darkcave@my-server/secondwitch\" to=\"david@my-server\">"
+             "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
+              "<item affiliation=\"member\" role=\"participant\"/>"
+             "</x>"
+            "</presence>";
+    TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+    TEST_EQ(chatroom_handler.StrClear(), "");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER);
+
+    input = "<presence from=\"darkcave@my-server/thirdwitch\" to=\"david@my-server\">"
+             "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
+              "<item affiliation=\"member\" role=\"participant\"/>"
+             "</x>"
+            "</presence>";
+    TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+    TEST_EQ(chatroom_handler.StrClear(),
+      "[ChatroomEnteredStatus status: success]");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM);
+
+    // simulate somebody else entering the room after we entered
+    input = "<presence from=\"darkcave@my-server/fourthwitch\" to=\"david@my-server\">"
+             "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
+              "<item affiliation=\"member\" role=\"participant\"/>"
+             "</x>"
+            "</presence>";
+    TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+    TEST_EQ(chatroom_handler.StrClear(), "[MemberEntered darkcave@my-server/fourthwitch]");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM);
+
+    // simulate somebody else leaving the room after we entered
+    input = "<presence from=\"darkcave@my-server/secondwitch\" to=\"david@my-server\" type=\"unavailable\">"
+             "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
+              "<item affiliation=\"member\" role=\"participant\"/>"
+             "</x>"
+            "</presence>";
+    TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+    TEST_EQ(chatroom_handler.StrClear(), "[MemberExited darkcave@my-server/secondwitch]");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM);
+
+    // try to leave the room
+    chatroom->RequestExitChatroom();
+    TEST_EQ(chatroom_handler.StrClear(), "");
+    TEST_EQ(handler.OutputActivity(),
+      "<presence to=\"darkcave@my-server/thirdwitch\" type=\"unavailable\"/>");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_EXIT);
+
+    // simulate the server and test the client
+    input = "<presence from=\"darkcave@my-server/thirdwitch\" to=\"david@my-server\" type=\"unavailable\">"
+             "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
+              "<item affiliation=\"member\" role=\"participant\"/>"
+             "</x>"
+            "</presence>";
+    TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+    TEST_EQ(chatroom_handler.StrClear(),
+      "[ChatroomExitedStatus status: requested]");
+    TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_NOT_IN_ROOM);
+  }
+
+};
+
+// A global function that creates the test suite for this set of tests.
+TestBase* ChatroomModuleTest_Create() {
+  TestSuite* suite = new TestSuite("ChatroomModuleTest");
+  ADD_TEST(suite, XmppChatroomModuleTest, TestEnterExitChatroom);
+  return suite;
+}
+
+}
diff --git a/libjingle/xmpp/chatroommoduleimpl.cc b/libjingle/xmpp/chatroommoduleimpl.cc
new file mode 100644
index 0000000..546aa75
--- /dev/null
+++ b/libjingle/xmpp/chatroommoduleimpl.cc
@@ -0,0 +1,735 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+#include "webrtc/libjingle/xmpp/chatroommodule.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/moduleimpl.h"
+#include "webrtc/base/common.h"
+
+namespace buzz {
+
+// forward declarations
+class XmppChatroomImpl;
+class XmppChatroomMemberImpl;
+
+//! Module that encapsulates multiple chatrooms.
+//! Each chatroom is represented by an XmppChatroomImpl instance
+class XmppChatroomModuleImpl : public XmppChatroomModule,
+  public XmppModuleImpl, public XmppIqHandler {
+public:
+  IMPLEMENT_XMPPMODULE
+
+   // Creates a chatroom with specified Jid
+  XmppChatroomModuleImpl();
+  ~XmppChatroomModuleImpl();
+
+  // XmppChatroomModule
+  virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler);
+  virtual XmppChatroomHandler* chatroom_handler();
+  virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid);
+  virtual const Jid& chatroom_jid() const;
+  virtual XmppReturnStatus set_nickname(const std::string& nickname);
+  virtual const std::string& nickname() const;
+  virtual const Jid member_jid() const;
+  virtual XmppReturnStatus RequestEnterChatroom(const std::string& password,
+      const std::string& client_version,
+      const std::string& locale);
+  virtual XmppReturnStatus RequestExitChatroom();
+  virtual XmppReturnStatus RequestConnectionStatusChange(
+      XmppPresenceConnectionStatus connection_status);
+  virtual size_t GetChatroomMemberCount();
+  virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator);
+  virtual const std::string subject();
+  virtual XmppChatroomState state() { return chatroom_state_; }
+  virtual XmppReturnStatus SendMessage(const XmlElement& message);
+
+  // XmppModule
+  virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) {RTC_UNUSED2(cookie, pelStanza);}
+  virtual bool HandleStanza(const XmlElement *);
+
+private:
+  friend class XmppChatroomMemberEnumeratorImpl;
+
+  XmppReturnStatus ServerChangeMyPresence(const XmlElement& presence);
+  XmppReturnStatus ClientChangeMyPresence(XmppChatroomState new_state);
+  XmppReturnStatus ChangePresence(XmppChatroomState new_state, const XmlElement* presence, bool isServer);
+  XmppReturnStatus ServerChangedOtherPresence(const XmlElement& presence_element);
+  XmppChatroomEnteredStatus GetEnterFailureFromXml(const XmlElement* presence);
+  XmppChatroomExitedStatus GetExitFailureFromXml(const XmlElement* presence);
+
+  bool CheckEnterChatroomStateOk();
+
+  void FireEnteredStatus(const XmlElement* presence,
+                         XmppChatroomEnteredStatus status);
+  void FireExitStatus(XmppChatroomExitedStatus status);
+  void FireMessageReceived(const XmlElement& message);
+  void FireMemberEntered(const XmppChatroomMember* entered_member);
+  void FireMemberChanged(const XmppChatroomMember* changed_member);
+  void FireMemberExited(const XmppChatroomMember* exited_member);
+
+
+  typedef std::map<Jid, XmppChatroomMemberImpl*> JidMemberMap;
+
+  XmppChatroomHandler*              chatroom_handler_;
+  Jid                               chatroom_jid_;
+  std::string                       nickname_;
+  XmppChatroomState                 chatroom_state_;
+  JidMemberMap                      chatroom_jid_members_;
+  int                               chatroom_jid_members_version_;
+};
+
+
+class XmppChatroomMemberImpl : public XmppChatroomMember {
+public:
+  ~XmppChatroomMemberImpl() {}
+  XmppReturnStatus SetPresence(const XmppPresence* presence);
+
+  // XmppChatroomMember
+  const Jid member_jid() const;
+  const Jid full_jid() const;
+  const std::string name() const;
+  const XmppPresence* presence() const;
+
+private:
+  rtc::scoped_ptr<XmppPresence>  presence_;
+};
+
+class XmppChatroomMemberEnumeratorImpl :
+        public XmppChatroomMemberEnumerator  {
+public:
+  XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap* chatroom_jid_members,
+                                        int* map_version);
+
+  // XmppChatroomMemberEnumerator
+  virtual XmppChatroomMember* current();
+  virtual bool Next();
+  virtual bool Prev();
+  virtual bool IsValid();
+  virtual bool IsBeforeBeginning();
+  virtual bool IsAfterEnd();
+
+private:
+  XmppChatroomModuleImpl::JidMemberMap*           map_;
+  int                                             map_version_created_;
+  int*                                            map_version_;
+  XmppChatroomModuleImpl::JidMemberMap::iterator  iterator_;
+  bool                                            before_beginning_;
+};
+
+
+// XmppChatroomModuleImpl ------------------------------------------------
+XmppChatroomModule *
+XmppChatroomModule::Create() {
+  return new XmppChatroomModuleImpl();
+}
+
+XmppChatroomModuleImpl::XmppChatroomModuleImpl() :
+  chatroom_handler_(NULL),
+  chatroom_jid_(STR_EMPTY),
+  chatroom_state_(XMPP_CHATROOM_STATE_NOT_IN_ROOM),
+  chatroom_jid_members_version_(0) {
+}
+
+XmppChatroomModuleImpl::~XmppChatroomModuleImpl() {
+  JidMemberMap::iterator iterator = chatroom_jid_members_.begin();
+  while (iterator != chatroom_jid_members_.end()) {
+    delete iterator->second;
+    iterator++;
+  }
+}
+
+
+bool
+XmppChatroomModuleImpl::HandleStanza(const XmlElement* stanza) {
+  ASSERT(engine() != NULL);
+
+  // we handle stanzas that are for one of our chatrooms
+  Jid from_jid = Jid(stanza->Attr(QN_FROM));
+  // see if it's one of our chatrooms
+  if (chatroom_jid_ != from_jid.BareJid()) {
+    return false; // not one of our chatrooms
+  } else {
+    // handle presence stanza
+    if (stanza->Name() == QN_PRESENCE) {
+      if (from_jid == member_jid()) {
+        ServerChangeMyPresence(*stanza);
+      } else {
+        ServerChangedOtherPresence(*stanza);
+      }
+    } else if (stanza->Name() == QN_MESSAGE) {
+      FireMessageReceived(*stanza);
+    }
+    return true;
+  }
+}
+
+
+XmppReturnStatus
+XmppChatroomModuleImpl::set_chatroom_handler(XmppChatroomHandler* handler) {
+  // Calling with NULL removes the handler.
+  chatroom_handler_ = handler;
+  return XMPP_RETURN_OK;
+}
+
+
+XmppChatroomHandler*
+XmppChatroomModuleImpl::chatroom_handler() {
+  return chatroom_handler_;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::set_chatroom_jid(const Jid& chatroom_jid) {
+  if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
+    return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
+  }
+  if (chatroom_jid != chatroom_jid.BareJid()) {
+    // chatroom_jid must be a bare jid
+    return XMPP_RETURN_BADARGUMENT;
+  }
+
+  chatroom_jid_ = chatroom_jid;
+  return XMPP_RETURN_OK;
+}
+
+const Jid&
+XmppChatroomModuleImpl::chatroom_jid() const {
+  return chatroom_jid_;
+}
+
+ XmppReturnStatus
+ XmppChatroomModuleImpl::set_nickname(const std::string& nickname) {
+  if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) {
+    return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
+  }
+  nickname_ = nickname;
+  return XMPP_RETURN_OK;
+ }
+
+ const std::string&
+ XmppChatroomModuleImpl::nickname() const {
+  return nickname_;
+ }
+
+const Jid
+XmppChatroomModuleImpl::member_jid() const {
+  return Jid(chatroom_jid_.node(), chatroom_jid_.domain(), nickname_);
+}
+
+
+bool
+XmppChatroomModuleImpl::CheckEnterChatroomStateOk() {
+  if (chatroom_jid_.IsValid() == false) {
+    ASSERT(0);
+    return false;
+  }
+  if (nickname_ == STR_EMPTY) {
+    ASSERT(0);
+    return false;
+  }
+  return true;
+}
+
+std::string GetAttrValueFor(XmppPresenceConnectionStatus connection_status) {
+  switch (connection_status) {
+    default:
+    case XMPP_CONNECTION_STATUS_UNKNOWN:
+      return "";
+    case XMPP_CONNECTION_STATUS_CONNECTING:
+      return STR_PSTN_CONFERENCE_STATUS_CONNECTING;
+    case XMPP_CONNECTION_STATUS_CONNECTED:
+      return STR_PSTN_CONFERENCE_STATUS_CONNECTED;
+  }
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::RequestEnterChatroom(
+    const std::string& password,
+    const std::string& client_version,
+    const std::string& locale) {
+  RTC_UNUSED(password);
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM)
+    return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
+
+  if (CheckEnterChatroomStateOk() == false) {
+    return XMPP_RETURN_BADSTATE;
+  }
+
+  // entering a chatroom is a presence request to the server
+  XmlElement element(QN_PRESENCE);
+  element.AddAttr(QN_TO, member_jid().Str());
+
+  XmlElement* muc_x = new XmlElement(QN_MUC_X);
+  element.AddElement(muc_x);
+
+  if (!client_version.empty()) {
+    XmlElement* client_version_element = new XmlElement(QN_CLIENT_VERSION,
+                                                        false);
+    client_version_element->SetBodyText(client_version);
+    muc_x->AddElement(client_version_element);
+  }
+
+  if (!locale.empty()) {
+    XmlElement* locale_element = new XmlElement(QN_LOCALE, false);
+
+    locale_element->SetBodyText(locale);
+    muc_x->AddElement(locale_element);
+  }
+
+  XmppReturnStatus status = engine()->SendStanza(&element);
+  if (status == XMPP_RETURN_OK) {
+    return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_ENTER);
+  }
+  return status;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::RequestExitChatroom() {
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  // exiting a chatroom is a presence request to the server
+  XmlElement element(QN_PRESENCE);
+  element.AddAttr(QN_TO, member_jid().Str());
+  element.AddAttr(QN_TYPE, "unavailable");
+  XmppReturnStatus status = engine()->SendStanza(&element);
+  if (status == XMPP_RETURN_OK &&
+      chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) {
+    return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_EXIT);
+  }
+  return status;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::RequestConnectionStatusChange(
+    XmppPresenceConnectionStatus connection_status) {
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
+    // $TODO - this isn't a bad state, it's a bad call,  diff error code?
+    return XMPP_RETURN_BADSTATE;
+  }
+
+  if (CheckEnterChatroomStateOk() == false) {
+    return XMPP_RETURN_BADSTATE;
+  }
+
+  // entering a chatroom is a presence request to the server
+  XmlElement element(QN_PRESENCE);
+  element.AddAttr(QN_TO, member_jid().Str());
+  element.AddElement(new XmlElement(QN_MUC_X));
+  if (connection_status != XMPP_CONNECTION_STATUS_UNKNOWN) {
+    XmlElement* con_status_element =
+        new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
+    con_status_element->AddAttr(QN_STATUS, GetAttrValueFor(connection_status));
+    element.AddElement(con_status_element);
+  }
+  XmppReturnStatus status = engine()->SendStanza(&element);
+
+  return status;
+}
+
+size_t
+XmppChatroomModuleImpl::GetChatroomMemberCount() {
+  return chatroom_jid_members_.size();
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) {
+  *enumerator = new XmppChatroomMemberEnumeratorImpl(&chatroom_jid_members_, &chatroom_jid_members_version_);
+  return XMPP_RETURN_OK;
+}
+
+const std::string
+XmppChatroomModuleImpl::subject() {
+  return ""; //NYI
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::SendMessage(const XmlElement& message) {
+  XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
+
+  // can only send a message if we're in the room
+  if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) {
+    return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call,  diff error code?
+  }
+
+  if (message.Name() != QN_MESSAGE) {
+    IFR(XMPP_RETURN_BADARGUMENT);
+  }
+
+  const std::string& type = message.Attr(QN_TYPE);
+  if (type != "groupchat") {
+    IFR(XMPP_RETURN_BADARGUMENT);
+  }
+
+  if (message.HasAttr(QN_FROM)) {
+    IFR(XMPP_RETURN_BADARGUMENT);
+  }
+
+  if (message.Attr(QN_TO) != chatroom_jid_.Str()) {
+    IFR(XMPP_RETURN_BADARGUMENT);
+  }
+
+  IFR(engine()->SendStanza(&message));
+
+  return xmpp_status;
+}
+
+enum TransitionType {
+  TRANSITION_TYPE_NONE                 = 0,
+  TRANSITION_TYPE_ENTER_SUCCESS        = 1,
+  TRANSITION_TYPE_ENTER_FAILURE        = 2,
+  TRANSITION_TYPE_EXIT_VOLUNTARILY     = 3,
+  TRANSITION_TYPE_EXIT_INVOLUNTARILY   = 4,
+};
+
+struct StateTransitionDescription {
+  XmppChatroomState old_state;
+  XmppChatroomState new_state;
+  bool              is_valid_server_transition;
+  bool              is_valid_client_transition;
+  TransitionType    transition_type;
+};
+
+StateTransitionDescription Transitions[] = {
+  { XMPP_CHATROOM_STATE_NOT_IN_ROOM,     XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, true,  TRANSITION_TYPE_NONE, },
+  { XMPP_CHATROOM_STATE_NOT_IN_ROOM,     XMPP_CHATROOM_STATE_IN_ROOM,         false, false, TRANSITION_TYPE_ENTER_SUCCESS, },
+  { XMPP_CHATROOM_STATE_NOT_IN_ROOM,     XMPP_CHATROOM_STATE_REQUESTED_EXIT,  false, false, TRANSITION_TYPE_NONE, },
+  { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_NOT_IN_ROOM,     true,  false, TRANSITION_TYPE_ENTER_FAILURE, },
+  { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_IN_ROOM,         true,  false, TRANSITION_TYPE_ENTER_SUCCESS, },
+  { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_REQUESTED_EXIT,  false, false, TRANSITION_TYPE_NONE, },
+  { XMPP_CHATROOM_STATE_IN_ROOM,         XMPP_CHATROOM_STATE_NOT_IN_ROOM,     true,  false, TRANSITION_TYPE_EXIT_INVOLUNTARILY,  },
+  { XMPP_CHATROOM_STATE_IN_ROOM,         XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
+  { XMPP_CHATROOM_STATE_IN_ROOM,         XMPP_CHATROOM_STATE_REQUESTED_EXIT,  false, true,  TRANSITION_TYPE_NONE, },
+  { XMPP_CHATROOM_STATE_REQUESTED_EXIT,  XMPP_CHATROOM_STATE_NOT_IN_ROOM,     true,  false, TRANSITION_TYPE_EXIT_VOLUNTARILY, },
+  { XMPP_CHATROOM_STATE_REQUESTED_EXIT,  XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, },
+  { XMPP_CHATROOM_STATE_REQUESTED_EXIT,  XMPP_CHATROOM_STATE_IN_ROOM,         false, false, TRANSITION_TYPE_NONE, },
+};
+
+
+
+void
+XmppChatroomModuleImpl::FireEnteredStatus(const XmlElement* presence,
+                                          XmppChatroomEnteredStatus status) {
+  if (chatroom_handler_) {
+    rtc::scoped_ptr<XmppPresence> xmpp_presence(XmppPresence::Create());
+    xmpp_presence->set_raw_xml(presence);
+    chatroom_handler_->ChatroomEnteredStatus(this, xmpp_presence.get(), status);
+  }
+}
+
+void
+XmppChatroomModuleImpl::FireExitStatus(XmppChatroomExitedStatus status) {
+  if (chatroom_handler_)
+    chatroom_handler_->ChatroomExitedStatus(this, status);
+}
+
+void
+XmppChatroomModuleImpl::FireMessageReceived(const XmlElement& message) {
+  if (chatroom_handler_)
+    chatroom_handler_->MessageReceived(this, message);
+}
+
+void
+XmppChatroomModuleImpl::FireMemberEntered(const XmppChatroomMember* entered_member) {
+  if (chatroom_handler_)
+    chatroom_handler_->MemberEntered(this, entered_member);
+}
+
+void
+XmppChatroomModuleImpl::FireMemberChanged(
+    const XmppChatroomMember* changed_member) {
+  if (chatroom_handler_)
+    chatroom_handler_->MemberChanged(this, changed_member);
+}
+
+void
+XmppChatroomModuleImpl::FireMemberExited(const XmppChatroomMember* exited_member) {
+  if (chatroom_handler_)
+    chatroom_handler_->MemberExited(this, exited_member);
+}
+
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement&
+                                                   presence_element) {
+  XmppReturnStatus xmpp_status = XMPP_RETURN_OK;
+  rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create());
+  IFR(presence->set_raw_xml(&presence_element));
+
+  JidMemberMap::iterator pos = chatroom_jid_members_.find(presence->jid());
+
+  if (pos == chatroom_jid_members_.end()) {
+    if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
+      XmppChatroomMemberImpl* member = new XmppChatroomMemberImpl();
+      member->SetPresence(presence.get());
+      chatroom_jid_members_.insert(std::make_pair(member->member_jid(), member));
+      chatroom_jid_members_version_++;
+      FireMemberEntered(member);
+    }
+  } else {
+    XmppChatroomMemberImpl* member = pos->second;
+    if (presence->available() == XMPP_PRESENCE_AVAILABLE) {
+      member->SetPresence(presence.get());
+      chatroom_jid_members_version_++;
+      FireMemberChanged(member);
+    }
+    else if (presence->available() == XMPP_PRESENCE_UNAVAILABLE) {
+      member->SetPresence(presence.get());
+      chatroom_jid_members_.erase(pos);
+      chatroom_jid_members_version_++;
+      FireMemberExited(member);
+      delete member;
+    }
+  }
+
+  return xmpp_status;
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ClientChangeMyPresence(XmppChatroomState new_state) {
+  return ChangePresence(new_state, NULL, false);
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ServerChangeMyPresence(const XmlElement& presence) {
+   XmppChatroomState new_state;
+
+   if (presence.HasAttr(QN_TYPE) == false) {
+      new_state = XMPP_CHATROOM_STATE_IN_ROOM;
+   } else {
+     new_state = XMPP_CHATROOM_STATE_NOT_IN_ROOM;
+   }
+  return ChangePresence(new_state, &presence, true);
+
+}
+
+XmppReturnStatus
+XmppChatroomModuleImpl::ChangePresence(XmppChatroomState new_state,
+                                       const XmlElement* presence,
+                                       bool isServer) {
+  RTC_UNUSED(presence);
+
+  XmppChatroomState old_state = chatroom_state_;
+
+  // do nothing if state hasn't changed
+  if (old_state == new_state)
+    return XMPP_RETURN_OK;
+
+  // find the right transition description
+  StateTransitionDescription* transition_desc = NULL;
+  for (int i=0; i < ARRAY_SIZE(Transitions); i++) {
+    if (Transitions[i].old_state == old_state &&
+        Transitions[i].new_state == new_state) {
+        transition_desc = &Transitions[i];
+        break;
+    }
+  }
+
+  if (transition_desc == NULL) {
+    ASSERT(0);
+    return XMPP_RETURN_BADSTATE;
+  }
+
+  // we assert for any invalid transition states, and we'll
+  if (isServer) {
+    // $TODO send original stanza back to server and log an error?
+    // Disable the assert because of b/6133072
+    // ASSERT(transition_desc->is_valid_server_transition);
+    if (!transition_desc->is_valid_server_transition) {
+      return XMPP_RETURN_BADSTATE;
+    }
+  } else {
+    if (transition_desc->is_valid_client_transition == false) {
+      ASSERT(0);
+      return XMPP_RETURN_BADARGUMENT;
+    }
+  }
+
+  // set the new state and then fire any notifications to the handler
+  chatroom_state_ = new_state;
+
+  switch (transition_desc->transition_type) {
+    case TRANSITION_TYPE_ENTER_SUCCESS:
+      FireEnteredStatus(presence, XMPP_CHATROOM_ENTERED_SUCCESS);
+      break;
+    case TRANSITION_TYPE_ENTER_FAILURE:
+      FireEnteredStatus(presence, GetEnterFailureFromXml(presence));
+      break;
+    case TRANSITION_TYPE_EXIT_INVOLUNTARILY:
+      FireExitStatus(GetExitFailureFromXml(presence));
+      break;
+    case TRANSITION_TYPE_EXIT_VOLUNTARILY:
+      FireExitStatus(XMPP_CHATROOM_EXITED_REQUESTED);
+      break;
+    case TRANSITION_TYPE_NONE:
+      break;
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+XmppChatroomEnteredStatus
+XmppChatroomModuleImpl::GetEnterFailureFromXml(const XmlElement* presence) {
+  XmppChatroomEnteredStatus status = XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED;
+  const XmlElement* error = presence->FirstNamed(QN_ERROR);
+  if (error != NULL && error->HasAttr(QN_CODE)) {
+    int code = atoi(error->Attr(QN_CODE).c_str());
+    switch (code) {
+      case 401: status = XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED; break;
+      case 403: {
+        status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED;
+        if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKED)) {
+          status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED;
+        } else if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKING)) {
+          status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING;
+        }
+        break;
+      }
+      case 405: status = XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED; break;
+      case 406: status = XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT; break;
+      case 407: status = XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER; break;
+      case 409: status = XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT; break;
+      // http://xmpp.org/extensions/xep-0045.html#enter-maxusers
+      case 503: status = XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS; break;
+    }
+  }
+  return status;
+}
+
+XmppChatroomExitedStatus
+XmppChatroomModuleImpl::GetExitFailureFromXml(const XmlElement* presence) {
+  XmppChatroomExitedStatus status = XMPP_CHATROOM_EXITED_UNSPECIFIED;
+  const XmlElement* muc_user = presence->FirstNamed(QN_MUC_USER_X);
+  if (muc_user != NULL) {
+    const XmlElement* user_status = muc_user->FirstNamed(QN_MUC_USER_STATUS);
+    if (user_status != NULL && user_status->HasAttr(QN_CODE)) {
+      int code = atoi(user_status->Attr(QN_CODE).c_str());
+      switch (code) {
+        case 307: status = XMPP_CHATROOM_EXITED_KICKED; break;
+        case 322: status = XMPP_CHATROOM_EXITED_NOT_A_MEMBER; break;
+        case 332: status = XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN; break;
+      }
+    }
+  }
+  return status;
+}
+
+XmppReturnStatus
+XmppChatroomMemberImpl::SetPresence(const XmppPresence* presence) {
+  ASSERT(presence != NULL);
+
+  // copy presence
+  presence_.reset(XmppPresence::Create());
+  presence_->set_raw_xml(presence->raw_xml());
+  return XMPP_RETURN_OK;
+}
+
+const Jid
+XmppChatroomMemberImpl::member_jid() const {
+  return presence_->jid();
+}
+
+const Jid
+XmppChatroomMemberImpl::full_jid() const {
+  return Jid("");
+}
+
+const std::string
+XmppChatroomMemberImpl::name() const {
+  return member_jid().resource();
+}
+
+const XmppPresence*
+XmppChatroomMemberImpl::presence() const {
+  return presence_.get();
+}
+
+
+// XmppChatroomMemberEnumeratorImpl --------------------------------------
+XmppChatroomMemberEnumeratorImpl::XmppChatroomMemberEnumeratorImpl(
+        XmppChatroomModuleImpl::JidMemberMap* map, int* map_version) {
+  map_ = map;
+  map_version_ = map_version;
+  map_version_created_ = *map_version_;
+  iterator_ = map->begin();
+  before_beginning_ = true;
+}
+
+XmppChatroomMember*
+XmppChatroomMemberEnumeratorImpl::current() {
+  if (IsValid() == false) {
+    return NULL;
+  } else if (IsBeforeBeginning() || IsAfterEnd()) {
+    return NULL;
+  } else {
+    return iterator_->second;
+  }
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::Prev() {
+  if (IsValid() == false) {
+    return false;
+  } else if (IsBeforeBeginning()) {
+    return false;
+  } else if (iterator_ == map_->begin()) {
+    before_beginning_ = true;
+    return false;
+  } else {
+    iterator_--;
+    return current() != NULL;
+  }
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::Next() {
+  if (IsValid() == false) {
+    return false;
+  } else if (IsBeforeBeginning()) {
+    before_beginning_ = false;
+    iterator_ = map_->begin();
+    return current() != NULL;
+  } else if (IsAfterEnd()) {
+    return false;
+  } else {
+    iterator_++;
+    return current() != NULL;
+  }
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::IsValid() {
+  return map_version_created_ == *map_version_;
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::IsBeforeBeginning() {
+  return before_beginning_;
+}
+
+bool
+XmppChatroomMemberEnumeratorImpl::IsAfterEnd() {
+  return (iterator_ == map_->end());
+}
+
+
+
+} // namespace buzz
diff --git a/libjingle/xmpp/constants.cc b/libjingle/xmpp/constants.cc
new file mode 100644
index 0000000..38e0cec
--- /dev/null
+++ b/libjingle/xmpp/constants.cc
@@ -0,0 +1,614 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/constants.h"
+
+#include <string>
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlconstants.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/base/basicdefs.h"
+
+namespace buzz {
+
+// TODO: Remove static objects of complex types, particularly
+// Jid and QName.
+
+const char NS_CLIENT[] = "jabber:client";
+const char NS_SERVER[] = "jabber:server";
+const char NS_STREAM[] = "http://etherx.jabber.org/streams";
+const char NS_XSTREAM[] = "urn:ietf:params:xml:ns:xmpp-streams";
+const char NS_TLS[] = "urn:ietf:params:xml:ns:xmpp-tls";
+const char NS_SASL[] = "urn:ietf:params:xml:ns:xmpp-sasl";
+const char NS_BIND[] = "urn:ietf:params:xml:ns:xmpp-bind";
+const char NS_DIALBACK[] = "jabber:server:dialback";
+const char NS_SESSION[] = "urn:ietf:params:xml:ns:xmpp-session";
+const char NS_STANZA[] = "urn:ietf:params:xml:ns:xmpp-stanzas";
+const char NS_PRIVACY[] = "jabber:iq:privacy";
+const char NS_ROSTER[] = "jabber:iq:roster";
+const char NS_VCARD[] = "vcard-temp";
+const char NS_AVATAR_HASH[] = "google:avatar";
+const char NS_VCARD_UPDATE[] = "vcard-temp:x:update";
+const char STR_CLIENT[] = "client";
+const char STR_SERVER[] = "server";
+const char STR_STREAM[] = "stream";
+
+const char STR_GET[] = "get";
+const char STR_SET[] = "set";
+const char STR_RESULT[] = "result";
+const char STR_ERROR[] = "error";
+
+const char STR_FORM[] = "form";
+const char STR_SUBMIT[] = "submit";
+const char STR_TEXT_SINGLE[] = "text-single";
+const char STR_LIST_SINGLE[] = "list-single";
+const char STR_LIST_MULTI[] = "list-multi";
+const char STR_HIDDEN[] = "hidden";
+const char STR_FORM_TYPE[] = "FORM_TYPE";
+
+const char STR_FROM[] = "from";
+const char STR_TO[] = "to";
+const char STR_BOTH[] = "both";
+const char STR_REMOVE[] = "remove";
+const char STR_TRUE[] = "true";
+
+const char STR_TYPE[] = "type";
+const char STR_NAME[] = "name";
+const char STR_ID[] = "id";
+const char STR_JID[] = "jid";
+const char STR_SUBSCRIPTION[] = "subscription";
+const char STR_ASK[] = "ask";
+const char STR_X[] = "x";
+const char STR_GOOGLE_COM[] = "google.com";
+const char STR_GMAIL_COM[] = "gmail.com";
+const char STR_GOOGLEMAIL_COM[] = "googlemail.com";
+const char STR_DEFAULT_DOMAIN[] = "default.talk.google.com";
+const char STR_TALK_GOOGLE_COM[] = "talk.google.com";
+const char STR_TALKX_L_GOOGLE_COM[] = "talkx.l.google.com";
+const char STR_XMPP_GOOGLE_COM[] = "xmpp.google.com";
+const char STR_XMPPX_L_GOOGLE_COM[] = "xmppx.l.google.com";
+
+#ifdef FEATURE_ENABLE_VOICEMAIL
+const char STR_VOICEMAIL[] = "voicemail";
+const char STR_OUTGOINGVOICEMAIL[] = "outgoingvoicemail";
+#endif
+
+const char STR_UNAVAILABLE[] = "unavailable";
+
+const char NS_PING[] = "urn:xmpp:ping";
+const StaticQName QN_PING = { NS_PING, "ping" };
+
+const char NS_MUC_UNIQUE[] = "http://jabber.org/protocol/muc#unique";
+const StaticQName QN_MUC_UNIQUE_QUERY = { NS_MUC_UNIQUE, "unique" };
+const StaticQName QN_HANGOUT_ID = { STR_EMPTY, "hangout-id" };
+
+const char STR_GOOGLE_MUC_LOOKUP_JID[] = "lookup.groupchat.google.com";
+
+const char STR_MUC_ROOMCONFIG_ROOMNAME[] = "muc#roomconfig_roomname";
+const char STR_MUC_ROOMCONFIG_FEATURES[] = "muc#roomconfig_features";
+const char STR_MUC_ROOM_FEATURE_ENTERPRISE[] = "muc_enterprise";
+const char STR_MUC_ROOMCONFIG[] = "http://jabber.org/protocol/muc#roomconfig";
+const char STR_MUC_ROOM_FEATURE_HANGOUT[] = "muc_es";
+const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[] = "muc_lite";
+const char STR_MUC_ROOM_FEATURE_BROADCAST[] = "broadcast";
+const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[] = "muc_muvc";
+const char STR_MUC_ROOM_FEATURE_RECORDABLE[] = "recordable";
+const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[] = "custom_recording";
+const char STR_MUC_ROOM_OWNER_PROFILE_ID[] = "muc#roominfo_owner_profile_id";
+const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[] = "abuse_recordable";
+
+const char STR_ID_TYPE_CONVERSATION[] = "conversation";
+const char NS_GOOGLE_MUC_HANGOUT[] = "google:muc#hangout";
+const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE =
+    { NS_GOOGLE_MUC_HANGOUT, "invite" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE =
+    { NS_GOOGLE_MUC_HANGOUT, "invite-type" };
+const StaticQName QN_ATTR_CREATE_ACTIVITY =
+    { STR_EMPTY, "create-activity" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC =
+    { NS_GOOGLE_MUC_HANGOUT, "public" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE =
+    { NS_GOOGLE_MUC_HANGOUT, "invitee" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS =
+    { NS_GOOGLE_MUC_HANGOUT, "notification-status" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE = {
+    NS_GOOGLE_MUC_HANGOUT, "notification-type" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT = {
+    NS_GOOGLE_MUC_HANGOUT, "hangout-start-context" };
+const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID = {
+    NS_GOOGLE_MUC_HANGOUT, "conversation-id" };
+
+const StaticQName QN_STREAM_STREAM = { NS_STREAM, STR_STREAM };
+const StaticQName QN_STREAM_FEATURES = { NS_STREAM, "features" };
+const StaticQName QN_STREAM_ERROR = { NS_STREAM, "error" };
+
+const StaticQName QN_XSTREAM_BAD_FORMAT = { NS_XSTREAM, "bad-format" };
+const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX =
+    { NS_XSTREAM, "bad-namespace-prefix" };
+const StaticQName QN_XSTREAM_CONFLICT = { NS_XSTREAM, "conflict" };
+const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT =
+    { NS_XSTREAM, "connection-timeout" };
+const StaticQName QN_XSTREAM_HOST_GONE = { NS_XSTREAM, "host-gone" };
+const StaticQName QN_XSTREAM_HOST_UNKNOWN = { NS_XSTREAM, "host-unknown" };
+const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING =
+     { NS_XSTREAM, "improper-addressing" };
+const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR =
+    { NS_XSTREAM, "internal-server-error" };
+const StaticQName QN_XSTREAM_INVALID_FROM = { NS_XSTREAM, "invalid-from" };
+const StaticQName QN_XSTREAM_INVALID_ID = { NS_XSTREAM, "invalid-id" };
+const StaticQName QN_XSTREAM_INVALID_NAMESPACE =
+    { NS_XSTREAM, "invalid-namespace" };
+const StaticQName QN_XSTREAM_INVALID_XML = { NS_XSTREAM, "invalid-xml" };
+const StaticQName QN_XSTREAM_NOT_AUTHORIZED = { NS_XSTREAM, "not-authorized" };
+const StaticQName QN_XSTREAM_POLICY_VIOLATION =
+    { NS_XSTREAM, "policy-violation" };
+const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED =
+    { NS_XSTREAM, "remote-connection-failed" };
+const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT =
+    { NS_XSTREAM, "resource-constraint" };
+const StaticQName QN_XSTREAM_RESTRICTED_XML = { NS_XSTREAM, "restricted-xml" };
+const StaticQName QN_XSTREAM_SEE_OTHER_HOST = { NS_XSTREAM, "see-other-host" };
+const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN =
+    { NS_XSTREAM, "system-shutdown" };
+const StaticQName QN_XSTREAM_UNDEFINED_CONDITION =
+    { NS_XSTREAM, "undefined-condition" };
+const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING =
+    { NS_XSTREAM, "unsupported-encoding" };
+const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE =
+    { NS_XSTREAM, "unsupported-stanza-type" };
+const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION =
+    { NS_XSTREAM, "unsupported-version" };
+const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED =
+    { NS_XSTREAM, "xml-not-well-formed" };
+const StaticQName QN_XSTREAM_TEXT = { NS_XSTREAM, "text" };
+
+const StaticQName QN_TLS_STARTTLS = { NS_TLS, "starttls" };
+const StaticQName QN_TLS_REQUIRED = { NS_TLS, "required" };
+const StaticQName QN_TLS_PROCEED = { NS_TLS, "proceed" };
+const StaticQName QN_TLS_FAILURE = { NS_TLS, "failure" };
+
+const StaticQName QN_SASL_MECHANISMS = { NS_SASL, "mechanisms" };
+const StaticQName QN_SASL_MECHANISM = { NS_SASL, "mechanism" };
+const StaticQName QN_SASL_AUTH = { NS_SASL, "auth" };
+const StaticQName QN_SASL_CHALLENGE = { NS_SASL, "challenge" };
+const StaticQName QN_SASL_RESPONSE = { NS_SASL, "response" };
+const StaticQName QN_SASL_ABORT = { NS_SASL, "abort" };
+const StaticQName QN_SASL_SUCCESS = { NS_SASL, "success" };
+const StaticQName QN_SASL_FAILURE = { NS_SASL, "failure" };
+const StaticQName QN_SASL_ABORTED = { NS_SASL, "aborted" };
+const StaticQName QN_SASL_INCORRECT_ENCODING =
+    { NS_SASL, "incorrect-encoding" };
+const StaticQName QN_SASL_INVALID_AUTHZID = { NS_SASL, "invalid-authzid" };
+const StaticQName QN_SASL_INVALID_MECHANISM = { NS_SASL, "invalid-mechanism" };
+const StaticQName QN_SASL_MECHANISM_TOO_WEAK =
+    { NS_SASL, "mechanism-too-weak" };
+const StaticQName QN_SASL_NOT_AUTHORIZED = { NS_SASL, "not-authorized" };
+const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE =
+    { NS_SASL, "temporary-auth-failure" };
+
+// These are non-standard.
+const char NS_GOOGLE_AUTH_PROTOCOL[] =
+    "http://www.google.com/talk/protocol/auth";
+const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT =
+    { NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result" };
+const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN =
+    { NS_GOOGLE_AUTH_PROTOCOL, "allow-non-google-login" };
+const StaticQName QN_GOOGLE_AUTH_SERVICE =
+    { NS_GOOGLE_AUTH_PROTOCOL, "service" };
+
+const StaticQName QN_DIALBACK_RESULT = { NS_DIALBACK, "result" };
+const StaticQName QN_DIALBACK_VERIFY = { NS_DIALBACK, "verify" };
+
+const StaticQName QN_STANZA_BAD_REQUEST = { NS_STANZA, "bad-request" };
+const StaticQName QN_STANZA_CONFLICT = { NS_STANZA, "conflict" };
+const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED =
+    { NS_STANZA, "feature-not-implemented" };
+const StaticQName QN_STANZA_FORBIDDEN = { NS_STANZA, "forbidden" };
+const StaticQName QN_STANZA_GONE = { NS_STANZA, "gone" };
+const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR =
+    { NS_STANZA, "internal-server-error" };
+const StaticQName QN_STANZA_ITEM_NOT_FOUND = { NS_STANZA, "item-not-found" };
+const StaticQName QN_STANZA_JID_MALFORMED = { NS_STANZA, "jid-malformed" };
+const StaticQName QN_STANZA_NOT_ACCEPTABLE = { NS_STANZA, "not-acceptable" };
+const StaticQName QN_STANZA_NOT_ALLOWED = { NS_STANZA, "not-allowed" };
+const StaticQName QN_STANZA_PAYMENT_REQUIRED =
+    { NS_STANZA, "payment-required" };
+const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE =
+    { NS_STANZA, "recipient-unavailable" };
+const StaticQName QN_STANZA_REDIRECT = { NS_STANZA, "redirect" };
+const StaticQName QN_STANZA_REGISTRATION_REQUIRED =
+    { NS_STANZA, "registration-required" };
+const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND =
+    { NS_STANZA, "remote-server-not-found" };
+const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT =
+    { NS_STANZA, "remote-server-timeout" };
+const StaticQName QN_STANZA_RESOURCE_CONSTRAINT =
+    { NS_STANZA, "resource-constraint" };
+const StaticQName QN_STANZA_SERVICE_UNAVAILABLE =
+    { NS_STANZA, "service-unavailable" };
+const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED =
+    { NS_STANZA, "subscription-required" };
+const StaticQName QN_STANZA_UNDEFINED_CONDITION =
+    { NS_STANZA, "undefined-condition" };
+const StaticQName QN_STANZA_UNEXPECTED_REQUEST =
+    { NS_STANZA, "unexpected-request" };
+const StaticQName QN_STANZA_TEXT = { NS_STANZA, "text" };
+
+const StaticQName QN_BIND_BIND = { NS_BIND, "bind" };
+const StaticQName QN_BIND_RESOURCE = { NS_BIND, "resource" };
+const StaticQName QN_BIND_JID = { NS_BIND, "jid" };
+
+const StaticQName QN_MESSAGE = { NS_CLIENT, "message" };
+const StaticQName QN_BODY = { NS_CLIENT, "body" };
+const StaticQName QN_SUBJECT = { NS_CLIENT, "subject" };
+const StaticQName QN_THREAD = { NS_CLIENT, "thread" };
+const StaticQName QN_PRESENCE = { NS_CLIENT, "presence" };
+const StaticQName QN_SHOW = { NS_CLIENT, "show" };
+const StaticQName QN_STATUS = { NS_CLIENT, "status" };
+const StaticQName QN_LANG = { NS_CLIENT, "lang" };
+const StaticQName QN_PRIORITY = { NS_CLIENT, "priority" };
+const StaticQName QN_IQ = { NS_CLIENT, "iq" };
+const StaticQName QN_ERROR = { NS_CLIENT, "error" };
+
+const StaticQName QN_SERVER_MESSAGE = { NS_SERVER, "message" };
+const StaticQName QN_SERVER_BODY = { NS_SERVER, "body" };
+const StaticQName QN_SERVER_SUBJECT = { NS_SERVER, "subject" };
+const StaticQName QN_SERVER_THREAD = { NS_SERVER, "thread" };
+const StaticQName QN_SERVER_PRESENCE = { NS_SERVER, "presence" };
+const StaticQName QN_SERVER_SHOW = { NS_SERVER, "show" };
+const StaticQName QN_SERVER_STATUS = { NS_SERVER, "status" };
+const StaticQName QN_SERVER_LANG = { NS_SERVER, "lang" };
+const StaticQName QN_SERVER_PRIORITY = { NS_SERVER, "priority" };
+const StaticQName QN_SERVER_IQ = { NS_SERVER, "iq" };
+const StaticQName QN_SERVER_ERROR = { NS_SERVER, "error" };
+
+const StaticQName QN_SESSION_SESSION = { NS_SESSION, "session" };
+
+const StaticQName QN_PRIVACY_QUERY = { NS_PRIVACY, "query" };
+const StaticQName QN_PRIVACY_ACTIVE = { NS_PRIVACY, "active" };
+const StaticQName QN_PRIVACY_DEFAULT = { NS_PRIVACY, "default" };
+const StaticQName QN_PRIVACY_LIST = { NS_PRIVACY, "list" };
+const StaticQName QN_PRIVACY_ITEM = { NS_PRIVACY, "item" };
+const StaticQName QN_PRIVACY_IQ = { NS_PRIVACY, "iq" };
+const StaticQName QN_PRIVACY_MESSAGE = { NS_PRIVACY, "message" };
+const StaticQName QN_PRIVACY_PRESENCE_IN = { NS_PRIVACY, "presence-in" };
+const StaticQName QN_PRIVACY_PRESENCE_OUT = { NS_PRIVACY, "presence-out" };
+
+const StaticQName QN_ROSTER_QUERY = { NS_ROSTER, "query" };
+const StaticQName QN_ROSTER_ITEM = { NS_ROSTER, "item" };
+const StaticQName QN_ROSTER_GROUP = { NS_ROSTER, "group" };
+
+const StaticQName QN_VCARD = { NS_VCARD, "vCard" };
+const StaticQName QN_VCARD_FN = { NS_VCARD, "FN" };
+const StaticQName QN_VCARD_PHOTO = { NS_VCARD, "PHOTO" };
+const StaticQName QN_VCARD_PHOTO_BINVAL = { NS_VCARD, "BINVAL" };
+const StaticQName QN_VCARD_AVATAR_HASH = { NS_AVATAR_HASH, "hash" };
+const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED =
+    { NS_AVATAR_HASH, "modified" };
+
+const StaticQName QN_NAME = { STR_EMPTY, "name" };
+const StaticQName QN_AFFILIATION = { STR_EMPTY, "affiliation" };
+const StaticQName QN_ROLE = { STR_EMPTY, "role" };
+
+#if defined(FEATURE_ENABLE_PSTN)
+const StaticQName QN_VCARD_TEL = { NS_VCARD, "TEL" };
+const StaticQName QN_VCARD_VOICE = { NS_VCARD, "VOICE" };
+const StaticQName QN_VCARD_HOME = { NS_VCARD, "HOME" };
+const StaticQName QN_VCARD_WORK = { NS_VCARD, "WORK" };
+const StaticQName QN_VCARD_CELL = { NS_VCARD, "CELL" };
+const StaticQName QN_VCARD_NUMBER = { NS_VCARD, "NUMBER" };
+#endif
+
+const StaticQName QN_XML_LANG = { NS_XML, "lang" };
+
+const StaticQName QN_ENCODING = { STR_EMPTY, STR_ENCODING };
+const StaticQName QN_VERSION = { STR_EMPTY, STR_VERSION };
+const StaticQName QN_TO = { STR_EMPTY, "to" };
+const StaticQName QN_FROM = { STR_EMPTY, "from" };
+const StaticQName QN_TYPE = { STR_EMPTY, "type" };
+const StaticQName QN_ID = { STR_EMPTY, "id" };
+const StaticQName QN_CODE = { STR_EMPTY, "code" };
+
+const StaticQName QN_VALUE = { STR_EMPTY, "value" };
+const StaticQName QN_ACTION = { STR_EMPTY, "action" };
+const StaticQName QN_ORDER = { STR_EMPTY, "order" };
+const StaticQName QN_MECHANISM = { STR_EMPTY, "mechanism" };
+const StaticQName QN_ASK = { STR_EMPTY, "ask" };
+const StaticQName QN_JID = { STR_EMPTY, "jid" };
+const StaticQName QN_NICK = { STR_EMPTY, "nick" };
+const StaticQName QN_SUBSCRIPTION = { STR_EMPTY, "subscription" };
+const StaticQName QN_TITLE1 = { STR_EMPTY, "title1" };
+const StaticQName QN_TITLE2 = { STR_EMPTY, "title2" };
+
+const StaticQName QN_XMLNS_CLIENT = { NS_XMLNS, STR_CLIENT };
+const StaticQName QN_XMLNS_SERVER = { NS_XMLNS, STR_SERVER };
+const StaticQName QN_XMLNS_STREAM = { NS_XMLNS, STR_STREAM };
+
+
+// Presence
+const char STR_SHOW_AWAY[] = "away";
+const char STR_SHOW_CHAT[] = "chat";
+const char STR_SHOW_DND[] = "dnd";
+const char STR_SHOW_XA[] = "xa";
+const char STR_SHOW_OFFLINE[] = "offline";
+
+const char NS_GOOGLE_PSTN_CONFERENCE[] = "http://www.google.com/pstn-conference";
+const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS = { NS_GOOGLE_PSTN_CONFERENCE, "status" };
+const StaticQName QN_ATTR_STATUS = { STR_EMPTY, "status" };
+
+// Presence connection status
+const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[] = "connecting";
+const char STR_PSTN_CONFERENCE_STATUS_JOINING[] = "joining";
+const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[] = "connected";
+const char STR_PSTN_CONFERENCE_STATUS_HANGUP[] = "hangup";
+
+// Subscription
+const char STR_SUBSCRIBE[] = "subscribe";
+const char STR_SUBSCRIBED[] = "subscribed";
+const char STR_UNSUBSCRIBE[] = "unsubscribe";
+const char STR_UNSUBSCRIBED[] = "unsubscribed";
+
+// Google Invite
+const char NS_GOOGLE_SUBSCRIBE[] = "google:subscribe";
+const StaticQName QN_INVITATION = { NS_GOOGLE_SUBSCRIBE, "invitation" };
+const StaticQName QN_INVITE_NAME = { NS_GOOGLE_SUBSCRIBE, "name" };
+const StaticQName QN_INVITE_SUBJECT = { NS_GOOGLE_SUBSCRIBE, "subject" };
+const StaticQName QN_INVITE_MESSAGE = { NS_GOOGLE_SUBSCRIBE, "body" };
+
+// Kick
+const char NS_GOOGLE_MUC_ADMIN[] = "google:muc#admin";
+const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY = { NS_GOOGLE_MUC_ADMIN, "query" };
+const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM =
+    { NS_GOOGLE_MUC_ADMIN, "item" };
+const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON =
+    { NS_GOOGLE_MUC_ADMIN, "reason" };
+
+// PubSub: http://xmpp.org/extensions/xep-0060.html
+const char NS_PUBSUB[] = "http://jabber.org/protocol/pubsub";
+const StaticQName QN_PUBSUB = { NS_PUBSUB, "pubsub" };
+const StaticQName QN_PUBSUB_ITEMS = { NS_PUBSUB, "items" };
+const StaticQName QN_PUBSUB_ITEM = { NS_PUBSUB, "item" };
+const StaticQName QN_PUBSUB_PUBLISH = { NS_PUBSUB, "publish" };
+const StaticQName QN_PUBSUB_RETRACT = { NS_PUBSUB, "retract" };
+const StaticQName QN_ATTR_PUBLISHER = { STR_EMPTY, "publisher" };
+
+const char NS_PUBSUB_EVENT[] = "http://jabber.org/protocol/pubsub#event";
+const StaticQName QN_NODE = { STR_EMPTY, "node" };
+const StaticQName QN_PUBSUB_EVENT = { NS_PUBSUB_EVENT, "event" };
+const StaticQName QN_PUBSUB_EVENT_ITEMS = { NS_PUBSUB_EVENT, "items" };
+const StaticQName QN_PUBSUB_EVENT_ITEM = { NS_PUBSUB_EVENT, "item" };
+const StaticQName QN_PUBSUB_EVENT_RETRACT = { NS_PUBSUB_EVENT, "retract" };
+const StaticQName QN_NOTIFY = { STR_EMPTY, "notify" };
+
+const char NS_PRESENTER[] = "google:presenter";
+const StaticQName QN_PRESENTER_PRESENTER = { NS_PRESENTER, "presenter" };
+const StaticQName QN_PRESENTER_PRESENTATION_ITEM =
+    { NS_PRESENTER, "presentation-item" };
+const StaticQName QN_PRESENTER_PRESENTATION_TYPE =
+    { NS_PRESENTER, "presentation-type" };
+const StaticQName QN_PRESENTER_PRESENTATION_ID =
+    { NS_PRESENTER, "presentation-id" };
+
+// JEP 0030
+const StaticQName QN_CATEGORY = { STR_EMPTY, "category" };
+const StaticQName QN_VAR = { STR_EMPTY, "var" };
+const char NS_DISCO_INFO[] = "http://jabber.org/protocol/disco#info";
+const char NS_DISCO_ITEMS[] = "http://jabber.org/protocol/disco#items";
+const StaticQName QN_DISCO_INFO_QUERY = { NS_DISCO_INFO, "query" };
+const StaticQName QN_DISCO_IDENTITY = { NS_DISCO_INFO, "identity" };
+const StaticQName QN_DISCO_FEATURE = { NS_DISCO_INFO, "feature" };
+
+const StaticQName QN_DISCO_ITEMS_QUERY = { NS_DISCO_ITEMS, "query" };
+const StaticQName QN_DISCO_ITEM = { NS_DISCO_ITEMS, "item" };
+
+// JEP 0020
+const char NS_FEATURE[] = "http://jabber.org/protocol/feature-neg";
+const StaticQName QN_FEATURE_FEATURE = { NS_FEATURE, "feature" };
+
+// JEP 0004
+const char NS_XDATA[] = "jabber:x:data";
+const StaticQName QN_XDATA_X = { NS_XDATA, "x" };
+const StaticQName QN_XDATA_INSTRUCTIONS = { NS_XDATA, "instructions" };
+const StaticQName QN_XDATA_TITLE = { NS_XDATA, "title" };
+const StaticQName QN_XDATA_FIELD = { NS_XDATA, "field" };
+const StaticQName QN_XDATA_REPORTED = { NS_XDATA, "reported" };
+const StaticQName QN_XDATA_ITEM = { NS_XDATA, "item" };
+const StaticQName QN_XDATA_DESC = { NS_XDATA, "desc" };
+const StaticQName QN_XDATA_REQUIRED = { NS_XDATA, "required" };
+const StaticQName QN_XDATA_VALUE = { NS_XDATA, "value" };
+const StaticQName QN_XDATA_OPTION = { NS_XDATA, "option" };
+
+// JEP 0045
+const char NS_MUC[] = "http://jabber.org/protocol/muc";
+const StaticQName QN_MUC_X = { NS_MUC, "x" };
+const StaticQName QN_MUC_ITEM = { NS_MUC, "item" };
+const StaticQName QN_MUC_AFFILIATION = { NS_MUC, "affiliation" };
+const StaticQName QN_MUC_ROLE = { NS_MUC, "role" };
+const char STR_AFFILIATION_NONE[] = "none";
+const char STR_ROLE_PARTICIPANT[] = "participant";
+
+const char NS_GOOGLE_SESSION[] = "http://www.google.com/session";
+const StaticQName QN_GOOGLE_CIRCLE_ID = { STR_EMPTY, "google-circle-id" };
+const StaticQName QN_GOOGLE_USER_ID = { STR_EMPTY, "google-user-id" };
+const StaticQName QN_GOOGLE_SESSION_BLOCKED = { NS_GOOGLE_SESSION, "blocked" };
+const StaticQName QN_GOOGLE_SESSION_BLOCKING =
+    { NS_GOOGLE_SESSION, "blocking" };
+
+const char NS_MUC_OWNER[] = "http://jabber.org/protocol/muc#owner";
+const StaticQName QN_MUC_OWNER_QUERY = { NS_MUC_OWNER, "query" };
+
+const char NS_MUC_USER[] = "http://jabber.org/protocol/muc#user";
+const StaticQName QN_MUC_USER_CONTINUE = { NS_MUC_USER, "continue" };
+const StaticQName QN_MUC_USER_X = { NS_MUC_USER, "x" };
+const StaticQName QN_MUC_USER_ITEM = { NS_MUC_USER, "item" };
+const StaticQName QN_MUC_USER_STATUS = { NS_MUC_USER, "status" };
+const StaticQName QN_MUC_USER_REASON = { NS_MUC_USER, "reason" };
+const StaticQName QN_MUC_USER_ABUSE_VIOLATION = { NS_MUC_USER, "abuse-violation" };
+
+// JEP 0055 - Jabber Search
+const char NS_SEARCH[] = "jabber:iq:search";
+const StaticQName QN_SEARCH_QUERY = { NS_SEARCH, "query" };
+const StaticQName QN_SEARCH_ITEM = { NS_SEARCH, "item" };
+const StaticQName QN_SEARCH_ROOM_NAME = { NS_SEARCH, "room-name" };
+const StaticQName QN_SEARCH_ROOM_DOMAIN = { NS_SEARCH, "room-domain" };
+const StaticQName QN_SEARCH_ROOM_JID = { NS_SEARCH, "room-jid" };
+const StaticQName QN_SEARCH_HANGOUT_ID = { NS_SEARCH, "hangout-id" };
+const StaticQName QN_SEARCH_EXTERNAL_ID = { NS_SEARCH, "external-id" };
+
+// JEP 0115
+const char NS_CAPS[] = "http://jabber.org/protocol/caps";
+const StaticQName QN_CAPS_C = { NS_CAPS, "c" };
+const StaticQName QN_VER = { STR_EMPTY, "ver" };
+const StaticQName QN_EXT = { STR_EMPTY, "ext" };
+
+// JEP 0153
+const char kNSVCard[] = "vcard-temp:x:update";
+const StaticQName kQnVCardX = { kNSVCard, "x" };
+const StaticQName kQnVCardPhoto = { kNSVCard, "photo" };
+
+// JEP 0172 User Nickname
+const char NS_NICKNAME[] = "http://jabber.org/protocol/nick";
+const StaticQName QN_NICKNAME = { NS_NICKNAME, "nick" };
+
+// JEP 0085 chat state
+const char NS_CHATSTATE[] = "http://jabber.org/protocol/chatstates";
+const StaticQName QN_CS_ACTIVE = { NS_CHATSTATE, "active" };
+const StaticQName QN_CS_COMPOSING = { NS_CHATSTATE, "composing" };
+const StaticQName QN_CS_PAUSED = { NS_CHATSTATE, "paused" };
+const StaticQName QN_CS_INACTIVE = { NS_CHATSTATE, "inactive" };
+const StaticQName QN_CS_GONE = { NS_CHATSTATE, "gone" };
+
+// JEP 0091 Delayed Delivery
+const char kNSDelay[] = "jabber:x:delay";
+const StaticQName kQnDelayX = { kNSDelay, "x" };
+const StaticQName kQnStamp = { STR_EMPTY, "stamp" };
+
+// Google time stamping (higher resolution)
+const char kNSTimestamp[] = "google:timestamp";
+const StaticQName kQnTime = { kNSTimestamp, "time" };
+const StaticQName kQnMilliseconds = { STR_EMPTY, "ms" };
+
+// Jingle Info
+const char NS_JINGLE_INFO[] = "google:jingleinfo";
+const StaticQName QN_JINGLE_INFO_QUERY = { NS_JINGLE_INFO, "query" };
+const StaticQName QN_JINGLE_INFO_STUN = { NS_JINGLE_INFO, "stun" };
+const StaticQName QN_JINGLE_INFO_RELAY = { NS_JINGLE_INFO, "relay" };
+const StaticQName QN_JINGLE_INFO_SERVER = { NS_JINGLE_INFO, "server" };
+const StaticQName QN_JINGLE_INFO_TOKEN = { NS_JINGLE_INFO, "token" };
+const StaticQName QN_JINGLE_INFO_HOST = { STR_EMPTY, "host" };
+const StaticQName QN_JINGLE_INFO_TCP = { STR_EMPTY, "tcp" };
+const StaticQName QN_JINGLE_INFO_UDP = { STR_EMPTY, "udp" };
+const StaticQName QN_JINGLE_INFO_TCPSSL = { STR_EMPTY, "tcpssl" };
+
+// Call Performance Logging
+const char NS_GOOGLE_CALLPERF_STATS[] = "google:call-perf-stats";
+const StaticQName QN_CALLPERF_STATS =
+    { NS_GOOGLE_CALLPERF_STATS, "callPerfStats" };
+const StaticQName QN_CALLPERF_SESSIONID = { STR_EMPTY, "sessionId" };
+const StaticQName QN_CALLPERF_LOCALUSER = { STR_EMPTY, "localUser" };
+const StaticQName QN_CALLPERF_REMOTEUSER = { STR_EMPTY, "remoteUser" };
+const StaticQName QN_CALLPERF_STARTTIME = { STR_EMPTY, "startTime" };
+const StaticQName QN_CALLPERF_CALL_LENGTH = { STR_EMPTY, "callLength" };
+const StaticQName QN_CALLPERF_CALL_ACCEPTED = { STR_EMPTY, "callAccepted" };
+const StaticQName QN_CALLPERF_CALL_ERROR_CODE = { STR_EMPTY, "callErrorCode" };
+const StaticQName QN_CALLPERF_TERMINATE_CODE = { STR_EMPTY, "terminateCode" };
+const StaticQName QN_CALLPERF_DATAPOINT =
+    { NS_GOOGLE_CALLPERF_STATS, "dataPoint" };
+const StaticQName QN_CALLPERF_DATAPOINT_TIME = { STR_EMPTY, "timeStamp" };
+const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST =
+    { STR_EMPTY, "fraction_lost" };
+const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST = { STR_EMPTY, "cum_lost" };
+const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX = { STR_EMPTY, "ext_max" };
+const StaticQName QN_CALLPERF_DATAPOINT_JITTER = { STR_EMPTY, "jitter" };
+const StaticQName QN_CALLPERF_DATAPOINT_RTT = { STR_EMPTY, "RTT" };
+const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R =
+    { STR_EMPTY, "bytesReceived" };
+const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R =
+    { STR_EMPTY, "packetsReceived" };
+const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S = { STR_EMPTY, "bytesSent" };
+const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S =
+    { STR_EMPTY, "packetsSent" };
+const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU =
+    { STR_EMPTY, "processCpu" };
+const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU = { STR_EMPTY, "systemCpu" };
+const StaticQName QN_CALLPERF_DATAPOINT_CPUS = { STR_EMPTY, "cpus" };
+const StaticQName QN_CALLPERF_CONNECTION =
+    { NS_GOOGLE_CALLPERF_STATS, "connection" };
+const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS =
+    { STR_EMPTY, "localAddress" };
+const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS =
+    { STR_EMPTY, "remoteAddress" };
+const StaticQName QN_CALLPERF_CONNECTION_FLAGS = { STR_EMPTY, "flags" };
+const StaticQName QN_CALLPERF_CONNECTION_RTT = { STR_EMPTY, "rtt" };
+const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S =
+    { STR_EMPTY, "totalBytesSent" };
+const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S =
+    { STR_EMPTY, "bytesSecondSent" };
+const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R =
+    { STR_EMPTY, "totalBytesRecv" };
+const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R =
+    { STR_EMPTY, "bytesSecondRecv" };
+const StaticQName QN_CALLPERF_CANDIDATE =
+    { NS_GOOGLE_CALLPERF_STATS, "candidate" };
+const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT = { STR_EMPTY, "endpoint" };
+const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL = { STR_EMPTY, "protocol" };
+const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS = { STR_EMPTY, "address" };
+const StaticQName QN_CALLPERF_MEDIA = { NS_GOOGLE_CALLPERF_STATS, "media" };
+const StaticQName QN_CALLPERF_MEDIA_DIRECTION = { STR_EMPTY, "direction" };
+const StaticQName QN_CALLPERF_MEDIA_SSRC = { STR_EMPTY, "SSRC" };
+const StaticQName QN_CALLPERF_MEDIA_ENERGY = { STR_EMPTY, "energy" };
+const StaticQName QN_CALLPERF_MEDIA_FIR = { STR_EMPTY, "fir" };
+const StaticQName QN_CALLPERF_MEDIA_NACK = { STR_EMPTY, "nack" };
+const StaticQName QN_CALLPERF_MEDIA_FPS = { STR_EMPTY, "fps" };
+const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK = { STR_EMPTY, "fpsNetwork" };
+const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED = { STR_EMPTY, "fpsDecoded" };
+const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE =
+    { STR_EMPTY, "jitterBufferSize" };
+const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE =
+    { STR_EMPTY, "preferredJitterBufferSize" };
+const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY =
+    { STR_EMPTY, "totalPlayoutDelay" };
+
+// Muc invites.
+const StaticQName QN_MUC_USER_INVITE = { NS_MUC_USER, "invite" };
+
+// Multiway audio/video.
+const char NS_GOOGLE_MUC_USER[] = "google:muc#user";
+const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA =
+    { NS_GOOGLE_MUC_USER, "available-media" };
+const StaticQName QN_GOOGLE_MUC_USER_ENTRY = { NS_GOOGLE_MUC_USER, "entry" };
+const StaticQName QN_GOOGLE_MUC_USER_MEDIA = { NS_GOOGLE_MUC_USER, "media" };
+const StaticQName QN_GOOGLE_MUC_USER_TYPE = { NS_GOOGLE_MUC_USER, "type" };
+const StaticQName QN_GOOGLE_MUC_USER_SRC_ID = { NS_GOOGLE_MUC_USER, "src-id" };
+const StaticQName QN_GOOGLE_MUC_USER_STATUS = { NS_GOOGLE_MUC_USER, "status" };
+const StaticQName QN_CLIENT_VERSION = { NS_GOOGLE_MUC_USER, "client-version" };
+const StaticQName QN_LOCALE = { NS_GOOGLE_MUC_USER, "locale" };
+const StaticQName QN_LABEL = { STR_EMPTY, "label" };
+
+const char NS_GOOGLE_MUC_MEDIA[] = "google:muc#media";
+const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE =
+    { NS_GOOGLE_MUC_MEDIA, "audio-mute" };
+const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE =
+    { NS_GOOGLE_MUC_MEDIA, "video-mute" };
+const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE =
+    { NS_GOOGLE_MUC_MEDIA, "video-pause" };
+const StaticQName QN_GOOGLE_MUC_RECORDING =
+    { NS_GOOGLE_MUC_MEDIA, "recording" };
+const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK = { NS_GOOGLE_MUC_MEDIA, "block" };
+const StaticQName QN_STATE_ATTR = { STR_EMPTY, "state" };
+
+const char AUTH_MECHANISM_GOOGLE_COOKIE[] = "X-GOOGLE-COOKIE";
+const char AUTH_MECHANISM_GOOGLE_TOKEN[] = "X-GOOGLE-TOKEN";
+const char AUTH_MECHANISM_OAUTH2[] = "X-OAUTH2";
+const char AUTH_MECHANISM_PLAIN[] = "PLAIN";
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/constants.h b/libjingle/xmpp/constants.h
new file mode 100644
index 0000000..5c1967e
--- /dev/null
+++ b/libjingle/xmpp/constants.h
@@ -0,0 +1,551 @@
+/*
+ *  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_LIBJINGLE_XMPP_CONSTANTS_H_
+#define WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
+
+#include <string>
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+
+namespace buzz {
+
+extern const char NS_CLIENT[];
+extern const char NS_SERVER[];
+extern const char NS_STREAM[];
+extern const char NS_XSTREAM[];
+extern const char NS_TLS[];
+extern const char NS_SASL[];
+extern const char NS_BIND[];
+extern const char NS_DIALBACK[];
+extern const char NS_SESSION[];
+extern const char NS_STANZA[];
+extern const char NS_PRIVACY[];
+extern const char NS_ROSTER[];
+extern const char NS_VCARD[];
+extern const char NS_AVATAR_HASH[];
+extern const char NS_VCARD_UPDATE[];
+extern const char STR_CLIENT[];
+extern const char STR_SERVER[];
+extern const char STR_STREAM[];
+
+extern const char STR_GET[];
+extern const char STR_SET[];
+extern const char STR_RESULT[];
+extern const char STR_ERROR[];
+
+extern const char STR_FORM[];
+extern const char STR_SUBMIT[];
+extern const char STR_TEXT_SINGLE[];
+extern const char STR_LIST_SINGLE[];
+extern const char STR_LIST_MULTI[];
+extern const char STR_HIDDEN[];
+extern const char STR_FORM_TYPE[];
+
+extern const char STR_FROM[];
+extern const char STR_TO[];
+extern const char STR_BOTH[];
+extern const char STR_REMOVE[];
+extern const char STR_TRUE[];
+
+extern const char STR_TYPE[];
+extern const char STR_NAME[];
+extern const char STR_ID[];
+extern const char STR_JID[];
+extern const char STR_SUBSCRIPTION[];
+extern const char STR_ASK[];
+extern const char STR_X[];
+extern const char STR_GOOGLE_COM[];
+extern const char STR_GMAIL_COM[];
+extern const char STR_GOOGLEMAIL_COM[];
+extern const char STR_DEFAULT_DOMAIN[];
+extern const char STR_TALK_GOOGLE_COM[];
+extern const char STR_TALKX_L_GOOGLE_COM[];
+extern const char STR_XMPP_GOOGLE_COM[];
+extern const char STR_XMPPX_L_GOOGLE_COM[];
+
+#ifdef FEATURE_ENABLE_VOICEMAIL
+extern const char STR_VOICEMAIL[];
+extern const char STR_OUTGOINGVOICEMAIL[];
+#endif
+
+extern const char STR_UNAVAILABLE[];
+
+extern const char NS_PING[];
+extern const StaticQName QN_PING;
+
+extern const char NS_MUC_UNIQUE[];
+extern const StaticQName QN_MUC_UNIQUE_QUERY;
+extern const StaticQName QN_HANGOUT_ID;
+
+extern const char STR_GOOGLE_MUC_LOOKUP_JID[];
+extern const char STR_MUC_ROOMCONFIG_ROOMNAME[];
+extern const char STR_MUC_ROOMCONFIG_FEATURES[];
+extern const char STR_MUC_ROOM_FEATURE_ENTERPRISE[];
+extern const char STR_MUC_ROOMCONFIG[];
+extern const char STR_MUC_ROOM_FEATURE_HANGOUT[];
+extern const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[];
+extern const char STR_MUC_ROOM_FEATURE_BROADCAST[];
+extern const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[];
+extern const char STR_MUC_ROOM_FEATURE_RECORDABLE[];
+extern const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[];
+extern const char STR_MUC_ROOM_OWNER_PROFILE_ID[];
+extern const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[];
+
+extern const char STR_ID_TYPE_CONVERSATION[];
+extern const char NS_GOOGLE_MUC_HANGOUT[];
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE;
+extern const StaticQName QN_ATTR_CREATE_ACTIVITY;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID;
+
+extern const StaticQName QN_STREAM_STREAM;
+extern const StaticQName QN_STREAM_FEATURES;
+extern const StaticQName QN_STREAM_ERROR;
+
+extern const StaticQName QN_XSTREAM_BAD_FORMAT;
+extern const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX;
+extern const StaticQName QN_XSTREAM_CONFLICT;
+extern const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT;
+extern const StaticQName QN_XSTREAM_HOST_GONE;
+extern const StaticQName QN_XSTREAM_HOST_UNKNOWN;
+extern const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING;
+extern const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR;
+extern const StaticQName QN_XSTREAM_INVALID_FROM;
+extern const StaticQName QN_XSTREAM_INVALID_ID;
+extern const StaticQName QN_XSTREAM_INVALID_NAMESPACE;
+extern const StaticQName QN_XSTREAM_INVALID_XML;
+extern const StaticQName QN_XSTREAM_NOT_AUTHORIZED;
+extern const StaticQName QN_XSTREAM_POLICY_VIOLATION;
+extern const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED;
+extern const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT;
+extern const StaticQName QN_XSTREAM_RESTRICTED_XML;
+extern const StaticQName QN_XSTREAM_SEE_OTHER_HOST;
+extern const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN;
+extern const StaticQName QN_XSTREAM_UNDEFINED_CONDITION;
+extern const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING;
+extern const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE;
+extern const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION;
+extern const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED;
+extern const StaticQName QN_XSTREAM_TEXT;
+
+extern const StaticQName QN_TLS_STARTTLS;
+extern const StaticQName QN_TLS_REQUIRED;
+extern const StaticQName QN_TLS_PROCEED;
+extern const StaticQName QN_TLS_FAILURE;
+
+extern const StaticQName QN_SASL_MECHANISMS;
+extern const StaticQName QN_SASL_MECHANISM;
+extern const StaticQName QN_SASL_AUTH;
+extern const StaticQName QN_SASL_CHALLENGE;
+extern const StaticQName QN_SASL_RESPONSE;
+extern const StaticQName QN_SASL_ABORT;
+extern const StaticQName QN_SASL_SUCCESS;
+extern const StaticQName QN_SASL_FAILURE;
+extern const StaticQName QN_SASL_ABORTED;
+extern const StaticQName QN_SASL_INCORRECT_ENCODING;
+extern const StaticQName QN_SASL_INVALID_AUTHZID;
+extern const StaticQName QN_SASL_INVALID_MECHANISM;
+extern const StaticQName QN_SASL_MECHANISM_TOO_WEAK;
+extern const StaticQName QN_SASL_NOT_AUTHORIZED;
+extern const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE;
+
+// These are non-standard.
+extern const char NS_GOOGLE_AUTH[];
+extern const char NS_GOOGLE_AUTH_PROTOCOL[];
+extern const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT;
+extern const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN;
+extern const StaticQName QN_GOOGLE_AUTH_SERVICE;
+
+extern const StaticQName QN_DIALBACK_RESULT;
+extern const StaticQName QN_DIALBACK_VERIFY;
+
+extern const StaticQName QN_STANZA_BAD_REQUEST;
+extern const StaticQName QN_STANZA_CONFLICT;
+extern const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED;
+extern const StaticQName QN_STANZA_FORBIDDEN;
+extern const StaticQName QN_STANZA_GONE;
+extern const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR;
+extern const StaticQName QN_STANZA_ITEM_NOT_FOUND;
+extern const StaticQName QN_STANZA_JID_MALFORMED;
+extern const StaticQName QN_STANZA_NOT_ACCEPTABLE;
+extern const StaticQName QN_STANZA_NOT_ALLOWED;
+extern const StaticQName QN_STANZA_PAYMENT_REQUIRED;
+extern const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE;
+extern const StaticQName QN_STANZA_REDIRECT;
+extern const StaticQName QN_STANZA_REGISTRATION_REQUIRED;
+extern const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND;
+extern const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT;
+extern const StaticQName QN_STANZA_RESOURCE_CONSTRAINT;
+extern const StaticQName QN_STANZA_SERVICE_UNAVAILABLE;
+extern const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED;
+extern const StaticQName QN_STANZA_UNDEFINED_CONDITION;
+extern const StaticQName QN_STANZA_UNEXPECTED_REQUEST;
+extern const StaticQName QN_STANZA_TEXT;
+
+extern const StaticQName QN_BIND_BIND;
+extern const StaticQName QN_BIND_RESOURCE;
+extern const StaticQName QN_BIND_JID;
+
+extern const StaticQName QN_MESSAGE;
+extern const StaticQName QN_BODY;
+extern const StaticQName QN_SUBJECT;
+extern const StaticQName QN_THREAD;
+extern const StaticQName QN_PRESENCE;
+extern const StaticQName QN_SHOW;
+extern const StaticQName QN_STATUS;
+extern const StaticQName QN_LANG;
+extern const StaticQName QN_PRIORITY;
+extern const StaticQName QN_IQ;
+extern const StaticQName QN_ERROR;
+
+extern const StaticQName QN_SERVER_MESSAGE;
+extern const StaticQName QN_SERVER_BODY;
+extern const StaticQName QN_SERVER_SUBJECT;
+extern const StaticQName QN_SERVER_THREAD;
+extern const StaticQName QN_SERVER_PRESENCE;
+extern const StaticQName QN_SERVER_SHOW;
+extern const StaticQName QN_SERVER_STATUS;
+extern const StaticQName QN_SERVER_LANG;
+extern const StaticQName QN_SERVER_PRIORITY;
+extern const StaticQName QN_SERVER_IQ;
+extern const StaticQName QN_SERVER_ERROR;
+
+extern const StaticQName QN_SESSION_SESSION;
+
+extern const StaticQName QN_PRIVACY_QUERY;
+extern const StaticQName QN_PRIVACY_ACTIVE;
+extern const StaticQName QN_PRIVACY_DEFAULT;
+extern const StaticQName QN_PRIVACY_LIST;
+extern const StaticQName QN_PRIVACY_ITEM;
+extern const StaticQName QN_PRIVACY_IQ;
+extern const StaticQName QN_PRIVACY_MESSAGE;
+extern const StaticQName QN_PRIVACY_PRESENCE_IN;
+extern const StaticQName QN_PRIVACY_PRESENCE_OUT;
+
+extern const StaticQName QN_ROSTER_QUERY;
+extern const StaticQName QN_ROSTER_ITEM;
+extern const StaticQName QN_ROSTER_GROUP;
+
+extern const StaticQName QN_VCARD;
+extern const StaticQName QN_VCARD_FN;
+extern const StaticQName QN_VCARD_PHOTO;
+extern const StaticQName QN_VCARD_PHOTO_BINVAL;
+extern const StaticQName QN_VCARD_AVATAR_HASH;
+extern const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED;
+
+#if defined(FEATURE_ENABLE_PSTN)
+extern const StaticQName QN_VCARD_TEL;
+extern const StaticQName QN_VCARD_VOICE;
+extern const StaticQName QN_VCARD_HOME;
+extern const StaticQName QN_VCARD_WORK;
+extern const StaticQName QN_VCARD_CELL;
+extern const StaticQName QN_VCARD_NUMBER;
+#endif
+
+#if defined(FEATURE_ENABLE_RICHPROFILES)
+extern const StaticQName QN_USER_PROFILE_QUERY;
+extern const StaticQName QN_USER_PROFILE_URL;
+
+extern const StaticQName QN_ATOM_FEED;
+extern const StaticQName QN_ATOM_ENTRY;
+extern const StaticQName QN_ATOM_TITLE;
+extern const StaticQName QN_ATOM_ID;
+extern const StaticQName QN_ATOM_MODIFIED;
+extern const StaticQName QN_ATOM_IMAGE;
+extern const StaticQName QN_ATOM_LINK;
+extern const StaticQName QN_ATOM_HREF;
+#endif
+
+extern const StaticQName QN_XML_LANG;
+
+extern const StaticQName QN_ENCODING;
+extern const StaticQName QN_VERSION;
+extern const StaticQName QN_TO;
+extern const StaticQName QN_FROM;
+extern const StaticQName QN_TYPE;
+extern const StaticQName QN_ID;
+extern const StaticQName QN_CODE;
+extern const StaticQName QN_NAME;
+extern const StaticQName QN_VALUE;
+extern const StaticQName QN_ACTION;
+extern const StaticQName QN_ORDER;
+extern const StaticQName QN_MECHANISM;
+extern const StaticQName QN_ASK;
+extern const StaticQName QN_JID;
+extern const StaticQName QN_NICK;
+extern const StaticQName QN_SUBSCRIPTION;
+extern const StaticQName QN_TITLE1;
+extern const StaticQName QN_TITLE2;
+extern const StaticQName QN_AFFILIATION;
+extern const StaticQName QN_ROLE;
+extern const StaticQName QN_TIME;
+
+extern const StaticQName QN_XMLNS_CLIENT;
+extern const StaticQName QN_XMLNS_SERVER;
+extern const StaticQName QN_XMLNS_STREAM;
+
+// Presence
+extern const char STR_SHOW_AWAY[];
+extern const char STR_SHOW_CHAT[];
+extern const char STR_SHOW_DND[];
+extern const char STR_SHOW_XA[];
+extern const char STR_SHOW_OFFLINE[];
+
+extern const char NS_GOOGLE_PSTN_CONFERENCE[];
+extern const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS;
+extern const StaticQName QN_ATTR_STATUS;
+
+// Presence connection status
+extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[];
+extern const char STR_PSTN_CONFERENCE_STATUS_JOINING[];
+extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[];
+extern const char STR_PSTN_CONFERENCE_STATUS_HANGUP[];
+
+// Subscription
+extern const char STR_SUBSCRIBE[];
+extern const char STR_SUBSCRIBED[];
+extern const char STR_UNSUBSCRIBE[];
+extern const char STR_UNSUBSCRIBED[];
+
+// Google Invite
+extern const char NS_GOOGLE_SUBSCRIBE[];
+extern const StaticQName QN_INVITATION;
+extern const StaticQName QN_INVITE_NAME;
+extern const StaticQName QN_INVITE_SUBJECT;
+extern const StaticQName QN_INVITE_MESSAGE;
+
+// Kick
+extern const char NS_GOOGLE_MUC_ADMIN[];
+extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY;
+extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM;
+extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON;
+
+// PubSub: http://xmpp.org/extensions/xep-0060.html
+extern const char NS_PUBSUB[];
+extern const StaticQName QN_PUBSUB;
+extern const StaticQName QN_PUBSUB_ITEMS;
+extern const StaticQName QN_PUBSUB_ITEM;
+extern const StaticQName QN_PUBSUB_PUBLISH;
+extern const StaticQName QN_PUBSUB_RETRACT;
+extern const StaticQName QN_ATTR_PUBLISHER;
+
+extern const char NS_PUBSUB_EVENT[];
+extern const StaticQName QN_NODE;
+extern const StaticQName QN_PUBSUB_EVENT;
+extern const StaticQName QN_PUBSUB_EVENT_ITEMS;
+extern const StaticQName QN_PUBSUB_EVENT_ITEM;
+extern const StaticQName QN_PUBSUB_EVENT_RETRACT;
+extern const StaticQName QN_NOTIFY;
+
+extern const char NS_PRESENTER[];
+extern const StaticQName QN_PRESENTER_PRESENTER;
+extern const StaticQName QN_PRESENTER_PRESENTATION_ITEM;
+extern const StaticQName QN_PRESENTER_PRESENTATION_TYPE;
+extern const StaticQName QN_PRESENTER_PRESENTATION_ID;
+
+// JEP 0030
+extern const StaticQName QN_CATEGORY;
+extern const StaticQName QN_VAR;
+extern const char NS_DISCO_INFO[];
+extern const char NS_DISCO_ITEMS[];
+
+extern const StaticQName QN_DISCO_INFO_QUERY;
+extern const StaticQName QN_DISCO_IDENTITY;
+extern const StaticQName QN_DISCO_FEATURE;
+
+extern const StaticQName QN_DISCO_ITEMS_QUERY;
+extern const StaticQName QN_DISCO_ITEM;
+
+// JEP 0020
+extern const char NS_FEATURE[];
+extern const StaticQName QN_FEATURE_FEATURE;
+
+// JEP 0004
+extern const char NS_XDATA[];
+extern const StaticQName QN_XDATA_X;
+extern const StaticQName QN_XDATA_INSTRUCTIONS;
+extern const StaticQName QN_XDATA_TITLE;
+extern const StaticQName QN_XDATA_FIELD;
+extern const StaticQName QN_XDATA_REPORTED;
+extern const StaticQName QN_XDATA_ITEM;
+extern const StaticQName QN_XDATA_DESC;
+extern const StaticQName QN_XDATA_REQUIRED;
+extern const StaticQName QN_XDATA_VALUE;
+extern const StaticQName QN_XDATA_OPTION;
+
+// JEP 0045
+extern const char NS_MUC[];
+extern const StaticQName QN_MUC_X;
+extern const StaticQName QN_MUC_ITEM;
+extern const StaticQName QN_MUC_AFFILIATION;
+extern const StaticQName QN_MUC_ROLE;
+extern const StaticQName QN_CLIENT_VERSION;
+extern const StaticQName QN_LOCALE;
+extern const char STR_AFFILIATION_NONE[];
+extern const char STR_ROLE_PARTICIPANT[];
+
+extern const char NS_GOOGLE_SESSION[];
+extern const StaticQName QN_GOOGLE_USER_ID;
+extern const StaticQName QN_GOOGLE_CIRCLE_ID;
+extern const StaticQName QN_GOOGLE_SESSION_BLOCKED;
+extern const StaticQName QN_GOOGLE_SESSION_BLOCKING;
+
+extern const char NS_MUC_OWNER[];
+extern const StaticQName QN_MUC_OWNER_QUERY;
+
+extern const char NS_MUC_USER[];
+extern const StaticQName QN_MUC_USER_CONTINUE;
+extern const StaticQName QN_MUC_USER_X;
+extern const StaticQName QN_MUC_USER_ITEM;
+extern const StaticQName QN_MUC_USER_STATUS;
+extern const StaticQName QN_MUC_USER_REASON;
+extern const StaticQName QN_MUC_USER_ABUSE_VIOLATION;
+
+// JEP 0055 - Jabber Search
+extern const char NS_SEARCH[];
+extern const StaticQName QN_SEARCH_QUERY;
+extern const StaticQName QN_SEARCH_ITEM;
+extern const StaticQName QN_SEARCH_ROOM_NAME;
+extern const StaticQName QN_SEARCH_ROOM_JID;
+extern const StaticQName QN_SEARCH_ROOM_DOMAIN;
+extern const StaticQName QN_SEARCH_HANGOUT_ID;
+extern const StaticQName QN_SEARCH_EXTERNAL_ID;
+
+// JEP 0115
+extern const char NS_CAPS[];
+extern const StaticQName QN_CAPS_C;
+extern const StaticQName QN_VER;
+extern const StaticQName QN_EXT;
+
+
+// Avatar - JEP 0153
+extern const char kNSVCard[];
+extern const StaticQName kQnVCardX;
+extern const StaticQName kQnVCardPhoto;
+
+// JEP 0172 User Nickname
+extern const char NS_NICKNAME[];
+extern const StaticQName QN_NICKNAME;
+
+// JEP 0085 chat state
+extern const char NS_CHATSTATE[];
+extern const StaticQName QN_CS_ACTIVE;
+extern const StaticQName QN_CS_COMPOSING;
+extern const StaticQName QN_CS_PAUSED;
+extern const StaticQName QN_CS_INACTIVE;
+extern const StaticQName QN_CS_GONE;
+
+// JEP 0091 Delayed Delivery
+extern const char kNSDelay[];
+extern const StaticQName kQnDelayX;
+extern const StaticQName kQnStamp;
+
+// Google time stamping (higher resolution)
+extern const char kNSTimestamp[];
+extern const StaticQName kQnTime;
+extern const StaticQName kQnMilliseconds;
+
+extern const char NS_JINGLE_INFO[];
+extern const StaticQName QN_JINGLE_INFO_QUERY;
+extern const StaticQName QN_JINGLE_INFO_STUN;
+extern const StaticQName QN_JINGLE_INFO_RELAY;
+extern const StaticQName QN_JINGLE_INFO_SERVER;
+extern const StaticQName QN_JINGLE_INFO_TOKEN;
+extern const StaticQName QN_JINGLE_INFO_HOST;
+extern const StaticQName QN_JINGLE_INFO_TCP;
+extern const StaticQName QN_JINGLE_INFO_UDP;
+extern const StaticQName QN_JINGLE_INFO_TCPSSL;
+
+extern const char NS_GOOGLE_CALLPERF_STATS[];
+extern const StaticQName QN_CALLPERF_STATS;
+extern const StaticQName QN_CALLPERF_SESSIONID;
+extern const StaticQName QN_CALLPERF_LOCALUSER;
+extern const StaticQName QN_CALLPERF_REMOTEUSER;
+extern const StaticQName QN_CALLPERF_STARTTIME;
+extern const StaticQName QN_CALLPERF_CALL_LENGTH;
+extern const StaticQName QN_CALLPERF_CALL_ACCEPTED;
+extern const StaticQName QN_CALLPERF_CALL_ERROR_CODE;
+extern const StaticQName QN_CALLPERF_TERMINATE_CODE;
+extern const StaticQName QN_CALLPERF_DATAPOINT;
+extern const StaticQName QN_CALLPERF_DATAPOINT_TIME;
+extern const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST;
+extern const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST;
+extern const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX;
+extern const StaticQName QN_CALLPERF_DATAPOINT_JITTER;
+extern const StaticQName QN_CALLPERF_DATAPOINT_RTT;
+extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R;
+extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R;
+extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S;
+extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S;
+extern const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU;
+extern const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU;
+extern const StaticQName QN_CALLPERF_DATAPOINT_CPUS;
+extern const StaticQName QN_CALLPERF_CONNECTION;
+extern const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS;
+extern const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS;
+extern const StaticQName QN_CALLPERF_CONNECTION_FLAGS;
+extern const StaticQName QN_CALLPERF_CONNECTION_RTT;
+extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S;
+extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S;
+extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R;
+extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R;
+extern const StaticQName QN_CALLPERF_CANDIDATE;
+extern const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT;
+extern const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL;
+extern const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS;
+extern const StaticQName QN_CALLPERF_MEDIA;
+extern const StaticQName QN_CALLPERF_MEDIA_DIRECTION;
+extern const StaticQName QN_CALLPERF_MEDIA_SSRC;
+extern const StaticQName QN_CALLPERF_MEDIA_ENERGY;
+extern const StaticQName QN_CALLPERF_MEDIA_FIR;
+extern const StaticQName QN_CALLPERF_MEDIA_NACK;
+extern const StaticQName QN_CALLPERF_MEDIA_FPS;
+extern const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK;
+extern const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED;
+extern const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE;
+extern const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE;
+extern const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY;
+
+// Muc invites.
+extern const StaticQName QN_MUC_USER_INVITE;
+
+// Multiway audio/video.
+extern const char NS_GOOGLE_MUC_USER[];
+extern const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA;
+extern const StaticQName QN_GOOGLE_MUC_USER_ENTRY;
+extern const StaticQName QN_GOOGLE_MUC_USER_MEDIA;
+extern const StaticQName QN_GOOGLE_MUC_USER_TYPE;
+extern const StaticQName QN_GOOGLE_MUC_USER_SRC_ID;
+extern const StaticQName QN_GOOGLE_MUC_USER_STATUS;
+extern const StaticQName QN_LABEL;
+
+extern const char NS_GOOGLE_MUC_MEDIA[];
+extern const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE;
+extern const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE;
+extern const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE;
+extern const StaticQName QN_GOOGLE_MUC_RECORDING;
+extern const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK;
+extern const StaticQName QN_STATE_ATTR;
+
+
+extern const char AUTH_MECHANISM_GOOGLE_COOKIE[];
+extern const char AUTH_MECHANISM_GOOGLE_TOKEN[];
+extern const char AUTH_MECHANISM_OAUTH2[];
+extern const char AUTH_MECHANISM_PLAIN[];
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
diff --git a/libjingle/xmpp/discoitemsquerytask.cc b/libjingle/xmpp/discoitemsquerytask.cc
new file mode 100644
index 0000000..765ee14
--- /dev/null
+++ b/libjingle/xmpp/discoitemsquerytask.cc
@@ -0,0 +1,62 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/discoitemsquerytask.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace buzz {
+
+DiscoItemsQueryTask::DiscoItemsQueryTask(XmppTaskParentInterface* parent,
+                                         const Jid& to,
+                                         const std::string& node)
+    : IqTask(parent, STR_GET, to, MakeRequest(node)) {
+}
+
+XmlElement* DiscoItemsQueryTask::MakeRequest(const std::string& node) {
+  XmlElement* element = new XmlElement(QN_DISCO_ITEMS_QUERY, true);
+  if (!node.empty()) {
+    element->AddAttr(QN_NODE, node);
+  }
+  return element;
+}
+
+void DiscoItemsQueryTask::HandleResult(const XmlElement* stanza) {
+  const XmlElement* query = stanza->FirstNamed(QN_DISCO_ITEMS_QUERY);
+  if (query) {
+    std::vector<DiscoItem> items;
+    for (const buzz::XmlChild* child = query->FirstChild(); child;
+         child = child->NextChild()) {
+      DiscoItem item;
+      const buzz::XmlElement* child_element = child->AsElement();
+      if (ParseItem(child_element, &item)) {
+        items.push_back(item);
+      }
+    }
+    SignalResult(items);
+  } else {
+    SignalError(this, NULL);
+  }
+}
+
+bool DiscoItemsQueryTask::ParseItem(const XmlElement* element,
+                                    DiscoItem* item) {
+  if (element->HasAttr(QN_JID)) {
+    return false;
+  }
+
+  item->jid = element->Attr(QN_JID);
+  item->name = element->Attr(QN_NAME);
+  item->node = element->Attr(QN_NODE);
+  return true;
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/discoitemsquerytask.h b/libjingle/xmpp/discoitemsquerytask.h
new file mode 100644
index 0000000..62e862e
--- /dev/null
+++ b/libjingle/xmpp/discoitemsquerytask.h
@@ -0,0 +1,65 @@
+/*
+ *  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.
+ */
+
+// Fires a disco items query, such as the following example:
+//
+//      <iq type='get'
+//          from='foo@gmail.com/asdf'
+//          to='bar@google.com'
+//          id='1234'>
+//          <query xmlns=' http://jabber.org/protocol/disco#items'
+//                 node='blah '/>
+//      </iq>
+//
+// Sample response:
+//
+//      <iq type='result'
+//          from=' hendriks@google.com'
+//          to='rsturgell@google.com/asdf'
+//          id='1234'>
+//          <query xmlns=' http://jabber.org/protocol/disco#items '
+//                 node='blah'>
+//                 <item something='somethingelse'/>
+//          </query>
+//      </iq>
+
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_DISCOITEMSQUERYTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_DISCOITEMSQUERYTASK_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/iqtask.h"
+
+namespace buzz {
+
+struct DiscoItem {
+  std::string jid;
+  std::string node;
+  std::string name;
+};
+
+class DiscoItemsQueryTask : public IqTask {
+ public:
+  DiscoItemsQueryTask(XmppTaskParentInterface* parent,
+                      const Jid& to, const std::string& node);
+
+  sigslot::signal1<std::vector<DiscoItem> > SignalResult;
+
+ private:
+  static XmlElement* MakeRequest(const std::string& node);
+  virtual void HandleResult(const XmlElement* result);
+  static bool ParseItem(const XmlElement* element, DiscoItem* item);
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_DISCOITEMSQUERYTASK_H_
diff --git a/libjingle/xmpp/fakexmppclient.h b/libjingle/xmpp/fakexmppclient.h
new file mode 100644
index 0000000..453a7c8
--- /dev/null
+++ b/libjingle/xmpp/fakexmppclient.h
@@ -0,0 +1,106 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+// A fake XmppClient for use in unit tests.
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace buzz {
+
+class XmlElement;
+
+class FakeXmppClient : public XmppTaskParentInterface,
+                       public XmppClientInterface {
+ public:
+  explicit FakeXmppClient(rtc::TaskParent* parent)
+      : XmppTaskParentInterface(parent) {
+  }
+
+  // As XmppTaskParentInterface
+  virtual XmppClientInterface* GetClient() {
+    return this;
+  }
+
+  virtual int ProcessStart() {
+    return STATE_RESPONSE;
+  }
+
+  // As XmppClientInterface
+  virtual XmppEngine::State GetState() const {
+    return XmppEngine::STATE_OPEN;
+  }
+
+  virtual const Jid& jid() const {
+    return jid_;
+  }
+
+  virtual std::string NextId() {
+    // Implement if needed for tests.
+    return "0";
+  }
+
+  virtual XmppReturnStatus SendStanza(const XmlElement* stanza) {
+    sent_stanzas_.push_back(stanza);
+    return XMPP_RETURN_OK;
+  }
+
+  const std::vector<const XmlElement*>& sent_stanzas() {
+    return sent_stanzas_;
+  }
+
+  virtual XmppReturnStatus SendStanzaError(
+      const XmlElement * pelOriginal,
+      XmppStanzaError code,
+      const std::string & text) {
+    // Implement if needed for tests.
+    return XMPP_RETURN_OK;
+  }
+
+  virtual void AddXmppTask(XmppTask* task,
+                           XmppEngine::HandlerLevel level) {
+    tasks_.push_back(task);
+  }
+
+  virtual void RemoveXmppTask(XmppTask* task) {
+    std::remove(tasks_.begin(), tasks_.end(), task);
+  }
+
+  // As FakeXmppClient
+  void set_jid(const Jid& jid) {
+    jid_ = jid;
+  }
+
+  // Takes ownership of stanza.
+  void HandleStanza(XmlElement* stanza) {
+    for (std::vector<XmppTask*>::iterator task = tasks_.begin();
+         task != tasks_.end(); ++task) {
+      if ((*task)->HandleStanza(stanza)) {
+        delete stanza;
+        return;
+      }
+    }
+    delete stanza;
+  }
+
+ private:
+  Jid jid_;
+  std::vector<XmppTask*> tasks_;
+  std::vector<const XmlElement*> sent_stanzas_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
diff --git a/libjingle/xmpp/hangoutpubsubclient.cc b/libjingle/xmpp/hangoutpubsubclient.cc
new file mode 100644
index 0000000..db1ac31
--- /dev/null
+++ b/libjingle/xmpp/hangoutpubsubclient.cc
@@ -0,0 +1,400 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/hangoutpubsubclient.h"
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/base/logging.h"
+
+
+// Gives a high-level API for MUC call PubSub needs such as
+// presenter state, recording state, mute state, and remote mute.
+
+namespace buzz {
+
+namespace {
+const char kPresenting[] = "s";
+const char kNotPresenting[] = "o";
+
+}  // namespace
+
+// A simple serialiazer where presence of item => true, lack of item
+// => false.
+class BoolStateSerializer : public PubSubStateSerializer<bool> {
+  virtual XmlElement* Write(const QName& state_name, const bool& state) {
+    if (!state) {
+      return NULL;
+    }
+
+    return new XmlElement(state_name, true);
+  }
+
+  virtual void Parse(const XmlElement* state_elem, bool *state_out) {
+    *state_out = state_elem != NULL;
+  }
+};
+
+class PresenterStateClient : public PubSubStateClient<bool> {
+ public:
+  PresenterStateClient(const std::string& publisher_nick,
+                       PubSubClient* client,
+                       const QName& state_name,
+                       bool default_state)
+      : PubSubStateClient<bool>(
+          publisher_nick, client, state_name, default_state,
+          new PublishedNickKeySerializer(), NULL) {
+  }
+
+  virtual void Publish(const std::string& published_nick,
+                       const bool& state,
+                       std::string* task_id_out) {
+    XmlElement* presenter_elem = new XmlElement(QN_PRESENTER_PRESENTER, true);
+    presenter_elem->AddAttr(QN_NICK, published_nick);
+
+    XmlElement* presentation_item_elem =
+        new XmlElement(QN_PRESENTER_PRESENTATION_ITEM, false);
+    const std::string& presentation_type = state ? kPresenting : kNotPresenting;
+    presentation_item_elem->AddAttr(
+        QN_PRESENTER_PRESENTATION_TYPE, presentation_type);
+
+    // The Presenter state is kind of dumb in that it doesn't always use
+    // retracts.  It relies on setting the "type" to a special value.
+    std::string itemid = published_nick;
+    std::vector<XmlElement*> children;
+    children.push_back(presenter_elem);
+    children.push_back(presentation_item_elem);
+    client()->PublishItem(itemid, children, task_id_out);
+  }
+
+ protected:
+  virtual bool ParseStateItem(const PubSubItem& item,
+                              StateItemInfo* info_out,
+                              bool* state_out) {
+    const XmlElement* presenter_elem =
+        item.elem->FirstNamed(QN_PRESENTER_PRESENTER);
+    const XmlElement* presentation_item_elem =
+        item.elem->FirstNamed(QN_PRESENTER_PRESENTATION_ITEM);
+    if (presentation_item_elem == NULL || presenter_elem == NULL) {
+      return false;
+    }
+
+    info_out->publisher_nick =
+        client()->GetPublisherNickFromPubSubItem(item.elem);
+    info_out->published_nick = presenter_elem->Attr(QN_NICK);
+    *state_out = (presentation_item_elem->Attr(
+        QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting);
+    return true;
+  }
+
+  virtual bool StatesEqual(const bool& state1, const bool& state2) {
+    // Make every item trigger an event, even if state doesn't change.
+    return false;
+  }
+};
+
+HangoutPubSubClient::HangoutPubSubClient(XmppTaskParentInterface* parent,
+                                         const Jid& mucjid,
+                                         const std::string& nick)
+    : mucjid_(mucjid),
+      nick_(nick) {
+  presenter_client_.reset(new PubSubClient(parent, mucjid, NS_PRESENTER));
+  presenter_client_->SignalRequestError.connect(
+      this, &HangoutPubSubClient::OnPresenterRequestError);
+
+  media_client_.reset(new PubSubClient(parent, mucjid, NS_GOOGLE_MUC_MEDIA));
+  media_client_->SignalRequestError.connect(
+      this, &HangoutPubSubClient::OnMediaRequestError);
+
+  presenter_state_client_.reset(new PresenterStateClient(
+      nick_, presenter_client_.get(), QN_PRESENTER_PRESENTER, false));
+  presenter_state_client_->SignalStateChange.connect(
+      this, &HangoutPubSubClient::OnPresenterStateChange);
+  presenter_state_client_->SignalPublishResult.connect(
+      this, &HangoutPubSubClient::OnPresenterPublishResult);
+  presenter_state_client_->SignalPublishError.connect(
+      this, &HangoutPubSubClient::OnPresenterPublishError);
+
+  audio_mute_state_client_.reset(new PubSubStateClient<bool>(
+      nick_, media_client_.get(), QN_GOOGLE_MUC_AUDIO_MUTE, false,
+      new PublishedNickKeySerializer(), new BoolStateSerializer()));
+  // Can't just repeat because we need to watch for remote mutes.
+  audio_mute_state_client_->SignalStateChange.connect(
+      this, &HangoutPubSubClient::OnAudioMuteStateChange);
+  audio_mute_state_client_->SignalPublishResult.connect(
+      this, &HangoutPubSubClient::OnAudioMutePublishResult);
+  audio_mute_state_client_->SignalPublishError.connect(
+      this, &HangoutPubSubClient::OnAudioMutePublishError);
+
+  video_mute_state_client_.reset(new PubSubStateClient<bool>(
+      nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_MUTE, false,
+      new PublishedNickKeySerializer(), new BoolStateSerializer()));
+  // Can't just repeat because we need to watch for remote mutes.
+  video_mute_state_client_->SignalStateChange.connect(
+      this, &HangoutPubSubClient::OnVideoMuteStateChange);
+  video_mute_state_client_->SignalPublishResult.connect(
+      this, &HangoutPubSubClient::OnVideoMutePublishResult);
+  video_mute_state_client_->SignalPublishError.connect(
+      this, &HangoutPubSubClient::OnVideoMutePublishError);
+
+  video_pause_state_client_.reset(new PubSubStateClient<bool>(
+      nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_PAUSE, false,
+      new PublishedNickKeySerializer(), new BoolStateSerializer()));
+  video_pause_state_client_->SignalStateChange.connect(
+      this, &HangoutPubSubClient::OnVideoPauseStateChange);
+  video_pause_state_client_->SignalPublishResult.connect(
+      this, &HangoutPubSubClient::OnVideoPausePublishResult);
+  video_pause_state_client_->SignalPublishError.connect(
+      this, &HangoutPubSubClient::OnVideoPausePublishError);
+
+  recording_state_client_.reset(new PubSubStateClient<bool>(
+      nick_, media_client_.get(), QN_GOOGLE_MUC_RECORDING, false,
+      new PublishedNickKeySerializer(), new BoolStateSerializer()));
+  recording_state_client_->SignalStateChange.connect(
+      this, &HangoutPubSubClient::OnRecordingStateChange);
+  recording_state_client_->SignalPublishResult.connect(
+      this, &HangoutPubSubClient::OnRecordingPublishResult);
+  recording_state_client_->SignalPublishError.connect(
+      this, &HangoutPubSubClient::OnRecordingPublishError);
+
+  media_block_state_client_.reset(new PubSubStateClient<bool>(
+      nick_, media_client_.get(), QN_GOOGLE_MUC_MEDIA_BLOCK, false,
+      new PublisherAndPublishedNicksKeySerializer(),
+      new BoolStateSerializer()));
+  media_block_state_client_->SignalStateChange.connect(
+      this, &HangoutPubSubClient::OnMediaBlockStateChange);
+  media_block_state_client_->SignalPublishResult.connect(
+      this, &HangoutPubSubClient::OnMediaBlockPublishResult);
+  media_block_state_client_->SignalPublishError.connect(
+      this, &HangoutPubSubClient::OnMediaBlockPublishError);
+}
+
+HangoutPubSubClient::~HangoutPubSubClient() {
+}
+
+void HangoutPubSubClient::RequestAll() {
+  presenter_client_->RequestItems();
+  media_client_->RequestItems();
+}
+
+void HangoutPubSubClient::OnPresenterRequestError(
+    PubSubClient* client, const XmlElement* stanza) {
+  SignalRequestError(client->node(), stanza);
+}
+
+void HangoutPubSubClient::OnMediaRequestError(
+    PubSubClient* client, const XmlElement* stanza) {
+  SignalRequestError(client->node(), stanza);
+}
+
+void HangoutPubSubClient::PublishPresenterState(
+    bool presenting, std::string* task_id_out) {
+  presenter_state_client_->Publish(nick_, presenting, task_id_out);
+}
+
+void HangoutPubSubClient::PublishAudioMuteState(
+    bool muted, std::string* task_id_out) {
+  audio_mute_state_client_->Publish(nick_, muted, task_id_out);
+}
+
+void HangoutPubSubClient::PublishVideoMuteState(
+    bool muted, std::string* task_id_out) {
+  video_mute_state_client_->Publish(nick_, muted, task_id_out);
+}
+
+void HangoutPubSubClient::PublishVideoPauseState(
+    bool paused, std::string* task_id_out) {
+  video_pause_state_client_->Publish(nick_, paused, task_id_out);
+}
+
+void HangoutPubSubClient::PublishRecordingState(
+    bool recording, std::string* task_id_out) {
+  recording_state_client_->Publish(nick_, recording, task_id_out);
+}
+
+// Remote mute is accomplished by setting another client's mute state.
+void HangoutPubSubClient::RemoteMute(
+    const std::string& mutee_nick, std::string* task_id_out) {
+  audio_mute_state_client_->Publish(mutee_nick, true, task_id_out);
+}
+
+// Block media is accomplished by setting another client's block
+// state, kind of like remote mute.
+void HangoutPubSubClient::BlockMedia(
+    const std::string& blockee_nick, std::string* task_id_out) {
+  media_block_state_client_->Publish(blockee_nick, true, task_id_out);
+}
+
+void HangoutPubSubClient::OnPresenterStateChange(
+    const PubSubStateChange<bool>& change) {
+  SignalPresenterStateChange(
+      change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnPresenterPublishResult(
+    const std::string& task_id, const XmlElement* item) {
+  SignalPublishPresenterResult(task_id);
+}
+
+void HangoutPubSubClient::OnPresenterPublishError(
+    const std::string& task_id, const XmlElement* item,
+    const XmlElement* stanza) {
+  SignalPublishPresenterError(task_id, stanza);
+}
+
+// Since a remote mute is accomplished by another client setting our
+// mute state, if our state changes to muted, we should mute ourselves.
+// Note that remote un-muting is disallowed by the RoomServer.
+void HangoutPubSubClient::OnAudioMuteStateChange(
+    const PubSubStateChange<bool>& change) {
+  bool was_muted = change.old_state;
+  bool is_muted = change.new_state;
+  bool remote_action = (!change.publisher_nick.empty() &&
+                        (change.publisher_nick != change.published_nick));
+
+  if (remote_action) {
+    const std::string& mutee_nick = change.published_nick;
+    const std::string& muter_nick = change.publisher_nick;
+    if (!is_muted) {
+      // The server should prevent remote un-mute.
+      LOG(LS_WARNING) << muter_nick << " remote unmuted " << mutee_nick;
+      return;
+    }
+    bool should_mute_locally = (mutee_nick == nick_);
+    SignalRemoteMute(mutee_nick, muter_nick, should_mute_locally);
+  }
+  SignalAudioMuteStateChange(change.published_nick, was_muted, is_muted);
+}
+
+const std::string GetAudioMuteNickFromItem(const XmlElement* item) {
+  if (item != NULL) {
+    const XmlElement* audio_mute_state =
+        item->FirstNamed(QN_GOOGLE_MUC_AUDIO_MUTE);
+    if (audio_mute_state != NULL) {
+      return audio_mute_state->Attr(QN_NICK);
+    }
+  }
+  return std::string();
+}
+
+const std::string GetBlockeeNickFromItem(const XmlElement* item) {
+  if (item != NULL) {
+    const XmlElement* media_block_state =
+        item->FirstNamed(QN_GOOGLE_MUC_MEDIA_BLOCK);
+    if (media_block_state != NULL) {
+      return media_block_state->Attr(QN_NICK);
+    }
+  }
+  return std::string();
+}
+
+void HangoutPubSubClient::OnAudioMutePublishResult(
+    const std::string& task_id, const XmlElement* item) {
+  const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
+  if (mutee_nick != nick_) {
+    SignalRemoteMuteResult(task_id, mutee_nick);
+  } else {
+    SignalPublishAudioMuteResult(task_id);
+  }
+}
+
+void HangoutPubSubClient::OnAudioMutePublishError(
+    const std::string& task_id, const XmlElement* item,
+    const XmlElement* stanza) {
+  const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
+  if (mutee_nick != nick_) {
+    SignalRemoteMuteError(task_id, mutee_nick, stanza);
+  } else {
+    SignalPublishAudioMuteError(task_id, stanza);
+  }
+}
+
+void HangoutPubSubClient::OnVideoMuteStateChange(
+    const PubSubStateChange<bool>& change) {
+  SignalVideoMuteStateChange(
+      change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnVideoMutePublishResult(
+    const std::string& task_id, const XmlElement* item) {
+  SignalPublishVideoMuteResult(task_id);
+}
+
+void HangoutPubSubClient::OnVideoMutePublishError(
+    const std::string& task_id, const XmlElement* item,
+    const XmlElement* stanza) {
+  SignalPublishVideoMuteError(task_id, stanza);
+}
+
+void HangoutPubSubClient::OnVideoPauseStateChange(
+    const PubSubStateChange<bool>& change) {
+  SignalVideoPauseStateChange(
+      change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnVideoPausePublishResult(
+    const std::string& task_id, const XmlElement* item) {
+  SignalPublishVideoPauseResult(task_id);
+}
+
+void HangoutPubSubClient::OnVideoPausePublishError(
+    const std::string& task_id, const XmlElement* item,
+    const XmlElement* stanza) {
+  SignalPublishVideoPauseError(task_id, stanza);
+}
+
+void HangoutPubSubClient::OnRecordingStateChange(
+    const PubSubStateChange<bool>& change) {
+  SignalRecordingStateChange(
+      change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnRecordingPublishResult(
+    const std::string& task_id, const XmlElement* item) {
+  SignalPublishRecordingResult(task_id);
+}
+
+void HangoutPubSubClient::OnRecordingPublishError(
+    const std::string& task_id, const XmlElement* item,
+    const XmlElement* stanza) {
+  SignalPublishRecordingError(task_id, stanza);
+}
+
+void HangoutPubSubClient::OnMediaBlockStateChange(
+    const PubSubStateChange<bool>& change) {
+  const std::string& blockee_nick = change.published_nick;
+  const std::string& blocker_nick = change.publisher_nick;
+
+  bool was_blockee = change.old_state;
+  bool is_blockee = change.new_state;
+  if (!was_blockee && is_blockee) {
+    SignalMediaBlock(blockee_nick, blocker_nick);
+  }
+  // TODO: Should we bother signaling unblock? Currently
+  // it isn't allowed, but it might happen when a participant leaves
+  // the room and the item is retracted.
+}
+
+void HangoutPubSubClient::OnMediaBlockPublishResult(
+    const std::string& task_id, const XmlElement* item) {
+  const std::string& blockee_nick = GetBlockeeNickFromItem(item);
+  SignalMediaBlockResult(task_id, blockee_nick);
+}
+
+void HangoutPubSubClient::OnMediaBlockPublishError(
+    const std::string& task_id, const XmlElement* item,
+    const XmlElement* stanza) {
+  const std::string& blockee_nick = GetBlockeeNickFromItem(item);
+  SignalMediaBlockError(task_id, blockee_nick, stanza);
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/hangoutpubsubclient.h b/libjingle/xmpp/hangoutpubsubclient.h
new file mode 100644
index 0000000..2586768
--- /dev/null
+++ b/libjingle/xmpp/hangoutpubsubclient.h
@@ -0,0 +1,178 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_HANGOUTPUBSUBCLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_HANGOUTPUBSUBCLIENT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/pubsubclient.h"
+#include "webrtc/libjingle/xmpp/pubsubstateclient.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/sigslotrepeater.h"
+
+// Gives a high-level API for MUC call PubSub needs such as
+// presenter state, recording state, mute state, and remote mute.
+
+namespace buzz {
+
+class Jid;
+class XmlElement;
+class XmppTaskParentInterface;
+
+// A client tied to a specific MUC jid and local nick.  Provides ways
+// to get updates and publish state and events.  Must call
+// RequestAll() to start getting updates.
+class HangoutPubSubClient : public sigslot::has_slots<> {
+ public:
+  HangoutPubSubClient(XmppTaskParentInterface* parent,
+                      const Jid& mucjid,
+                      const std::string& nick);
+  ~HangoutPubSubClient();
+  const Jid& mucjid() const { return mucjid_; }
+  const std::string& nick() const { return nick_; }
+
+  // Requests all of the different states and subscribes for updates.
+  // Responses and updates will be signalled via the various signals.
+  void RequestAll();
+  // Signal (nick, was_presenting, is_presenting)
+  sigslot::signal3<const std::string&, bool, bool> SignalPresenterStateChange;
+  // Signal (nick, was_muted, is_muted)
+  sigslot::signal3<const std::string&, bool, bool> SignalAudioMuteStateChange;
+  // Signal (nick, was_muted, is_muted)
+  sigslot::signal3<const std::string&, bool, bool> SignalVideoMuteStateChange;
+  // Signal (nick, was_paused, is_paused)
+  sigslot::signal3<const std::string&, bool, bool> SignalVideoPauseStateChange;
+  // Signal (nick, was_recording, is_recording)
+  sigslot::signal3<const std::string&, bool, bool> SignalRecordingStateChange;
+  // Signal (mutee_nick, muter_nick, should_mute_locally)
+  sigslot::signal3<const std::string&,
+                   const std::string&,
+                   bool> SignalRemoteMute;
+  // Signal (blockee_nick, blocker_nick)
+  sigslot::signal2<const std::string&, const std::string&> SignalMediaBlock;
+
+  // Signal (node, error stanza)
+  sigslot::signal2<const std::string&, const XmlElement*> SignalRequestError;
+
+  // On each of these, provide a task_id_out to get the task_id, which
+  // can be correlated to the error and result signals.
+  void PublishPresenterState(
+      bool presenting, std::string* task_id_out = NULL);
+  void PublishAudioMuteState(
+      bool muted, std::string* task_id_out = NULL);
+  void PublishVideoMuteState(
+      bool muted, std::string* task_id_out = NULL);
+  void PublishVideoPauseState(
+      bool paused, std::string* task_id_out = NULL);
+  void PublishRecordingState(
+      bool recording, std::string* task_id_out = NULL);
+  void RemoteMute(
+      const std::string& mutee_nick, std::string* task_id_out = NULL);
+  void BlockMedia(
+      const std::string& blockee_nick, std::string* task_id_out = NULL);
+
+  // Signal task_id
+  sigslot::signal1<const std::string&> SignalPublishAudioMuteResult;
+  sigslot::signal1<const std::string&> SignalPublishVideoMuteResult;
+  sigslot::signal1<const std::string&> SignalPublishVideoPauseResult;
+  sigslot::signal1<const std::string&> SignalPublishPresenterResult;
+  sigslot::signal1<const std::string&> SignalPublishRecordingResult;
+  // Signal (task_id, mutee_nick)
+  sigslot::signal2<const std::string&,
+                   const std::string&> SignalRemoteMuteResult;
+  // Signal (task_id, blockee_nick)
+  sigslot::signal2<const std::string&,
+                   const std::string&> SignalMediaBlockResult;
+
+  // Signal (task_id, error stanza)
+  sigslot::signal2<const std::string&,
+                   const XmlElement*> SignalPublishAudioMuteError;
+  sigslot::signal2<const std::string&,
+                   const XmlElement*> SignalPublishVideoMuteError;
+  sigslot::signal2<const std::string&,
+                   const XmlElement*> SignalPublishVideoPauseError;
+  sigslot::signal2<const std::string&,
+                   const XmlElement*> SignalPublishPresenterError;
+  sigslot::signal2<const std::string&,
+                   const XmlElement*> SignalPublishRecordingError;
+  sigslot::signal2<const std::string&,
+                   const XmlElement*> SignalPublishMediaBlockError;
+  // Signal (task_id, mutee_nick, error stanza)
+  sigslot::signal3<const std::string&,
+                   const std::string&,
+                   const XmlElement*> SignalRemoteMuteError;
+  // Signal (task_id, blockee_nick, error stanza)
+  sigslot::signal3<const std::string&,
+                   const std::string&,
+                   const XmlElement*> SignalMediaBlockError;
+
+
+ private:
+  void OnPresenterRequestError(PubSubClient* client,
+                               const XmlElement* stanza);
+  void OnMediaRequestError(PubSubClient* client,
+                           const XmlElement* stanza);
+
+  void OnPresenterStateChange(const PubSubStateChange<bool>& change);
+  void OnPresenterPublishResult(const std::string& task_id,
+                               const XmlElement* item);
+  void OnPresenterPublishError(const std::string& task_id,
+                               const XmlElement* item,
+                               const XmlElement* stanza);
+  void OnAudioMuteStateChange(const PubSubStateChange<bool>& change);
+  void OnAudioMutePublishResult(const std::string& task_id,
+                               const XmlElement* item);
+  void OnAudioMutePublishError(const std::string& task_id,
+                               const XmlElement* item,
+                               const XmlElement* stanza);
+  void OnVideoMuteStateChange(const PubSubStateChange<bool>& change);
+  void OnVideoMutePublishResult(const std::string& task_id,
+                               const XmlElement* item);
+  void OnVideoMutePublishError(const std::string& task_id,
+                               const XmlElement* item,
+                               const XmlElement* stanza);
+  void OnVideoPauseStateChange(const PubSubStateChange<bool>& change);
+  void OnVideoPausePublishResult(const std::string& task_id,
+                               const XmlElement* item);
+  void OnVideoPausePublishError(const std::string& task_id,
+                               const XmlElement* item,
+                               const XmlElement* stanza);
+  void OnRecordingStateChange(const PubSubStateChange<bool>& change);
+  void OnRecordingPublishResult(const std::string& task_id,
+                               const XmlElement* item);
+  void OnRecordingPublishError(const std::string& task_id,
+                               const XmlElement* item,
+                               const XmlElement* stanza);
+  void OnMediaBlockStateChange(const PubSubStateChange<bool>& change);
+  void OnMediaBlockPublishResult(const std::string& task_id,
+                                 const XmlElement* item);
+  void OnMediaBlockPublishError(const std::string& task_id,
+                                const XmlElement* item,
+                                const XmlElement* stanza);
+  Jid mucjid_;
+  std::string nick_;
+  rtc::scoped_ptr<PubSubClient> media_client_;
+  rtc::scoped_ptr<PubSubClient> presenter_client_;
+  rtc::scoped_ptr<PubSubStateClient<bool> > presenter_state_client_;
+  rtc::scoped_ptr<PubSubStateClient<bool> > audio_mute_state_client_;
+  rtc::scoped_ptr<PubSubStateClient<bool> > video_mute_state_client_;
+  rtc::scoped_ptr<PubSubStateClient<bool> > video_pause_state_client_;
+  rtc::scoped_ptr<PubSubStateClient<bool> > recording_state_client_;
+  rtc::scoped_ptr<PubSubStateClient<bool> > media_block_state_client_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_HANGOUTPUBSUBCLIENT_H_
diff --git a/libjingle/xmpp/hangoutpubsubclient_unittest.cc b/libjingle/xmpp/hangoutpubsubclient_unittest.cc
new file mode 100644
index 0000000..7c6ea58
--- /dev/null
+++ b/libjingle/xmpp/hangoutpubsubclient_unittest.cc
@@ -0,0 +1,753 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+class TestHangoutPubSubListener : public sigslot::has_slots<> {
+ public:
+  TestHangoutPubSubListener() :
+      request_error_count(0),
+      publish_audio_mute_error_count(0),
+      publish_video_mute_error_count(0),
+      publish_video_pause_error_count(0),
+      publish_presenter_error_count(0),
+      publish_recording_error_count(0),
+      remote_mute_error_count(0) {
+  }
+
+  void OnPresenterStateChange(
+      const std::string& nick, bool was_presenting, bool is_presenting) {
+    last_presenter_nick = nick;
+    last_was_presenting = was_presenting;
+    last_is_presenting = is_presenting;
+  }
+
+  void OnAudioMuteStateChange(
+      const std::string& nick, bool was_muted, bool is_muted) {
+    last_audio_muted_nick = nick;
+    last_was_audio_muted = was_muted;
+    last_is_audio_muted = is_muted;
+  }
+
+  void OnVideoMuteStateChange(
+      const std::string& nick, bool was_muted, bool is_muted) {
+    last_video_muted_nick = nick;
+    last_was_video_muted = was_muted;
+    last_is_video_muted = is_muted;
+  }
+
+  void OnVideoPauseStateChange(
+      const std::string& nick, bool was_paused, bool is_paused) {
+    last_video_paused_nick = nick;
+    last_was_video_paused = was_paused;
+    last_is_video_paused = is_paused;
+  }
+
+  void OnRecordingStateChange(
+      const std::string& nick, bool was_recording, bool is_recording) {
+    last_recording_nick = nick;
+    last_was_recording = was_recording;
+    last_is_recording = is_recording;
+  }
+
+  void OnRemoteMute(
+      const std::string& mutee_nick,
+      const std::string& muter_nick,
+      bool should_mute_locally) {
+    last_mutee_nick = mutee_nick;
+    last_muter_nick = muter_nick;
+    last_should_mute = should_mute_locally;
+  }
+
+  void OnMediaBlock(
+      const std::string& blockee_nick,
+      const std::string& blocker_nick) {
+    last_blockee_nick = blockee_nick;
+    last_blocker_nick = blocker_nick;
+  }
+
+  void OnRequestError(const std::string& node, const buzz::XmlElement* stanza) {
+    ++request_error_count;
+    request_error_node = node;
+  }
+
+  void OnPublishAudioMuteError(const std::string& task_id,
+                               const buzz::XmlElement* stanza) {
+    ++publish_audio_mute_error_count;
+    error_task_id = task_id;
+  }
+
+  void OnPublishVideoMuteError(const std::string& task_id,
+                               const buzz::XmlElement* stanza) {
+    ++publish_video_mute_error_count;
+    error_task_id = task_id;
+  }
+
+  void OnPublishVideoPauseError(const std::string& task_id,
+                               const buzz::XmlElement* stanza) {
+    ++publish_video_pause_error_count;
+    error_task_id = task_id;
+  }
+
+  void OnPublishPresenterError(const std::string& task_id,
+                               const buzz::XmlElement* stanza) {
+    ++publish_presenter_error_count;
+    error_task_id = task_id;
+  }
+
+  void OnPublishRecordingError(const std::string& task_id,
+                               const buzz::XmlElement* stanza) {
+    ++publish_recording_error_count;
+    error_task_id = task_id;
+  }
+
+  void OnRemoteMuteResult(const std::string& task_id,
+                          const std::string& mutee_nick) {
+    result_task_id = task_id;
+    remote_mute_mutee_nick = mutee_nick;
+  }
+
+  void OnRemoteMuteError(const std::string& task_id,
+                         const std::string& mutee_nick,
+                         const buzz::XmlElement* stanza) {
+    ++remote_mute_error_count;
+    error_task_id = task_id;
+    remote_mute_mutee_nick = mutee_nick;
+  }
+
+  void OnMediaBlockResult(const std::string& task_id,
+                          const std::string& blockee_nick) {
+    result_task_id = task_id;
+    media_blockee_nick = blockee_nick;
+  }
+
+  void OnMediaBlockError(const std::string& task_id,
+                         const std::string& blockee_nick,
+                         const buzz::XmlElement* stanza) {
+    ++media_block_error_count;
+    error_task_id = task_id;
+    media_blockee_nick = blockee_nick;
+  }
+
+  std::string last_presenter_nick;
+  bool last_is_presenting;
+  bool last_was_presenting;
+  std::string last_audio_muted_nick;
+  bool last_is_audio_muted;
+  bool last_was_audio_muted;
+  std::string last_video_muted_nick;
+  bool last_is_video_muted;
+  bool last_was_video_muted;
+  std::string last_video_paused_nick;
+  bool last_is_video_paused;
+  bool last_was_video_paused;
+  std::string last_recording_nick;
+  bool last_is_recording;
+  bool last_was_recording;
+  std::string last_mutee_nick;
+  std::string last_muter_nick;
+  bool last_should_mute;
+  std::string last_blockee_nick;
+  std::string last_blocker_nick;
+
+  int request_error_count;
+  std::string request_error_node;
+  int publish_audio_mute_error_count;
+  int publish_video_mute_error_count;
+  int publish_video_pause_error_count;
+  int publish_presenter_error_count;
+  int publish_recording_error_count;
+  int remote_mute_error_count;
+  std::string result_task_id;
+  std::string error_task_id;
+  std::string remote_mute_mutee_nick;
+  int media_block_error_count;
+  std::string media_blockee_nick;
+};
+
+class HangoutPubSubClientTest : public testing::Test {
+ public:
+  HangoutPubSubClientTest() :
+      pubsubjid("room@domain.com"),
+      nick("me") {
+
+    runner.reset(new rtc::FakeTaskRunner());
+    xmpp_client = new buzz::FakeXmppClient(runner.get());
+    client.reset(new buzz::HangoutPubSubClient(xmpp_client, pubsubjid, nick));
+    listener.reset(new TestHangoutPubSubListener());
+    client->SignalPresenterStateChange.connect(
+        listener.get(), &TestHangoutPubSubListener::OnPresenterStateChange);
+    client->SignalAudioMuteStateChange.connect(
+        listener.get(), &TestHangoutPubSubListener::OnAudioMuteStateChange);
+    client->SignalVideoMuteStateChange.connect(
+        listener.get(), &TestHangoutPubSubListener::OnVideoMuteStateChange);
+    client->SignalVideoPauseStateChange.connect(
+        listener.get(), &TestHangoutPubSubListener::OnVideoPauseStateChange);
+    client->SignalRecordingStateChange.connect(
+        listener.get(), &TestHangoutPubSubListener::OnRecordingStateChange);
+    client->SignalRemoteMute.connect(
+        listener.get(), &TestHangoutPubSubListener::OnRemoteMute);
+    client->SignalMediaBlock.connect(
+        listener.get(), &TestHangoutPubSubListener::OnMediaBlock);
+    client->SignalRequestError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnRequestError);
+    client->SignalPublishAudioMuteError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnPublishAudioMuteError);
+    client->SignalPublishVideoMuteError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnPublishVideoMuteError);
+    client->SignalPublishVideoPauseError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnPublishVideoPauseError);
+    client->SignalPublishPresenterError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnPublishPresenterError);
+    client->SignalPublishRecordingError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnPublishRecordingError);
+    client->SignalRemoteMuteResult.connect(
+        listener.get(), &TestHangoutPubSubListener::OnRemoteMuteResult);
+    client->SignalRemoteMuteError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnRemoteMuteError);
+    client->SignalMediaBlockResult.connect(
+        listener.get(), &TestHangoutPubSubListener::OnMediaBlockResult);
+    client->SignalMediaBlockError.connect(
+        listener.get(), &TestHangoutPubSubListener::OnMediaBlockError);
+  }
+
+  rtc::scoped_ptr<rtc::FakeTaskRunner> runner;
+  // xmpp_client deleted by deleting runner.
+  buzz::FakeXmppClient* xmpp_client;
+  rtc::scoped_ptr<buzz::HangoutPubSubClient> client;
+  rtc::scoped_ptr<TestHangoutPubSubListener> listener;
+  buzz::Jid pubsubjid;
+  std::string nick;
+};
+
+TEST_F(HangoutPubSubClientTest, TestRequest) {
+  ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
+
+  client->RequestAll();
+  std::string expected_presenter_request =
+      "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
+          "<pub:items node=\"google:presenter\"/>"
+        "</pub:pubsub>"
+      "</cli:iq>";
+
+  std::string expected_media_request =
+      "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
+          "<pub:items node=\"google:muc#media\"/>"
+        "</pub:pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(2U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_presenter_request, xmpp_client->sent_stanzas()[0]->Str());
+  EXPECT_EQ(expected_media_request, xmpp_client->sent_stanzas()[1]->Str());
+
+  std::string presenter_response =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
+      "  <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
+      "    <items node='google:presenter'>"
+      "      <item id='12344'>"
+      "        <presenter xmlns='google:presenter' nick='presenting-nick2'/>"
+      "        <pre:presentation-item xmlns:pre='google:presenter'"
+      "          pre:presentation-type='s'/>"
+      "      </item>"
+      "      <item id='12345'>"
+      "        <presenter xmlns='google:presenter' nick='presenting-nick'/>"
+      "        <pre:presentation-item xmlns:pre='google:presenter'"
+      "          pre:presentation-type='o'/>"
+      "      </item>"
+      // Some clients are "bad" in that they'll jam multiple states in
+      // all at once.  We have to deal with it.
+      "      <item id='12346'>"
+      "        <presenter xmlns='google:presenter' nick='presenting-nick'/>"
+      "        <pre:presentation-item xmlns:pre='google:presenter'"
+      "          pre:presentation-type='s'/>"
+      "      </item>"
+      "    </items>"
+      "  </pubsub>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(presenter_response));
+  EXPECT_EQ("presenting-nick", listener->last_presenter_nick);
+  EXPECT_FALSE(listener->last_was_presenting);
+  EXPECT_TRUE(listener->last_is_presenting);
+
+  std::string media_response =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
+      "  <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
+      "    <items node='google:muc#media'>"
+      "      <item id='audio-mute:muted-nick'>"
+      "        <audio-mute nick='muted-nick' xmlns='google:muc#media'/>"
+      "      </item>"
+      "      <item id='video-mute:video-muted-nick'>"
+      "        <video-mute nick='video-muted-nick' xmlns='google:muc#media'/>"
+      "      </item>"
+      "      <item id='video-pause:video-paused-nick'>"
+      "        <video-pause nick='video-paused-nick' xmlns='google:muc#media'/>"
+      "      </item>"
+      "      <item id='recording:recording-nick'>"
+      "        <recording nick='recording-nick' xmlns='google:muc#media'/>"
+      "      </item>"
+      "    </items>"
+      "  </pubsub>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(media_response));
+  EXPECT_EQ("muted-nick", listener->last_audio_muted_nick);
+  EXPECT_FALSE(listener->last_was_audio_muted);
+  EXPECT_TRUE(listener->last_is_audio_muted);
+
+  EXPECT_EQ("video-muted-nick", listener->last_video_muted_nick);
+  EXPECT_FALSE(listener->last_was_video_muted);
+  EXPECT_TRUE(listener->last_is_video_muted);
+
+  EXPECT_EQ("video-paused-nick", listener->last_video_paused_nick);
+  EXPECT_FALSE(listener->last_was_video_paused);
+  EXPECT_TRUE(listener->last_is_video_paused);
+
+  EXPECT_EQ("recording-nick", listener->last_recording_nick);
+  EXPECT_FALSE(listener->last_was_recording);
+  EXPECT_TRUE(listener->last_is_recording);
+
+  std::string incoming_presenter_resets_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:presenter'>"
+      "      <item id='12348'>"
+      "        <presenter xmlns='google:presenter' nick='presenting-nick'/>"
+      "        <pre:presentation-item xmlns:pre='google:presenter'"
+      "          pre:presentation-type='o'/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_presenter_resets_message));
+  EXPECT_EQ("presenting-nick", listener->last_presenter_nick);
+  //EXPECT_TRUE(listener->last_was_presenting);
+  EXPECT_FALSE(listener->last_is_presenting);
+
+  std::string incoming_presenter_retracts_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:presenter'>"
+      "      <retract id='12344'/>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_presenter_retracts_message));
+  EXPECT_EQ("presenting-nick2", listener->last_presenter_nick);
+  EXPECT_TRUE(listener->last_was_presenting);
+  EXPECT_FALSE(listener->last_is_presenting);
+
+  std::string incoming_media_retracts_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:muc#media'>"
+      "      <item id='audio-mute:muted-nick'>"
+      "      </item>"
+      "      <retract id='video-mute:video-muted-nick'/>"
+      "      <retract id='video-pause:video-paused-nick'/>"
+      "      <retract id='recording:recording-nick'/>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_media_retracts_message));
+  EXPECT_EQ("muted-nick", listener->last_audio_muted_nick);
+  EXPECT_TRUE(listener->last_was_audio_muted);
+  EXPECT_FALSE(listener->last_is_audio_muted);
+
+  EXPECT_EQ("video-paused-nick", listener->last_video_paused_nick);
+  EXPECT_TRUE(listener->last_was_video_paused);
+  EXPECT_FALSE(listener->last_is_video_paused);
+
+  EXPECT_EQ("recording-nick", listener->last_recording_nick);
+  EXPECT_TRUE(listener->last_was_recording);
+  EXPECT_FALSE(listener->last_is_recording);
+
+  std::string incoming_presenter_changes_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:presenter'>"
+      "      <item id='presenting-nick2'>"
+      "        <presenter xmlns='google:presenter' nick='presenting-nick2'/>"
+      "        <pre:presentation-item xmlns:pre='google:presenter'"
+      "          pre:presentation-type='s'/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_presenter_changes_message));
+  EXPECT_EQ("presenting-nick2", listener->last_presenter_nick);
+  EXPECT_FALSE(listener->last_was_presenting);
+  EXPECT_TRUE(listener->last_is_presenting);
+
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_presenter_changes_message));
+  EXPECT_EQ("presenting-nick2", listener->last_presenter_nick);
+  EXPECT_TRUE(listener->last_was_presenting);
+  EXPECT_TRUE(listener->last_is_presenting);
+
+  std::string incoming_media_changes_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:muc#media'>"
+      "      <item id='audio-mute:muted-nick2'>"
+      "        <audio-mute nick='muted-nick2' xmlns='google:muc#media'/>"
+      "      </item>"
+      "      <item id='video-pause:video-paused-nick2'>"
+      "        <video-pause nick='video-paused-nick2' xmlns='google:muc#media'/>"
+      "      </item>"
+      "      <item id='recording:recording-nick2'>"
+      "        <recording nick='recording-nick2' xmlns='google:muc#media'/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_media_changes_message));
+  EXPECT_EQ("muted-nick2", listener->last_audio_muted_nick);
+  EXPECT_FALSE(listener->last_was_audio_muted);
+  EXPECT_TRUE(listener->last_is_audio_muted);
+
+  EXPECT_EQ("video-paused-nick2", listener->last_video_paused_nick);
+  EXPECT_FALSE(listener->last_was_video_paused);
+  EXPECT_TRUE(listener->last_is_video_paused);
+
+  EXPECT_EQ("recording-nick2", listener->last_recording_nick);
+  EXPECT_FALSE(listener->last_was_recording);
+  EXPECT_TRUE(listener->last_is_recording);
+
+  std::string incoming_remote_mute_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:muc#media'>"
+      "      <item id='audio-mute:mutee' publisher='room@domain.com/muter'>"
+      "        <audio-mute nick='mutee' xmlns='google:muc#media'/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  listener->last_is_audio_muted = false;
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_remote_mute_message));
+  EXPECT_EQ("mutee", listener->last_mutee_nick);
+  EXPECT_EQ("muter", listener->last_muter_nick);
+  EXPECT_FALSE(listener->last_should_mute);
+  EXPECT_EQ("mutee", listener->last_audio_muted_nick);
+  EXPECT_TRUE(listener->last_is_audio_muted);
+
+  std::string incoming_remote_mute_me_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:muc#media'>"
+      "      <item id='audio-mute:me' publisher='room@domain.com/muter'>"
+      "        <audio-mute nick='me' xmlns='google:muc#media'/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  listener->last_is_audio_muted = false;
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_remote_mute_me_message));
+  EXPECT_EQ("me", listener->last_mutee_nick);
+  EXPECT_EQ("muter", listener->last_muter_nick);
+  EXPECT_TRUE(listener->last_should_mute);
+  EXPECT_EQ("me", listener->last_audio_muted_nick);
+  EXPECT_TRUE(listener->last_is_audio_muted);
+
+  std::string incoming_media_block_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='google:muc#media'>"
+      "      <item id='block:blocker:blockee'"
+      "            publisher='room@domain.com/blocker'>"
+      "        <block nick='blockee' xmlns='google:muc#media'/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  xmpp_client->HandleStanza(
+      buzz::XmlElement::ForStr(incoming_media_block_message));
+  EXPECT_EQ("blockee", listener->last_blockee_nick);
+  EXPECT_EQ("blocker", listener->last_blocker_nick);
+}
+
+TEST_F(HangoutPubSubClientTest, TestRequestError) {
+  client->RequestAll();
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
+      "  <error type='auth'>"
+      "    <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
+      "  </error>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->request_error_count);
+  EXPECT_EQ("google:presenter", listener->request_error_node);
+}
+
+TEST_F(HangoutPubSubClientTest, TestPublish) {
+  client->PublishPresenterState(true);
+  std::string expected_presenter_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"google:presenter\">"
+            "<item id=\"me\">"
+              "<presenter xmlns=\"google:presenter\""
+              " nick=\"me\"/>"
+              "<pre:presentation-item"
+              " pre:presentation-type=\"s\" xmlns:pre=\"google:presenter\"/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_presenter_iq,
+            xmpp_client->sent_stanzas()[0]->Str());
+
+  client->PublishAudioMuteState(true);
+  std::string expected_audio_mute_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"google:muc#media\">"
+            "<item id=\"audio-mute:me\">"
+              "<audio-mute xmlns=\"google:muc#media\" nick=\"me\"/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(2U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_audio_mute_iq, xmpp_client->sent_stanzas()[1]->Str());
+
+  client->PublishVideoPauseState(true);
+  std::string expected_video_pause_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"google:muc#media\">"
+            "<item id=\"video-pause:me\">"
+              "<video-pause xmlns=\"google:muc#media\" nick=\"me\"/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(3U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_video_pause_iq, xmpp_client->sent_stanzas()[2]->Str());
+
+  client->PublishRecordingState(true);
+  std::string expected_recording_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"google:muc#media\">"
+            "<item id=\"recording:me\">"
+              "<recording xmlns=\"google:muc#media\" nick=\"me\"/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(4U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_recording_iq, xmpp_client->sent_stanzas()[3]->Str());
+
+  client->RemoteMute("mutee");
+  std::string expected_remote_mute_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"google:muc#media\">"
+            "<item id=\"audio-mute:mutee\">"
+              "<audio-mute xmlns=\"google:muc#media\" nick=\"mutee\"/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(5U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_remote_mute_iq, xmpp_client->sent_stanzas()[4]->Str());
+
+  client->PublishPresenterState(false);
+  std::string expected_presenter_retract_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"google:presenter\">"
+            "<item id=\"me\">"
+              "<presenter xmlns=\"google:presenter\""
+              " nick=\"me\"/>"
+              "<pre:presentation-item"
+              " pre:presentation-type=\"o\" xmlns:pre=\"google:presenter\"/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(6U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_presenter_retract_iq,
+            xmpp_client->sent_stanzas()[5]->Str());
+
+  client->PublishAudioMuteState(false);
+  std::string expected_audio_mute_retract_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<retract node=\"google:muc#media\" notify=\"true\">"
+            "<item id=\"audio-mute:me\"/>"
+          "</retract>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(7U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_audio_mute_retract_iq,
+            xmpp_client->sent_stanzas()[6]->Str());
+
+  client->PublishVideoPauseState(false);
+  std::string expected_video_pause_retract_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<retract node=\"google:muc#media\" notify=\"true\">"
+            "<item id=\"video-pause:me\"/>"
+          "</retract>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(8U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_video_pause_retract_iq,
+            xmpp_client->sent_stanzas()[7]->Str());
+
+  client->BlockMedia("blockee");
+  std::string expected_media_block_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"google:muc#media\">"
+            "<item id=\"block:me:blockee\">"
+              "<block xmlns=\"google:muc#media\" nick=\"blockee\"/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(9U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_media_block_iq, xmpp_client->sent_stanzas()[8]->Str());
+}
+
+TEST_F(HangoutPubSubClientTest, TestPublishPresenterError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
+
+  client->PublishPresenterState(true);
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->publish_presenter_error_count);
+  EXPECT_EQ("0", listener->error_task_id);
+}
+
+
+TEST_F(HangoutPubSubClientTest, TestPublishAudioMuteError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
+
+  client->PublishAudioMuteState(true);
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->publish_audio_mute_error_count);
+  EXPECT_EQ("0", listener->error_task_id);
+}
+
+TEST_F(HangoutPubSubClientTest, TestPublishVideoPauseError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
+
+  client->PublishVideoPauseState(true);
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->publish_video_pause_error_count);
+  EXPECT_EQ("0", listener->error_task_id);
+}
+
+TEST_F(HangoutPubSubClientTest, TestPublishRecordingError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
+
+  client->PublishRecordingState(true);
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->publish_recording_error_count);
+  EXPECT_EQ("0", listener->error_task_id);
+}
+
+TEST_F(HangoutPubSubClientTest, TestPublishRemoteMuteResult) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
+
+  client->RemoteMute("joe");
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ("joe", listener->remote_mute_mutee_nick);
+  EXPECT_EQ("0", listener->result_task_id);
+}
+
+TEST_F(HangoutPubSubClientTest, TestRemoteMuteError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
+
+  client->RemoteMute("joe");
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->remote_mute_error_count);
+  EXPECT_EQ("joe", listener->remote_mute_mutee_nick);
+  EXPECT_EQ("0", listener->error_task_id);
+}
+
+TEST_F(HangoutPubSubClientTest, TestPublishMediaBlockResult) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
+
+  client->BlockMedia("joe");
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ("joe", listener->media_blockee_nick);
+  EXPECT_EQ("0", listener->result_task_id);
+}
+
+TEST_F(HangoutPubSubClientTest, TestMediaBlockError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>";
+
+  client->BlockMedia("joe");
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->remote_mute_error_count);
+  EXPECT_EQ("joe", listener->media_blockee_nick);
+  EXPECT_EQ("0", listener->error_task_id);
+}
diff --git a/libjingle/xmpp/iqtask.cc b/libjingle/xmpp/iqtask.cc
new file mode 100644
index 0000000..a7a41ee
--- /dev/null
+++ b/libjingle/xmpp/iqtask.cc
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/iqtask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+
+namespace buzz {
+
+static const int kDefaultIqTimeoutSecs = 15;
+
+IqTask::IqTask(XmppTaskParentInterface* parent,
+               const std::string& verb,
+               const buzz::Jid& to,
+               buzz::XmlElement* el)
+    : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
+      to_(to),
+      stanza_(MakeIq(verb, to_, task_id())) {
+  stanza_->AddElement(el);
+  set_timeout_seconds(kDefaultIqTimeoutSecs);
+}
+
+int IqTask::ProcessStart() {
+  buzz::XmppReturnStatus ret = SendStanza(stanza_.get());
+  // TODO: HandleError(NULL) if SendStanza fails?
+  return (ret == buzz::XMPP_RETURN_OK) ? STATE_RESPONSE : STATE_ERROR;
+}
+
+bool IqTask::HandleStanza(const buzz::XmlElement* stanza) {
+  if (!MatchResponseIq(stanza, to_, task_id()))
+    return false;
+
+  if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT &&
+      stanza->Attr(buzz::QN_TYPE) != buzz::STR_ERROR) {
+    return false;
+  }
+
+  QueueStanza(stanza);
+  return true;
+}
+
+int IqTask::ProcessResponse() {
+  const buzz::XmlElement* stanza = NextStanza();
+  if (stanza == NULL)
+    return STATE_BLOCKED;
+
+  bool success = (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT);
+  if (success) {
+    HandleResult(stanza);
+  } else {
+    SignalError(this, stanza->FirstNamed(QN_ERROR));
+  }
+  return STATE_DONE;
+}
+
+int IqTask::OnTimeout() {
+  SignalError(this, NULL);
+  return XmppTask::OnTimeout();
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/iqtask.h b/libjingle/xmpp/iqtask.h
new file mode 100644
index 0000000..1d50c38
--- /dev/null
+++ b/libjingle/xmpp/iqtask.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_IQTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_IQTASK_H_
+
+#include <string>
+
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace buzz {
+
+class IqTask : public XmppTask {
+ public:
+  IqTask(XmppTaskParentInterface* parent,
+         const std::string& verb, const Jid& to,
+         XmlElement* el);
+  virtual ~IqTask() {}
+
+  const XmlElement* stanza() const { return stanza_.get(); }
+
+  sigslot::signal2<IqTask*,
+                   const XmlElement*> SignalError;
+
+ protected:
+  virtual void HandleResult(const XmlElement* element) = 0;
+
+ private:
+  virtual int ProcessStart();
+  virtual bool HandleStanza(const XmlElement* stanza);
+  virtual int ProcessResponse();
+  virtual int OnTimeout();
+
+  Jid to_;
+  rtc::scoped_ptr<XmlElement> stanza_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_IQTASK_H_
diff --git a/libjingle/xmpp/jid.cc b/libjingle/xmpp/jid.cc
new file mode 100644
index 0000000..ad05380
--- /dev/null
+++ b/libjingle/xmpp/jid.cc
@@ -0,0 +1,379 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/jid.h"
+
+#include <ctype.h>
+
+#include <algorithm>
+#include <string>
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+
+namespace buzz {
+
+Jid::Jid() {
+}
+
+Jid::Jid(const std::string& jid_string) {
+  if (jid_string.empty())
+    return;
+
+  // First find the slash and slice off that part
+  size_t slash = jid_string.find('/');
+  resource_name_ = (slash == std::string::npos ? STR_EMPTY :
+                    jid_string.substr(slash + 1));
+
+  // Now look for the node
+  size_t at = jid_string.find('@');
+  size_t domain_begin;
+  if (at < slash && at != std::string::npos) {
+    node_name_ = jid_string.substr(0, at);
+    domain_begin = at + 1;
+  } else {
+    domain_begin = 0;
+  }
+
+  // Now take what is left as the domain
+  size_t domain_length = (slash == std::string::npos) ?
+      (jid_string.length() - domain_begin) : (slash - domain_begin);
+  domain_name_ = jid_string.substr(domain_begin, domain_length);
+
+  ValidateOrReset();
+}
+
+Jid::Jid(const std::string& node_name,
+         const std::string& domain_name,
+         const std::string& resource_name)
+    :  node_name_(node_name),
+       domain_name_(domain_name),
+       resource_name_(resource_name) {
+  ValidateOrReset();
+}
+
+void Jid::ValidateOrReset() {
+  bool valid_node;
+  bool valid_domain;
+  bool valid_resource;
+
+  node_name_ = PrepNode(node_name_, &valid_node);
+  domain_name_ = PrepDomain(domain_name_, &valid_domain);
+  resource_name_ = PrepResource(resource_name_, &valid_resource);
+
+  if (!valid_node || !valid_domain || !valid_resource) {
+    node_name_.clear();
+    domain_name_.clear();
+    resource_name_.clear();
+  }
+}
+
+std::string Jid::Str() const {
+  if (!IsValid())
+    return STR_EMPTY;
+
+  std::string ret;
+
+  if (!node_name_.empty())
+    ret = node_name_ + "@";
+
+  ASSERT(domain_name_ != STR_EMPTY);
+  ret += domain_name_;
+
+  if (!resource_name_.empty())
+    ret += "/" + resource_name_;
+
+  return ret;
+}
+
+Jid::~Jid() {
+}
+
+bool Jid::IsEmpty() const {
+  return (node_name_.empty() && domain_name_.empty() &&
+          resource_name_.empty());
+}
+
+bool Jid::IsValid() const {
+  return !domain_name_.empty();
+}
+
+bool Jid::IsBare() const {
+  if (IsEmpty()) {
+    LOG(LS_VERBOSE) << "Warning: Calling IsBare() on the empty jid.";
+    return true;
+  }
+  return IsValid() && resource_name_.empty();
+}
+
+bool Jid::IsFull() const {
+  return IsValid() && !resource_name_.empty();
+}
+
+Jid Jid::BareJid() const {
+  if (!IsValid())
+    return Jid();
+  if (!IsFull())
+    return *this;
+  return Jid(node_name_, domain_name_, STR_EMPTY);
+}
+
+bool Jid::BareEquals(const Jid& other) const {
+  return other.node_name_ == node_name_ &&
+      other.domain_name_ == domain_name_;
+}
+
+void Jid::CopyFrom(const Jid& jid) {
+  this->node_name_ = jid.node_name_;
+  this->domain_name_ = jid.domain_name_;
+  this->resource_name_ = jid.resource_name_;
+}
+
+bool Jid::operator==(const Jid& other) const {
+  return other.node_name_ == node_name_ &&
+      other.domain_name_ == domain_name_ &&
+      other.resource_name_ == resource_name_;
+}
+
+int Jid::Compare(const Jid& other) const {
+  int compare_result;
+  compare_result = node_name_.compare(other.node_name_);
+  if (0 != compare_result)
+    return compare_result;
+  compare_result = domain_name_.compare(other.domain_name_);
+  if (0 != compare_result)
+    return compare_result;
+  compare_result = resource_name_.compare(other.resource_name_);
+  return compare_result;
+}
+
+// --- JID parsing code: ---
+
+// Checks and normalizes the node part of a JID.
+std::string Jid::PrepNode(const std::string& node, bool* valid) {
+  *valid = false;
+  std::string result;
+
+  for (std::string::const_iterator i = node.begin(); i < node.end(); ++i) {
+    bool char_valid = true;
+    unsigned char ch = *i;
+    if (ch <= 0x7F) {
+      result += PrepNodeAscii(ch, &char_valid);
+    }
+    else {
+      // TODO: implement the correct stringprep protocol for these
+      result += tolower(ch);
+    }
+    if (!char_valid) {
+      return STR_EMPTY;
+    }
+  }
+
+  if (result.length() > 1023) {
+    return STR_EMPTY;
+  }
+  *valid = true;
+  return result;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a node.
+char Jid::PrepNodeAscii(char ch, bool* valid) {
+  *valid = true;
+  switch (ch) {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+    case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+    case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+    case 'V': case 'W': case 'X': case 'Y': case 'Z':
+      return (char)(ch + ('a' - 'A'));
+
+    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+    case ' ': case '&': case '/': case ':': case '<': case '>': case '@':
+    case '\"': case '\'':
+    case 0x7F:
+      *valid = false;
+      return 0;
+
+    default:
+      return ch;
+  }
+}
+
+
+// Checks and normalizes the resource part of a JID.
+std::string Jid::PrepResource(const std::string& resource, bool* valid) {
+  *valid = false;
+  std::string result;
+
+  for (std::string::const_iterator i = resource.begin();
+       i < resource.end(); ++i) {
+    bool char_valid = true;
+    unsigned char ch = *i;
+    if (ch <= 0x7F) {
+      result += PrepResourceAscii(ch, &char_valid);
+    }
+    else {
+      // TODO: implement the correct stringprep protocol for these
+      result += ch;
+    }
+  }
+
+  if (result.length() > 1023) {
+    return STR_EMPTY;
+  }
+  *valid = true;
+  return result;
+}
+
+// Returns the appropriate mapping for an ASCII character in a resource.
+char Jid::PrepResourceAscii(char ch, bool* valid) {
+  *valid = true;
+  switch (ch) {
+    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+    case 0x7F:
+      *valid = false;
+      return 0;
+
+    default:
+      return ch;
+  }
+}
+
+// Checks and normalizes the domain part of a JID.
+std::string Jid::PrepDomain(const std::string& domain, bool* valid) {
+  *valid = false;
+  std::string result;
+
+  // TODO: if the domain contains a ':', then we should parse it
+  // as an IPv6 address rather than giving an error about illegal domain.
+  PrepDomain(domain, &result, valid);
+  if (!*valid) {
+    return STR_EMPTY;
+  }
+
+  if (result.length() > 1023) {
+    return STR_EMPTY;
+  }
+  *valid = true;
+  return result;
+}
+
+
+// Checks and normalizes an IDNA domain.
+void Jid::PrepDomain(const std::string& domain, std::string* buf, bool* valid) {
+  *valid = false;
+  std::string::const_iterator last = domain.begin();
+  for (std::string::const_iterator i = domain.begin(); i < domain.end(); ++i) {
+    bool label_valid = true;
+    char ch = *i;
+    switch (ch) {
+      case 0x002E:
+#if 0 // FIX: This isn't UTF-8-aware.
+      case 0x3002:
+      case 0xFF0E:
+      case 0xFF61:
+#endif
+        PrepDomainLabel(last, i, buf, &label_valid);
+        *buf += '.';
+        last = i + 1;
+        break;
+    }
+    if (!label_valid) {
+      return;
+    }
+  }
+  PrepDomainLabel(last, domain.end(), buf, valid);
+}
+
+// Checks and normalizes a domain label.
+void Jid::PrepDomainLabel(
+    std::string::const_iterator start, std::string::const_iterator end,
+    std::string* buf, bool* valid) {
+  *valid = false;
+
+  int start_len = static_cast<int>(buf->length());
+  for (std::string::const_iterator i = start; i < end; ++i) {
+    bool char_valid = true;
+    unsigned char ch = *i;
+    if (ch <= 0x7F) {
+      *buf += PrepDomainLabelAscii(ch, &char_valid);
+    }
+    else {
+      // TODO: implement ToASCII for these
+      *buf += ch;
+    }
+    if (!char_valid) {
+      return;
+    }
+  }
+
+  int count = static_cast<int>(buf->length() - start_len);
+  if (count == 0) {
+    return;
+  }
+  else if (count > 63) {
+    return;
+  }
+
+  // Is this check needed? See comment in PrepDomainLabelAscii.
+  if ((*buf)[start_len] == '-') {
+    return;
+  }
+  if ((*buf)[buf->length() - 1] == '-') {
+    return;
+  }
+  *valid = true;
+}
+
+
+// Returns the appropriate mapping for an ASCII character in a domain label.
+char Jid::PrepDomainLabelAscii(char ch, bool* valid) {
+  *valid = true;
+  // TODO: A literal reading of the spec seems to say that we do
+  // not need to check for these illegal characters (an "internationalized
+  // domain label" runs ToASCII with UseSTD3... set to false).  But that
+  // can't be right.  We should at least be checking that there are no '/'
+  // or '@' characters in the domain.  Perhaps we should see what others
+  // do in this case.
+
+  switch (ch) {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+    case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+    case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+    case 'V': case 'W': case 'X': case 'Y': case 'Z':
+      return (char)(ch + ('a' - 'A'));
+
+    case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
+    case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B:
+    case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11:
+    case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+    case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D:
+    case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23:
+    case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29:
+    case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A:
+    case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40:
+    case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60:
+    case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
+      *valid = false;
+      return 0;
+
+    default:
+      return ch;
+  }
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/jid.h b/libjingle/xmpp/jid.h
new file mode 100644
index 0000000..94ad7c8
--- /dev/null
+++ b/libjingle/xmpp/jid.h
@@ -0,0 +1,81 @@
+/*
+ *  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_LIBJINGLE_XMPP_JID_H_
+#define WEBRTC_LIBJINGLE_XMPP_JID_H_
+
+#include <string>
+#include "webrtc/libjingle/xmllite/xmlconstants.h"
+#include "webrtc/base/basictypes.h"
+
+namespace buzz {
+
+// The Jid class encapsulates and provides parsing help for Jids. A Jid
+// consists of three parts: the node, the domain and the resource, e.g.:
+//
+// node@domain/resource
+//
+// The node and resource are both optional. A valid jid is defined to have
+// a domain. A bare jid is defined to not have a resource and a full jid
+// *does* have a resource.
+class Jid {
+public:
+  explicit Jid();
+  explicit Jid(const std::string& jid_string);
+  explicit Jid(const std::string& node_name,
+               const std::string& domain_name,
+               const std::string& resource_name);
+  ~Jid();
+
+  const std::string & node() const { return node_name_; }
+  const std::string & domain() const { return domain_name_;  }
+  const std::string & resource() const { return resource_name_; }
+
+  std::string Str() const;
+  Jid BareJid() const;
+
+  bool IsEmpty() const;
+  bool IsValid() const;
+  bool IsBare() const;
+  bool IsFull() const;
+
+  bool BareEquals(const Jid& other) const;
+  void CopyFrom(const Jid& jid);
+  bool operator==(const Jid& other) const;
+  bool operator!=(const Jid& other) const { return !operator==(other); }
+
+  bool operator<(const Jid& other) const { return Compare(other) < 0; };
+  bool operator>(const Jid& other) const { return Compare(other) > 0; };
+
+  int Compare(const Jid & other) const;
+
+private:
+  void ValidateOrReset();
+
+  static std::string PrepNode(const std::string& node, bool* valid);
+  static char PrepNodeAscii(char ch, bool* valid);
+  static std::string PrepResource(const std::string& start, bool* valid);
+  static char PrepResourceAscii(char ch, bool* valid);
+  static std::string PrepDomain(const std::string& domain, bool* valid);
+  static void PrepDomain(const std::string& domain,
+                         std::string* buf, bool* valid);
+  static void PrepDomainLabel(
+      std::string::const_iterator start, std::string::const_iterator end,
+      std::string* buf, bool* valid);
+  static char PrepDomainLabelAscii(char ch, bool *valid);
+
+  std::string node_name_;
+  std::string domain_name_;
+  std::string resource_name_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_JID_H_
diff --git a/libjingle/xmpp/jid_unittest.cc b/libjingle/xmpp/jid_unittest.cc
new file mode 100644
index 0000000..e22f6a2
--- /dev/null
+++ b/libjingle/xmpp/jid_unittest.cc
@@ -0,0 +1,122 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/base/gunit.h"
+
+using buzz::Jid;
+
+TEST(JidTest, TestDomain) {
+  Jid jid("dude");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("dude", jid.Str());
+  EXPECT_EQ("dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestNodeDomain) {
+  Jid jid("walter@dude");
+  EXPECT_EQ("walter", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("walter@dude", jid.Str());
+  EXPECT_EQ("walter@dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestDomainResource) {
+  Jid jid("dude/bowlingalley");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("bowlingalley", jid.resource());
+  EXPECT_EQ("dude/bowlingalley", jid.Str());
+  EXPECT_EQ("dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
+
+TEST(JidTest, TestNodeDomainResource) {
+  Jid jid("walter@dude/bowlingalley");
+  EXPECT_EQ("walter", jid.node());
+  EXPECT_EQ("dude", jid.domain());
+  EXPECT_EQ("bowlingalley", jid.resource());
+  EXPECT_EQ("walter@dude/bowlingalley", jid.Str());
+  EXPECT_EQ("walter@dude", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
+
+TEST(JidTest, TestNode) {
+  Jid jid("walter@");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("", jid.Str());
+  EXPECT_EQ("", jid.BareJid().Str());
+  EXPECT_FALSE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestResource) {
+  Jid jid("/bowlingalley");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("", jid.Str());
+  EXPECT_EQ("", jid.BareJid().Str());
+  EXPECT_FALSE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestNodeResource) {
+  Jid jid("walter@/bowlingalley");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("", jid.domain());
+  EXPECT_EQ("", jid.resource());
+  EXPECT_EQ("", jid.Str());
+  EXPECT_EQ("", jid.BareJid().Str());
+  EXPECT_FALSE(jid.IsValid());
+  EXPECT_TRUE(jid.IsBare());
+  EXPECT_FALSE(jid.IsFull());
+}
+
+TEST(JidTest, TestFunky) {
+  Jid jid("bowling@muchat/walter@dude");
+  EXPECT_EQ("bowling", jid.node());
+  EXPECT_EQ("muchat", jid.domain());
+  EXPECT_EQ("walter@dude", jid.resource());
+  EXPECT_EQ("bowling@muchat/walter@dude", jid.Str());
+  EXPECT_EQ("bowling@muchat", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
+
+TEST(JidTest, TestFunky2) {
+  Jid jid("muchat/walter@dude");
+  EXPECT_EQ("", jid.node());
+  EXPECT_EQ("muchat", jid.domain());
+  EXPECT_EQ("walter@dude", jid.resource());
+  EXPECT_EQ("muchat/walter@dude", jid.Str());
+  EXPECT_EQ("muchat", jid.BareJid().Str());
+  EXPECT_TRUE(jid.IsValid());
+  EXPECT_FALSE(jid.IsBare());
+  EXPECT_TRUE(jid.IsFull());
+}
diff --git a/libjingle/xmpp/jingleinfotask.cc b/libjingle/xmpp/jingleinfotask.cc
new file mode 100644
index 0000000..a5a0712
--- /dev/null
+++ b/libjingle/xmpp/jingleinfotask.cc
@@ -0,0 +1,121 @@
+/*
+ *  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 "webrtc/libjingle/xmpp/jingleinfotask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace buzz {
+
+class JingleInfoTask::JingleInfoGetTask : public XmppTask {
+ public:
+  explicit JingleInfoGetTask(XmppTaskParentInterface* parent)
+      : XmppTask(parent, XmppEngine::HL_SINGLE),
+        done_(false) {}
+
+  virtual int ProcessStart() {
+    rtc::scoped_ptr<XmlElement> get(
+        MakeIq(STR_GET, Jid(), task_id()));
+    get->AddElement(new XmlElement(QN_JINGLE_INFO_QUERY, true));
+    if (SendStanza(get.get()) != XMPP_RETURN_OK) {
+      return STATE_ERROR;
+    }
+    return STATE_RESPONSE;
+  }
+  virtual int ProcessResponse() {
+    if (done_)
+      return STATE_DONE;
+    return STATE_BLOCKED;
+  }
+
+ protected:
+  virtual bool HandleStanza(const XmlElement * stanza) {
+    if (!MatchResponseIq(stanza, Jid(), task_id()))
+      return false;
+
+    if (stanza->Attr(QN_TYPE) != STR_RESULT)
+      return false;
+
+    // Queue the stanza with the parent so these don't get handled out of order
+    JingleInfoTask* parent = static_cast<JingleInfoTask*>(GetParent());
+    parent->QueueStanza(stanza);
+
+    // Wake ourselves so we can go into the done state
+    done_ = true;
+    Wake();
+    return true;
+  }
+
+  bool done_;
+};
+
+
+void JingleInfoTask::RefreshJingleInfoNow() {
+  JingleInfoGetTask* get_task = new JingleInfoGetTask(this);
+  get_task->Start();
+}
+
+bool
+JingleInfoTask::HandleStanza(const XmlElement * stanza) {
+  if (!MatchRequestIq(stanza, "set", QN_JINGLE_INFO_QUERY))
+    return false;
+
+  // only respect relay push from the server
+  Jid from(stanza->Attr(QN_FROM));
+  if (!from.IsEmpty() &&
+      !from.BareEquals(GetClient()->jid()) &&
+      from != Jid(GetClient()->jid().domain()))
+    return false;
+
+  QueueStanza(stanza);
+  return true;
+}
+
+int
+JingleInfoTask::ProcessStart() {
+  std::vector<std::string> relay_hosts;
+  std::vector<rtc::SocketAddress> stun_hosts;
+  std::string relay_token;
+  const XmlElement * stanza = NextStanza();
+  if (stanza == NULL)
+    return STATE_BLOCKED;
+  const XmlElement * query = stanza->FirstNamed(QN_JINGLE_INFO_QUERY);
+  if (query == NULL)
+    return STATE_START;
+  const XmlElement *stun = query->FirstNamed(QN_JINGLE_INFO_STUN);
+  if (stun) {
+    for (const XmlElement *server = stun->FirstNamed(QN_JINGLE_INFO_SERVER);
+         server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) {
+      std::string host = server->Attr(QN_JINGLE_INFO_HOST);
+      std::string port = server->Attr(QN_JINGLE_INFO_UDP);
+      if (host != STR_EMPTY && host != STR_EMPTY) {
+        stun_hosts.push_back(rtc::SocketAddress(host, atoi(port.c_str())));
+      }
+    }
+  }
+
+  const XmlElement *relay = query->FirstNamed(QN_JINGLE_INFO_RELAY);
+  if (relay) {
+    relay_token = relay->TextNamed(QN_JINGLE_INFO_TOKEN);
+    for (const XmlElement *server = relay->FirstNamed(QN_JINGLE_INFO_SERVER);
+         server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) {
+      std::string host = server->Attr(QN_JINGLE_INFO_HOST);
+      if (host != STR_EMPTY) {
+        relay_hosts.push_back(host);
+      }
+    }
+  }
+  SignalJingleInfo(relay_token, relay_hosts, stun_hosts);
+  return STATE_START;
+}
+}
diff --git a/libjingle/xmpp/jingleinfotask.h b/libjingle/xmpp/jingleinfotask.h
new file mode 100644
index 0000000..6ed701d
--- /dev/null
+++ b/libjingle/xmpp/jingleinfotask.h
@@ -0,0 +1,44 @@
+/*
+ *  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.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_JINGLEINFOTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_JINGLEINFOTASK_H_
+
+#include <vector>
+
+#include "webrtc/p2p/client/httpportallocator.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "webrtc/base/sigslot.h"
+
+namespace buzz {
+
+class JingleInfoTask : public XmppTask {
+ public:
+  explicit JingleInfoTask(XmppTaskParentInterface* parent) :
+    XmppTask(parent, XmppEngine::HL_TYPE) {}
+
+  virtual int ProcessStart();
+  void RefreshJingleInfoNow();
+
+  sigslot::signal3<const std::string &,
+                   const std::vector<std::string> &,
+                   const std::vector<rtc::SocketAddress> &>
+                       SignalJingleInfo;
+
+ protected:
+  class JingleInfoGetTask;
+  friend class JingleInfoGetTask;
+
+  virtual bool HandleStanza(const XmlElement * stanza);
+};
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_JINGLEINFOTASK_H_
diff --git a/libjingle/xmpp/module.h b/libjingle/xmpp/module.h
new file mode 100644
index 0000000..fa26df3
--- /dev/null
+++ b/libjingle/xmpp/module.h
@@ -0,0 +1,35 @@
+/*
+ *  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_LIBJINGLE_XMPP_MODULE_H_
+#define WEBRTC_LIBJINGLE_XMPP_MODULE_H_
+
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+
+namespace buzz {
+
+class XmppEngine;
+
+//! This is the base class for extension modules.
+//! An engine is registered with the module and the module then hooks the
+//! appropriate parts of the engine to implement that set of features.  It is
+//! important to unregister modules before destructing the engine.
+class XmppModule {
+public:
+  virtual ~XmppModule() {}
+
+  //! Register the engine with the module.  Only one engine can be associated
+  //! with a module at a time.  This method will return an error if there is
+  //! already an engine registered.
+  virtual XmppReturnStatus RegisterEngine(XmppEngine* engine) = 0;
+};
+
+}
+#endif  // WEBRTC_LIBJINGLE_XMPP_MODULE_H_
diff --git a/libjingle/xmpp/moduleimpl.cc b/libjingle/xmpp/moduleimpl.cc
new file mode 100644
index 0000000..b5337a6
--- /dev/null
+++ b/libjingle/xmpp/moduleimpl.cc
@@ -0,0 +1,48 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/moduleimpl.h"
+#include "webrtc/base/common.h"
+
+namespace buzz {
+
+XmppModuleImpl::XmppModuleImpl() :
+  engine_(NULL),
+  stanza_handler_(this) {
+}
+
+XmppModuleImpl::~XmppModuleImpl()
+{
+  if (engine_ != NULL) {
+    engine_->RemoveStanzaHandler(&stanza_handler_);
+    engine_ = NULL;
+  }
+}
+
+XmppReturnStatus
+XmppModuleImpl::RegisterEngine(XmppEngine* engine)
+{
+  if (NULL == engine || NULL != engine_)
+    return XMPP_RETURN_BADARGUMENT;
+
+  engine->AddStanzaHandler(&stanza_handler_);
+  engine_ = engine;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppEngine*
+XmppModuleImpl::engine() {
+  ASSERT(NULL != engine_);
+  return engine_;
+}
+
+}
+
diff --git a/libjingle/xmpp/moduleimpl.h b/libjingle/xmpp/moduleimpl.h
new file mode 100644
index 0000000..5a7c6e3
--- /dev/null
+++ b/libjingle/xmpp/moduleimpl.h
@@ -0,0 +1,76 @@
+/*
+ *  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_LIBJINGLE_XMPP_MODULEIMPL_H_
+#define WEBRTC_LIBJINGLE_XMPP_MODULEIMPL_H_
+
+#include "webrtc/libjingle/xmpp/module.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+
+namespace buzz {
+
+//! This is the base implementation class for extension modules.
+//! An engine is registered with the module and the module then hooks the
+//! appropriate parts of the engine to implement that set of features.  It is
+//! important to unregister modules before destructing the engine.
+class XmppModuleImpl {
+protected:
+  XmppModuleImpl();
+  virtual ~XmppModuleImpl();
+
+  //! Register the engine with the module.  Only one engine can be associated
+  //! with a module at a time.  This method will return an error if there is
+  //! already an engine registered.
+  XmppReturnStatus RegisterEngine(XmppEngine* engine);
+
+  //! Gets the engine that this module is attached to.
+  XmppEngine* engine();
+
+  //! Process the given stanza.
+  //! The module must return true if it has handled the stanza.
+  //! A false return value causes the stanza to be passed on to
+  //! the next registered handler.
+  virtual bool HandleStanza(const XmlElement *) { return false; };
+
+private:
+
+  //! The ModuleSessionHelper nested class allows the Module
+  //! to hook into and get stanzas and events from the engine.
+  class ModuleStanzaHandler : public XmppStanzaHandler {
+    friend class XmppModuleImpl;
+
+    ModuleStanzaHandler(XmppModuleImpl* module) :
+      module_(module) {
+    }
+
+    bool HandleStanza(const XmlElement* stanza) {
+      return module_->HandleStanza(stanza);
+    }
+
+    XmppModuleImpl* module_;
+  };
+
+  friend class ModuleStanzaHandler;
+
+  XmppEngine* engine_;
+  ModuleStanzaHandler stanza_handler_;
+};
+
+
+// This macro will implement the XmppModule interface for a class
+// that derives from both XmppModuleImpl and XmppModule
+#define IMPLEMENT_XMPPMODULE \
+  XmppReturnStatus RegisterEngine(XmppEngine* engine) { \
+    return XmppModuleImpl::RegisterEngine(engine); \
+  }
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_MODULEIMPL_H_
diff --git a/libjingle/xmpp/mucroomconfigtask.cc b/libjingle/xmpp/mucroomconfigtask.cc
new file mode 100644
index 0000000..08b1065
--- /dev/null
+++ b/libjingle/xmpp/mucroomconfigtask.cc
@@ -0,0 +1,74 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/mucroomconfigtask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace buzz {
+
+MucRoomConfigTask::MucRoomConfigTask(
+    XmppTaskParentInterface* parent,
+    const Jid& room_jid,
+    const std::string& room_name,
+    const std::vector<std::string>& room_features)
+    : IqTask(parent, STR_SET, room_jid,
+             MakeRequest(room_name, room_features)),
+      room_jid_(room_jid) {
+}
+
+XmlElement* MucRoomConfigTask::MakeRequest(
+    const std::string& room_name,
+    const std::vector<std::string>& room_features) {
+  buzz::XmlElement* owner_query = new
+      buzz::XmlElement(buzz::QN_MUC_OWNER_QUERY, true);
+
+  buzz::XmlElement* x_form = new buzz::XmlElement(buzz::QN_XDATA_X, true);
+  x_form->SetAttr(buzz::QN_TYPE, buzz::STR_FORM);
+
+  buzz::XmlElement* roomname_field =
+      new buzz::XmlElement(buzz::QN_XDATA_FIELD, false);
+  roomname_field->SetAttr(buzz::QN_VAR, buzz::STR_MUC_ROOMCONFIG_ROOMNAME);
+  roomname_field->SetAttr(buzz::QN_TYPE, buzz::STR_TEXT_SINGLE);
+
+  buzz::XmlElement* roomname_value =
+      new buzz::XmlElement(buzz::QN_XDATA_VALUE, false);
+  roomname_value->SetBodyText(room_name);
+
+  roomname_field->AddElement(roomname_value);
+  x_form->AddElement(roomname_field);
+
+  buzz::XmlElement* features_field =
+      new buzz::XmlElement(buzz::QN_XDATA_FIELD, false);
+  features_field->SetAttr(buzz::QN_VAR, buzz::STR_MUC_ROOMCONFIG_FEATURES);
+  features_field->SetAttr(buzz::QN_TYPE, buzz::STR_LIST_MULTI);
+
+  for (std::vector<std::string>::const_iterator feature = room_features.begin();
+       feature != room_features.end(); ++feature) {
+    buzz::XmlElement* features_value =
+        new buzz::XmlElement(buzz::QN_XDATA_VALUE, false);
+    features_value->SetBodyText(*feature);
+    features_field->AddElement(features_value);
+  }
+
+  x_form->AddElement(features_field);
+  owner_query->AddElement(x_form);
+  return owner_query;
+}
+
+void MucRoomConfigTask::HandleResult(const XmlElement* element) {
+  SignalResult(this);
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/mucroomconfigtask.h b/libjingle/xmpp/mucroomconfigtask.h
new file mode 100644
index 0000000..d297d02
--- /dev/null
+++ b/libjingle/xmpp/mucroomconfigtask.h
@@ -0,0 +1,47 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_MUCROOMCONFIGTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_MUCROOMCONFIGTASK_H_
+
+#include <string>
+#include "webrtc/libjingle/xmpp/iqtask.h"
+
+namespace buzz {
+
+// This task configures the muc room for document sharing and other enterprise
+// specific goodies.
+class MucRoomConfigTask : public IqTask {
+ public:
+  MucRoomConfigTask(XmppTaskParentInterface* parent,
+                    const Jid& room_jid,
+                    const std::string& room_name,
+                    const std::vector<std::string>& room_features);
+
+  // Room configuration does not return any reasonable error
+  // values. The First config request configures the room, subseqent
+  // ones are just ignored by server and server returns empty
+  // response.
+  sigslot::signal1<MucRoomConfigTask*> SignalResult;
+
+  const Jid& room_jid() const { return room_jid_; }
+
+ protected:
+  virtual void HandleResult(const XmlElement* stanza);
+
+ private:
+  static XmlElement* MakeRequest(const std::string& room_name,
+                                 const std::vector<std::string>& room_features);
+  Jid room_jid_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_MUCROOMCONFIGTASK_H_
diff --git a/libjingle/xmpp/mucroomconfigtask_unittest.cc b/libjingle/xmpp/mucroomconfigtask_unittest.cc
new file mode 100644
index 0000000..a86dd14
--- /dev/null
+++ b/libjingle/xmpp/mucroomconfigtask_unittest.cc
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/mucroomconfigtask.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+class MucRoomConfigListener : public sigslot::has_slots<> {
+ public:
+  MucRoomConfigListener() : result_count(0), error_count(0) {}
+
+  void OnResult(buzz::MucRoomConfigTask*) {
+    ++result_count;
+  }
+
+  void OnError(buzz::IqTask* task,
+               const buzz::XmlElement* error) {
+    ++error_count;
+  }
+
+  int result_count;
+  int error_count;
+};
+
+class MucRoomConfigTaskTest : public testing::Test {
+ public:
+  MucRoomConfigTaskTest() :
+      room_jid("muc-jid-ponies@domain.com"),
+      room_name("ponies") {
+  }
+
+  virtual void SetUp() {
+    runner = new rtc::FakeTaskRunner();
+    xmpp_client = new buzz::FakeXmppClient(runner);
+    listener = new MucRoomConfigListener();
+  }
+
+  virtual void TearDown() {
+    delete listener;
+    // delete xmpp_client;  Deleted by deleting runner.
+    delete runner;
+  }
+
+  rtc::FakeTaskRunner* runner;
+  buzz::FakeXmppClient* xmpp_client;
+  MucRoomConfigListener* listener;
+  buzz::Jid room_jid;
+  std::string room_name;
+};
+
+TEST_F(MucRoomConfigTaskTest, TestConfigEnterprise) {
+  ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
+
+  std::vector<std::string> room_features;
+  room_features.push_back("feature1");
+  room_features.push_back("feature2");
+  buzz::MucRoomConfigTask* task = new buzz::MucRoomConfigTask(
+      xmpp_client, room_jid, "ponies", room_features);
+  EXPECT_EQ(room_jid, task->room_jid());
+
+  task->SignalResult.connect(listener, &MucRoomConfigListener::OnResult);
+  task->Start();
+
+  std::string expected_iq =
+      "<cli:iq type=\"set\" to=\"muc-jid-ponies@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<query xmlns=\"http://jabber.org/protocol/muc#owner\">"
+          "<x xmlns=\"jabber:x:data\" type=\"form\">"
+            "<field var=\"muc#roomconfig_roomname\" type=\"text-single\">"
+              "<value>ponies</value>"
+            "</field>"
+            "<field var=\"muc#roomconfig_features\" type=\"list-multi\">"
+              "<value>feature1</value>"
+              "<value>feature2</value>"
+            "</field>"
+          "</x>"
+        "</query>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  EXPECT_EQ(0, listener->result_count);
+  EXPECT_EQ(0, listener->error_count);
+
+  std::string response_iq =
+      "<iq xmlns='jabber:client' id='0' type='result'"
+      "  from='muc-jid-ponies@domain.com'>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
+
+  EXPECT_EQ(1, listener->result_count);
+  EXPECT_EQ(0, listener->error_count);
+}
+
+TEST_F(MucRoomConfigTaskTest, TestError) {
+  std::vector<std::string> room_features;
+  buzz::MucRoomConfigTask* task = new buzz::MucRoomConfigTask(
+      xmpp_client, room_jid, "ponies", room_features);
+  task->SignalError.connect(listener, &MucRoomConfigListener::OnError);
+  task->Start();
+
+  std::string error_iq =
+      "<iq xmlns='jabber:client' id='0' type='error'"
+      " from='muc-jid-ponies@domain.com'>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq));
+
+  EXPECT_EQ(0, listener->result_count);
+  EXPECT_EQ(1, listener->error_count);
+}
diff --git a/libjingle/xmpp/mucroomdiscoverytask.cc b/libjingle/xmpp/mucroomdiscoverytask.cc
new file mode 100644
index 0000000..05a5671
--- /dev/null
+++ b/libjingle/xmpp/mucroomdiscoverytask.cc
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 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/libjingle/xmpp/mucroomdiscoverytask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+
+namespace buzz {
+
+MucRoomDiscoveryTask::MucRoomDiscoveryTask(
+    XmppTaskParentInterface* parent,
+    const Jid& room_jid)
+    : IqTask(parent, STR_GET, room_jid,
+             new buzz::XmlElement(buzz::QN_DISCO_INFO_QUERY)) {
+}
+
+void MucRoomDiscoveryTask::HandleResult(const XmlElement* stanza) {
+  const XmlElement* query = stanza->FirstNamed(QN_DISCO_INFO_QUERY);
+  if (query == NULL) {
+    SignalError(this, NULL);
+    return;
+  }
+
+  std::set<std::string> features;
+  std::map<std::string, std::string> extended_info;
+  const XmlElement* identity = query->FirstNamed(QN_DISCO_IDENTITY);
+  if (identity == NULL || !identity->HasAttr(QN_NAME)) {
+    SignalResult(this, false, "", "", features, extended_info);
+    return;
+  }
+
+  const std::string name(identity->Attr(QN_NAME));
+
+  // Get the conversation id
+  const XmlElement* conversation =
+      identity->FirstNamed(QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID);
+  std::string conversation_id;
+  if (conversation != NULL) {
+    conversation_id = conversation->BodyText();
+  }
+
+  for (const XmlElement* feature = query->FirstNamed(QN_DISCO_FEATURE);
+       feature != NULL; feature = feature->NextNamed(QN_DISCO_FEATURE)) {
+    features.insert(feature->Attr(QN_VAR));
+  }
+
+  const XmlElement* data_x = query->FirstNamed(QN_XDATA_X);
+  if (data_x != NULL) {
+    for (const XmlElement* field = data_x->FirstNamed(QN_XDATA_FIELD);
+         field != NULL; field = field->NextNamed(QN_XDATA_FIELD)) {
+      const std::string key(field->Attr(QN_VAR));
+      extended_info[key] = field->Attr(QN_XDATA_VALUE);
+    }
+  }
+
+  SignalResult(this, true, name, conversation_id, features, extended_info);
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/mucroomdiscoverytask.h b/libjingle/xmpp/mucroomdiscoverytask.h
new file mode 100644
index 0000000..3e332bd
--- /dev/null
+++ b/libjingle/xmpp/mucroomdiscoverytask.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 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_LIBJINGLE_XMPP_MUCROOMDISCOVERYTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_MUCROOMDISCOVERYTASK_H_
+
+#include <map>
+#include <string>
+#include "webrtc/libjingle/xmpp/iqtask.h"
+
+namespace buzz {
+
+// This task requests the feature capabilities of the room. It is based on
+// XEP-0030, and extended using XEP-0004.
+class MucRoomDiscoveryTask : public IqTask {
+ public:
+  MucRoomDiscoveryTask(XmppTaskParentInterface* parent,
+                       const Jid& room_jid);
+
+  // Signal (exists, name, conversationId, features, extended_info)
+  sigslot::signal6<MucRoomDiscoveryTask*,
+                   bool,
+                   const std::string&,
+                   const std::string&,
+                   const std::set<std::string>&,
+                   const std::map<std::string, std::string>& > SignalResult;
+
+ protected:
+  virtual void HandleResult(const XmlElement* stanza);
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_MUCROOMDISCOVERYTASK_H_
diff --git a/libjingle/xmpp/mucroomdiscoverytask_unittest.cc b/libjingle/xmpp/mucroomdiscoverytask_unittest.cc
new file mode 100644
index 0000000..cdb50c2
--- /dev/null
+++ b/libjingle/xmpp/mucroomdiscoverytask_unittest.cc
@@ -0,0 +1,145 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/mucroomdiscoverytask.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+class MucRoomDiscoveryListener : public sigslot::has_slots<> {
+ public:
+  MucRoomDiscoveryListener() : error_count(0) {}
+
+  void OnResult(buzz::MucRoomDiscoveryTask* task,
+                bool exists,
+                const std::string& name,
+                const std::string& conversation_id,
+                const std::set<std::string>& features,
+                const std::map<std::string, std::string>& extended_info) {
+    last_exists = exists;
+    last_name = name;
+    last_conversation_id = conversation_id;
+    last_features = features;
+    last_extended_info = extended_info;
+  }
+
+  void OnError(buzz::IqTask* task,
+               const buzz::XmlElement* error) {
+    ++error_count;
+  }
+
+  bool last_exists;
+  std::string last_name;
+  std::string last_conversation_id;
+  std::set<std::string> last_features;
+  std::map<std::string, std::string> last_extended_info;
+  int error_count;
+};
+
+class MucRoomDiscoveryTaskTest : public testing::Test {
+ public:
+  MucRoomDiscoveryTaskTest() :
+      room_jid("muc-jid-ponies@domain.com"),
+      room_name("ponies"),
+      conversation_id("test_conversation_id") {
+  }
+
+  virtual void SetUp() {
+    runner = new rtc::FakeTaskRunner();
+    xmpp_client = new buzz::FakeXmppClient(runner);
+    listener = new MucRoomDiscoveryListener();
+  }
+
+  virtual void TearDown() {
+    delete listener;
+    // delete xmpp_client;  Deleted by deleting runner.
+    delete runner;
+  }
+
+  rtc::FakeTaskRunner* runner;
+  buzz::FakeXmppClient* xmpp_client;
+  MucRoomDiscoveryListener* listener;
+  buzz::Jid room_jid;
+  std::string room_name;
+  std::string conversation_id;
+};
+
+TEST_F(MucRoomDiscoveryTaskTest, TestDiscovery) {
+  ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
+
+  buzz::MucRoomDiscoveryTask* task = new buzz::MucRoomDiscoveryTask(
+      xmpp_client, room_jid);
+  task->SignalResult.connect(listener, &MucRoomDiscoveryListener::OnResult);
+  task->Start();
+
+  std::string expected_iq =
+      "<cli:iq type=\"get\" to=\"muc-jid-ponies@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<info:query xmlns:info=\"http://jabber.org/protocol/disco#info\"/>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  EXPECT_EQ("", listener->last_name);
+  EXPECT_EQ("", listener->last_conversation_id);
+
+  std::string response_iq =
+      "<iq xmlns='jabber:client'"
+      "    from='muc-jid-ponies@domain.com' id='0' type='result'>"
+      "  <info:query xmlns:info='http://jabber.org/protocol/disco#info'>"
+      "    <info:identity name='ponies'>"
+      "      <han:conversation-id xmlns:han='google:muc#hangout'>"
+      "test_conversation_id</han:conversation-id>"
+      "    </info:identity>"
+      "    <info:feature var='feature1'/>"
+      "    <info:feature var='feature2'/>"
+      "    <data:x xmlns:data='jabber:x:data'>"
+      "      <data:field var='var1' data:value='value1' />"
+      "      <data:field var='var2' data:value='value2' />"
+      "    </data:x>"
+      "  </info:query>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
+
+  EXPECT_EQ(true, listener->last_exists);
+  EXPECT_EQ(room_name, listener->last_name);
+  EXPECT_EQ(conversation_id, listener->last_conversation_id);
+  EXPECT_EQ(2U, listener->last_features.size());
+  EXPECT_EQ(1U, listener->last_features.count("feature1"));
+  EXPECT_EQ(2U, listener->last_extended_info.size());
+  EXPECT_EQ("value1", listener->last_extended_info["var1"]);
+  EXPECT_EQ(0, listener->error_count);
+}
+
+TEST_F(MucRoomDiscoveryTaskTest, TestMissingName) {
+  buzz::MucRoomDiscoveryTask* task = new buzz::MucRoomDiscoveryTask(
+      xmpp_client, room_jid);
+  task->SignalError.connect(listener, &MucRoomDiscoveryListener::OnError);
+  task->Start();
+
+  std::string error_iq =
+      "<iq xmlns='jabber:client'"
+      "    from='muc-jid-ponies@domain.com' id='0' type='result'>"
+      "  <info:query xmlns:info='http://jabber.org/protocol/disco#info'>"
+      "    <info:identity />"
+      "  </info:query>"
+      "</iq>";
+  EXPECT_EQ(0, listener->error_count);
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq));
+  EXPECT_EQ(0, listener->error_count);
+}
diff --git a/libjingle/xmpp/mucroomlookuptask.cc b/libjingle/xmpp/mucroomlookuptask.cc
new file mode 100644
index 0000000..8c0a4d7
--- /dev/null
+++ b/libjingle/xmpp/mucroomlookuptask.cc
@@ -0,0 +1,159 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/mucroomlookuptask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+
+
+namespace buzz {
+
+MucRoomLookupTask*
+MucRoomLookupTask::CreateLookupTaskForRoomName(XmppTaskParentInterface* parent,
+                                     const Jid& lookup_server_jid,
+                                     const std::string& room_name,
+                                     const std::string& room_domain) {
+  return new MucRoomLookupTask(parent, lookup_server_jid,
+                               MakeNameQuery(room_name, room_domain));
+}
+
+MucRoomLookupTask*
+MucRoomLookupTask::CreateLookupTaskForRoomJid(XmppTaskParentInterface* parent,
+                                              const Jid& lookup_server_jid,
+                                              const Jid& room_jid) {
+  return new MucRoomLookupTask(parent, lookup_server_jid,
+                               MakeJidQuery(room_jid));
+}
+
+MucRoomLookupTask*
+MucRoomLookupTask::CreateLookupTaskForHangoutId(XmppTaskParentInterface* parent,
+                                                const Jid& lookup_server_jid,
+                                                const std::string& hangout_id) {
+  return new MucRoomLookupTask(parent, lookup_server_jid,
+                               MakeHangoutIdQuery(hangout_id));
+}
+
+MucRoomLookupTask*
+MucRoomLookupTask::CreateLookupTaskForExternalId(
+    XmppTaskParentInterface* parent,
+    const Jid& lookup_server_jid,
+    const std::string& external_id,
+    const std::string& type) {
+  return new MucRoomLookupTask(parent, lookup_server_jid,
+                               MakeExternalIdQuery(external_id, type));
+}
+
+MucRoomLookupTask::MucRoomLookupTask(XmppTaskParentInterface* parent,
+                                     const Jid& lookup_server_jid,
+                                     XmlElement* query)
+    : IqTask(parent, STR_SET, lookup_server_jid, query) {
+}
+
+XmlElement* MucRoomLookupTask::MakeNameQuery(
+    const std::string& room_name, const std::string& room_domain) {
+  XmlElement* name_elem = new XmlElement(QN_SEARCH_ROOM_NAME, false);
+  name_elem->SetBodyText(room_name);
+
+  XmlElement* domain_elem = new XmlElement(QN_SEARCH_ROOM_DOMAIN, false);
+  domain_elem->SetBodyText(room_domain);
+
+  XmlElement* query = new XmlElement(QN_SEARCH_QUERY, true);
+  query->AddElement(name_elem);
+  query->AddElement(domain_elem);
+  return query;
+}
+
+XmlElement* MucRoomLookupTask::MakeJidQuery(const Jid& room_jid) {
+  XmlElement* jid_elem = new XmlElement(QN_SEARCH_ROOM_JID);
+  jid_elem->SetBodyText(room_jid.Str());
+
+  XmlElement* query = new XmlElement(QN_SEARCH_QUERY);
+  query->AddElement(jid_elem);
+  return query;
+}
+
+XmlElement* MucRoomLookupTask::MakeExternalIdQuery(
+    const std::string& external_id, const std::string& type) {
+  XmlElement* external_id_elem = new XmlElement(QN_SEARCH_EXTERNAL_ID);
+  external_id_elem->SetAttr(QN_TYPE, type);
+  external_id_elem->SetBodyText(external_id);
+
+  XmlElement* query = new XmlElement(QN_SEARCH_QUERY);
+  query->AddElement(external_id_elem);
+  return query;
+}
+
+// Construct a stanza to lookup the muc jid for a given hangout id. eg:
+//
+// <query xmlns="jabber:iq:search">
+//   <hangout-id>0b48ad092c893a53b7bfc87422caf38e93978798e</hangout-id>
+// </query>
+XmlElement* MucRoomLookupTask::MakeHangoutIdQuery(
+    const std::string& hangout_id) {
+  XmlElement* hangout_id_elem = new XmlElement(QN_SEARCH_HANGOUT_ID, false);
+  hangout_id_elem->SetBodyText(hangout_id);
+
+  XmlElement* query = new XmlElement(QN_SEARCH_QUERY, true);
+  query->AddElement(hangout_id_elem);
+  return query;
+}
+
+// Handle a response like the following:
+//
+// <query xmlns="jabber:iq:search">
+//   <item jid="muvc-private-chat-guid@groupchat.google.com">
+//     <room-name>0b48ad092c893a53b7bfc87422caf38e93978798e</room-name>
+//     <room-domain>hangout.google.com</room-domain>
+//   </item>
+// </query>
+void MucRoomLookupTask::HandleResult(const XmlElement* stanza) {
+  const XmlElement* query_elem = stanza->FirstNamed(QN_SEARCH_QUERY);
+  if (query_elem == NULL) {
+    SignalError(this, stanza);
+    return;
+  }
+
+  const XmlElement* item_elem = query_elem->FirstNamed(QN_SEARCH_ITEM);
+  if (item_elem == NULL) {
+    SignalError(this, stanza);
+    return;
+  }
+
+  MucRoomInfo room;
+  room.jid = Jid(item_elem->Attr(buzz::QN_JID));
+  if (!room.jid.IsValid()) {
+    SignalError(this, stanza);
+    return;
+  }
+
+  const XmlElement* room_name_elem =
+      item_elem->FirstNamed(QN_SEARCH_ROOM_NAME);
+  if (room_name_elem != NULL) {
+    room.name = room_name_elem->BodyText();
+  }
+
+  const XmlElement* room_domain_elem =
+      item_elem->FirstNamed(QN_SEARCH_ROOM_DOMAIN);
+  if (room_domain_elem != NULL) {
+    room.domain = room_domain_elem->BodyText();
+  }
+
+  const XmlElement* hangout_id_elem =
+      item_elem->FirstNamed(QN_SEARCH_HANGOUT_ID);
+  if (hangout_id_elem != NULL) {
+    room.hangout_id = hangout_id_elem->BodyText();
+  }
+
+  SignalResult(this, room);
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/mucroomlookuptask.h b/libjingle/xmpp/mucroomlookuptask.h
new file mode 100644
index 0000000..d87b3da
--- /dev/null
+++ b/libjingle/xmpp/mucroomlookuptask.h
@@ -0,0 +1,76 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_MUCROOMLOOKUPTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_MUCROOMLOOKUPTASK_H_
+
+#include <string>
+#include "webrtc/libjingle/xmpp/iqtask.h"
+
+namespace buzz {
+
+struct MucRoomInfo {
+  Jid jid;
+  std::string name;
+  std::string domain;
+  std::string hangout_id;
+
+  std::string full_name() const {
+    return name + "@" + domain;
+  }
+};
+
+class MucRoomLookupTask : public IqTask {
+ public:
+  enum IdType {
+    ID_TYPE_CONVERSATION,
+    ID_TYPE_HANGOUT
+  };
+
+  static MucRoomLookupTask*
+      CreateLookupTaskForRoomName(XmppTaskParentInterface* parent,
+                                  const Jid& lookup_server_jid,
+                                  const std::string& room_name,
+                                  const std::string& room_domain);
+  static MucRoomLookupTask*
+      CreateLookupTaskForRoomJid(XmppTaskParentInterface* parent,
+                                 const Jid& lookup_server_jid,
+                                 const Jid& room_jid);
+  static MucRoomLookupTask*
+      CreateLookupTaskForHangoutId(XmppTaskParentInterface* parent,
+                                   const Jid& lookup_server_jid,
+                                   const std::string& hangout_id);
+  static MucRoomLookupTask*
+      CreateLookupTaskForExternalId(XmppTaskParentInterface* parent,
+                                    const Jid& lookup_server_jid,
+                                    const std::string& external_id,
+                                    const std::string& type);
+
+  sigslot::signal2<MucRoomLookupTask*,
+                   const MucRoomInfo&> SignalResult;
+
+ protected:
+  virtual void HandleResult(const XmlElement* element);
+
+ private:
+  MucRoomLookupTask(XmppTaskParentInterface* parent,
+                    const Jid& lookup_server_jid,
+                    XmlElement* query);
+  static XmlElement* MakeNameQuery(const std::string& room_name,
+                                   const std::string& room_domain);
+  static XmlElement* MakeJidQuery(const Jid& room_jid);
+  static XmlElement* MakeHangoutIdQuery(const std::string& hangout_id);
+  static XmlElement* MakeExternalIdQuery(const std::string& external_id,
+                                         const std::string& type);
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_MUCROOMLOOKUPTASK_H_
diff --git a/libjingle/xmpp/mucroomlookuptask_unittest.cc b/libjingle/xmpp/mucroomlookuptask_unittest.cc
new file mode 100644
index 0000000..da5b145
--- /dev/null
+++ b/libjingle/xmpp/mucroomlookuptask_unittest.cc
@@ -0,0 +1,187 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/mucroomlookuptask.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+class MucRoomLookupListener : public sigslot::has_slots<> {
+ public:
+  MucRoomLookupListener() : error_count(0) {}
+
+  void OnResult(buzz::MucRoomLookupTask* task,
+                const buzz::MucRoomInfo& room) {
+    last_room = room;
+  }
+
+  void OnError(buzz::IqTask* task,
+               const buzz::XmlElement* error) {
+    ++error_count;
+  }
+
+  buzz::MucRoomInfo last_room;
+  int error_count;
+};
+
+class MucRoomLookupTaskTest : public testing::Test {
+ public:
+  MucRoomLookupTaskTest() :
+      lookup_server_jid("lookup@domain.com"),
+      room_jid("muc-jid-ponies@domain.com"),
+      room_name("ponies"),
+      room_domain("domain.com"),
+      room_full_name("ponies@domain.com"),
+      hangout_id("some_hangout_id") {
+  }
+
+  virtual void SetUp() {
+    runner = new rtc::FakeTaskRunner();
+    xmpp_client = new buzz::FakeXmppClient(runner);
+    listener = new MucRoomLookupListener();
+  }
+
+  virtual void TearDown() {
+    delete listener;
+    // delete xmpp_client;  Deleted by deleting runner.
+    delete runner;
+  }
+
+  rtc::FakeTaskRunner* runner;
+  buzz::FakeXmppClient* xmpp_client;
+  MucRoomLookupListener* listener;
+  buzz::Jid lookup_server_jid;
+  buzz::Jid room_jid;
+  std::string room_name;
+  std::string room_domain;
+  std::string room_full_name;
+  std::string hangout_id;
+};
+
+TEST_F(MucRoomLookupTaskTest, TestLookupName) {
+  ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
+
+  buzz::MucRoomLookupTask* task =
+      buzz::MucRoomLookupTask::CreateLookupTaskForRoomName(
+          xmpp_client, lookup_server_jid, room_name, room_domain);
+  task->SignalResult.connect(listener, &MucRoomLookupListener::OnResult);
+  task->Start();
+
+  std::string expected_iq =
+      "<cli:iq type=\"set\" to=\"lookup@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<query xmlns=\"jabber:iq:search\">"
+          "<room-name>ponies</room-name>"
+          "<room-domain>domain.com</room-domain>"
+        "</query>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  EXPECT_EQ("", listener->last_room.name);
+
+  std::string response_iq =
+      "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
+      "  <query xmlns='jabber:iq:search'>"
+      "    <item jid='muc-jid-ponies@domain.com'>"
+      "      <room-name>ponies</room-name>"
+      "      <room-domain>domain.com</room-domain>"
+      "    </item>"
+      "  </query>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
+
+  EXPECT_EQ(room_name, listener->last_room.name);
+  EXPECT_EQ(room_domain, listener->last_room.domain);
+  EXPECT_EQ(room_jid, listener->last_room.jid);
+  EXPECT_EQ(room_full_name, listener->last_room.full_name());
+  EXPECT_EQ(0, listener->error_count);
+}
+
+TEST_F(MucRoomLookupTaskTest, TestLookupHangoutId) {
+  ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
+
+  buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForHangoutId(
+      xmpp_client, lookup_server_jid, hangout_id);
+  task->SignalResult.connect(listener, &MucRoomLookupListener::OnResult);
+  task->Start();
+
+  std::string expected_iq =
+      "<cli:iq type=\"set\" to=\"lookup@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<query xmlns=\"jabber:iq:search\">"
+          "<hangout-id>some_hangout_id</hangout-id>"
+        "</query>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  EXPECT_EQ("", listener->last_room.name);
+
+  std::string response_iq =
+      "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
+      "  <query xmlns='jabber:iq:search'>"
+      "    <item jid='muc-jid-ponies@domain.com'>"
+      "      <room-name>some_hangout_id</room-name>"
+      "      <room-domain>domain.com</room-domain>"
+      "    </item>"
+      "  </query>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
+
+  EXPECT_EQ(hangout_id, listener->last_room.name);
+  EXPECT_EQ(room_domain, listener->last_room.domain);
+  EXPECT_EQ(room_jid, listener->last_room.jid);
+  EXPECT_EQ(0, listener->error_count);
+}
+
+TEST_F(MucRoomLookupTaskTest, TestError) {
+  buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForRoomName(
+      xmpp_client, lookup_server_jid, room_name, room_domain);
+  task->SignalError.connect(listener, &MucRoomLookupListener::OnError);
+  task->Start();
+
+  std::string error_iq =
+      "<iq xmlns='jabber:client' id='0' type='error'"
+      "  from='lookup@domain.com'>"
+      "</iq>";
+
+  EXPECT_EQ(0, listener->error_count);
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq));
+  EXPECT_EQ(1, listener->error_count);
+}
+
+TEST_F(MucRoomLookupTaskTest, TestBadJid) {
+  buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForRoomName(
+      xmpp_client, lookup_server_jid, room_name, room_domain);
+  task->SignalError.connect(listener, &MucRoomLookupListener::OnError);
+  task->Start();
+
+  std::string response_iq =
+      "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
+      "  <query xmlns='jabber:iq:search'>"
+      "    <item/>"
+      "  </query>"
+      "</iq>";
+
+  EXPECT_EQ(0, listener->error_count);
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
+  EXPECT_EQ(1, listener->error_count);
+}
diff --git a/libjingle/xmpp/mucroomuniquehangoutidtask.cc b/libjingle/xmpp/mucroomuniquehangoutidtask.cc
new file mode 100644
index 0000000..79ccc29
--- /dev/null
+++ b/libjingle/xmpp/mucroomuniquehangoutidtask.cc
@@ -0,0 +1,51 @@
+/*
+ *  Copyright 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/libjingle/xmpp/mucroomuniquehangoutidtask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+
+namespace buzz {
+
+MucRoomUniqueHangoutIdTask::MucRoomUniqueHangoutIdTask(XmppTaskParentInterface* parent,
+                                             const Jid& lookup_server_jid)
+    : IqTask(parent, STR_GET, lookup_server_jid, MakeUniqueRequestXml()) {
+}
+
+// Construct a stanza to request a unique room id. eg:
+//
+// <unique hangout-id="true" xmlns="http://jabber.org/protocol/muc#unique"/>
+XmlElement* MucRoomUniqueHangoutIdTask::MakeUniqueRequestXml() {
+  XmlElement* xml = new XmlElement(QN_MUC_UNIQUE_QUERY, false);
+  xml->SetAttr(QN_HANGOUT_ID, STR_TRUE);
+  return xml;
+}
+
+// Handle a response like the following:
+//
+// <unique hangout-id="hangout_id"
+//    xmlns="http://jabber.org/protocol/muc#unique"/>
+//  muvc-private-chat-guid@groupchat.google.com
+// </unique>
+void MucRoomUniqueHangoutIdTask::HandleResult(const XmlElement* stanza) {
+
+  const XmlElement* unique_elem = stanza->FirstNamed(QN_MUC_UNIQUE_QUERY);
+  if (unique_elem == NULL ||
+      !unique_elem->HasAttr(QN_HANGOUT_ID)) {
+    SignalError(this, stanza);
+    return;
+  }
+
+  std::string hangout_id = unique_elem->Attr(QN_HANGOUT_ID);
+
+  SignalResult(this, hangout_id);
+}
+
+} // namespace buzz
diff --git a/libjingle/xmpp/mucroomuniquehangoutidtask.h b/libjingle/xmpp/mucroomuniquehangoutidtask.h
new file mode 100644
index 0000000..ac66250
--- /dev/null
+++ b/libjingle/xmpp/mucroomuniquehangoutidtask.h
@@ -0,0 +1,38 @@
+/*
+ *  Copyright 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_LIBJINGLE_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_
+
+#include "webrtc/libjingle/xmpp/iqtask.h"
+
+namespace buzz {
+
+// Task to request a unique hangout id to be used when starting a hangout.
+// The protocol is described in https://docs.google.com/a/google.com/
+// document/d/1EFLT6rCYPDVdqQXSQliXwqB3iUkpZJ9B_MNFeOZgN7g/edit
+class MucRoomUniqueHangoutIdTask : public buzz::IqTask {
+ public:
+  MucRoomUniqueHangoutIdTask(buzz::XmppTaskParentInterface* parent,
+                        const Jid& lookup_server_jid);
+  // signal(task, hangout_id)
+  sigslot::signal2<MucRoomUniqueHangoutIdTask*, const std::string&> SignalResult;
+
+ protected:
+  virtual void HandleResult(const buzz::XmlElement* stanza);
+
+ private:
+  static buzz::XmlElement* MakeUniqueRequestXml();
+
+};
+
+} // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_
diff --git a/libjingle/xmpp/mucroomuniquehangoutidtask_unittest.cc b/libjingle/xmpp/mucroomuniquehangoutidtask_unittest.cc
new file mode 100644
index 0000000..2480528
--- /dev/null
+++ b/libjingle/xmpp/mucroomuniquehangoutidtask_unittest.cc
@@ -0,0 +1,99 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/mucroomuniquehangoutidtask.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+class MucRoomUniqueHangoutIdListener : public sigslot::has_slots<> {
+ public:
+  MucRoomUniqueHangoutIdListener() : error_count(0) {}
+
+  void OnResult(buzz::MucRoomUniqueHangoutIdTask* task,
+                const std::string& hangout_id) {
+    last_hangout_id = hangout_id;
+  }
+
+  void OnError(buzz::IqTask* task,
+               const buzz::XmlElement* error) {
+    ++error_count;
+  }
+
+  std::string last_hangout_id;
+  int error_count;
+};
+
+class MucRoomUniqueHangoutIdTaskTest : public testing::Test {
+ public:
+  MucRoomUniqueHangoutIdTaskTest() :
+      lookup_server_jid("lookup@domain.com"),
+      hangout_id("some_hangout_id") {
+  }
+
+  virtual void SetUp() {
+    runner = new rtc::FakeTaskRunner();
+    xmpp_client = new buzz::FakeXmppClient(runner);
+    listener = new MucRoomUniqueHangoutIdListener();
+  }
+
+  virtual void TearDown() {
+    delete listener;
+    // delete xmpp_client;  Deleted by deleting runner.
+    delete runner;
+  }
+
+  rtc::FakeTaskRunner* runner;
+  buzz::FakeXmppClient* xmpp_client;
+  MucRoomUniqueHangoutIdListener* listener;
+  buzz::Jid lookup_server_jid;
+  std::string hangout_id;
+};
+
+TEST_F(MucRoomUniqueHangoutIdTaskTest, Test) {
+  ASSERT_EQ(0U, xmpp_client->sent_stanzas().size());
+
+  buzz::MucRoomUniqueHangoutIdTask* task = new buzz::MucRoomUniqueHangoutIdTask(
+      xmpp_client, lookup_server_jid);
+  task->SignalResult.connect(listener, &MucRoomUniqueHangoutIdListener::OnResult);
+  task->Start();
+
+  std::string expected_iq =
+      "<cli:iq type=\"get\" to=\"lookup@domain.com\" id=\"0\" "
+          "xmlns:cli=\"jabber:client\">"
+        "<uni:unique hangout-id=\"true\" "
+          "xmlns:uni=\"http://jabber.org/protocol/muc#unique\"/>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  EXPECT_EQ("", listener->last_hangout_id);
+
+  std::string response_iq =
+      "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>"
+        "<unique hangout-id=\"some_hangout_id\" "
+            "xmlns=\"http://jabber.org/protocol/muc#unique\">"
+          "muvc-private-chat-00001234-5678-9abc-def0-123456789abc"
+        "</unique>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq));
+
+  EXPECT_EQ(hangout_id, listener->last_hangout_id);
+  EXPECT_EQ(0, listener->error_count);
+}
+
diff --git a/libjingle/xmpp/pingtask.cc b/libjingle/xmpp/pingtask.cc
new file mode 100644
index 0000000..d44a6d1
--- /dev/null
+++ b/libjingle/xmpp/pingtask.cc
@@ -0,0 +1,92 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/pingtask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace buzz {
+
+PingTask::PingTask(buzz::XmppTaskParentInterface* parent,
+                   rtc::MessageQueue* message_queue,
+                   uint32 ping_period_millis,
+                   uint32 ping_timeout_millis)
+    : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
+      message_queue_(message_queue),
+      ping_period_millis_(ping_period_millis),
+      ping_timeout_millis_(ping_timeout_millis),
+      next_ping_time_(0),
+      ping_response_deadline_(0) {
+  ASSERT(ping_period_millis >= ping_timeout_millis);
+}
+
+bool PingTask::HandleStanza(const buzz::XmlElement* stanza) {
+  if (!MatchResponseIq(stanza, Jid(STR_EMPTY), task_id())) {
+    return false;
+  }
+
+  if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT &&
+      stanza->Attr(buzz::QN_TYPE) != buzz::STR_ERROR) {
+    return false;
+  }
+
+  QueueStanza(stanza);
+  return true;
+}
+
+// This task runs indefinitely and remains in either the start or blocked
+// states.
+int PingTask::ProcessStart() {
+  if (ping_period_millis_ < ping_timeout_millis_) {
+    LOG(LS_ERROR) << "ping_period_millis should be >= ping_timeout_millis";
+    return STATE_ERROR;
+  }
+  const buzz::XmlElement* stanza = NextStanza();
+  if (stanza != NULL) {
+    // Received a ping response of some sort (don't care what it is).
+    ping_response_deadline_ = 0;
+  }
+
+  uint32 now = rtc::Time();
+
+  // If the ping timed out, signal.
+  if (ping_response_deadline_ != 0 && now >= ping_response_deadline_) {
+    SignalTimeout();
+    return STATE_ERROR;
+  }
+
+  // Send a ping if it's time.
+  if (now >= next_ping_time_) {
+    rtc::scoped_ptr<buzz::XmlElement> stanza(
+        MakeIq(buzz::STR_GET, Jid(STR_EMPTY), task_id()));
+    stanza->AddElement(new buzz::XmlElement(QN_PING));
+    SendStanza(stanza.get());
+
+    ping_response_deadline_ = now + ping_timeout_millis_;
+    next_ping_time_ = now + ping_period_millis_;
+
+    // Wake ourselves up when it's time to send another ping or when the ping
+    // times out (so we can fire a signal).
+    message_queue_->PostDelayed(ping_timeout_millis_, this);
+    message_queue_->PostDelayed(ping_period_millis_, this);
+  }
+
+  return STATE_BLOCKED;
+}
+
+void PingTask::OnMessage(rtc::Message* msg) {
+  // Get the task manager to run this task so we can send a ping or signal or
+  // process a ping response.
+  Wake();
+}
+
+} // namespace buzz
diff --git a/libjingle/xmpp/pingtask.h b/libjingle/xmpp/pingtask.h
new file mode 100644
index 0000000..9ea905b
--- /dev/null
+++ b/libjingle/xmpp/pingtask.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_PINGTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_PINGTASK_H_
+
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "webrtc/base/messagehandler.h"
+#include "webrtc/base/messagequeue.h"
+
+namespace buzz {
+
+// Task to periodically send pings to the server to ensure that the network
+// connection is valid, implementing XEP-0199.
+//
+// This is especially useful on cellular networks because:
+// 1. It keeps the connections alive through the cellular network's NATs or
+//    proxies.
+// 2. It detects when the server has crashed or any other case in which the
+//    connection has broken without a fin or reset packet being sent to us.
+class PingTask : public buzz::XmppTask, private rtc::MessageHandler {
+ public:
+  PingTask(buzz::XmppTaskParentInterface* parent,
+      rtc::MessageQueue* message_queue, uint32 ping_period_millis,
+      uint32 ping_timeout_millis);
+
+  virtual bool HandleStanza(const buzz::XmlElement* stanza);
+  virtual int ProcessStart();
+
+  // Raised if there is no response to a ping within ping_timeout_millis.
+  // The task is automatically aborted after a timeout.
+  sigslot::signal0<> SignalTimeout;
+
+ private:
+  // Implementation of MessageHandler.
+  virtual void OnMessage(rtc::Message* msg);
+
+  rtc::MessageQueue* message_queue_;
+  uint32 ping_period_millis_;
+  uint32 ping_timeout_millis_;
+  uint32 next_ping_time_;
+  uint32 ping_response_deadline_; // 0 if the response has been received
+};
+
+} // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PINGTASK_H_
diff --git a/libjingle/xmpp/pingtask_unittest.cc b/libjingle/xmpp/pingtask_unittest.cc
new file mode 100644
index 0000000..08a5770
--- /dev/null
+++ b/libjingle/xmpp/pingtask_unittest.cc
@@ -0,0 +1,101 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/pingtask.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+class PingTaskTest;
+
+class PingXmppClient : public buzz::FakeXmppClient {
+ public:
+  PingXmppClient(rtc::TaskParent* parent, PingTaskTest* tst) :
+      FakeXmppClient(parent), test(tst) {
+  }
+
+  buzz::XmppReturnStatus SendStanza(const buzz::XmlElement* stanza);
+
+ private:
+  PingTaskTest* test;
+};
+
+class PingTaskTest : public testing::Test, public sigslot::has_slots<> {
+ public:
+  PingTaskTest() : respond_to_pings(true), timed_out(false) {
+  }
+
+  virtual void SetUp() {
+    runner = new rtc::FakeTaskRunner();
+    xmpp_client = new PingXmppClient(runner, this);
+  }
+
+  virtual void TearDown() {
+    // delete xmpp_client;  Deleted by deleting runner.
+    delete runner;
+  }
+
+  void ConnectTimeoutSignal(buzz::PingTask* task) {
+    task->SignalTimeout.connect(this, &PingTaskTest::OnPingTimeout);
+  }
+
+  void OnPingTimeout() {
+    timed_out = true;
+  }
+
+  rtc::FakeTaskRunner* runner;
+  PingXmppClient* xmpp_client;
+  bool respond_to_pings;
+  bool timed_out;
+};
+
+buzz::XmppReturnStatus PingXmppClient::SendStanza(
+    const buzz::XmlElement* stanza) {
+  buzz::XmppReturnStatus result = FakeXmppClient::SendStanza(stanza);
+  if (test->respond_to_pings && (stanza->FirstNamed(buzz::QN_PING) != NULL)) {
+    std::string ping_response =
+        "<iq xmlns=\'jabber:client\' id='0' type='result'/>";
+    HandleStanza(buzz::XmlElement::ForStr(ping_response));
+  }
+  return result;
+}
+
+TEST_F(PingTaskTest, TestSuccess) {
+  uint32 ping_period_millis = 100;
+  buzz::PingTask* task = new buzz::PingTask(xmpp_client,
+      rtc::Thread::Current(),
+      ping_period_millis, ping_period_millis / 10);
+  ConnectTimeoutSignal(task);
+  task->Start();
+  unsigned int expected_ping_count = 5U;
+  EXPECT_EQ_WAIT(xmpp_client->sent_stanzas().size(), expected_ping_count,
+                 ping_period_millis * (expected_ping_count + 1));
+  EXPECT_FALSE(task->IsDone());
+  EXPECT_FALSE(timed_out);
+}
+
+TEST_F(PingTaskTest, TestTimeout) {
+  respond_to_pings = false;
+  uint32 ping_timeout_millis = 200;
+  buzz::PingTask* task = new buzz::PingTask(xmpp_client,
+      rtc::Thread::Current(),
+      ping_timeout_millis * 10, ping_timeout_millis);
+  ConnectTimeoutSignal(task);
+  task->Start();
+  WAIT(false, ping_timeout_millis / 2);
+  EXPECT_FALSE(timed_out);
+  EXPECT_TRUE_WAIT(timed_out, ping_timeout_millis * 2);
+}
diff --git a/libjingle/xmpp/plainsaslhandler.h b/libjingle/xmpp/plainsaslhandler.h
new file mode 100644
index 0000000..aa6a791
--- /dev/null
+++ b/libjingle/xmpp/plainsaslhandler.h
@@ -0,0 +1,64 @@
+/*
+ *  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_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
+#define WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
+
+#include <algorithm>
+#include "webrtc/libjingle/xmpp/saslhandler.h"
+#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
+#include "webrtc/base/cryptstring.h"
+
+namespace buzz {
+
+class PlainSaslHandler : public SaslHandler {
+public:
+  PlainSaslHandler(const Jid & jid, const rtc::CryptString & password, 
+      bool allow_plain) : jid_(jid), password_(password), 
+                          allow_plain_(allow_plain) {}
+    
+  virtual ~PlainSaslHandler() {}
+
+  // Should pick the best method according to this handler
+  // returns the empty string if none are suitable
+  virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
+  
+    if (!encrypted && !allow_plain_) {
+      return "";
+    }
+    
+    std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN");
+    if (it == mechanisms.end()) {
+      return "";
+    }
+    else {
+      return "PLAIN";
+    }
+  }
+
+  // Creates a SaslMechanism for the given mechanism name (you own it
+  // once you get it).  If not handled, return NULL.
+  virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) {
+    if (mechanism == "PLAIN") {
+      return new SaslPlainMechanism(jid_, password_);
+    }
+    return NULL;
+  }
+  
+private:
+  Jid jid_;
+  rtc::CryptString password_;
+  bool allow_plain_;
+};
+
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
diff --git a/libjingle/xmpp/presenceouttask.cc b/libjingle/xmpp/presenceouttask.cc
new file mode 100644
index 0000000..aa19c9d
--- /dev/null
+++ b/libjingle/xmpp/presenceouttask.cc
@@ -0,0 +1,140 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <time.h>
+#include <sstream>
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/presenceouttask.h"
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "webrtc/base/stringencode.h"
+
+namespace buzz {
+
+XmppReturnStatus
+PresenceOutTask::Send(const PresenceStatus & s) {
+  if (GetState() != STATE_INIT && GetState() != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement * presence = TranslateStatus(s);
+  QueueStanza(presence);
+  delete presence;
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+PresenceOutTask::SendDirected(const Jid & j, const PresenceStatus & s) {
+  if (GetState() != STATE_INIT && GetState() != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement * presence = TranslateStatus(s);
+  presence->AddAttr(QN_TO, j.Str());
+  QueueStanza(presence);
+  delete presence;
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus PresenceOutTask::SendProbe(const Jid & jid) {
+  if (GetState() != STATE_INIT && GetState() != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement * presence = new XmlElement(QN_PRESENCE);
+  presence->AddAttr(QN_TO, jid.Str());
+  presence->AddAttr(QN_TYPE, "probe");
+
+  QueueStanza(presence);
+  delete presence;
+  return XMPP_RETURN_OK;
+}
+
+int
+PresenceOutTask::ProcessStart() {
+  const XmlElement * stanza = NextStanza();
+  if (stanza == NULL)
+    return STATE_BLOCKED;
+
+  if (SendStanza(stanza) != XMPP_RETURN_OK)
+    return STATE_ERROR;
+
+  return STATE_START;
+}
+
+XmlElement *
+PresenceOutTask::TranslateStatus(const PresenceStatus & s) {
+  XmlElement * result = new XmlElement(QN_PRESENCE);
+  if (!s.available()) {
+    result->AddAttr(QN_TYPE, STR_UNAVAILABLE);
+  }
+  else {
+    if (s.show() != PresenceStatus::SHOW_ONLINE && 
+        s.show() != PresenceStatus::SHOW_OFFLINE) {
+      result->AddElement(new XmlElement(QN_SHOW));
+      switch (s.show()) {
+        default:
+          result->AddText(STR_SHOW_AWAY, 1);
+          break;
+        case PresenceStatus::SHOW_XA:
+          result->AddText(STR_SHOW_XA, 1);
+          break;
+        case PresenceStatus::SHOW_DND:
+          result->AddText(STR_SHOW_DND, 1);
+          break;
+        case PresenceStatus::SHOW_CHAT:
+          result->AddText(STR_SHOW_CHAT, 1);
+          break;
+      }
+    }
+
+    result->AddElement(new XmlElement(QN_STATUS));
+    result->AddText(s.status(), 1);
+
+    if (!s.nick().empty()) {
+      result->AddElement(new XmlElement(QN_NICKNAME));
+      result->AddText(s.nick(), 1);
+    }
+
+    std::string pri;
+    rtc::ToString(s.priority(), &pri);
+
+    result->AddElement(new XmlElement(QN_PRIORITY));
+    result->AddText(pri, 1);
+
+    if (s.know_capabilities()) {
+      result->AddElement(new XmlElement(QN_CAPS_C, true));
+      result->AddAttr(QN_NODE, s.caps_node(), 1);
+      result->AddAttr(QN_VER, s.version(), 1);
+
+      std::string caps;
+      caps.append(s.voice_capability() ? "voice-v1" : "");
+      caps.append(s.pmuc_capability() ? " pmuc-v1" : "");
+      caps.append(s.video_capability() ? " video-v1" : "");
+      caps.append(s.camera_capability() ? " camera-v1" : "");
+
+      result->AddAttr(QN_EXT, caps, 1);
+    }
+
+    // Put the delay mark on the presence according to JEP-0091
+    {
+      result->AddElement(new XmlElement(kQnDelayX, true));
+
+      // This here is why we *love* the C runtime
+      time_t current_time_seconds;
+      time(&current_time_seconds);
+      struct tm* current_time = gmtime(&current_time_seconds);
+      char output[256];
+      strftime(output, ARRAY_SIZE(output), "%Y%m%dT%H:%M:%S", current_time);
+      result->AddAttr(kQnStamp, output, 1);
+    }
+  }
+
+  return result;
+}
+
+
+}
diff --git a/libjingle/xmpp/presenceouttask.h b/libjingle/xmpp/presenceouttask.h
new file mode 100644
index 0000000..88869df
--- /dev/null
+++ b/libjingle/xmpp/presenceouttask.h
@@ -0,0 +1,37 @@
+/*
+ *  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_LIBJINGLE_XMPP_PRESENCEOUTTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_PRESENCEOUTTASK_H_
+
+#include "webrtc/libjingle/xmpp/presencestatus.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace buzz {
+
+class PresenceOutTask : public XmppTask {
+public:
+  explicit PresenceOutTask(XmppTaskParentInterface* parent)
+      : XmppTask(parent) {}
+  virtual ~PresenceOutTask() {}
+
+  XmppReturnStatus Send(const PresenceStatus & s);
+  XmppReturnStatus SendDirected(const Jid & j, const PresenceStatus & s);
+  XmppReturnStatus SendProbe(const Jid& jid);
+
+  virtual int ProcessStart();
+private:
+  XmlElement * TranslateStatus(const PresenceStatus & s);
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PRESENCEOUTTASK_H_
diff --git a/libjingle/xmpp/presencereceivetask.cc b/libjingle/xmpp/presencereceivetask.cc
new file mode 100644
index 0000000..3ea7274
--- /dev/null
+++ b/libjingle/xmpp/presencereceivetask.cc
@@ -0,0 +1,141 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/presencereceivetask.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/stringencode.h"
+
+namespace buzz {
+
+static bool IsUtf8FirstByte(int c) {
+  return (((c)&0x80)==0) || // is single byte
+    ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
+}
+
+PresenceReceiveTask::PresenceReceiveTask(XmppTaskParentInterface* parent)
+ : XmppTask(parent, XmppEngine::HL_TYPE) {
+}
+
+PresenceReceiveTask::~PresenceReceiveTask() {
+  Stop();
+}
+
+int PresenceReceiveTask::ProcessStart() {
+  const XmlElement * stanza = NextStanza();
+  if (stanza == NULL) {
+    return STATE_BLOCKED;
+  }
+
+  Jid from(stanza->Attr(QN_FROM));
+  HandlePresence(from, stanza);
+
+  return STATE_START;
+}
+
+bool PresenceReceiveTask::HandleStanza(const XmlElement * stanza) {
+  // Verify that this is a presence stanze
+  if (stanza->Name() != QN_PRESENCE) {
+    return false; // not sure if this ever happens.
+  }
+
+  // Queue it up
+  QueueStanza(stanza);
+
+  return true;
+}
+
+void PresenceReceiveTask::HandlePresence(const Jid& from,
+                                         const XmlElement* stanza) {
+  if (stanza->Attr(QN_TYPE) == STR_ERROR) {
+    return;
+  }
+
+  PresenceStatus status;
+  DecodeStatus(from, stanza, &status);
+  PresenceUpdate(status);
+}
+
+void PresenceReceiveTask::DecodeStatus(const Jid& from,
+                                       const XmlElement* stanza,
+                                       PresenceStatus* presence_status) {
+  presence_status->set_jid(from);
+  if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
+    presence_status->set_available(false);
+  } else {
+    presence_status->set_available(true);
+    const XmlElement * status_elem = stanza->FirstNamed(QN_STATUS);
+    if (status_elem != NULL) {
+      presence_status->set_status(status_elem->BodyText());
+
+      // Truncate status messages longer than 300 bytes
+      if (presence_status->status().length() > 300) {
+        size_t len = 300;
+
+        // Be careful not to split legal utf-8 chars in half
+        while (!IsUtf8FirstByte(presence_status->status()[len]) && len > 0) {
+          len -= 1;
+        }
+        std::string truncated(presence_status->status(), 0, len);
+        presence_status->set_status(truncated);
+      }
+    }
+
+    const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
+    if (priority != NULL) {
+      int pri;
+      if (rtc::FromString(priority->BodyText(), &pri)) {
+        presence_status->set_priority(pri);
+      }
+    }
+
+    const XmlElement * show = stanza->FirstNamed(QN_SHOW);
+    if (show == NULL || show->FirstChild() == NULL) {
+      presence_status->set_show(PresenceStatus::SHOW_ONLINE);
+    } else if (show->BodyText() == "away") {
+      presence_status->set_show(PresenceStatus::SHOW_AWAY);
+    } else if (show->BodyText() == "xa") {
+      presence_status->set_show(PresenceStatus::SHOW_XA);
+    } else if (show->BodyText() == "dnd") {
+      presence_status->set_show(PresenceStatus::SHOW_DND);
+    } else if (show->BodyText() == "chat") {
+      presence_status->set_show(PresenceStatus::SHOW_CHAT);
+    } else {
+      presence_status->set_show(PresenceStatus::SHOW_ONLINE);
+    }
+
+    const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
+    if (caps != NULL) {
+      std::string node = caps->Attr(QN_NODE);
+      std::string ver = caps->Attr(QN_VER);
+      std::string exts = caps->Attr(QN_EXT);
+
+      presence_status->set_know_capabilities(true);
+      presence_status->set_caps_node(node);
+      presence_status->set_version(ver);
+    }
+
+    const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
+    if (delay != NULL) {
+      // Ideally we would parse this according to the Psuedo ISO-8601 rules
+      // that are laid out in JEP-0082:
+      // http://www.jabber.org/jeps/jep-0082.html
+      std::string stamp = delay->Attr(kQnStamp);
+      presence_status->set_sent_time(stamp);
+    }
+
+    const XmlElement* nick = stanza->FirstNamed(QN_NICKNAME);
+    if (nick) {
+      presence_status->set_nick(nick->BodyText());
+    }
+  }
+}
+
+} // namespace buzz
diff --git a/libjingle/xmpp/presencereceivetask.h b/libjingle/xmpp/presencereceivetask.h
new file mode 100644
index 0000000..20e6c79
--- /dev/null
+++ b/libjingle/xmpp/presencereceivetask.h
@@ -0,0 +1,56 @@
+/*
+ *  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 THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCERECEIVETASK_H_
+#define THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCERECEIVETASK_H_
+
+#include "webrtc/base/sigslot.h"
+
+#include "webrtc/libjingle/xmpp/presencestatus.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace buzz {
+
+// A task to receive presence status callbacks from the XMPP server.
+class PresenceReceiveTask : public XmppTask {
+ public:
+  // Arguments:
+  //   parent a reference to task interface associated withe the XMPP client.
+  explicit PresenceReceiveTask(XmppTaskParentInterface* parent);
+
+  // Shuts down the thread associated with this task.
+  virtual ~PresenceReceiveTask();
+
+  // Starts pulling queued status messages and dispatching them to the
+  // PresenceUpdate() callback.
+  virtual int ProcessStart();
+
+  // Slot for presence message callbacks
+  sigslot::signal1<const PresenceStatus&> PresenceUpdate;
+
+ protected:
+  // Called by the XMPP engine when presence stanzas are received from the
+  // server.
+  virtual bool HandleStanza(const XmlElement * stanza);
+
+ private:
+  // Handles presence stanzas by converting the data to PresenceStatus
+  // objects and passing those along to the SignalStatusUpadate() callback.
+  void HandlePresence(const Jid& from, const XmlElement * stanza);
+
+  // Extracts presence information for the presence stanza sent form the
+  // server.
+  static void DecodeStatus(const Jid& from, const XmlElement * stanza,
+                           PresenceStatus* status);
+};
+
+} // namespace buzz
+
+#endif // THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCERECEIVETASK_H_
diff --git a/libjingle/xmpp/presencestatus.cc b/libjingle/xmpp/presencestatus.cc
new file mode 100644
index 0000000..da6c64f
--- /dev/null
+++ b/libjingle/xmpp/presencestatus.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/presencestatus.h"
+
+namespace buzz {
+PresenceStatus::PresenceStatus()
+  : pri_(0),
+    show_(SHOW_NONE),
+    available_(false),
+    e_code_(0),
+    feedback_probation_(false),
+    know_capabilities_(false),
+    voice_capability_(false),
+    pmuc_capability_(false),
+    video_capability_(false),
+    camera_capability_(false) {
+}
+
+void PresenceStatus::UpdateWith(const PresenceStatus& new_value) {
+  if (!new_value.know_capabilities()) {
+    bool k = know_capabilities();
+    bool p = voice_capability();
+    std::string node = caps_node();
+    std::string v = version();
+
+    *this = new_value;
+
+    set_know_capabilities(k);
+    set_caps_node(node);
+    set_voice_capability(p);
+     set_version(v);
+  } else {
+    *this = new_value;
+  }
+}
+
+} // namespace buzz
diff --git a/libjingle/xmpp/presencestatus.h b/libjingle/xmpp/presencestatus.h
new file mode 100644
index 0000000..0261c72
--- /dev/null
+++ b/libjingle/xmpp/presencestatus.h
@@ -0,0 +1,188 @@
+/*
+ *  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 THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCESTATUS_H_
+#define THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCESTATUS_H_
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+
+namespace buzz {
+
+class PresenceStatus {
+public:
+  PresenceStatus();
+  ~PresenceStatus() {}
+
+  // These are arranged in "priority order", i.e., if we see
+  // two statuses at the same priority but with different Shows,
+  // we will show the one with the highest show in the following
+  // order.
+  enum Show {
+    SHOW_NONE     = 0,
+    SHOW_OFFLINE  = 1,
+    SHOW_XA       = 2,
+    SHOW_AWAY     = 3,
+    SHOW_DND      = 4,
+    SHOW_ONLINE   = 5,
+    SHOW_CHAT     = 6,
+  };
+
+  const Jid& jid() const { return jid_; }
+  int priority() const { return pri_; }
+  Show show() const { return show_; }
+  const std::string& status() const { return status_; }
+  const std::string& nick() const { return nick_; }
+  bool available() const { return available_ ; }
+  int error_code() const { return e_code_; }
+  const std::string& error_string() const { return e_str_; }
+  bool know_capabilities() const { return know_capabilities_; }
+  bool voice_capability() const { return voice_capability_; }
+  bool pmuc_capability() const { return pmuc_capability_; }
+  bool video_capability() const { return video_capability_; }
+  bool camera_capability() const { return camera_capability_; }
+  const std::string& caps_node() const { return caps_node_; }
+  const std::string& version() const { return version_; }
+  bool feedback_probation() const { return feedback_probation_; }
+  const std::string& sent_time() const { return sent_time_; }
+
+  void set_jid(const Jid& jid) { jid_ = jid; }
+  void set_priority(int pri) { pri_ = pri; }
+  void set_show(Show show) { show_ = show; }
+  void set_status(const std::string& status) { status_ = status; }
+  void set_nick(const std::string& nick) { nick_ = nick; }
+  void set_available(bool a) { available_ = a; }
+  void set_error(int e_code, const std::string e_str)
+      { e_code_ = e_code; e_str_ = e_str; }
+  void set_know_capabilities(bool f) { know_capabilities_ = f; }
+  void set_voice_capability(bool f) { voice_capability_ = f; }
+  void set_pmuc_capability(bool f) { pmuc_capability_ = f; }
+  void set_video_capability(bool f) { video_capability_ = f; }
+  void set_camera_capability(bool f) { camera_capability_ = f; }
+  void set_caps_node(const std::string& f) { caps_node_ = f; }
+  void set_version(const std::string& v) { version_ = v; }
+  void set_feedback_probation(bool f) { feedback_probation_ = f; }
+  void set_sent_time(const std::string& time) { sent_time_ = time; }
+
+  void UpdateWith(const PresenceStatus& new_value);
+
+  bool HasQuietStatus() const {
+    if (status_.empty())
+      return false;
+    return !(QuietStatus().empty());
+  }
+
+  // Knowledge of other clients' silly automatic status strings -
+  // Don't show these.
+  std::string QuietStatus() const {
+    if (jid_.resource().find("Psi") != std::string::npos) {
+      if (status_ == "Online" ||
+          status_.find("Auto Status") != std::string::npos)
+        return STR_EMPTY;
+    }
+    if (jid_.resource().find("Gaim") != std::string::npos) {
+      if (status_ == "Sorry, I ran out for a bit!")
+        return STR_EMPTY;
+    }
+    return TrimStatus(status_);
+  }
+
+  std::string ExplicitStatus() const {
+    std::string result = QuietStatus();
+    if (result.empty()) {
+      result = ShowStatus();
+    }
+    return result;
+  }
+
+  std::string ShowStatus() const {
+    std::string result;
+    if (!available()) {
+      result = "Offline";
+    }
+    else {
+      switch (show()) {
+        case SHOW_AWAY:
+        case SHOW_XA:
+          result = "Idle";
+          break;
+        case SHOW_DND:
+          result = "Busy";
+          break;
+        case SHOW_CHAT:
+          result = "Chatty";
+          break;
+        default:
+          result = "Available";
+          break;
+      }
+    }
+    return result;
+  }
+
+  static std::string TrimStatus(const std::string& st) {
+    std::string s(st);
+    int j = 0;
+    bool collapsing = true;
+    for (unsigned int i = 0; i < s.length(); i+= 1) {
+      if (s[i] <= ' ' && s[i] >= 0) {
+        if (collapsing) {
+          continue;
+        }
+        else {
+          s[j] = ' ';
+          j += 1;
+          collapsing = true;
+        }
+      }
+      else {
+        s[j] = s[i];
+        j += 1;
+        collapsing = false;
+      }
+    }
+    if (collapsing && j > 0) {
+      j -= 1;
+    }
+    s.erase(j, s.length());
+    return s;
+  }
+
+private:
+  Jid jid_;
+  int pri_;
+  Show show_;
+  std::string status_;
+  std::string nick_;
+  bool available_;
+  int e_code_;
+  std::string e_str_;
+  bool feedback_probation_;
+
+  // capabilities (valid only if know_capabilities_
+  bool know_capabilities_;
+  bool voice_capability_;
+  bool pmuc_capability_;
+  bool video_capability_;
+  bool camera_capability_;
+  std::string caps_node_;
+  std::string version_;
+
+  std::string sent_time_; // from the jabber:x:delay element
+};
+
+class MucPresenceStatus : public PresenceStatus {
+};
+
+} // namespace buzz
+
+
+#endif // THIRD_PARTY_LIBJINGLE_FILES_WEBRTC_LIBJINGLE_XMPP_PRESENCESTATUS_H_
+
diff --git a/libjingle/xmpp/prexmppauth.h b/libjingle/xmpp/prexmppauth.h
new file mode 100644
index 0000000..3a1e610
--- /dev/null
+++ b/libjingle/xmpp/prexmppauth.h
@@ -0,0 +1,71 @@
+/*
+ *  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_LIBJINGLE_XMPP_PREXMPPAUTH_H_
+#define WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
+
+#include "webrtc/libjingle/xmpp/saslhandler.h"
+#include "webrtc/base/cryptstring.h"
+#include "webrtc/base/sigslot.h"
+
+namespace rtc {
+  class SocketAddress;
+}
+
+namespace buzz {
+
+class Jid;
+class SaslMechanism;
+
+class CaptchaChallenge {
+ public:
+  CaptchaChallenge() : captcha_needed_(false) {}
+  CaptchaChallenge(const std::string& token, const std::string& url)
+    : captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) {
+  }
+
+  bool captcha_needed() const { return captcha_needed_; }
+  const std::string& captcha_token() const { return captcha_token_; }
+
+  // This url is relative to the gaia server.  Once we have better tools
+  // for cracking URLs, we should probably make this a full URL
+  const std::string& captcha_image_url() const { return captcha_image_url_; }
+
+ private:
+  bool captcha_needed_;
+  std::string captcha_token_;
+  std::string captcha_image_url_;
+};
+
+class PreXmppAuth : public SaslHandler {
+public:
+  virtual ~PreXmppAuth() {}
+
+  virtual void StartPreXmppAuth(
+    const Jid& jid,
+    const rtc::SocketAddress& server,
+    const rtc::CryptString& pass,
+    const std::string& auth_mechanism,
+    const std::string& auth_token) = 0;
+
+  sigslot::signal0<> SignalAuthDone;
+
+  virtual bool IsAuthDone() const = 0;
+  virtual bool IsAuthorized() const = 0;
+  virtual bool HadError() const = 0;
+  virtual int GetError() const = 0;
+  virtual CaptchaChallenge GetCaptchaChallenge() const = 0;
+  virtual std::string GetAuthMechanism() const = 0;
+  virtual std::string GetAuthToken() const = 0;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
diff --git a/libjingle/xmpp/pubsub_task.cc b/libjingle/xmpp/pubsub_task.cc
new file mode 100644
index 0000000..f30c051
--- /dev/null
+++ b/libjingle/xmpp/pubsub_task.cc
@@ -0,0 +1,200 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/pubsub_task.h"
+
+#include <map>
+#include <string>
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/common.h"
+
+namespace buzz {
+
+PubsubTask::PubsubTask(XmppTaskParentInterface* parent,
+                       const buzz::Jid& pubsub_node_jid)
+    : buzz::XmppTask(parent, buzz::XmppEngine::HL_SENDER),
+      pubsub_node_jid_(pubsub_node_jid) {
+}
+
+PubsubTask::~PubsubTask() {
+}
+
+// Checks for pubsub publish events as well as responses to get IQs.
+bool PubsubTask::HandleStanza(const buzz::XmlElement* stanza) {
+  const buzz::QName& stanza_name(stanza->Name());
+  if (stanza_name == buzz::QN_MESSAGE) {
+    if (MatchStanzaFrom(stanza, pubsub_node_jid_)) {
+      const buzz::XmlElement* pubsub_event_item =
+          stanza->FirstNamed(QN_PUBSUB_EVENT);
+      if (pubsub_event_item != NULL) {
+        QueueStanza(pubsub_event_item);
+        return true;
+      }
+    }
+  } else if (stanza_name == buzz::QN_IQ) {
+    if (MatchResponseIq(stanza, pubsub_node_jid_, task_id())) {
+      const buzz::XmlElement* pubsub_item = stanza->FirstNamed(QN_PUBSUB);
+      if (pubsub_item != NULL) {
+        QueueStanza(pubsub_item);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+int PubsubTask::ProcessResponse() {
+  const buzz::XmlElement* stanza = NextStanza();
+  if (stanza == NULL) {
+    return STATE_BLOCKED;
+  }
+
+  if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) {
+    OnPubsubError(stanza->FirstNamed(buzz::QN_ERROR));
+    return STATE_RESPONSE;
+  }
+
+  const buzz::QName& stanza_name(stanza->Name());
+  if (stanza_name == QN_PUBSUB_EVENT) {
+    HandlePubsubEventMessage(stanza);
+  } else if (stanza_name == QN_PUBSUB) {
+    HandlePubsubIqGetResponse(stanza);
+  }
+
+  return STATE_RESPONSE;
+}
+
+// Registers a function pointer to be called when the value of the pubsub
+// node changes.
+// Note that this does not actually change the XMPP pubsub
+// subscription. All publish events are always received by everyone in the
+// MUC. This function just controls whether the handle function will get
+// called when the event is received.
+bool PubsubTask::SubscribeToNode(const std::string& pubsub_node,
+                                 NodeHandler handler) {
+  subscribed_nodes_[pubsub_node] = handler;
+  rtc::scoped_ptr<buzz::XmlElement> get_iq_request(
+      MakeIq(buzz::STR_GET, pubsub_node_jid_, task_id()));
+  if (!get_iq_request) {
+    return false;
+  }
+  buzz::XmlElement* pubsub_element = new buzz::XmlElement(QN_PUBSUB, true);
+  buzz::XmlElement* items_element = new buzz::XmlElement(QN_PUBSUB_ITEMS, true);
+
+  items_element->AddAttr(buzz::QN_NODE, pubsub_node);
+  pubsub_element->AddElement(items_element);
+  get_iq_request->AddElement(pubsub_element);
+
+  if (SendStanza(get_iq_request.get()) != buzz::XMPP_RETURN_OK) {
+    return false;
+  }
+
+  return true;
+}
+
+void PubsubTask::UnsubscribeFromNode(const std::string& pubsub_node) {
+  subscribed_nodes_.erase(pubsub_node);
+}
+
+void PubsubTask::OnPubsubError(const buzz::XmlElement* error_stanza) {
+}
+
+// Checks for a pubsub event message like the following:
+//
+//  <message from="muvc-private-chat-some-id@groupchat.google.com"
+//   to="john@site.com/gcomm582B14C9">
+//    <event xmlns:"http://jabber.org/protocol/pubsub#event">
+//      <items node="node-name">
+//        <item id="some-id">
+//          <payload/>
+//        </item>
+//      </items>
+//    </event>
+//  </message>
+//
+// It also checks for retraction event messages like the following:
+//
+//  <message from="muvc-private-chat-some-id@groupchat.google.com"
+//   to="john@site.com/gcomm582B14C9">
+//    <event xmlns:"http://jabber.org/protocol/pubsub#event">
+//      <items node="node-name">
+//        <retract id="some-id"/>
+//      </items>
+//    </event>
+//  </message>
+void PubsubTask::HandlePubsubEventMessage(
+    const buzz::XmlElement* pubsub_event) {
+  ASSERT(pubsub_event->Name() == QN_PUBSUB_EVENT);
+  for (const buzz::XmlChild* child = pubsub_event->FirstChild();
+       child != NULL;
+       child = child->NextChild()) {
+    const buzz::XmlElement* child_element = child->AsElement();
+    const buzz::QName& child_name(child_element->Name());
+    if (child_name == QN_PUBSUB_EVENT_ITEMS) {
+      HandlePubsubItems(child_element);
+    }
+  }
+}
+
+// Checks for a response to an pubsub IQ get like the following:
+//
+//  <iq from="muvc-private-chat-some-id@groupchat.google.com"
+//   to="john@site.com/gcomm582B14C9"
+//   type="result">
+//    <pubsub xmlns:"http://jabber.org/protocol/pubsub">
+//      <items node="node-name">
+//        <item id="some-id">
+//          <payload/>
+//        </item>
+//      </items>
+//    </event>
+//  </message>
+void PubsubTask::HandlePubsubIqGetResponse(
+    const buzz::XmlElement* pubsub_iq_response) {
+  ASSERT(pubsub_iq_response->Name() == QN_PUBSUB);
+  for (const buzz::XmlChild* child = pubsub_iq_response->FirstChild();
+       child != NULL;
+       child = child->NextChild()) {
+    const buzz::XmlElement* child_element = child->AsElement();
+    const buzz::QName& child_name(child_element->Name());
+    if (child_name == QN_PUBSUB_ITEMS) {
+      HandlePubsubItems(child_element);
+    }
+  }
+}
+
+// Calls registered handlers in response to pubsub event or response to
+// IQ pubsub get.
+// 'items' is the child of a pubsub#event:event node or pubsub:pubsub node.
+void PubsubTask::HandlePubsubItems(const buzz::XmlElement* items) {
+  ASSERT(items->HasAttr(QN_NODE));
+  const std::string& node_name(items->Attr(QN_NODE));
+  NodeSubscriptions::iterator iter = subscribed_nodes_.find(node_name);
+  if (iter != subscribed_nodes_.end()) {
+    NodeHandler handler = iter->second;
+    const buzz::XmlElement* item = items->FirstElement();
+    while (item != NULL) {
+      const buzz::QName& item_name(item->Name());
+      if (item_name != QN_PUBSUB_EVENT_ITEM &&
+          item_name != QN_PUBSUB_EVENT_RETRACT &&
+          item_name != QN_PUBSUB_ITEM) {
+        continue;
+      }
+
+      (this->*handler)(item);
+      item = item->NextElement();
+    }
+    return;
+  }
+}
+
+}
diff --git a/libjingle/xmpp/pubsub_task.h b/libjingle/xmpp/pubsub_task.h
new file mode 100644
index 0000000..b1923a0
--- /dev/null
+++ b/libjingle/xmpp/pubsub_task.h
@@ -0,0 +1,58 @@
+/*
+ *  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_LIBJINGLE_XMPP_PUBSUB_TASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_PUBSUB_TASK_H_
+
+#include <map>
+#include <string>
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace buzz {
+
+// Base class to help write pubsub tasks.
+// In ProcessStart call SubscribeNode with namespaces of interest along with
+// NodeHandlers.
+// When pubsub notifications arrive and matches the namespace, the NodeHandlers
+// will be called back.
+class PubsubTask : public buzz::XmppTask {
+ public:
+  virtual ~PubsubTask();
+
+ protected:
+  typedef void (PubsubTask::*NodeHandler)(const buzz::XmlElement* node);
+
+  PubsubTask(XmppTaskParentInterface* parent, const buzz::Jid& pubsub_node_jid);
+
+  virtual bool HandleStanza(const buzz::XmlElement* stanza);
+  virtual int ProcessResponse();
+
+  bool SubscribeToNode(const std::string& pubsub_node, NodeHandler handler);
+  void UnsubscribeFromNode(const std::string& pubsub_node);
+
+  // Called when there is an error. Derived class can do what it needs to.
+  virtual void OnPubsubError(const buzz::XmlElement* error_stanza);
+
+ private:
+  typedef std::map<std::string, NodeHandler> NodeSubscriptions;
+
+  void HandlePubsubIqGetResponse(const buzz::XmlElement* pubsub_iq_response);
+  void HandlePubsubEventMessage(const buzz::XmlElement* pubsub_event_message);
+  void HandlePubsubItems(const buzz::XmlElement* items);
+
+  buzz::Jid pubsub_node_jid_;
+  NodeSubscriptions subscribed_nodes_;
+};
+
+}  // namespace buzz
+
+#endif // WEBRTC_LIBJINGLE_XMPP_PUBSUB_TASK_H_
diff --git a/libjingle/xmpp/pubsubclient.cc b/libjingle/xmpp/pubsubclient.cc
new file mode 100644
index 0000000..41e4e98
--- /dev/null
+++ b/libjingle/xmpp/pubsubclient.cc
@@ -0,0 +1,129 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/pubsubclient.h"
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/pubsubtasks.h"
+
+namespace buzz {
+
+void PubSubClient::RequestItems() {
+  PubSubRequestTask* request_task =
+      new PubSubRequestTask(parent_, pubsubjid_, node_);
+  request_task->SignalResult.connect(this, &PubSubClient::OnRequestResult);
+  request_task->SignalError.connect(this, &PubSubClient::OnRequestError);
+
+  PubSubReceiveTask* receive_task =
+      new PubSubReceiveTask(parent_, pubsubjid_, node_);
+  receive_task->SignalUpdate.connect(this, &PubSubClient::OnReceiveUpdate);
+
+  receive_task->Start();
+  request_task->Start();
+}
+
+void PubSubClient::PublishItem(
+    const std::string& itemid, XmlElement* payload, std::string* task_id_out) {
+  std::vector<XmlElement*> children;
+  children.push_back(payload);
+  PublishItem(itemid, children, task_id_out);
+}
+
+void PubSubClient::PublishItem(
+    const std::string& itemid, const std::vector<XmlElement*>& children,
+    std::string* task_id_out) {
+  PubSubPublishTask* publish_task =
+      new PubSubPublishTask(parent_, pubsubjid_, node_, itemid, children);
+  publish_task->SignalError.connect(this, &PubSubClient::OnPublishError);
+  publish_task->SignalResult.connect(this, &PubSubClient::OnPublishResult);
+  publish_task->Start();
+  if (task_id_out) {
+    *task_id_out = publish_task->task_id();
+  }
+}
+
+void PubSubClient::RetractItem(
+    const std::string& itemid, std::string* task_id_out) {
+  PubSubRetractTask* retract_task =
+      new PubSubRetractTask(parent_, pubsubjid_, node_, itemid);
+  retract_task->SignalError.connect(this, &PubSubClient::OnRetractError);
+  retract_task->SignalResult.connect(this, &PubSubClient::OnRetractResult);
+  retract_task->Start();
+  if (task_id_out) {
+    *task_id_out = retract_task->task_id();
+  }
+}
+
+void PubSubClient::OnRequestResult(PubSubRequestTask* task,
+                                   const std::vector<PubSubItem>& items) {
+  SignalItems(this, items);
+}
+
+void PubSubClient::OnRequestError(IqTask* task,
+                                  const XmlElement* stanza) {
+  SignalRequestError(this, stanza);
+}
+
+void PubSubClient::OnReceiveUpdate(PubSubReceiveTask* task,
+                                   const std::vector<PubSubItem>& items) {
+  SignalItems(this, items);
+}
+
+const XmlElement* GetItemFromStanza(const XmlElement* stanza) {
+  if (stanza != NULL) {
+    const XmlElement* pubsub = stanza->FirstNamed(QN_PUBSUB);
+    if (pubsub != NULL) {
+      const XmlElement* publish = pubsub->FirstNamed(QN_PUBSUB_PUBLISH);
+      if (publish != NULL) {
+        return publish->FirstNamed(QN_PUBSUB_ITEM);
+      }
+    }
+  }
+  return NULL;
+}
+
+void PubSubClient::OnPublishResult(PubSubPublishTask* task) {
+  const XmlElement* item = GetItemFromStanza(task->stanza());
+  SignalPublishResult(this, task->task_id(), item);
+}
+
+void PubSubClient::OnPublishError(IqTask* task,
+                                  const XmlElement* error_stanza) {
+  PubSubPublishTask* publish_task =
+      static_cast<PubSubPublishTask*>(task);
+  const XmlElement* item = GetItemFromStanza(publish_task->stanza());
+  SignalPublishError(this, publish_task->task_id(), item, error_stanza);
+}
+
+void PubSubClient::OnRetractResult(PubSubRetractTask* task) {
+  SignalRetractResult(this, task->task_id());
+}
+
+void PubSubClient::OnRetractError(IqTask* task,
+                                  const XmlElement* stanza) {
+  PubSubRetractTask* retract_task =
+      static_cast<PubSubRetractTask*>(task);
+  SignalRetractError(this, retract_task->task_id(), stanza);
+}
+
+
+const std::string PubSubClient::GetPublisherNickFromPubSubItem(
+    const XmlElement* item_elem) {
+  if (item_elem == NULL) {
+    return "";
+  }
+
+  return Jid(item_elem->Attr(QN_ATTR_PUBLISHER)).resource();
+}
+}  // namespace buzz
diff --git a/libjingle/xmpp/pubsubclient.h b/libjingle/xmpp/pubsubclient.h
new file mode 100644
index 0000000..3044b9d
--- /dev/null
+++ b/libjingle/xmpp/pubsubclient.h
@@ -0,0 +1,111 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_PUBSUBCLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_PUBSUBCLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/pubsubtasks.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/sigslotrepeater.h"
+#include "webrtc/base/task.h"
+
+// Easy to use clients built on top of the tasks for XEP-0060
+// (http://xmpp.org/extensions/xep-0060.html).
+
+namespace buzz {
+
+class Jid;
+class XmlElement;
+class XmppTaskParentInterface;
+
+// An easy-to-use pubsub client that handles the three tasks of
+// getting, publishing, and listening for updates.  Tied to a specific
+// pubsub jid and node.  All you have to do is RequestItems, listen
+// for SignalItems and PublishItems.
+class PubSubClient : public sigslot::has_slots<> {
+ public:
+  PubSubClient(XmppTaskParentInterface* parent,
+               const Jid& pubsubjid,
+               const std::string& node)
+    : parent_(parent),
+      pubsubjid_(pubsubjid),
+      node_(node) {}
+
+  const std::string& node() const { return node_; }
+
+  // Requests the <pubsub><items>, which will be returned via
+  // SignalItems, or SignalRequestError if there is a failure.  Should
+  // auto-subscribe.
+  void RequestItems();
+  // Fired when either <pubsub><items> are returned or when
+  // <event><items> are received.
+  sigslot::signal2<PubSubClient*,
+                   const std::vector<PubSubItem>&> SignalItems;
+  // Signal (this, error stanza)
+  sigslot::signal2<PubSubClient*,
+                   const XmlElement*> SignalRequestError;
+  // Signal (this, task_id, item, error stanza)
+  sigslot::signal4<PubSubClient*,
+                   const std::string&,
+                   const XmlElement*,
+                   const XmlElement*> SignalPublishError;
+  // Signal (this, task_id, item)
+  sigslot::signal3<PubSubClient*,
+                   const std::string&,
+                   const XmlElement*> SignalPublishResult;
+  // Signal (this, task_id, error stanza)
+  sigslot::signal3<PubSubClient*,
+                   const std::string&,
+                   const XmlElement*> SignalRetractError;
+  // Signal (this, task_id)
+  sigslot::signal2<PubSubClient*,
+                   const std::string&> SignalRetractResult;
+
+  // Publish an item.  Takes ownership of payload.
+  void PublishItem(const std::string& itemid,
+                   XmlElement* payload,
+                   std::string* task_id_out);
+  // Publish an item.  Takes ownership of children.
+  void PublishItem(const std::string& itemid,
+                   const std::vector<XmlElement*>& children,
+                   std::string* task_id_out);
+  // Retract (delete) an item.
+  void RetractItem(const std::string& itemid,
+                   std::string* task_id_out);
+
+  // Get the publisher nick if it exists from the pubsub item.
+  const std::string GetPublisherNickFromPubSubItem(const XmlElement* item_elem);
+
+ private:
+  void OnRequestError(IqTask* task,
+                      const XmlElement* stanza);
+  void OnRequestResult(PubSubRequestTask* task,
+                       const std::vector<PubSubItem>& items);
+  void OnReceiveUpdate(PubSubReceiveTask* task,
+                       const std::vector<PubSubItem>& items);
+  void OnPublishResult(PubSubPublishTask* task);
+  void OnPublishError(IqTask* task,
+                      const XmlElement* stanza);
+  void OnRetractResult(PubSubRetractTask* task);
+  void OnRetractError(IqTask* task,
+                      const XmlElement* stanza);
+
+  XmppTaskParentInterface* parent_;
+  Jid pubsubjid_;
+  std::string node_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PUBSUBCLIENT_H_
diff --git a/libjingle/xmpp/pubsubclient_unittest.cc b/libjingle/xmpp/pubsubclient_unittest.cc
new file mode 100644
index 0000000..3815ef8
--- /dev/null
+++ b/libjingle/xmpp/pubsubclient_unittest.cc
@@ -0,0 +1,278 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/pubsubclient.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+struct HandledPubSubItem {
+  std::string itemid;
+  std::string payload;
+};
+
+class TestPubSubItemsListener : public sigslot::has_slots<> {
+ public:
+  TestPubSubItemsListener() : error_count(0) {}
+
+  void OnItems(buzz::PubSubClient*,
+               const std::vector<buzz::PubSubItem>& items) {
+    for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin();
+         item != items.end(); ++item) {
+      HandledPubSubItem handled_item;
+      handled_item.itemid = item->itemid;
+      if (item->elem->FirstElement() != NULL) {
+        handled_item.payload = item->elem->FirstElement()->Str();
+      }
+      this->items.push_back(handled_item);
+    }
+  }
+
+  void OnRequestError(buzz::PubSubClient* client,
+                      const buzz::XmlElement* stanza) {
+    error_count++;
+  }
+
+  void OnPublishResult(buzz::PubSubClient* client,
+                       const std::string& task_id,
+                       const buzz::XmlElement* item) {
+    result_task_id = task_id;
+  }
+
+  void OnPublishError(buzz::PubSubClient* client,
+                      const std::string& task_id,
+                      const buzz::XmlElement* item,
+                      const buzz::XmlElement* stanza) {
+    error_count++;
+    error_task_id = task_id;
+  }
+
+  void OnRetractResult(buzz::PubSubClient* client,
+                       const std::string& task_id) {
+    result_task_id = task_id;
+  }
+
+  void OnRetractError(buzz::PubSubClient* client,
+                      const std::string& task_id,
+                      const buzz::XmlElement* stanza) {
+    error_count++;
+    error_task_id = task_id;
+  }
+
+  std::vector<HandledPubSubItem> items;
+  int error_count;
+  std::string error_task_id;
+  std::string result_task_id;
+};
+
+class PubSubClientTest : public testing::Test {
+ public:
+  PubSubClientTest() :
+      pubsubjid("room@domain.com"),
+      node("topic"),
+      itemid("key") {
+    runner.reset(new rtc::FakeTaskRunner());
+    xmpp_client = new buzz::FakeXmppClient(runner.get());
+    client.reset(new buzz::PubSubClient(xmpp_client, pubsubjid, node));
+    listener.reset(new TestPubSubItemsListener());
+    client->SignalItems.connect(
+        listener.get(), &TestPubSubItemsListener::OnItems);
+    client->SignalRequestError.connect(
+        listener.get(), &TestPubSubItemsListener::OnRequestError);
+    client->SignalPublishResult.connect(
+        listener.get(), &TestPubSubItemsListener::OnPublishResult);
+    client->SignalPublishError.connect(
+        listener.get(), &TestPubSubItemsListener::OnPublishError);
+    client->SignalRetractResult.connect(
+        listener.get(), &TestPubSubItemsListener::OnRetractResult);
+    client->SignalRetractError.connect(
+        listener.get(), &TestPubSubItemsListener::OnRetractError);
+  }
+
+  rtc::scoped_ptr<rtc::FakeTaskRunner> runner;
+  // xmpp_client deleted by deleting runner.
+  buzz::FakeXmppClient* xmpp_client;
+  rtc::scoped_ptr<buzz::PubSubClient> client;
+  rtc::scoped_ptr<TestPubSubItemsListener> listener;
+  buzz::Jid pubsubjid;
+  std::string node;
+  std::string itemid;
+};
+
+TEST_F(PubSubClientTest, TestRequest) {
+  client->RequestItems();
+
+  std::string expected_iq =
+      "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
+          "<pub:items node=\"topic\"/>"
+        "</pub:pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
+      "  <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
+      "    <items node='topic'>"
+      "      <item id='key0'>"
+      "        <value0a/>"
+      "      </item>"
+      "      <item id='key1'>"
+      "        <value1a/>"
+      "      </item>"
+      "    </items>"
+      "  </pubsub>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  ASSERT_EQ(2U, listener->items.size());
+  EXPECT_EQ("key0", listener->items[0].itemid);
+  EXPECT_EQ("<pub:value0a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
+            listener->items[0].payload);
+  EXPECT_EQ("key1", listener->items[1].itemid);
+  EXPECT_EQ("<pub:value1a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
+            listener->items[1].payload);
+
+  std::string items_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='topic'>"
+      "      <item id='key0'>"
+      "        <value0b/>"
+      "      </item>"
+      "      <item id='key1'>"
+      "        <value1b/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(items_message));
+  ASSERT_EQ(4U, listener->items.size());
+  EXPECT_EQ("key0", listener->items[2].itemid);
+  EXPECT_EQ("<eve:value0b"
+            " xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
+            listener->items[2].payload);
+  EXPECT_EQ("key1", listener->items[3].itemid);
+  EXPECT_EQ("<eve:value1b"
+            " xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
+            listener->items[3].payload);
+}
+
+TEST_F(PubSubClientTest, TestRequestError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
+      "  <error type='auth'>"
+      "    <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
+      "  </error>"
+      "</iq>";
+
+  client->RequestItems();
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->error_count);
+}
+
+TEST_F(PubSubClientTest, TestPublish) {
+  buzz::XmlElement* payload =
+      new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
+
+  std::string task_id;
+  client->PublishItem(itemid, payload, &task_id);
+
+  std::string expected_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"topic\">"
+            "<item id=\"key\">"
+              "<value/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(task_id, listener->result_task_id);
+}
+
+TEST_F(PubSubClientTest, TestPublishError) {
+  buzz::XmlElement* payload =
+      new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
+
+  std::string task_id;
+  client->PublishItem(itemid, payload, &task_id);
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
+      "  <error type='auth'>"
+      "    <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
+      "  </error>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->error_count);
+  EXPECT_EQ(task_id, listener->error_task_id);
+}
+
+TEST_F(PubSubClientTest, TestRetract) {
+  std::string task_id;
+  client->RetractItem(itemid, &task_id);
+
+  std::string expected_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<retract node=\"topic\" notify=\"true\">"
+            "<item id=\"key\"/>"
+          "</retract>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, xmpp_client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(task_id, listener->result_task_id);
+}
+
+TEST_F(PubSubClientTest, TestRetractError) {
+  std::string task_id;
+  client->RetractItem(itemid, &task_id);
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
+      "  <error type='auth'>"
+      "    <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
+      "  </error>"
+      "</iq>";
+
+  xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+  EXPECT_EQ(1, listener->error_count);
+  EXPECT_EQ(task_id, listener->error_task_id);
+}
diff --git a/libjingle/xmpp/pubsubstateclient.cc b/libjingle/xmpp/pubsubstateclient.cc
new file mode 100644
index 0000000..1fae25d
--- /dev/null
+++ b/libjingle/xmpp/pubsubstateclient.cc
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/pubsubstateclient.h"
+
+namespace buzz {
+
+std::string PublishedNickKeySerializer::GetKey(
+    const std::string& publisher_nick, const std::string& published_nick) {
+  return published_nick;
+}
+
+std::string PublisherAndPublishedNicksKeySerializer::GetKey(
+    const std::string& publisher_nick, const std::string& published_nick) {
+  return publisher_nick + ":" + published_nick;
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/pubsubstateclient.h b/libjingle/xmpp/pubsubstateclient.h
new file mode 100644
index 0000000..0c53842
--- /dev/null
+++ b/libjingle/xmpp/pubsubstateclient.h
@@ -0,0 +1,270 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/pubsubclient.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/sigslotrepeater.h"
+
+namespace buzz {
+
+// To handle retracts correctly, we need to remember certain details
+// about an item.  We could just cache the entire XML element, but
+// that would take more memory and require re-parsing.
+struct StateItemInfo {
+  std::string published_nick;
+  std::string publisher_nick;
+};
+
+// Represents a PubSub state change.  Usually, the key is the nick,
+// but not always.  It's a per-state-type thing.  Look below on how keys are
+// computed.
+template <typename C>
+struct PubSubStateChange {
+  // The nick of the user changing the state.
+  std::string publisher_nick;
+  // The nick of the user whose state is changing.
+  std::string published_nick;
+  C old_state;
+  C new_state;
+};
+
+// Knows how to handle specific states and XML.
+template <typename C>
+class PubSubStateSerializer {
+ public:
+  virtual ~PubSubStateSerializer() {}
+  virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
+  virtual void Parse(const XmlElement* state_elem, C* state_out) = 0;
+};
+
+// Knows how to create "keys" for states, which determines their
+// uniqueness.  Most states are per-nick, but block is
+// per-blocker-and-blockee.  This is independent of itemid, especially
+// in the case of presenter state.
+class PubSubStateKeySerializer {
+ public:
+  virtual ~PubSubStateKeySerializer() {}
+  virtual std::string GetKey(const std::string& publisher_nick,
+                             const std::string& published_nick) = 0;
+};
+
+class PublishedNickKeySerializer : public PubSubStateKeySerializer {
+ public:
+  virtual std::string GetKey(const std::string& publisher_nick,
+                             const std::string& published_nick);
+};
+
+class PublisherAndPublishedNicksKeySerializer
+  : public PubSubStateKeySerializer {
+ public:
+  virtual std::string GetKey(const std::string& publisher_nick,
+                             const std::string& published_nick);
+};
+
+// Adapts PubSubClient to be specifically suited for pub sub call
+// states.  Signals state changes and keeps track of keys, which are
+// normally nicks.
+template <typename C>
+class PubSubStateClient : public sigslot::has_slots<> {
+ public:
+  // Gets ownership of the serializers, but not the client.
+  PubSubStateClient(const std::string& publisher_nick,
+                    PubSubClient* client,
+                    const QName& state_name,
+                    C default_state,
+                    PubSubStateKeySerializer* key_serializer,
+                    PubSubStateSerializer<C>* state_serializer)
+      : publisher_nick_(publisher_nick),
+        client_(client),
+        state_name_(state_name),
+        default_state_(default_state) {
+    key_serializer_.reset(key_serializer);
+    state_serializer_.reset(state_serializer);
+    client_->SignalItems.connect(
+        this, &PubSubStateClient<C>::OnItems);
+    client_->SignalPublishResult.connect(
+        this, &PubSubStateClient<C>::OnPublishResult);
+    client_->SignalPublishError.connect(
+        this, &PubSubStateClient<C>::OnPublishError);
+    client_->SignalRetractResult.connect(
+        this, &PubSubStateClient<C>::OnRetractResult);
+    client_->SignalRetractError.connect(
+        this, &PubSubStateClient<C>::OnRetractError);
+  }
+
+  virtual ~PubSubStateClient() {}
+
+  virtual void Publish(const std::string& published_nick,
+                       const C& state,
+                       std::string* task_id_out) {
+    std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
+    std::string itemid = state_name_.LocalPart() + ":" + key;
+    if (StatesEqual(state, default_state_)) {
+      client_->RetractItem(itemid, task_id_out);
+    } else {
+      XmlElement* state_elem = state_serializer_->Write(state_name_, state);
+      state_elem->AddAttr(QN_NICK, published_nick);
+      client_->PublishItem(itemid, state_elem, task_id_out);
+    }
+  }
+
+  sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
+  // Signal (task_id, item).  item is NULL for retract.
+  sigslot::signal2<const std::string&,
+  const XmlElement*> SignalPublishResult;
+  // Signal (task_id, item, error stanza).  item is NULL for retract.
+  sigslot::signal3<const std::string&,
+  const XmlElement*,
+  const XmlElement*> SignalPublishError;
+
+ protected:
+  // return false if retracted item (no info or state given)
+  virtual bool ParseStateItem(const PubSubItem& item,
+                              StateItemInfo* info_out,
+                              C* state_out) {
+    const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
+    if (state_elem == NULL) {
+      return false;
+    }
+
+    info_out->publisher_nick =
+        client_->GetPublisherNickFromPubSubItem(item.elem);
+    info_out->published_nick = state_elem->Attr(QN_NICK);
+    state_serializer_->Parse(state_elem, state_out);
+    return true;
+  }
+
+  virtual bool StatesEqual(const C& state1, const C& state2) {
+    return state1 == state2;
+  }
+
+  PubSubClient* client() { return client_; }
+  const QName& state_name() { return state_name_; }
+
+ private:
+  void OnItems(PubSubClient* pub_sub_client,
+               const std::vector<PubSubItem>& items) {
+    for (std::vector<PubSubItem>::const_iterator item = items.begin();
+         item != items.end(); ++item) {
+      OnItem(*item);
+    }
+  }
+
+  void OnItem(const PubSubItem& item) {
+    const std::string& itemid = item.itemid;
+    StateItemInfo info;
+    C new_state;
+
+    bool retracted = !ParseStateItem(item, &info, &new_state);
+    if (retracted) {
+      bool known_itemid =
+          (info_by_itemid_.find(itemid) != info_by_itemid_.end());
+      if (!known_itemid) {
+        // Nothing to retract, and nothing to publish.
+        // Probably a different state type.
+        return;
+      } else {
+        info = info_by_itemid_[itemid];
+        info_by_itemid_.erase(itemid);
+        new_state = default_state_;
+      }
+    } else {
+      // TODO: Assert new key matches the known key. It
+      // shouldn't change!
+      info_by_itemid_[itemid] = info;
+    }
+
+    std::string key = key_serializer_->GetKey(
+        info.publisher_nick, info.published_nick);
+    bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
+    C old_state = has_old_state ? state_by_key_[key] : default_state_;
+    if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
+      // Nothing change, so don't bother signalling.
+      return;
+    }
+
+    if (retracted || StatesEqual(new_state, default_state_)) {
+      // We treat a default state similar to a retract.
+      state_by_key_.erase(key);
+    } else {
+      state_by_key_[key] = new_state;
+    }
+
+    PubSubStateChange<C> change;
+    if (!retracted) {
+      // Retracts do not have publisher information.
+      change.publisher_nick = info.publisher_nick;
+    }
+    change.published_nick = info.published_nick;
+    change.old_state = old_state;
+    change.new_state = new_state;
+    SignalStateChange(change);
+  }
+
+  void OnPublishResult(PubSubClient* pub_sub_client,
+                       const std::string& task_id,
+                       const XmlElement* item) {
+    SignalPublishResult(task_id, item);
+  }
+
+  void OnPublishError(PubSubClient* pub_sub_client,
+                      const std::string& task_id,
+                      const buzz::XmlElement* item,
+                      const buzz::XmlElement* stanza) {
+    SignalPublishError(task_id, item, stanza);
+  }
+
+  void OnRetractResult(PubSubClient* pub_sub_client,
+                       const std::string& task_id) {
+    // There's no point in differentiating between publish and retract
+    // errors, so we simplify by making them both signal a publish
+    // result.
+    const XmlElement* item = NULL;
+    SignalPublishResult(task_id, item);
+  }
+
+  void OnRetractError(PubSubClient* pub_sub_client,
+                      const std::string& task_id,
+                      const buzz::XmlElement* stanza) {
+    // There's no point in differentiating between publish and retract
+    // errors, so we simplify by making them both signal a publish
+    // error.
+    const XmlElement* item = NULL;
+    SignalPublishError(task_id, item, stanza);
+  }
+
+  std::string publisher_nick_;
+  PubSubClient* client_;
+  const QName state_name_;
+  C default_state_;
+  rtc::scoped_ptr<PubSubStateKeySerializer> key_serializer_;
+  rtc::scoped_ptr<PubSubStateSerializer<C> > state_serializer_;
+  // key => state
+  std::map<std::string, C> state_by_key_;
+  // itemid => StateItemInfo
+  std::map<std::string, StateItemInfo> info_by_itemid_;
+
+  DISALLOW_COPY_AND_ASSIGN(PubSubStateClient);
+};
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
diff --git a/libjingle/xmpp/pubsubtasks.cc b/libjingle/xmpp/pubsubtasks.cc
new file mode 100644
index 0000000..d653259
--- /dev/null
+++ b/libjingle/xmpp/pubsubtasks.cc
@@ -0,0 +1,204 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/pubsubtasks.h"
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/receivetask.h"
+
+// An implementation of the tasks for XEP-0060
+// (http://xmpp.org/extensions/xep-0060.html).
+
+namespace buzz {
+
+namespace {
+
+bool IsPubSubEventItemsElem(const XmlElement* stanza,
+                            const std::string& expected_node) {
+  if (stanza->Name() != QN_MESSAGE) {
+    return false;
+  }
+
+  const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT);
+  if (event_elem == NULL) {
+    return false;
+  }
+
+  const XmlElement* items_elem = event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS);
+  if (items_elem == NULL) {
+    return false;
+  }
+
+  const std::string& actual_node = items_elem->Attr(QN_NODE);
+  return (actual_node == expected_node);
+}
+
+
+// Creates <pubsub node="node"><items></pubsub>
+XmlElement* CreatePubSubItemsElem(const std::string& node) {
+  XmlElement* items_elem = new XmlElement(QN_PUBSUB_ITEMS, false);
+  items_elem->AddAttr(QN_NODE, node);
+  XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, false);
+  pubsub_elem->AddElement(items_elem);
+  return pubsub_elem;
+}
+
+// Creates <pubsub node="node"><publish><item id="itemid">payload</item>...
+// Takes ownership of payload.
+XmlElement* CreatePubSubPublishItemElem(
+    const std::string& node,
+    const std::string& itemid,
+    const std::vector<XmlElement*>& children) {
+  XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true);
+  XmlElement* publish_elem = new XmlElement(QN_PUBSUB_PUBLISH, false);
+  publish_elem->AddAttr(QN_NODE, node);
+  XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false);
+  item_elem->AddAttr(QN_ID, itemid);
+  for (std::vector<XmlElement*>::const_iterator child = children.begin();
+       child != children.end(); ++child) {
+    item_elem->AddElement(*child);
+  }
+  publish_elem->AddElement(item_elem);
+  pubsub_elem->AddElement(publish_elem);
+  return pubsub_elem;
+}
+
+// Creates <pubsub node="node"><publish><item id="itemid">payload</item>...
+// Takes ownership of payload.
+XmlElement* CreatePubSubRetractItemElem(const std::string& node,
+                                        const std::string& itemid) {
+  XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true);
+  XmlElement* retract_elem = new XmlElement(QN_PUBSUB_RETRACT, false);
+  retract_elem->AddAttr(QN_NODE, node);
+  retract_elem->AddAttr(QN_NOTIFY, "true");
+  XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false);
+  item_elem->AddAttr(QN_ID, itemid);
+  retract_elem->AddElement(item_elem);
+  pubsub_elem->AddElement(retract_elem);
+  return pubsub_elem;
+}
+
+void ParseItem(const XmlElement* item_elem,
+               std::vector<PubSubItem>* items) {
+  PubSubItem item;
+  item.itemid = item_elem->Attr(QN_ID);
+  item.elem = item_elem;
+  items->push_back(item);
+}
+
+// Right now, <retract>s are treated the same as items with empty
+// payloads.  We may want to change it in the future, but right now
+// it's sufficient for our needs.
+void ParseRetract(const XmlElement* retract_elem,
+                  std::vector<PubSubItem>* items) {
+  ParseItem(retract_elem, items);
+}
+
+void ParseEventItemsElem(const XmlElement* stanza,
+                         std::vector<PubSubItem>* items) {
+  const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT);
+  if (event_elem != NULL) {
+    const XmlElement* items_elem =
+        event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS);
+    if (items_elem != NULL) {
+      for (const XmlElement* item_elem =
+             items_elem->FirstNamed(QN_PUBSUB_EVENT_ITEM);
+           item_elem != NULL;
+           item_elem = item_elem->NextNamed(QN_PUBSUB_EVENT_ITEM)) {
+        ParseItem(item_elem, items);
+      }
+      for (const XmlElement* retract_elem =
+             items_elem->FirstNamed(QN_PUBSUB_EVENT_RETRACT);
+           retract_elem != NULL;
+           retract_elem = retract_elem->NextNamed(QN_PUBSUB_EVENT_RETRACT)) {
+        ParseRetract(retract_elem, items);
+      }
+    }
+  }
+}
+
+void ParsePubSubItemsElem(const XmlElement* stanza,
+                          std::vector<PubSubItem>* items) {
+  const XmlElement* pubsub_elem = stanza->FirstNamed(QN_PUBSUB);
+  if (pubsub_elem != NULL) {
+    const XmlElement* items_elem = pubsub_elem->FirstNamed(QN_PUBSUB_ITEMS);
+    if (items_elem != NULL) {
+      for (const XmlElement* item_elem = items_elem->FirstNamed(QN_PUBSUB_ITEM);
+           item_elem != NULL;
+           item_elem = item_elem->NextNamed(QN_PUBSUB_ITEM)) {
+        ParseItem(item_elem, items);
+      }
+    }
+  }
+}
+
+}  // namespace
+
+PubSubRequestTask::PubSubRequestTask(XmppTaskParentInterface* parent,
+                                     const Jid& pubsubjid,
+                                     const std::string& node)
+    : IqTask(parent, STR_GET, pubsubjid, CreatePubSubItemsElem(node)) {
+}
+
+void PubSubRequestTask::HandleResult(const XmlElement* stanza) {
+  std::vector<PubSubItem> items;
+  ParsePubSubItemsElem(stanza, &items);
+  SignalResult(this, items);
+}
+
+int PubSubReceiveTask::ProcessStart() {
+  if (SignalUpdate.is_empty()) {
+    return STATE_DONE;
+  }
+  return ReceiveTask::ProcessStart();
+}
+
+bool PubSubReceiveTask::WantsStanza(const XmlElement* stanza) {
+  return MatchStanzaFrom(stanza, pubsubjid_) &&
+      IsPubSubEventItemsElem(stanza, node_) && !SignalUpdate.is_empty();
+}
+
+void PubSubReceiveTask::ReceiveStanza(const XmlElement* stanza) {
+  std::vector<PubSubItem> items;
+  ParseEventItemsElem(stanza, &items);
+  SignalUpdate(this, items);
+}
+
+PubSubPublishTask::PubSubPublishTask(XmppTaskParentInterface* parent,
+                                     const Jid& pubsubjid,
+                                     const std::string& node,
+                                     const std::string& itemid,
+                                     const std::vector<XmlElement*>& children)
+    : IqTask(parent, STR_SET, pubsubjid,
+             CreatePubSubPublishItemElem(node, itemid, children)),
+      itemid_(itemid) {
+}
+
+void PubSubPublishTask::HandleResult(const XmlElement* stanza) {
+  SignalResult(this);
+}
+
+PubSubRetractTask::PubSubRetractTask(XmppTaskParentInterface* parent,
+                                     const Jid& pubsubjid,
+                                     const std::string& node,
+                                     const std::string& itemid)
+    : IqTask(parent, STR_SET, pubsubjid,
+             CreatePubSubRetractItemElem(node, itemid)),
+      itemid_(itemid) {
+}
+
+void PubSubRetractTask::HandleResult(const XmlElement* stanza) {
+  SignalResult(this);
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/pubsubtasks.h b/libjingle/xmpp/pubsubtasks.h
new file mode 100644
index 0000000..2f56fa8
--- /dev/null
+++ b/libjingle/xmpp/pubsubtasks.h
@@ -0,0 +1,114 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_PUBSUBTASKS_H_
+#define WEBRTC_LIBJINGLE_XMPP_PUBSUBTASKS_H_
+
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/iqtask.h"
+#include "webrtc/libjingle/xmpp/receivetask.h"
+#include "webrtc/base/sigslot.h"
+
+namespace buzz {
+
+// A PubSub itemid + payload.  Useful for signaling items.
+struct PubSubItem {
+  std::string itemid;
+  // The entire <item>, owned by the stanza handler.  To keep a
+  // reference after handling, make a copy.
+  const XmlElement* elem;
+};
+
+// An IqTask which gets a <pubsub><items> for a particular jid and
+// node, parses the items in the response and signals the items.
+class PubSubRequestTask : public IqTask {
+ public:
+  PubSubRequestTask(XmppTaskParentInterface* parent,
+                    const Jid& pubsubjid,
+                    const std::string& node);
+
+  sigslot::signal2<PubSubRequestTask*,
+                   const std::vector<PubSubItem>&> SignalResult;
+  // SignalError inherited by IqTask.
+ private:
+  virtual void HandleResult(const XmlElement* stanza);
+};
+
+// A ReceiveTask which listens for <event><items> of a particular
+// pubsub JID and node and then signals them items.
+class PubSubReceiveTask : public ReceiveTask {
+ public:
+  PubSubReceiveTask(XmppTaskParentInterface* parent,
+                    const Jid& pubsubjid,
+                    const std::string& node)
+      : ReceiveTask(parent),
+        pubsubjid_(pubsubjid),
+        node_(node) {
+  }
+
+  virtual int ProcessStart();
+  sigslot::signal2<PubSubReceiveTask*,
+                   const std::vector<PubSubItem>&> SignalUpdate;
+
+ protected:
+  virtual bool WantsStanza(const XmlElement* stanza);
+  virtual void ReceiveStanza(const XmlElement* stanza);
+
+ private:
+  Jid pubsubjid_;
+  std::string node_;
+};
+
+// An IqTask which publishes a <pubsub><publish><item> to a particular
+// pubsub jid and node.
+class PubSubPublishTask : public IqTask {
+ public:
+  // Takes ownership of children
+  PubSubPublishTask(XmppTaskParentInterface* parent,
+                    const Jid& pubsubjid,
+                    const std::string& node,
+                    const std::string& itemid,
+                    const std::vector<XmlElement*>& children);
+
+  const std::string& itemid() const { return itemid_; }
+
+  sigslot::signal1<PubSubPublishTask*> SignalResult;
+
+ private:
+  // SignalError inherited by IqTask.
+  virtual void HandleResult(const XmlElement* stanza);
+
+  std::string itemid_;
+};
+
+// An IqTask which publishes a <pubsub><publish><retract> to a particular
+// pubsub jid and node.
+class PubSubRetractTask : public IqTask {
+ public:
+  PubSubRetractTask(XmppTaskParentInterface* parent,
+                    const Jid& pubsubjid,
+                    const std::string& node,
+                    const std::string& itemid);
+
+  const std::string& itemid() const { return itemid_; }
+
+  sigslot::signal1<PubSubRetractTask*> SignalResult;
+
+ private:
+  // SignalError inherited by IqTask.
+  virtual void HandleResult(const XmlElement* stanza);
+
+  std::string itemid_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_PUBSUBTASKS_H_
diff --git a/libjingle/xmpp/pubsubtasks_unittest.cc b/libjingle/xmpp/pubsubtasks_unittest.cc
new file mode 100644
index 0000000..8062e58
--- /dev/null
+++ b/libjingle/xmpp/pubsubtasks_unittest.cc
@@ -0,0 +1,280 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/fakexmppclient.h"
+#include "webrtc/libjingle/xmpp/iqtask.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/pubsubtasks.h"
+#include "webrtc/base/faketaskrunner.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/sigslot.h"
+
+struct HandledPubSubItem {
+  std::string itemid;
+  std::string payload;
+};
+
+class TestPubSubTasksListener : public sigslot::has_slots<> {
+ public:
+  TestPubSubTasksListener() : result_count(0), error_count(0) {}
+
+  void OnReceiveUpdate(buzz::PubSubReceiveTask* task,
+                       const std::vector<buzz::PubSubItem>& items) {
+    OnItems(items);
+  }
+
+  void OnRequestResult(buzz::PubSubRequestTask* task,
+                       const std::vector<buzz::PubSubItem>& items) {
+    OnItems(items);
+  }
+
+  void OnItems(const std::vector<buzz::PubSubItem>& items) {
+    for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin();
+         item != items.end(); ++item) {
+      HandledPubSubItem handled_item;
+      handled_item.itemid = item->itemid;
+      if (item->elem->FirstElement() != NULL) {
+        handled_item.payload = item->elem->FirstElement()->Str();
+      }
+      this->items.push_back(handled_item);
+    }
+  }
+
+  void OnPublishResult(buzz::PubSubPublishTask* task) {
+    ++result_count;
+  }
+
+  void OnRetractResult(buzz::PubSubRetractTask* task) {
+    ++result_count;
+  }
+
+  void OnError(buzz::IqTask* task, const buzz::XmlElement* stanza) {
+    ++error_count;
+  }
+
+  std::vector<HandledPubSubItem> items;
+  int result_count;
+  int error_count;
+};
+
+class PubSubTasksTest : public testing::Test {
+ public:
+  PubSubTasksTest() :
+      pubsubjid("room@domain.com"),
+      node("topic"),
+      itemid("key") {
+    runner.reset(new rtc::FakeTaskRunner());
+    client = new buzz::FakeXmppClient(runner.get());
+    listener.reset(new TestPubSubTasksListener());
+  }
+
+  rtc::scoped_ptr<rtc::FakeTaskRunner> runner;
+  // Client deleted by deleting runner.
+  buzz::FakeXmppClient* client;
+  rtc::scoped_ptr<TestPubSubTasksListener> listener;
+  buzz::Jid pubsubjid;
+  std::string node;
+  std::string itemid;
+};
+
+TEST_F(PubSubTasksTest, TestRequest) {
+  buzz::PubSubRequestTask* task =
+      new buzz::PubSubRequestTask(client, pubsubjid, node);
+  task->SignalResult.connect(
+      listener.get(), &TestPubSubTasksListener::OnRequestResult);
+  task->Start();
+
+  std::string expected_iq =
+      "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">"
+          "<pub:items node=\"topic\"/>"
+        "</pub:pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str());
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>"
+      "  <pubsub xmlns='http://jabber.org/protocol/pubsub'>"
+      "    <items node='topic'>"
+      "      <item id='key0'>"
+      "        <value0/>"
+      "      </item>"
+      "      <item id='key1'>"
+      "        <value1/>"
+      "      </item>"
+      "    </items>"
+      "  </pubsub>"
+      "</iq>";
+
+  client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+
+  ASSERT_EQ(2U, listener->items.size());
+  EXPECT_EQ("key0", listener->items[0].itemid);
+  EXPECT_EQ("<pub:value0 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
+            listener->items[0].payload);
+  EXPECT_EQ("key1", listener->items[1].itemid);
+  EXPECT_EQ("<pub:value1 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>",
+            listener->items[1].payload);
+}
+
+TEST_F(PubSubTasksTest, TestRequestError) {
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
+      "  <error type='auth'>"
+      "    <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
+      "  </error>"
+      "</iq>";
+
+  buzz::PubSubRequestTask* task =
+      new buzz::PubSubRequestTask(client, pubsubjid, node);
+  task->SignalResult.connect(
+      listener.get(), &TestPubSubTasksListener::OnRequestResult);
+  task->SignalError.connect(
+      listener.get(), &TestPubSubTasksListener::OnError);
+  task->Start();
+  client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+
+  EXPECT_EQ(0, listener->result_count);
+  EXPECT_EQ(1, listener->error_count);
+}
+
+TEST_F(PubSubTasksTest, TestReceive) {
+  std::string items_message =
+      "<message xmlns='jabber:client' from='room@domain.com'>"
+      "  <event xmlns='http://jabber.org/protocol/pubsub#event'>"
+      "    <items node='topic'>"
+      "      <item id='key0'>"
+      "        <value0/>"
+      "      </item>"
+      "      <item id='key1'>"
+      "        <value1/>"
+      "      </item>"
+      "    </items>"
+      "  </event>"
+      "</message>";
+
+  buzz::PubSubReceiveTask* task =
+      new buzz::PubSubReceiveTask(client, pubsubjid, node);
+  task->SignalUpdate.connect(
+      listener.get(), &TestPubSubTasksListener::OnReceiveUpdate);
+  task->Start();
+  client->HandleStanza(buzz::XmlElement::ForStr(items_message));
+
+  ASSERT_EQ(2U, listener->items.size());
+  EXPECT_EQ("key0", listener->items[0].itemid);
+  EXPECT_EQ(
+      "<eve:value0 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
+      listener->items[0].payload);
+  EXPECT_EQ("key1", listener->items[1].itemid);
+  EXPECT_EQ(
+      "<eve:value1 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>",
+      listener->items[1].payload);
+}
+
+TEST_F(PubSubTasksTest, TestPublish) {
+  buzz::XmlElement* payload =
+      new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
+  std::string expected_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<publish node=\"topic\">"
+            "<item id=\"key\">"
+              "<value/>"
+            "</item>"
+          "</publish>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  std::vector<buzz::XmlElement*> children;
+  children.push_back(payload);
+  buzz::PubSubPublishTask* task =
+      new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children);
+  task->SignalResult.connect(
+      listener.get(), &TestPubSubTasksListener::OnPublishResult);
+  task->Start();
+
+  ASSERT_EQ(1U, client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str());
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
+
+  client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+
+  EXPECT_EQ(1, listener->result_count);
+  EXPECT_EQ(0, listener->error_count);
+}
+
+TEST_F(PubSubTasksTest, TestPublishError) {
+  buzz::XmlElement* payload =
+      new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value"));
+
+  std::vector<buzz::XmlElement*> children;
+  children.push_back(payload);
+  buzz::PubSubPublishTask* task =
+      new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children);
+  task->SignalResult.connect(
+      listener.get(), &TestPubSubTasksListener::OnPublishResult);
+  task->SignalError.connect(
+      listener.get(), &TestPubSubTasksListener::OnError);
+  task->Start();
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>"
+      "  <error type='auth'>"
+      "    <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
+      "  </error>"
+      "</iq>";
+
+  client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+
+  EXPECT_EQ(0, listener->result_count);
+  EXPECT_EQ(1, listener->error_count);
+}
+
+TEST_F(PubSubTasksTest, TestRetract) {
+  buzz::PubSubRetractTask* task =
+      new buzz::PubSubRetractTask(client, pubsubjid, node, itemid);
+  task->SignalResult.connect(
+      listener.get(), &TestPubSubTasksListener::OnRetractResult);
+  task->SignalError.connect(
+      listener.get(), &TestPubSubTasksListener::OnError);
+  task->Start();
+
+  std::string expected_iq =
+      "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" "
+        "xmlns:cli=\"jabber:client\">"
+        "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">"
+          "<retract node=\"topic\" notify=\"true\">"
+            "<item id=\"key\"/>"
+          "</retract>"
+        "</pubsub>"
+      "</cli:iq>";
+
+  ASSERT_EQ(1U, client->sent_stanzas().size());
+  EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str());
+
+  std::string result_iq =
+      "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>";
+
+  client->HandleStanza(buzz::XmlElement::ForStr(result_iq));
+
+  EXPECT_EQ(1, listener->result_count);
+  EXPECT_EQ(0, listener->error_count);
+}
diff --git a/libjingle/xmpp/receivetask.cc b/libjingle/xmpp/receivetask.cc
new file mode 100644
index 0000000..9d4687c
--- /dev/null
+++ b/libjingle/xmpp/receivetask.cc
@@ -0,0 +1,34 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/receivetask.h"
+
+namespace buzz {
+
+bool ReceiveTask::HandleStanza(const XmlElement* stanza) {
+  if (WantsStanza(stanza)) {
+    QueueStanza(stanza);
+    return true;
+  }
+
+  return false;
+}
+
+int ReceiveTask::ProcessStart() {
+  const XmlElement* stanza = NextStanza();
+  if (stanza == NULL)
+    return STATE_BLOCKED;
+
+  ReceiveStanza(stanza);
+  return STATE_START;
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/receivetask.h b/libjingle/xmpp/receivetask.h
new file mode 100644
index 0000000..b776746
--- /dev/null
+++ b/libjingle/xmpp/receivetask.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_LIBJINGLE_XMPP_RECEIVETASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_RECEIVETASK_H_
+
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace buzz {
+
+// A base class for receiving stanzas.  Override WantsStanza to
+// indicate that a stanza should be received and ReceiveStanza to
+// process it.  Once started, ReceiveStanza will be called for all
+// stanzas that return true when passed to WantsStanza. This saves
+// you from having to remember how to setup the queueing and the task
+// states, etc.
+class ReceiveTask : public XmppTask {
+ public:
+  explicit ReceiveTask(XmppTaskParentInterface* parent) :
+      XmppTask(parent, XmppEngine::HL_TYPE) {}
+  virtual int ProcessStart();
+
+ protected:
+  virtual bool HandleStanza(const XmlElement* stanza);
+
+  // Return true if the stanza should be received.
+  virtual bool WantsStanza(const XmlElement* stanza) = 0;
+  // Process the received stanza.
+  virtual void ReceiveStanza(const XmlElement* stanza) = 0;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_RECEIVETASK_H_
diff --git a/libjingle/xmpp/rostermodule.h b/libjingle/xmpp/rostermodule.h
new file mode 100644
index 0000000..85d5d34
--- /dev/null
+++ b/libjingle/xmpp/rostermodule.h
@@ -0,0 +1,331 @@
+/*
+ *  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_LIBJINGLE_XMPP_ROSTERMODULE_H_
+#define WEBRTC_LIBJINGLE_XMPP_ROSTERMODULE_H_
+
+#include "webrtc/libjingle/xmpp/module.h"
+
+namespace buzz {
+
+class XmppRosterModule;
+
+// The main way you initialize and use the module would be like this:
+//    XmppRosterModule *roster_module = XmppRosterModule::Create();
+//    roster_module->RegisterEngine(engine);
+//    roster_module->BroadcastPresence();
+//    roster_module->RequestRosterUpdate();
+
+//! This enum captures the valid values for the show attribute in a presence
+//! stanza
+enum XmppPresenceShow
+{
+  XMPP_PRESENCE_CHAT = 0,
+  XMPP_PRESENCE_DEFAULT = 1,
+  XMPP_PRESENCE_AWAY = 2,
+  XMPP_PRESENCE_XA = 3,
+  XMPP_PRESENCE_DND = 4,
+};
+
+//! These are the valid subscription states in a roster contact.  This
+//! represents the combination of the subscription and ask attributes
+enum XmppSubscriptionState
+{
+  XMPP_SUBSCRIPTION_NONE = 0,
+  XMPP_SUBSCRIPTION_NONE_ASKED = 1,
+  XMPP_SUBSCRIPTION_TO = 2,
+  XMPP_SUBSCRIPTION_FROM = 3,
+  XMPP_SUBSCRIPTION_FROM_ASKED = 4,
+  XMPP_SUBSCRIPTION_BOTH = 5,
+};
+
+//! These represent the valid types of presence stanzas for managing
+//! subscriptions
+enum XmppSubscriptionRequestType
+{
+  XMPP_REQUEST_SUBSCRIBE = 0,
+  XMPP_REQUEST_UNSUBSCRIBE = 1,
+  XMPP_REQUEST_SUBSCRIBED = 2,
+  XMPP_REQUEST_UNSUBSCRIBED = 3,
+};
+
+enum XmppPresenceAvailable {
+  XMPP_PRESENCE_UNAVAILABLE = 0,
+  XMPP_PRESENCE_AVAILABLE   = 1,
+  XMPP_PRESENCE_ERROR       = 2,
+};
+
+enum XmppPresenceConnectionStatus {
+  XMPP_CONNECTION_STATUS_UNKNOWN    = 0,
+  // Status set by the server while the user is being rung.
+  XMPP_CONNECTION_STATUS_CONNECTING = 1,
+  // Status set by the client when the user has accepted the ring but before
+  // the client has joined the call.
+  XMPP_CONNECTION_STATUS_JOINING    = 2,
+  // Status set by the client as part of joining the call.
+  XMPP_CONNECTION_STATUS_CONNECTED  = 3,
+  XMPP_CONNECTION_STATUS_HANGUP     = 4,
+};
+
+//! Presence Information
+//! This class stores both presence information for outgoing presence and is
+//! returned by methods in XmppRosterModule to represent recieved incoming
+//! presence information.  When this class is writeable (non-const) then each
+//! update to any property will set the inner xml.  Setting the raw_xml will
+//! rederive all of the other properties.
+class XmppPresence {
+public:
+  virtual ~XmppPresence() {}
+
+  //! Create a new Presence
+  //! This is typically only used when sending a directed presence
+  static XmppPresence* Create();
+
+  //! The Jid of for the presence information.
+  //! Typically this will be a full Jid with resource specified.
+  virtual const Jid jid() const = 0;
+
+  //! Is the contact available?
+  virtual XmppPresenceAvailable available() const = 0;
+
+  //! Sets if the user is available or not
+  virtual XmppReturnStatus set_available(XmppPresenceAvailable available) = 0;
+
+  //! The show value of the presence info
+  virtual XmppPresenceShow presence_show() const = 0;
+
+  //! Set the presence show value
+  virtual XmppReturnStatus set_presence_show(XmppPresenceShow show) = 0;
+
+  //! The Priority of the presence info
+  virtual int priority() const = 0;
+
+  //! Set the priority of the presence
+  virtual XmppReturnStatus set_priority(int priority) = 0;
+
+  //! The plain text status of the presence info.
+  //! If there are multiple status because of language, this will either be a
+  //! status that is not tagged for language or the first available
+  virtual const std::string status() const = 0;
+
+  //! Sets the status for the presence info.
+  //! If there is more than one status present already then this will remove
+  //! them all and replace it with one status element we no specified language
+  virtual XmppReturnStatus set_status(const std::string& status) = 0;
+
+  //! The connection status
+  virtual XmppPresenceConnectionStatus connection_status() const = 0;
+
+  //! The focus obfuscated GAIA id
+  virtual const std::string google_user_id() const = 0;
+
+  //! The nickname in the presence
+  virtual const std::string nickname() const = 0;
+
+  //! The raw xml of the presence update
+  virtual const XmlElement* raw_xml() const = 0;
+
+  //! Sets the raw presence stanza for the presence update
+  //! This will cause all other data items in this structure to be rederived
+  virtual XmppReturnStatus set_raw_xml(const XmlElement * xml) = 0;
+};
+
+//! A contact as given by the server
+class XmppRosterContact {
+public:
+  virtual ~XmppRosterContact() {}
+
+  //! Create a new roster contact
+  //! This is typically only used when doing a roster update/add
+  static XmppRosterContact* Create();
+
+  //! The jid for the contact.
+  //! Typically this will be a bare Jid.
+  virtual const Jid jid() const = 0;
+
+  //! Sets the jid for the roster contact update
+  virtual XmppReturnStatus set_jid(const Jid& jid) = 0;
+
+  //! The name (nickname) stored for this contact
+  virtual const std::string name() const = 0;
+
+  //! Sets the name
+  virtual XmppReturnStatus set_name(const std::string& name) = 0;
+
+  //! The Presence subscription state stored on the server for this contact
+  //! This is never settable and will be ignored when generating a roster
+  //! add/update request
+  virtual XmppSubscriptionState subscription_state() const = 0;
+
+  //! The number of Groups applied to this contact
+  virtual size_t GetGroupCount() const = 0;
+
+  //! Gets a Group applied to the contact based on index.
+  //! range
+  virtual const std::string GetGroup(size_t index) const = 0;
+
+  //! Adds a group to this contact.
+  //! This will return a bad argument error if the group is already there.
+  virtual XmppReturnStatus AddGroup(const std::string& group) = 0;
+
+  //! Removes a group from the contact.
+  //! This will return an error if the group cannot be found in the group list.
+  virtual XmppReturnStatus RemoveGroup(const std::string& group) = 0;
+
+  //! The raw xml for this roster contact
+  virtual const XmlElement* raw_xml() const = 0;
+
+  //! Sets the raw presence stanza for the contact update/add
+  //! This will cause all other data items in this structure to be rederived
+  virtual XmppReturnStatus set_raw_xml(const XmlElement * xml) = 0;
+};
+
+//! The XmppRosterHandler is an interface for callbacks from the module
+class XmppRosterHandler {
+public:
+  virtual ~XmppRosterHandler() {}
+
+  //! A request for a subscription has come in.
+  //! Typically, the UI will ask the user if it is okay to let the requester
+  //! get presence notifications for the user.  The response is send back
+  //! by calling ApproveSubscriber or CancelSubscriber.
+  virtual void SubscriptionRequest(XmppRosterModule* roster,
+                                   const Jid& requesting_jid,
+                                   XmppSubscriptionRequestType type,
+                                   const XmlElement* raw_xml) = 0;
+
+  //! Some type of presence error has occured
+  virtual void SubscriptionError(XmppRosterModule* roster,
+                                 const Jid& from,
+                                 const XmlElement* raw_xml) = 0;
+
+  virtual void RosterError(XmppRosterModule* roster,
+                           const XmlElement* raw_xml) = 0;
+
+  //! New presence information has come in
+  //! The user is notified with the presence object directly.  This info is also
+  //! added to the store accessable from the engine.
+  virtual void IncomingPresenceChanged(XmppRosterModule* roster,
+                                       const XmppPresence* presence) = 0;
+
+  //! A contact has changed
+  //! This indicates that the data for a contact may have changed.  No
+  //! contacts have been added or removed.
+  virtual void ContactChanged(XmppRosterModule* roster,
+                              const XmppRosterContact* old_contact,
+                              size_t index) = 0;
+
+  //! A set of contacts have been added
+  //! These contacts may have been added in response to the original roster
+  //! request or due to a "roster push" from the server.
+  virtual void ContactsAdded(XmppRosterModule* roster,
+                             size_t index, size_t number) = 0;
+
+  //! A contact has been removed
+  //! This contact has been removed form the list.
+  virtual void ContactRemoved(XmppRosterModule* roster,
+                              const XmppRosterContact* removed_contact,
+                              size_t index) = 0;
+
+};
+
+//! An XmppModule for handle roster and presence functionality
+class XmppRosterModule : public XmppModule {
+public:
+  //! Creates a new XmppRosterModule
+  static XmppRosterModule * Create();
+  virtual ~XmppRosterModule() {}
+
+  //! Sets the roster handler (callbacks) for the module
+  virtual XmppReturnStatus set_roster_handler(XmppRosterHandler * handler) = 0;
+
+  //! Gets the roster handler for the module
+  virtual XmppRosterHandler* roster_handler() = 0;
+
+  // USER PRESENCE STATE -------------------------------------------------------
+
+  //! Gets the aggregate outgoing presence
+  //! This object is non-const and be edited directly.  No update is sent
+  //! to the server until a Broadcast is sent
+  virtual XmppPresence* outgoing_presence() = 0;
+
+  //! Broadcasts that the user is available.
+  //! Nothing with respect to presence is sent until this is called.
+  virtual XmppReturnStatus BroadcastPresence() = 0;
+
+  //! Sends a directed presence to a Jid
+  //! Note that the client doesn't store where directed presence notifications
+  //! have been sent.  The server can keep the appropriate state
+  virtual XmppReturnStatus SendDirectedPresence(const XmppPresence* presence,
+                                                const Jid& to_jid) = 0;
+
+  // INCOMING PRESENCE STATUS --------------------------------------------------
+
+  //! Returns the number of incoming presence data recorded
+  virtual size_t GetIncomingPresenceCount() = 0;
+
+  //! Returns an incoming presence datum based on index
+  virtual const XmppPresence* GetIncomingPresence(size_t index) = 0;
+
+  //! Gets the number of presence data for a bare Jid
+  //! There may be a datum per resource
+  virtual size_t GetIncomingPresenceForJidCount(const Jid& jid) = 0;
+
+  //! Returns a single presence data for a Jid based on index
+  virtual const XmppPresence* GetIncomingPresenceForJid(const Jid& jid,
+                                                        size_t index) = 0;
+
+  // ROSTER MANAGEMENT ---------------------------------------------------------
+
+  //! Requests an update of the roster from the server
+  //! This must be called to initialize the client side cache of the roster
+  //! After this is sent the server should keep this module apprised of any
+  //! changes.
+  virtual XmppReturnStatus RequestRosterUpdate() = 0;
+
+  //! Returns the number of contacts in the roster
+  virtual size_t GetRosterContactCount() = 0;
+
+  //! Returns a contact by index
+  virtual const XmppRosterContact* GetRosterContact(size_t index) = 0;
+
+  //! Finds a contact by Jid
+  virtual const XmppRosterContact* FindRosterContact(const Jid& jid) = 0;
+
+  //! Send a request to the server to add a contact
+  //! Note that the contact won't show up in the roster until the server can
+  //! respond.  This happens async when the socket is being serviced
+  virtual XmppReturnStatus RequestRosterChange(
+    const XmppRosterContact* contact) = 0;
+
+  //! Request that the server remove a contact
+  //! The jabber protocol specifies that the server should also cancel any
+  //! subscriptions when this is done.  Like adding, this contact won't be
+  //! removed until the server responds.
+  virtual XmppReturnStatus RequestRosterRemove(const Jid& jid) = 0;
+
+  // SUBSCRIPTION MANAGEMENT ---------------------------------------------------
+
+  //! Request a subscription to presence notifications form a Jid
+  virtual XmppReturnStatus RequestSubscription(const Jid& jid) = 0;
+
+  //! Cancel a subscription to presence notifications from a Jid
+  virtual XmppReturnStatus CancelSubscription(const Jid& jid) = 0;
+
+  //! Approve a request to deliver presence notifications to a jid
+  virtual XmppReturnStatus ApproveSubscriber(const Jid& jid) = 0;
+
+  //! Deny or cancel presence notification deliver to a jid
+  virtual XmppReturnStatus CancelSubscriber(const Jid& jid) = 0;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_ROSTERMODULE_H_
diff --git a/libjingle/xmpp/rostermodule_unittest.cc b/libjingle/xmpp/rostermodule_unittest.cc
new file mode 100644
index 0000000..1ae6c22
--- /dev/null
+++ b/libjingle/xmpp/rostermodule_unittest.cc
@@ -0,0 +1,832 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/rostermodule.h"
+#include "webrtc/libjingle/xmpp/util_unittest.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/scoped_ptr.h"
+
+#define TEST_OK(x) EXPECT_EQ((x),XMPP_RETURN_OK)
+#define TEST_BADARGUMENT(x) EXPECT_EQ((x),XMPP_RETURN_BADARGUMENT)
+
+
+namespace buzz {
+
+class RosterModuleTest;
+
+static void
+WriteString(std::ostream& os, const std::string& str) {
+  os<<str;
+}
+
+static void
+WriteSubscriptionState(std::ostream& os, XmppSubscriptionState state)
+{
+  switch (state) {
+    case XMPP_SUBSCRIPTION_NONE:
+      os<<"none";
+      break;
+    case XMPP_SUBSCRIPTION_NONE_ASKED:
+      os<<"none_asked";
+      break;
+    case XMPP_SUBSCRIPTION_TO:
+      os<<"to";
+      break;
+    case XMPP_SUBSCRIPTION_FROM:
+      os<<"from";
+      break;
+    case XMPP_SUBSCRIPTION_FROM_ASKED:
+      os<<"from_asked";
+      break;
+    case XMPP_SUBSCRIPTION_BOTH:
+      os<<"both";
+      break;
+    default:
+      os<<"unknown";
+      break;
+  }
+}
+
+static void
+WriteSubscriptionRequestType(std::ostream& os,
+                             XmppSubscriptionRequestType type) {
+  switch(type) {
+    case XMPP_REQUEST_SUBSCRIBE:
+      os<<"subscribe";
+      break;
+    case XMPP_REQUEST_UNSUBSCRIBE:
+      os<<"unsubscribe";
+      break;
+    case XMPP_REQUEST_SUBSCRIBED:
+      os<<"subscribed";
+      break;
+    case XMPP_REQUEST_UNSUBSCRIBED:
+      os<<"unsubscribe";
+      break;
+    default:
+      os<<"unknown";
+      break;
+  }
+}
+
+static void
+WritePresenceShow(std::ostream& os, XmppPresenceShow show) {
+  switch(show) {
+    case XMPP_PRESENCE_AWAY:
+      os<<"away";
+      break;
+    case XMPP_PRESENCE_CHAT:
+      os<<"chat";
+      break;
+    case XMPP_PRESENCE_DND:
+      os<<"dnd";
+      break;
+    case XMPP_PRESENCE_XA:
+      os<<"xa";
+      break;
+    case XMPP_PRESENCE_DEFAULT:
+      os<<"[default]";
+      break;
+    default:
+      os<<"[unknown]";
+      break;
+  }
+}
+
+static void
+WritePresence(std::ostream& os, const XmppPresence* presence) {
+  if (presence == NULL) {
+    os<<"NULL";
+    return;
+  }
+
+  os<<"[Presence jid:";
+  WriteString(os, presence->jid().Str());
+  os<<" available:"<<presence->available();
+  os<<" presence_show:";
+  WritePresenceShow(os, presence->presence_show());
+  os<<" priority:"<<presence->priority();
+  os<<" status:";
+  WriteString(os, presence->status());
+  os<<"]"<<presence->raw_xml()->Str();
+}
+
+static void
+WriteContact(std::ostream& os, const XmppRosterContact* contact) {
+  if (contact == NULL) {
+    os<<"NULL";
+    return;
+  }
+
+  os<<"[Contact jid:";
+  WriteString(os, contact->jid().Str());
+  os<<" name:";
+  WriteString(os, contact->name());
+  os<<" subscription_state:";
+  WriteSubscriptionState(os, contact->subscription_state());
+  os<<" groups:[";
+  for(size_t i=0; i < contact->GetGroupCount(); ++i) {
+    os<<(i==0?"":", ");
+    WriteString(os, contact->GetGroup(i));
+  }
+  os<<"]]"<<contact->raw_xml()->Str();
+}
+
+//! This session handler saves all calls to a string.  These are events and
+//! data delivered form the engine to application code.
+class XmppTestRosterHandler : public XmppRosterHandler {
+public:
+  XmppTestRosterHandler() {}
+  virtual ~XmppTestRosterHandler() {}
+
+  virtual void SubscriptionRequest(XmppRosterModule*,
+                                   const Jid& requesting_jid,
+                                   XmppSubscriptionRequestType type,
+                                   const XmlElement* raw_xml) {
+    ss_<<"[SubscriptionRequest Jid:" << requesting_jid.Str()<<" type:";
+    WriteSubscriptionRequestType(ss_, type);
+    ss_<<"]"<<raw_xml->Str();
+  }
+
+  //! Some type of presence error has occured
+  virtual void SubscriptionError(XmppRosterModule*,
+                                 const Jid& from,
+                                 const XmlElement* raw_xml) {
+    ss_<<"[SubscriptionError from:"<<from.Str()<<"]"<<raw_xml->Str();
+  }
+
+  virtual void RosterError(XmppRosterModule*,
+                           const XmlElement* raw_xml) {
+    ss_<<"[RosterError]"<<raw_xml->Str();
+  }
+
+  //! New presence information has come in
+  //! The user is notified with the presence object directly.  This info is also
+  //! added to the store accessable from the engine.
+  virtual void IncomingPresenceChanged(XmppRosterModule*,
+                                       const XmppPresence* presence) {
+    ss_<<"[IncomingPresenceChanged presence:";
+    WritePresence(ss_, presence);
+    ss_<<"]";
+  }
+
+  //! A contact has changed
+  //! This indicates that the data for a contact may have changed.  No
+  //! contacts have been added or removed.
+  virtual void ContactChanged(XmppRosterModule* roster,
+                              const XmppRosterContact* old_contact,
+                              size_t index) {
+    ss_<<"[ContactChanged old_contact:";
+    WriteContact(ss_, old_contact);
+    ss_<<" index:"<<index<<" new_contact:";
+    WriteContact(ss_, roster->GetRosterContact(index));
+    ss_<<"]";
+  }
+
+  //! A set of contacts have been added
+  //! These contacts may have been added in response to the original roster
+  //! request or due to a "roster push" from the server.
+  virtual void ContactsAdded(XmppRosterModule* roster,
+                             size_t index, size_t number) {
+    ss_<<"[ContactsAdded index:"<<index<<" number:"<<number;
+    for (size_t i = 0; i < number; ++i) {
+      ss_<<" "<<(index+i)<<":";
+      WriteContact(ss_, roster->GetRosterContact(index+i));
+    }
+    ss_<<"]";
+  }
+
+  //! A contact has been removed
+  //! This contact has been removed form the list.
+  virtual void ContactRemoved(XmppRosterModule*,
+                              const XmppRosterContact* removed_contact,
+                              size_t index) {
+    ss_<<"[ContactRemoved old_contact:";
+    WriteContact(ss_, removed_contact);
+    ss_<<" index:"<<index<<"]";
+  }
+
+  std::string Str() {
+    return ss_.str();
+  }
+
+  std::string StrClear() {
+    std::string result = ss_.str();
+    ss_.str("");
+    return result;
+  }
+
+private:
+  std::stringstream ss_;
+};
+
+//! This is the class that holds all of the unit test code for the
+//! roster module
+class RosterModuleTest : public testing::Test {
+public:
+  RosterModuleTest() {}
+  static void RunLogin(RosterModuleTest* obj, XmppEngine* engine,
+                       XmppTestHandler* handler) {
+    // Needs to be similar to XmppEngineTest::RunLogin
+  }
+};
+
+TEST_F(RosterModuleTest, TestPresence) {
+  XmlElement* status = new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
+  status->AddAttr(QN_STATUS, STR_PSTN_CONFERENCE_STATUS_CONNECTING);
+  XmlElement presence_xml(QN_PRESENCE);
+  presence_xml.AddElement(status);
+  rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create());
+  presence->set_raw_xml(&presence_xml);
+  EXPECT_EQ(presence->connection_status(), XMPP_CONNECTION_STATUS_CONNECTING);
+}
+
+TEST_F(RosterModuleTest, TestOutgoingPresence) {
+  std::stringstream dump;
+
+  rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
+  XmppTestHandler handler(engine.get());
+  XmppTestRosterHandler roster_handler;
+
+  rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
+  roster->set_roster_handler(&roster_handler);
+
+  // Configure the roster module
+  roster->RegisterEngine(engine.get());
+
+  // Set up callbacks
+  engine->SetOutputHandler(&handler);
+  engine->AddStanzaHandler(&handler);
+  engine->SetSessionHandler(&handler);
+
+  // Set up minimal login info
+  engine->SetUser(Jid("david@my-server"));
+  // engine->SetPassword("david");
+
+  // Do the whole login handshake
+  RunLogin(this, engine.get(), &handler);
+  EXPECT_EQ("", handler.OutputActivity());
+
+  // Set some presence and broadcast it
+  TEST_OK(roster->outgoing_presence()->
+    set_available(XMPP_PRESENCE_AVAILABLE));
+  TEST_OK(roster->outgoing_presence()->set_priority(-37));
+  TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_DND));
+  TEST_OK(roster->outgoing_presence()->
+    set_status("I'm off to the races!<>&"));
+  TEST_OK(roster->BroadcastPresence());
+
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<presence>"
+      "<priority>-37</priority>"
+      "<show>dnd</show>"
+      "<status>I'm off to the races!&lt;&gt;&amp;</status>"
+    "</presence>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Try some more
+  TEST_OK(roster->outgoing_presence()->
+    set_available(XMPP_PRESENCE_UNAVAILABLE));
+  TEST_OK(roster->outgoing_presence()->set_priority(0));
+  TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_XA));
+  TEST_OK(roster->outgoing_presence()->set_status("Gone fishin'"));
+  TEST_OK(roster->BroadcastPresence());
+
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<presence type=\"unavailable\">"
+      "<show>xa</show>"
+      "<status>Gone fishin'</status>"
+    "</presence>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Okay -- we are back on
+  TEST_OK(roster->outgoing_presence()->
+    set_available(XMPP_PRESENCE_AVAILABLE));
+  TEST_BADARGUMENT(roster->outgoing_presence()->set_priority(128));
+  TEST_OK(roster->outgoing_presence()->
+      set_presence_show(XMPP_PRESENCE_DEFAULT));
+  TEST_OK(roster->outgoing_presence()->set_status("Cookin' wit gas"));
+  TEST_OK(roster->BroadcastPresence());
+
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<presence>"
+      "<status>Cookin' wit gas</status>"
+    "</presence>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Set it via XML
+  XmlElement presence_input(QN_PRESENCE);
+  presence_input.AddAttr(QN_TYPE, "unavailable");
+  presence_input.AddElement(new XmlElement(QN_PRIORITY));
+  presence_input.AddText("42", 1);
+  presence_input.AddElement(new XmlElement(QN_STATUS));
+  presence_input.AddAttr(QN_XML_LANG, "es", 1);
+  presence_input.AddText("Hola Amigos!", 1);
+  presence_input.AddElement(new XmlElement(QN_STATUS));
+  presence_input.AddText("Hey there, friend!", 1);
+  TEST_OK(roster->outgoing_presence()->set_raw_xml(&presence_input));
+  TEST_OK(roster->BroadcastPresence());
+
+  WritePresence(dump, roster->outgoing_presence());
+  EXPECT_EQ(dump.str(),
+    "[Presence jid: available:0 presence_show:[default] "
+              "priority:42 status:Hey there, friend!]"
+    "<cli:presence type=\"unavailable\" xmlns:cli=\"jabber:client\">"
+      "<cli:priority>42</cli:priority>"
+      "<cli:status xml:lang=\"es\">Hola Amigos!</cli:status>"
+      "<cli:status>Hey there, friend!</cli:status>"
+    "</cli:presence>");
+  dump.str("");
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<presence type=\"unavailable\">"
+      "<priority>42</priority>"
+      "<status xml:lang=\"es\">Hola Amigos!</status>"
+      "<status>Hey there, friend!</status>"
+    "</presence>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Construct a directed presence
+  rtc::scoped_ptr<XmppPresence> directed_presence(XmppPresence::Create());
+  TEST_OK(directed_presence->set_available(XMPP_PRESENCE_AVAILABLE));
+  TEST_OK(directed_presence->set_priority(120));
+  TEST_OK(directed_presence->set_status("*very* available"));
+  TEST_OK(roster->SendDirectedPresence(directed_presence.get(),
+                                       Jid("myhoney@honey.net")));
+
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<presence to=\"myhoney@honey.net\">"
+      "<priority>120</priority>"
+      "<status>*very* available</status>"
+    "</presence>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+}
+
+TEST_F(RosterModuleTest, TestIncomingPresence) {
+  rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
+  XmppTestHandler handler(engine.get());
+  XmppTestRosterHandler roster_handler;
+
+  rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
+  roster->set_roster_handler(&roster_handler);
+
+  // Configure the roster module
+  roster->RegisterEngine(engine.get());
+
+  // Set up callbacks
+  engine->SetOutputHandler(&handler);
+  engine->AddStanzaHandler(&handler);
+  engine->SetSessionHandler(&handler);
+
+  // Set up minimal login info
+  engine->SetUser(Jid("david@my-server"));
+  // engine->SetPassword("david");
+
+  // Do the whole login handshake
+  RunLogin(this, engine.get(), &handler);
+  EXPECT_EQ("", handler.OutputActivity());
+
+  // Load up with a bunch of data
+  std::string input;
+  input = "<presence from='maude@example.net/studio' "
+                    "to='david@my-server/test'/>"
+          "<presence from='walter@example.net/home' "
+                    "to='david@my-server/test'>"
+            "<priority>-10</priority>"
+            "<show>xa</show>"
+            "<status>Off bowling</status>"
+          "</presence>"
+          "<presence from='walter@example.net/alley' "
+                    "to='david@my-server/test'>"
+            "<priority>20</priority>"
+            "<status>Looking for toes...</status>"
+          "</presence>"
+          "<presence from='donny@example.net/alley' "
+                    "to='david@my-server/test'>"
+            "<priority>10</priority>"
+            "<status>Throwing rocks</status>"
+          "</presence>";
+  TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+
+  EXPECT_EQ(roster_handler.StrClear(),
+    "[IncomingPresenceChanged "
+      "presence:[Presence jid:maude@example.net/studio available:1 "
+                 "presence_show:[default] priority:0 status:]"
+        "<cli:presence from=\"maude@example.net/studio\" "
+                      "to=\"david@my-server/test\" "
+                      "xmlns:cli=\"jabber:client\"/>]"
+    "[IncomingPresenceChanged "
+      "presence:[Presence jid:walter@example.net/home available:1 "
+                 "presence_show:xa priority:-10 status:Off bowling]"
+        "<cli:presence from=\"walter@example.net/home\" "
+                      "to=\"david@my-server/test\" "
+                      "xmlns:cli=\"jabber:client\">"
+          "<cli:priority>-10</cli:priority>"
+          "<cli:show>xa</cli:show>"
+          "<cli:status>Off bowling</cli:status>"
+        "</cli:presence>]"
+    "[IncomingPresenceChanged "
+      "presence:[Presence jid:walter@example.net/alley available:1 "
+                 "presence_show:[default] "
+                 "priority:20 status:Looking for toes...]"
+        "<cli:presence from=\"walter@example.net/alley\" "
+                       "to=\"david@my-server/test\" "
+                       "xmlns:cli=\"jabber:client\">"
+          "<cli:priority>20</cli:priority>"
+          "<cli:status>Looking for toes...</cli:status>"
+        "</cli:presence>]"
+    "[IncomingPresenceChanged "
+      "presence:[Presence jid:donny@example.net/alley available:1 "
+                 "presence_show:[default] priority:10 status:Throwing rocks]"
+        "<cli:presence from=\"donny@example.net/alley\" "
+                      "to=\"david@my-server/test\" "
+                      "xmlns:cli=\"jabber:client\">"
+          "<cli:priority>10</cli:priority>"
+          "<cli:status>Throwing rocks</cli:status>"
+        "</cli:presence>]");
+  EXPECT_EQ(handler.OutputActivity(), "");
+  handler.SessionActivity(); // Ignore the session output
+
+  // Now look at the data structure we've built
+  EXPECT_EQ(roster->GetIncomingPresenceCount(), static_cast<size_t>(4));
+  EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("maude@example.net")),
+            static_cast<size_t>(1));
+  EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("walter@example.net")),
+            static_cast<size_t>(2));
+
+  const XmppPresence * presence;
+  presence = roster->GetIncomingPresenceForJid(Jid("walter@example.net"), 1);
+
+  std::stringstream dump;
+  WritePresence(dump, presence);
+  EXPECT_EQ(dump.str(),
+          "[Presence jid:walter@example.net/alley available:1 "
+            "presence_show:[default] priority:20 status:Looking for toes...]"
+              "<cli:presence from=\"walter@example.net/alley\" "
+                            "to=\"david@my-server/test\" "
+                            "xmlns:cli=\"jabber:client\">"
+                "<cli:priority>20</cli:priority>"
+                "<cli:status>Looking for toes...</cli:status>"
+              "</cli:presence>");
+  dump.str("");
+
+  // Maude took off...
+  input = "<presence from='maude@example.net/studio' "
+                    "to='david@my-server/test' "
+                    "type='unavailable'>"
+            "<status>Stealing my rug back</status>"
+            "<priority>-10</priority>"
+          "</presence>";
+  TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+
+  EXPECT_EQ(roster_handler.StrClear(),
+    "[IncomingPresenceChanged "
+      "presence:[Presence jid:maude@example.net/studio available:0 "
+                 "presence_show:[default] priority:-10 "
+                 "status:Stealing my rug back]"
+        "<cli:presence from=\"maude@example.net/studio\" "
+                      "to=\"david@my-server/test\" type=\"unavailable\" "
+                      "xmlns:cli=\"jabber:client\">"
+          "<cli:status>Stealing my rug back</cli:status>"
+          "<cli:priority>-10</cli:priority>"
+        "</cli:presence>]");
+  EXPECT_EQ(handler.OutputActivity(), "");
+  handler.SessionActivity(); // Ignore the session output
+}
+
+TEST_F(RosterModuleTest, TestPresenceSubscription) {
+  rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
+  XmppTestHandler handler(engine.get());
+  XmppTestRosterHandler roster_handler;
+
+  rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
+  roster->set_roster_handler(&roster_handler);
+
+  // Configure the roster module
+  roster->RegisterEngine(engine.get());
+
+  // Set up callbacks
+  engine->SetOutputHandler(&handler);
+  engine->AddStanzaHandler(&handler);
+  engine->SetSessionHandler(&handler);
+
+  // Set up minimal login info
+  engine->SetUser(Jid("david@my-server"));
+  // engine->SetPassword("david");
+
+  // Do the whole login handshake
+  RunLogin(this, engine.get(), &handler);
+  EXPECT_EQ("", handler.OutputActivity());
+
+  // Test incoming requests
+  std::string input;
+  input =
+    "<presence from='maude@example.net' type='subscribe'/>"
+    "<presence from='maude@example.net' type='unsubscribe'/>"
+    "<presence from='maude@example.net' type='subscribed'/>"
+    "<presence from='maude@example.net' type='unsubscribed'/>";
+  TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+
+  EXPECT_EQ(roster_handler.StrClear(),
+    "[SubscriptionRequest Jid:maude@example.net type:subscribe]"
+      "<cli:presence from=\"maude@example.net\" type=\"subscribe\" "
+                    "xmlns:cli=\"jabber:client\"/>"
+    "[SubscriptionRequest Jid:maude@example.net type:unsubscribe]"
+      "<cli:presence from=\"maude@example.net\" type=\"unsubscribe\" "
+                    "xmlns:cli=\"jabber:client\"/>"
+    "[SubscriptionRequest Jid:maude@example.net type:subscribed]"
+      "<cli:presence from=\"maude@example.net\" type=\"subscribed\" "
+                    "xmlns:cli=\"jabber:client\"/>"
+    "[SubscriptionRequest Jid:maude@example.net type:unsubscribe]"
+      "<cli:presence from=\"maude@example.net\" type=\"unsubscribed\" "
+                    "xmlns:cli=\"jabber:client\"/>");
+  EXPECT_EQ(handler.OutputActivity(), "");
+  handler.SessionActivity(); // Ignore the session output
+
+  TEST_OK(roster->RequestSubscription(Jid("maude@example.net")));
+  TEST_OK(roster->CancelSubscription(Jid("maude@example.net")));
+  TEST_OK(roster->ApproveSubscriber(Jid("maude@example.net")));
+  TEST_OK(roster->CancelSubscriber(Jid("maude@example.net")));
+
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<presence to=\"maude@example.net\" type=\"subscribe\"/>"
+    "<presence to=\"maude@example.net\" type=\"unsubscribe\"/>"
+    "<presence to=\"maude@example.net\" type=\"subscribed\"/>"
+    "<presence to=\"maude@example.net\" type=\"unsubscribed\"/>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+}
+
+TEST_F(RosterModuleTest, TestRosterReceive) {
+  rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
+  XmppTestHandler handler(engine.get());
+  XmppTestRosterHandler roster_handler;
+
+  rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create());
+  roster->set_roster_handler(&roster_handler);
+
+  // Configure the roster module
+  roster->RegisterEngine(engine.get());
+
+  // Set up callbacks
+  engine->SetOutputHandler(&handler);
+  engine->AddStanzaHandler(&handler);
+  engine->SetSessionHandler(&handler);
+
+  // Set up minimal login info
+  engine->SetUser(Jid("david@my-server"));
+  // engine->SetPassword("david");
+
+  // Do the whole login handshake
+  RunLogin(this, engine.get(), &handler);
+  EXPECT_EQ("", handler.OutputActivity());
+
+  // Request a roster update
+  TEST_OK(roster->RequestRosterUpdate());
+
+  EXPECT_EQ(roster_handler.StrClear(),"");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<iq type=\"get\" id=\"2\">"
+      "<query xmlns=\"jabber:iq:roster\"/>"
+    "</iq>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Prime the roster with a starting set
+  std::string input =
+    "<iq to='david@myserver/test' type='result' id='2'>"
+      "<query xmlns='jabber:iq:roster'>"
+        "<item jid='maude@example.net' "
+              "name='Maude Lebowski' "
+              "subscription='none' "
+              "ask='subscribe'>"
+          "<group>Business Partners</group>"
+        "</item>"
+        "<item jid='walter@example.net' "
+              "name='Walter Sobchak' "
+              "subscription='both'>"
+          "<group>Friends</group>"
+          "<group>Bowling Team</group>"
+          "<group>Bowling League</group>"
+        "</item>"
+        "<item jid='donny@example.net' "
+              "name='Donny' "
+              "subscription='both'>"
+          "<group>Friends</group>"
+          "<group>Bowling Team</group>"
+          "<group>Bowling League</group>"
+        "</item>"
+        "<item jid='jeffrey@example.net' "
+              "name='The Big Lebowski' "
+              "subscription='to'>"
+          "<group>Business Partners</group>"
+        "</item>"
+        "<item jid='jesus@example.net' "
+              "name='Jesus Quintana' "
+              "subscription='from'>"
+          "<group>Bowling League</group>"
+        "</item>"
+      "</query>"
+    "</iq>";
+
+  TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+
+  EXPECT_EQ(roster_handler.StrClear(),
+    "[ContactsAdded index:0 number:5 "
+      "0:[Contact jid:maude@example.net name:Maude Lebowski "
+                 "subscription_state:none_asked "
+                 "groups:[Business Partners]]"
+        "<ros:item jid=\"maude@example.net\" name=\"Maude Lebowski\" "
+                  "subscription=\"none\" ask=\"subscribe\" "
+                  "xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Business Partners</ros:group>"
+        "</ros:item> "
+      "1:[Contact jid:walter@example.net name:Walter Sobchak "
+                 "subscription_state:both "
+                 "groups:[Friends, Bowling Team, Bowling League]]"
+        "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" "
+                  "subscription=\"both\" "
+                  "xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Friends</ros:group>"
+          "<ros:group>Bowling Team</ros:group>"
+          "<ros:group>Bowling League</ros:group>"
+        "</ros:item> "
+      "2:[Contact jid:donny@example.net name:Donny "
+                 "subscription_state:both "
+                 "groups:[Friends, Bowling Team, Bowling League]]"
+        "<ros:item jid=\"donny@example.net\" name=\"Donny\" "
+                  "subscription=\"both\" "
+                  "xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Friends</ros:group>"
+          "<ros:group>Bowling Team</ros:group>"
+          "<ros:group>Bowling League</ros:group>"
+        "</ros:item> "
+      "3:[Contact jid:jeffrey@example.net name:The Big Lebowski "
+                 "subscription_state:to "
+                 "groups:[Business Partners]]"
+        "<ros:item jid=\"jeffrey@example.net\" name=\"The Big Lebowski\" "
+                  "subscription=\"to\" "
+                  "xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Business Partners</ros:group>"
+        "</ros:item> "
+      "4:[Contact jid:jesus@example.net name:Jesus Quintana "
+                 "subscription_state:from groups:[Bowling League]]"
+        "<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" "
+                  "subscription=\"from\" xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Bowling League</ros:group>"
+        "</ros:item>]");
+  EXPECT_EQ(handler.OutputActivity(), "");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Request that someone be added
+  rtc::scoped_ptr<XmppRosterContact> contact(XmppRosterContact::Create());
+  TEST_OK(contact->set_jid(Jid("brandt@example.net")));
+  TEST_OK(contact->set_name("Brandt"));
+  TEST_OK(contact->AddGroup("Business Partners"));
+  TEST_OK(contact->AddGroup("Watchers"));
+  TEST_OK(contact->AddGroup("Friends"));
+  TEST_OK(contact->RemoveGroup("Friends")); // Maybe not...
+  TEST_OK(roster->RequestRosterChange(contact.get()));
+
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<iq type=\"set\" id=\"3\">"
+      "<query xmlns=\"jabber:iq:roster\">"
+        "<item jid=\"brandt@example.net\" "
+              "name=\"Brandt\">"
+          "<group>Business Partners</group>"
+          "<group>Watchers</group>"
+        "</item>"
+      "</query>"
+    "</iq>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Get the push from the server
+  input =
+    "<iq type='result' to='david@my-server/test' id='3'/>"
+    "<iq type='set' id='server_1'>"
+      "<query xmlns='jabber:iq:roster'>"
+        "<item jid='brandt@example.net' "
+              "name='Brandt' "
+              "subscription='none'>"
+          "<group>Business Partners</group>"
+          "<group>Watchers</group>"
+        "</item>"
+      "</query>"
+    "</iq>";
+  TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+
+  EXPECT_EQ(roster_handler.StrClear(),
+    "[ContactsAdded index:5 number:1 "
+      "5:[Contact jid:brandt@example.net name:Brandt "
+                 "subscription_state:none "
+                 "groups:[Business Partners, Watchers]]"
+        "<ros:item jid=\"brandt@example.net\" name=\"Brandt\" "
+                  "subscription=\"none\" "
+                  "xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Business Partners</ros:group>"
+          "<ros:group>Watchers</ros:group>"
+        "</ros:item>]");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<iq type=\"result\" id=\"server_1\"/>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Get a contact update
+  input =
+    "<iq type='set' id='server_2'>"
+      "<query xmlns='jabber:iq:roster'>"
+        "<item jid='walter@example.net' "
+              "name='Walter Sobchak' "
+              "subscription='both'>"
+          "<group>Friends</group>"
+          "<group>Bowling Team</group>"
+          "<group>Bowling League</group>"
+          "<group>Not wrong, just an...</group>"
+        "</item>"
+      "</query>"
+    "</iq>";
+
+  TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+
+  EXPECT_EQ(roster_handler.StrClear(),
+    "[ContactChanged "
+      "old_contact:[Contact jid:walter@example.net name:Walter Sobchak "
+                           "subscription_state:both "
+                           "groups:[Friends, Bowling Team, Bowling League]]"
+        "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" "
+                  "subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Friends</ros:group>"
+          "<ros:group>Bowling Team</ros:group>"
+          "<ros:group>Bowling League</ros:group>"
+          "</ros:item> "
+      "index:1 "
+      "new_contact:[Contact jid:walter@example.net name:Walter Sobchak "
+                           "subscription_state:both "
+                           "groups:[Friends, Bowling Team, Bowling League, "
+                                   "Not wrong, just an...]]"
+        "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" "
+                  "subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Friends</ros:group>"
+          "<ros:group>Bowling Team</ros:group>"
+          "<ros:group>Bowling League</ros:group>"
+          "<ros:group>Not wrong, just an...</ros:group>"
+        "</ros:item>]");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<iq type=\"result\" id=\"server_2\"/>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Remove a contact
+  TEST_OK(roster->RequestRosterRemove(Jid("jesus@example.net")));
+
+  EXPECT_EQ(roster_handler.StrClear(), "");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<iq type=\"set\" id=\"4\">"
+      "<query xmlns=\"jabber:iq:roster\" jid=\"jesus@example.net\" "
+             "subscription=\"remove\"/>"
+    "</iq>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+
+  // Response from the server
+  input =
+    "<iq type='result' to='david@my-server/test' id='4'/>"
+    "<iq type='set' id='server_3'>"
+      "<query xmlns='jabber:iq:roster'>"
+        "<item jid='jesus@example.net' "
+              "subscription='remove'>"
+        "</item>"
+      "</query>"
+    "</iq>";
+  TEST_OK(engine->HandleInput(input.c_str(), input.length()));
+
+  EXPECT_EQ(roster_handler.StrClear(),
+    "[ContactRemoved "
+      "old_contact:[Contact jid:jesus@example.net name:Jesus Quintana "
+                           "subscription_state:from groups:[Bowling League]]"
+        "<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" "
+                  "subscription=\"from\" "
+                  "xmlns:ros=\"jabber:iq:roster\">"
+          "<ros:group>Bowling League</ros:group>"
+        "</ros:item> index:4]");
+  EXPECT_EQ(handler.OutputActivity(),
+    "<iq type=\"result\" id=\"server_3\"/>");
+  EXPECT_EQ(handler.SessionActivity(), "");
+}
+
+}
diff --git a/libjingle/xmpp/rostermoduleimpl.cc b/libjingle/xmpp/rostermoduleimpl.cc
new file mode 100644
index 0000000..b975289
--- /dev/null
+++ b/libjingle/xmpp/rostermoduleimpl.cc
@@ -0,0 +1,1064 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/rostermoduleimpl.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/stringencode.h"
+
+namespace buzz {
+
+// enum prase and persist helpers ----------------------------------------------
+static bool
+StringToPresenceShow(const std::string& input, XmppPresenceShow* show) {
+  // If this becomes a perf issue we can use a hash or a map here
+  if (STR_SHOW_AWAY == input)
+    *show = XMPP_PRESENCE_AWAY;
+  else if (STR_SHOW_DND == input)
+    *show = XMPP_PRESENCE_DND;
+  else if (STR_SHOW_XA == input)
+    *show = XMPP_PRESENCE_XA;
+  else if (STR_SHOW_CHAT == input)
+    *show = XMPP_PRESENCE_CHAT;
+  else if (STR_EMPTY == input)
+    *show = XMPP_PRESENCE_DEFAULT;
+  else
+    return false;
+
+  return true;
+}
+
+static bool
+PresenceShowToString(XmppPresenceShow show, const char** output) {
+  switch(show) {
+    case XMPP_PRESENCE_AWAY:
+      *output = STR_SHOW_AWAY;
+      return true;
+    case XMPP_PRESENCE_CHAT:
+      *output = STR_SHOW_CHAT;
+      return true;
+    case XMPP_PRESENCE_XA:
+      *output = STR_SHOW_XA;
+      return true;
+    case XMPP_PRESENCE_DND:
+      *output = STR_SHOW_DND;
+      return true;
+    case XMPP_PRESENCE_DEFAULT:
+      *output = STR_EMPTY;
+      return true;
+  }
+
+  *output = STR_EMPTY;
+  return false;
+}
+
+static bool
+StringToSubscriptionState(const std::string& subscription,
+                          const std::string& ask,
+                          XmppSubscriptionState* state)
+{
+  if (ask == "subscribe")
+  {
+    if (subscription == "none") {
+      *state = XMPP_SUBSCRIPTION_NONE_ASKED;
+      return true;
+    }
+    if (subscription == "from") {
+      *state = XMPP_SUBSCRIPTION_FROM_ASKED;
+      return true;
+    }
+  } else if (ask == STR_EMPTY)
+  {
+    if (subscription == "none") {
+      *state = XMPP_SUBSCRIPTION_NONE;
+      return true;
+    }
+    if (subscription == "from") {
+      *state = XMPP_SUBSCRIPTION_FROM;
+      return true;
+    }
+    if (subscription == "to") {
+      *state = XMPP_SUBSCRIPTION_TO;
+      return true;
+    }
+    if (subscription == "both") {
+      *state = XMPP_SUBSCRIPTION_BOTH;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static bool
+StringToSubscriptionRequestType(const std::string& string,
+                                XmppSubscriptionRequestType* type)
+{
+  if (string == "subscribe")
+    *type = XMPP_REQUEST_SUBSCRIBE;
+  else if (string == "unsubscribe")
+    *type = XMPP_REQUEST_UNSUBSCRIBE;
+  else if (string == "subscribed")
+    *type = XMPP_REQUEST_SUBSCRIBED;
+  else if (string == "unsubscribed")
+    *type = XMPP_REQUEST_UNSUBSCRIBED;
+  else
+    return false;
+  return true;
+}
+
+// XmppPresenceImpl class ------------------------------------------------------
+XmppPresence*
+XmppPresence::Create() {
+  return new XmppPresenceImpl();
+}
+
+XmppPresenceImpl::XmppPresenceImpl() {
+}
+
+const Jid
+XmppPresenceImpl::jid() const {
+  if (!raw_xml_)
+    return Jid();
+
+  return Jid(raw_xml_->Attr(QN_FROM));
+}
+
+XmppPresenceAvailable
+XmppPresenceImpl::available() const {
+  if (!raw_xml_)
+    return XMPP_PRESENCE_UNAVAILABLE;
+
+  if (raw_xml_->Attr(QN_TYPE) == "unavailable")
+    return XMPP_PRESENCE_UNAVAILABLE;
+  else if (raw_xml_->Attr(QN_TYPE) == "error")
+    return XMPP_PRESENCE_ERROR;
+  else
+    return XMPP_PRESENCE_AVAILABLE;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_available(XmppPresenceAvailable available) {
+  if (!raw_xml_)
+    CreateRawXmlSkeleton();
+
+  if (available == XMPP_PRESENCE_AVAILABLE)
+    raw_xml_->ClearAttr(QN_TYPE);
+  else if (available == XMPP_PRESENCE_UNAVAILABLE)
+    raw_xml_->SetAttr(QN_TYPE, "unavailable");
+  else if (available == XMPP_PRESENCE_ERROR)
+    raw_xml_->SetAttr(QN_TYPE, "error");
+  return XMPP_RETURN_OK;
+}
+
+XmppPresenceShow
+XmppPresenceImpl::presence_show() const {
+  if (!raw_xml_)
+    return XMPP_PRESENCE_DEFAULT;
+
+  XmppPresenceShow show = XMPP_PRESENCE_DEFAULT;
+  StringToPresenceShow(raw_xml_->TextNamed(QN_SHOW), &show);
+  return show;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_presence_show(XmppPresenceShow show) {
+  if (!raw_xml_)
+    CreateRawXmlSkeleton();
+
+  const char* show_string;
+
+  if(!PresenceShowToString(show, &show_string))
+    return XMPP_RETURN_BADARGUMENT;
+
+  raw_xml_->ClearNamedChildren(QN_SHOW);
+
+  if (show!=XMPP_PRESENCE_DEFAULT) {
+    raw_xml_->AddElement(new XmlElement(QN_SHOW));
+    raw_xml_->AddText(show_string, 1);
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+int
+XmppPresenceImpl::priority() const {
+  if (!raw_xml_)
+    return 0;
+
+  int raw_priority = 0;
+  if (!rtc::FromString(raw_xml_->TextNamed(QN_PRIORITY), &raw_priority))
+    raw_priority = 0;
+  if (raw_priority < -128)
+    raw_priority = -128;
+  if (raw_priority > 127)
+    raw_priority = 127;
+
+  return raw_priority;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_priority(int priority) {
+  if (!raw_xml_)
+    CreateRawXmlSkeleton();
+
+  if (priority < -128 || priority > 127)
+    return XMPP_RETURN_BADARGUMENT;
+
+  raw_xml_->ClearNamedChildren(QN_PRIORITY);
+  if (0 != priority) {
+    std::string priority_string;
+    if (rtc::ToString(priority, &priority_string)) {
+      raw_xml_->AddElement(new XmlElement(QN_PRIORITY));
+      raw_xml_->AddText(priority_string, 1);
+    }
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+const std::string
+XmppPresenceImpl::status() const {
+  if (!raw_xml_)
+    return STR_EMPTY;
+
+  XmlElement* status_element;
+  XmlElement* element;
+
+  // Search for a status element with no xml:lang attribute on it.  if we can't
+  // find that then just return the first status element in the stanza.
+  for (status_element = element = raw_xml_->FirstNamed(QN_STATUS);
+       element;
+       element = element->NextNamed(QN_STATUS)) {
+    if (!element->HasAttr(QN_XML_LANG)) {
+      status_element = element;
+      break;
+    }
+  }
+
+  if (status_element) {
+    return status_element->BodyText();
+  }
+
+  return STR_EMPTY;
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_status(const std::string& status) {
+  if (!raw_xml_)
+    CreateRawXmlSkeleton();
+
+  raw_xml_->ClearNamedChildren(QN_STATUS);
+
+  if (status != STR_EMPTY) {
+    raw_xml_->AddElement(new XmlElement(QN_STATUS));
+    raw_xml_->AddText(status, 1);
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+XmppPresenceConnectionStatus
+XmppPresenceImpl::connection_status() const {
+  if (!raw_xml_)
+      return XMPP_CONNECTION_STATUS_UNKNOWN;
+
+  XmlElement* con = raw_xml_->FirstNamed(QN_GOOGLE_PSTN_CONFERENCE_STATUS);
+  if (con) {
+    std::string status = con->Attr(QN_ATTR_STATUS);
+    if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTING)
+      return XMPP_CONNECTION_STATUS_CONNECTING;
+    else if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTED)
+      return XMPP_CONNECTION_STATUS_CONNECTED;
+    else if (status == STR_PSTN_CONFERENCE_STATUS_JOINING)
+            return XMPP_CONNECTION_STATUS_JOINING;
+    else if (status == STR_PSTN_CONFERENCE_STATUS_HANGUP)
+        return XMPP_CONNECTION_STATUS_HANGUP;
+  }
+
+  return XMPP_CONNECTION_STATUS_CONNECTED;
+}
+
+const std::string
+XmppPresenceImpl::google_user_id() const {
+  if (!raw_xml_)
+    return std::string();
+
+  XmlElement* muc_user_x = raw_xml_->FirstNamed(QN_MUC_USER_X);
+  if (muc_user_x) {
+    XmlElement* muc_user_item = muc_user_x->FirstNamed(QN_MUC_USER_ITEM);
+    if (muc_user_item) {
+      return muc_user_item->Attr(QN_GOOGLE_USER_ID);
+    }
+  }
+
+  return std::string();
+}
+
+const std::string
+XmppPresenceImpl::nickname() const {
+  if (!raw_xml_)
+    return std::string();
+
+  XmlElement* nickname = raw_xml_->FirstNamed(QN_NICKNAME);
+  if (nickname) {
+    return nickname->BodyText();
+  }
+
+  return std::string();
+}
+
+const XmlElement*
+XmppPresenceImpl::raw_xml() const {
+  if (!raw_xml_)
+    const_cast<XmppPresenceImpl*>(this)->CreateRawXmlSkeleton();
+  return raw_xml_.get();
+}
+
+XmppReturnStatus
+XmppPresenceImpl::set_raw_xml(const XmlElement * xml) {
+  if (!xml ||
+      xml->Name() != QN_PRESENCE)
+    return XMPP_RETURN_BADARGUMENT;
+
+  raw_xml_.reset(new XmlElement(*xml));
+  return XMPP_RETURN_OK;
+}
+
+void
+XmppPresenceImpl::CreateRawXmlSkeleton() {
+  raw_xml_.reset(new XmlElement(QN_PRESENCE));
+}
+
+// XmppRosterContactImpl -------------------------------------------------------
+XmppRosterContact*
+XmppRosterContact::Create() {
+  return new XmppRosterContactImpl();
+}
+
+XmppRosterContactImpl::XmppRosterContactImpl() {
+  ResetGroupCache();
+}
+
+void
+XmppRosterContactImpl::SetXmlFromWire(const XmlElement* xml) {
+  ResetGroupCache();
+  if (xml)
+    raw_xml_.reset(new XmlElement(*xml));
+  else
+    raw_xml_.reset(NULL);
+}
+
+void
+XmppRosterContactImpl::ResetGroupCache() {
+  group_count_ = -1;
+  group_index_returned_ = -1;
+  group_returned_ = NULL;
+}
+
+const Jid
+XmppRosterContactImpl::jid() const {
+  return Jid(raw_xml_->Attr(QN_JID));
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::set_jid(const Jid& jid)
+{
+  if (!raw_xml_)
+    CreateRawXmlSkeleton();
+
+  if (!jid.IsValid())
+    return XMPP_RETURN_BADARGUMENT;
+
+  raw_xml_->SetAttr(QN_JID, jid.Str());
+
+  return XMPP_RETURN_OK;
+}
+
+const std::string
+XmppRosterContactImpl::name() const {
+  return raw_xml_->Attr(QN_NAME);
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::set_name(const std::string& name) {
+  if (!raw_xml_)
+    CreateRawXmlSkeleton();
+
+  if (name == STR_EMPTY)
+    raw_xml_->ClearAttr(QN_NAME);
+  else
+    raw_xml_->SetAttr(QN_NAME, name);
+
+  return XMPP_RETURN_OK;
+}
+
+XmppSubscriptionState
+XmppRosterContactImpl::subscription_state() const {
+  if (!raw_xml_)
+    return XMPP_SUBSCRIPTION_NONE;
+
+  XmppSubscriptionState state = XMPP_SUBSCRIPTION_NONE;
+
+  if (StringToSubscriptionState(raw_xml_->Attr(QN_SUBSCRIPTION),
+                                raw_xml_->Attr(QN_ASK),
+                                &state))
+    return state;
+
+  return XMPP_SUBSCRIPTION_NONE;
+}
+
+size_t
+XmppRosterContactImpl::GetGroupCount() const {
+  if (!raw_xml_)
+    return 0;
+
+  if (-1 == group_count_) {
+    XmlElement *group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
+    int group_count = 0;
+    while(group_element) {
+      group_count++;
+      group_element = group_element->NextNamed(QN_ROSTER_GROUP);
+    }
+
+    ASSERT(group_count > 0); // protect the cast
+    XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
+    me->group_count_ = group_count;
+  }
+
+  return group_count_;
+}
+
+const std::string
+XmppRosterContactImpl::GetGroup(size_t index) const {
+  if (index >= GetGroupCount())
+    return STR_EMPTY;
+
+  // We cache the last group index and element that we returned.  This way
+  // going through the groups in order is order n and not n^2.  This could be
+  // enhanced if necessary by starting at the cached value if the index asked
+  // is after the cached one.
+  if (group_index_returned_ >= 0 &&
+      index == static_cast<size_t>(group_index_returned_) + 1)
+  {
+    XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
+    me->group_returned_ = group_returned_->NextNamed(QN_ROSTER_GROUP);
+    ASSERT(group_returned_ != NULL);
+    me->group_index_returned_++;
+  } else if (group_index_returned_ < 0 ||
+             static_cast<size_t>(group_index_returned_) != index) {
+    XmlElement * group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP);
+    size_t group_index = 0;
+    while(group_index < index) {
+      ASSERT(group_element != NULL);
+      group_index++;
+      group_element = group_element->NextNamed(QN_ROSTER_GROUP);
+    }
+
+    XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this);
+    me->group_index_returned_ = static_cast<int>(group_index);
+    me->group_returned_ = group_element;
+  }
+
+  return group_returned_->BodyText();
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::AddGroup(const std::string& group) {
+  if (group == STR_EMPTY)
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!raw_xml_)
+    CreateRawXmlSkeleton();
+
+  if (FindGroup(group, NULL, NULL))
+    return XMPP_RETURN_OK;
+
+  raw_xml_->AddElement(new XmlElement(QN_ROSTER_GROUP));
+  raw_xml_->AddText(group, 1);
+  ++group_count_;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::RemoveGroup(const std::string& group) {
+  if (group == STR_EMPTY)
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!raw_xml_)
+    return XMPP_RETURN_OK;
+
+  XmlChild * child_before;
+  if (FindGroup(group, NULL, &child_before)) {
+    raw_xml_->RemoveChildAfter(child_before);
+    ResetGroupCache();
+  }
+  return XMPP_RETURN_OK;
+}
+
+bool
+XmppRosterContactImpl::FindGroup(const std::string& group,
+                                 XmlElement** element,
+                                 XmlChild** child_before) {
+  XmlChild * prev_child = NULL;
+  XmlChild * next_child;
+  XmlChild * child;
+  for (child = raw_xml_->FirstChild(); child; child = next_child) {
+    next_child = child->NextChild();
+    if (!child->IsText() &&
+        child->AsElement()->Name() == QN_ROSTER_GROUP &&
+        child->AsElement()->BodyText() == group) {
+      if (element)
+        *element = child->AsElement();
+      if (child_before)
+        *child_before = prev_child;
+      return true;
+    }
+    prev_child = child;
+  }
+
+  return false;
+}
+
+const XmlElement*
+XmppRosterContactImpl::raw_xml() const {
+  if (!raw_xml_)
+    const_cast<XmppRosterContactImpl*>(this)->CreateRawXmlSkeleton();
+  return raw_xml_.get();
+}
+
+XmppReturnStatus
+XmppRosterContactImpl::set_raw_xml(const XmlElement* xml) {
+  if (!xml ||
+      xml->Name() != QN_ROSTER_ITEM ||
+      xml->HasAttr(QN_SUBSCRIPTION) ||
+      xml->HasAttr(QN_ASK))
+    return XMPP_RETURN_BADARGUMENT;
+
+  ResetGroupCache();
+
+  raw_xml_.reset(new XmlElement(*xml));
+
+  return XMPP_RETURN_OK;
+}
+
+void
+XmppRosterContactImpl::CreateRawXmlSkeleton() {
+  raw_xml_.reset(new XmlElement(QN_ROSTER_ITEM));
+}
+
+// XmppRosterModuleImpl --------------------------------------------------------
+XmppRosterModule *
+XmppRosterModule::Create() {
+  return new XmppRosterModuleImpl();
+}
+
+XmppRosterModuleImpl::XmppRosterModuleImpl() :
+  roster_handler_(NULL),
+  incoming_presence_map_(new JidPresenceVectorMap()),
+  incoming_presence_vector_(new PresenceVector()),
+  contacts_(new ContactVector()) {
+
+}
+
+XmppRosterModuleImpl::~XmppRosterModuleImpl() {
+  DeleteIncomingPresence();
+  DeleteContacts();
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::set_roster_handler(XmppRosterHandler * handler) {
+  roster_handler_ = handler;
+  return XMPP_RETURN_OK;
+}
+
+XmppRosterHandler*
+XmppRosterModuleImpl::roster_handler() {
+  return roster_handler_;
+}
+
+XmppPresence*
+XmppRosterModuleImpl::outgoing_presence() {
+  return &outgoing_presence_;
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::BroadcastPresence() {
+  // Scrub the outgoing presence
+  const XmlElement* element = outgoing_presence_.raw_xml();
+
+  ASSERT(!element->HasAttr(QN_TO) &&
+         !element->HasAttr(QN_FROM) &&
+          (element->Attr(QN_TYPE) == STR_EMPTY ||
+           element->Attr(QN_TYPE) == "unavailable"));
+
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  return engine()->SendStanza(element);
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::SendDirectedPresence(const XmppPresence* presence,
+                                           const Jid& to_jid) {
+  if (!presence)
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement element(*(presence->raw_xml()));
+
+  if (element.Name() != QN_PRESENCE ||
+      element.HasAttr(QN_TO) ||
+      element.HasAttr(QN_FROM))
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (element.HasAttr(QN_TYPE)) {
+    if (element.Attr(QN_TYPE) != STR_EMPTY &&
+        element.Attr(QN_TYPE) != "unavailable") {
+      return XMPP_RETURN_BADARGUMENT;
+    }
+  }
+
+  element.SetAttr(QN_TO, to_jid.Str());
+
+  return engine()->SendStanza(&element);
+}
+
+size_t
+XmppRosterModuleImpl::GetIncomingPresenceCount() {
+  return incoming_presence_vector_->size();
+}
+
+const XmppPresence*
+XmppRosterModuleImpl::GetIncomingPresence(size_t index) {
+  if (index >= incoming_presence_vector_->size())
+    return NULL;
+  return (*incoming_presence_vector_)[index];
+}
+
+size_t
+XmppRosterModuleImpl::GetIncomingPresenceForJidCount(const Jid& jid)
+{
+  // find the vector in the map
+  JidPresenceVectorMap::iterator pos;
+  pos = incoming_presence_map_->find(jid);
+  if (pos == incoming_presence_map_->end())
+    return 0;
+
+  ASSERT(pos->second != NULL);
+
+  return pos->second->size();
+}
+
+const XmppPresence*
+XmppRosterModuleImpl::GetIncomingPresenceForJid(const Jid& jid,
+                                                size_t index) {
+  JidPresenceVectorMap::iterator pos;
+  pos = incoming_presence_map_->find(jid);
+  if (pos == incoming_presence_map_->end())
+    return NULL;
+
+  ASSERT(pos->second != NULL);
+
+  if (index >= pos->second->size())
+    return NULL;
+
+  return (*pos->second)[index];
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestRosterUpdate() {
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement roster_get(QN_IQ);
+  roster_get.AddAttr(QN_TYPE, "get");
+  roster_get.AddAttr(QN_ID, engine()->NextId());
+  roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+  return engine()->SendIq(&roster_get, this, NULL);
+}
+
+size_t
+XmppRosterModuleImpl::GetRosterContactCount() {
+  return contacts_->size();
+}
+
+const XmppRosterContact*
+XmppRosterModuleImpl::GetRosterContact(size_t index) {
+  if (index >= contacts_->size())
+    return NULL;
+  return (*contacts_)[index];
+}
+
+class RosterPredicate {
+public:
+  explicit RosterPredicate(const Jid& jid) : jid_(jid) {
+  }
+
+  bool operator() (XmppRosterContactImpl *& contact) {
+    return contact->jid() == jid_;
+  }
+
+private:
+  Jid jid_;
+};
+
+const XmppRosterContact*
+XmppRosterModuleImpl::FindRosterContact(const Jid& jid) {
+  ContactVector::iterator pos;
+
+  pos = std::find_if(contacts_->begin(),
+                     contacts_->end(),
+                     RosterPredicate(jid));
+  if (pos == contacts_->end())
+    return NULL;
+
+  return *pos;
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestRosterChange(
+  const XmppRosterContact* contact) {
+  if (!contact)
+    return XMPP_RETURN_BADARGUMENT;
+
+  Jid jid = contact->jid();
+
+  if (!jid.IsValid())
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  const XmlElement* contact_xml = contact->raw_xml();
+  if (contact_xml->Name() != QN_ROSTER_ITEM ||
+      contact_xml->HasAttr(QN_SUBSCRIPTION) ||
+      contact_xml->HasAttr(QN_ASK))
+    return XMPP_RETURN_BADARGUMENT;
+
+  XmlElement roster_add(QN_IQ);
+  roster_add.AddAttr(QN_TYPE, "set");
+  roster_add.AddAttr(QN_ID, engine()->NextId());
+  roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+  roster_add.AddElement(new XmlElement(*contact_xml), 1);
+
+  return engine()->SendIq(&roster_add, this, NULL);
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestRosterRemove(const Jid& jid) {
+  if (!jid.IsValid())
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement roster_add(QN_IQ);
+  roster_add.AddAttr(QN_TYPE, "set");
+  roster_add.AddAttr(QN_ID, engine()->NextId());
+  roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+  roster_add.AddAttr(QN_JID, jid.Str(), 1);
+  roster_add.AddAttr(QN_SUBSCRIPTION, "remove", 1);
+
+  return engine()->SendIq(&roster_add, this, NULL);
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::RequestSubscription(const Jid& jid) {
+  return SendSubscriptionRequest(jid, "subscribe");
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::CancelSubscription(const Jid& jid) {
+  return SendSubscriptionRequest(jid, "unsubscribe");
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::ApproveSubscriber(const Jid& jid) {
+  return SendSubscriptionRequest(jid, "subscribed");
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::CancelSubscriber(const Jid& jid) {
+  return SendSubscriptionRequest(jid, "unsubscribed");
+}
+
+void
+XmppRosterModuleImpl::IqResponse(XmppIqCookie, const XmlElement * stanza) {
+  // The only real Iq response that we expect to recieve are initial roster
+  // population
+  if (stanza->Attr(QN_TYPE) == "error")
+  {
+    if (roster_handler_)
+      roster_handler_->RosterError(this, stanza);
+
+    return;
+  }
+
+  ASSERT(stanza->Attr(QN_TYPE) == "result");
+
+  InternalRosterItems(stanza);
+}
+
+bool
+XmppRosterModuleImpl::HandleStanza(const XmlElement * stanza)
+{
+  ASSERT(engine() != NULL);
+
+  // There are two types of stanzas that we care about: presence and roster push
+  // Iqs
+  if (stanza->Name() == QN_PRESENCE) {
+    const std::string&  jid_string = stanza->Attr(QN_FROM);
+    Jid jid(jid_string);
+
+    if (!jid.IsValid())
+      return false; // if the Jid isn't valid, don't process
+
+    const std::string& type = stanza->Attr(QN_TYPE);
+    XmppSubscriptionRequestType request_type;
+    if (StringToSubscriptionRequestType(type, &request_type))
+      InternalSubscriptionRequest(jid, stanza, request_type);
+    else if (type == "unavailable" || type == STR_EMPTY)
+      InternalIncomingPresence(jid, stanza);
+    else if (type == "error")
+      InternalIncomingPresenceError(jid, stanza);
+    else
+      return false;
+
+    return true;
+  } else if (stanza->Name() == QN_IQ) {
+    const XmlElement * roster_query = stanza->FirstNamed(QN_ROSTER_QUERY);
+    if (!roster_query || stanza->Attr(QN_TYPE) != "set")
+      return false;
+
+    InternalRosterItems(stanza);
+
+    // respond to the IQ
+    XmlElement result(QN_IQ);
+    result.AddAttr(QN_TYPE, "result");
+    result.AddAttr(QN_TO, stanza->Attr(QN_FROM));
+    result.AddAttr(QN_ID, stanza->Attr(QN_ID));
+
+    engine()->SendStanza(&result);
+    return true;
+  }
+
+  return false;
+}
+
+void
+XmppRosterModuleImpl::DeleteIncomingPresence() {
+  // Clear out the vector of all presence notifications
+  {
+    PresenceVector::iterator pos;
+    for (pos = incoming_presence_vector_->begin();
+         pos < incoming_presence_vector_->end();
+         ++pos) {
+      XmppPresenceImpl * presence = *pos;
+      *pos = NULL;
+      delete presence;
+    }
+    incoming_presence_vector_->clear();
+  }
+
+  // Clear out all of the small presence vectors per Jid
+  {
+    JidPresenceVectorMap::iterator pos;
+    for (pos = incoming_presence_map_->begin();
+         pos != incoming_presence_map_->end();
+         ++pos) {
+      PresenceVector* presence_vector = pos->second;
+      pos->second = NULL;
+      delete presence_vector;
+    }
+    incoming_presence_map_->clear();
+  }
+}
+
+void
+XmppRosterModuleImpl::DeleteContacts() {
+  ContactVector::iterator pos;
+  for (pos = contacts_->begin();
+       pos < contacts_->end();
+       ++pos) {
+    XmppRosterContact* contact = *pos;
+    *pos = NULL;
+    delete contact;
+  }
+  contacts_->clear();
+}
+
+XmppReturnStatus
+XmppRosterModuleImpl::SendSubscriptionRequest(const Jid& jid,
+                                              const std::string& type) {
+  if (!jid.IsValid())
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!engine())
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement presence_request(QN_PRESENCE);
+  presence_request.AddAttr(QN_TO, jid.Str());
+  presence_request.AddAttr(QN_TYPE, type);
+
+  return engine()->SendStanza(&presence_request);
+}
+
+
+void
+XmppRosterModuleImpl::InternalSubscriptionRequest(const Jid& jid,
+                                                  const XmlElement* stanza,
+                                                  XmppSubscriptionRequestType
+                                                    request_type) {
+  if (roster_handler_)
+    roster_handler_->SubscriptionRequest(this, jid, request_type, stanza);
+}
+
+class PresencePredicate {
+public:
+  explicit PresencePredicate(const Jid& jid) : jid_(jid) {
+  }
+
+  bool operator() (XmppPresenceImpl *& contact) {
+    return contact->jid() == jid_;
+  }
+
+private:
+  Jid jid_;
+};
+
+void
+XmppRosterModuleImpl::InternalIncomingPresence(const Jid& jid,
+                                               const XmlElement* stanza) {
+  bool added = false;
+  Jid bare_jid = jid.BareJid();
+
+  // First add the presence to the map
+  JidPresenceVectorMap::iterator pos;
+  pos = incoming_presence_map_->find(jid.BareJid());
+  if (pos == incoming_presence_map_->end()) {
+    // Insert a new entry into the map.  Get the position of this new entry
+    pos = (incoming_presence_map_->insert(
+            std::make_pair(bare_jid, new PresenceVector()))).first;
+  }
+
+  PresenceVector * presence_vector = pos->second;
+  ASSERT(presence_vector != NULL);
+
+  // Try to find this jid in the bare jid bucket
+  PresenceVector::iterator presence_pos;
+  XmppPresenceImpl* presence;
+  presence_pos = std::find_if(presence_vector->begin(),
+                              presence_vector->end(),
+                              PresencePredicate(jid));
+
+  // Update/add it to the bucket
+  if (presence_pos == presence_vector->end()) {
+    presence = new XmppPresenceImpl();
+    if (XMPP_RETURN_OK == presence->set_raw_xml(stanza)) {
+      added = true;
+      presence_vector->push_back(presence);
+    } else {
+      delete presence;
+      presence = NULL;
+    }
+  } else {
+    presence = *presence_pos;
+    presence->set_raw_xml(stanza);
+  }
+
+  // now add to the comprehensive vector
+  if (added)
+    incoming_presence_vector_->push_back(presence);
+
+  // Call back to the user with the changed presence information
+  if (roster_handler_)
+    roster_handler_->IncomingPresenceChanged(this, presence);
+}
+
+
+void
+XmppRosterModuleImpl::InternalIncomingPresenceError(const Jid& jid,
+                                                    const XmlElement* stanza) {
+  if (roster_handler_)
+    roster_handler_->SubscriptionError(this, jid, stanza);
+}
+
+void
+XmppRosterModuleImpl::InternalRosterItems(const XmlElement* stanza) {
+  const XmlElement* result_data = stanza->FirstNamed(QN_ROSTER_QUERY);
+  if (!result_data)
+    return; // unknown stuff in result!
+
+  bool all_new = contacts_->empty();
+
+  for (const XmlElement* roster_item = result_data->FirstNamed(QN_ROSTER_ITEM);
+       roster_item;
+       roster_item = roster_item->NextNamed(QN_ROSTER_ITEM))
+  {
+    const std::string& jid_string = roster_item->Attr(QN_JID);
+    Jid jid(jid_string);
+    if (!jid.IsValid())
+      continue;
+
+    // This algorithm is N^2 on the number of incoming contacts after the
+    // initial load. There is no way to do this faster without allowing
+    // duplicates, introducing more data structures or write a custom data
+    // structure.  We'll see if this becomes a perf problem and fix it if it
+    // does.
+    ContactVector::iterator pos = contacts_->end();
+
+    if (!all_new) {
+      pos = std::find_if(contacts_->begin(),
+                         contacts_->end(),
+                         RosterPredicate(jid));
+    }
+
+    if (pos != contacts_->end()) { // Update/remove a current contact
+      if (roster_item->Attr(QN_SUBSCRIPTION) == "remove") {
+        XmppRosterContact* contact = *pos;
+        contacts_->erase(pos);
+        if (roster_handler_)
+          roster_handler_->ContactRemoved(this, contact,
+            std::distance(contacts_->begin(), pos));
+        delete contact;
+      } else {
+        XmppRosterContact* old_contact = *pos;
+        *pos = new XmppRosterContactImpl();
+        (*pos)->SetXmlFromWire(roster_item);
+        if (roster_handler_)
+          roster_handler_->ContactChanged(this, old_contact,
+            std::distance(contacts_->begin(), pos));
+        delete old_contact;
+      }
+    } else { // Add a new contact
+      XmppRosterContactImpl* contact = new XmppRosterContactImpl();
+      contact->SetXmlFromWire(roster_item);
+      contacts_->push_back(contact);
+      if (roster_handler_ && !all_new)
+        roster_handler_->ContactsAdded(this, contacts_->size() - 1, 1);
+    }
+  }
+
+  // Send a consolidated update if all contacts are new
+  if (roster_handler_ && all_new)
+    roster_handler_->ContactsAdded(this, 0, contacts_->size());
+}
+
+}
diff --git a/libjingle/xmpp/rostermoduleimpl.h b/libjingle/xmpp/rostermoduleimpl.h
new file mode 100644
index 0000000..6e3bd91
--- /dev/null
+++ b/libjingle/xmpp/rostermoduleimpl.h
@@ -0,0 +1,285 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPTHREAD_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPTHREAD_H_
+
+#include "webrtc/libjingle/xmpp/moduleimpl.h"
+#include "webrtc/libjingle/xmpp/rostermodule.h"
+
+namespace buzz {
+
+//! Presence Information
+//! This class stores both presence information for outgoing presence and is
+//! returned by methods in XmppRosterModule to represent received incoming
+//! presence information.  When this class is writeable (non-const) then each
+//! update to any property will set the inner xml.  Setting the raw_xml will
+//! rederive all of the other properties.
+class XmppPresenceImpl : public XmppPresence {
+public:
+  virtual ~XmppPresenceImpl() {}
+
+  //! The from Jid of for the presence information.
+  //! Typically this will be a full Jid with resource specified.  For outgoing
+  //! presence this should remain JID_NULL and will be scrubbed from the
+  //! stanza when being sent.
+  virtual const Jid jid() const;
+
+  //! Is the contact available?
+  virtual XmppPresenceAvailable available() const;
+
+  //! Sets if the user is available or not
+  virtual XmppReturnStatus set_available(XmppPresenceAvailable available);
+
+  //! The show value of the presence info
+  virtual XmppPresenceShow presence_show() const;
+
+  //! Set the presence show value
+  virtual XmppReturnStatus set_presence_show(XmppPresenceShow show);
+
+  //! The Priority of the presence info
+  virtual int priority() const;
+
+  //! Set the priority of the presence
+  virtual XmppReturnStatus set_priority(int priority);
+
+  //! The plain text status of the presence info.
+  //! If there are multiple status because of language, this will either be a
+  //! status that is not tagged for language or the first available
+  virtual const std::string status() const;
+
+  //! Sets the status for the presence info.
+  //! If there is more than one status present already then this will remove
+  //! them all and replace it with one status element we no specified language
+  virtual XmppReturnStatus set_status(const std::string& status);
+
+  //! The connection status
+  virtual XmppPresenceConnectionStatus connection_status() const;
+
+  //! The focus obfuscated GAIA id
+  virtual const std::string google_user_id() const;
+
+  //! The nickname in the presence
+  virtual const std::string nickname() const;
+
+  //! The raw xml of the presence update
+  virtual const XmlElement* raw_xml() const;
+
+  //! Sets the raw presence stanza for the presence update
+  //! This will cause all other data items in this structure to be rederived
+  virtual XmppReturnStatus set_raw_xml(const XmlElement * xml);
+
+private:
+  XmppPresenceImpl();
+
+  friend class XmppPresence;
+  friend class XmppRosterModuleImpl;
+
+  void CreateRawXmlSkeleton();
+
+  // Store everything in the XML element. If this becomes a perf issue we can
+  // cache the data.
+  rtc::scoped_ptr<XmlElement> raw_xml_;
+};
+
+//! A contact as given by the server
+class XmppRosterContactImpl : public XmppRosterContact {
+public:
+  virtual ~XmppRosterContactImpl() {}
+
+  //! The jid for the contact.
+  //! Typically this will be a bare Jid.
+  virtual const Jid jid() const;
+
+  //! Sets the jid for the roster contact update
+  virtual XmppReturnStatus set_jid(const Jid& jid);
+
+  //! The name (nickname) stored for this contact
+  virtual const std::string name() const;
+
+  //! Sets the name
+  virtual XmppReturnStatus set_name(const std::string& name);
+
+  //! The Presence subscription state stored on the server for this contact
+  //! This is never settable and will be ignored when generating a roster
+  //! add/update request
+  virtual XmppSubscriptionState subscription_state() const;
+
+  //! The number of Groups applied to this contact
+  virtual size_t GetGroupCount() const;
+
+  //! Gets a Group applied to the contact based on index.
+  virtual const std::string GetGroup(size_t index) const;
+
+  //! Adds a group to this contact.
+  //! This will return a no error if the group is already present.
+  virtual XmppReturnStatus AddGroup(const std::string& group);
+
+  //! Removes a group from the contact.
+  //! This will return no error if the group isn't there
+  virtual XmppReturnStatus RemoveGroup(const std::string& group);
+
+  //! The raw xml for this roster contact
+  virtual const XmlElement* raw_xml() const;
+
+  //! Sets the raw presence stanza for the presence update
+  //! This will cause all other data items in this structure to be rederived
+  virtual XmppReturnStatus set_raw_xml(const XmlElement * xml);
+
+private:
+  XmppRosterContactImpl();
+
+  void CreateRawXmlSkeleton();
+  void SetXmlFromWire(const XmlElement * xml);
+  void ResetGroupCache();
+
+  bool FindGroup(const std::string& group,
+                 XmlElement** element,
+                 XmlChild** child_before);
+
+
+  friend class XmppRosterContact;
+  friend class XmppRosterModuleImpl;
+
+  int group_count_;
+  int group_index_returned_;
+  XmlElement * group_returned_;
+  rtc::scoped_ptr<XmlElement> raw_xml_;
+};
+
+//! An XmppModule for handle roster and presence functionality
+class XmppRosterModuleImpl : public XmppModuleImpl,
+  public XmppRosterModule, public XmppIqHandler {
+public:
+  virtual ~XmppRosterModuleImpl();
+
+  IMPLEMENT_XMPPMODULE
+
+  //! Sets the roster handler (callbacks) for the module
+  virtual XmppReturnStatus set_roster_handler(XmppRosterHandler * handler);
+
+  //! Gets the roster handler for the module
+  virtual XmppRosterHandler* roster_handler();
+
+  // USER PRESENCE STATE -------------------------------------------------------
+
+  //! Gets the aggregate outgoing presence
+  //! This object is non-const and be edited directly.  No update is sent
+  //! to the server until a Broadcast is sent
+  virtual XmppPresence* outgoing_presence();
+
+  //! Broadcasts that the user is available.
+  //! Nothing with respect to presence is sent until this is called.
+  virtual XmppReturnStatus BroadcastPresence();
+
+  //! Sends a directed presence to a Jid
+  //! Note that the client doesn't store where directed presence notifications
+  //! have been sent.  The server can keep the appropriate state
+  virtual XmppReturnStatus SendDirectedPresence(const XmppPresence* presence,
+                                                const Jid& to_jid);
+
+  // INCOMING PRESENCE STATUS --------------------------------------------------
+
+  //! Returns the number of incoming presence data recorded
+  virtual size_t GetIncomingPresenceCount();
+
+  //! Returns an incoming presence datum based on index
+  virtual const XmppPresence* GetIncomingPresence(size_t index);
+
+  //! Gets the number of presence data for a bare Jid
+  //! There may be a datum per resource
+  virtual size_t GetIncomingPresenceForJidCount(const Jid& jid);
+
+  //! Returns a single presence data for a Jid based on index
+  virtual const XmppPresence* GetIncomingPresenceForJid(const Jid& jid,
+                                                        size_t index);
+
+  // ROSTER MANAGEMENT ---------------------------------------------------------
+
+  //! Requests an update of the roster from the server
+  //! This must be called to initialize the client side cache of the roster
+  //! After this is sent the server should keep this module apprised of any
+  //! changes.
+  virtual XmppReturnStatus RequestRosterUpdate();
+
+  //! Returns the number of contacts in the roster
+  virtual size_t GetRosterContactCount();
+
+  //! Returns a contact by index
+  virtual const XmppRosterContact* GetRosterContact(size_t index);
+
+  //! Finds a contact by Jid
+  virtual const XmppRosterContact* FindRosterContact(const Jid& jid);
+
+  //! Send a request to the server to add a contact
+  //! Note that the contact won't show up in the roster until the server can
+  //! respond.  This happens async when the socket is being serviced
+  virtual XmppReturnStatus RequestRosterChange(
+    const XmppRosterContact* contact);
+
+  //! Request that the server remove a contact
+  //! The jabber protocol specifies that the server should also cancel any
+  //! subscriptions when this is done.  Like adding, this contact won't be
+  //! removed until the server responds.
+  virtual XmppReturnStatus RequestRosterRemove(const Jid& jid);
+
+  // SUBSCRIPTION MANAGEMENT ---------------------------------------------------
+
+  //! Request a subscription to presence notifications form a Jid
+  virtual XmppReturnStatus RequestSubscription(const Jid& jid);
+
+  //! Cancel a subscription to presence notifications from a Jid
+  virtual XmppReturnStatus CancelSubscription(const Jid& jid);
+
+  //! Approve a request to deliver presence notifications to a jid
+  virtual XmppReturnStatus ApproveSubscriber(const Jid& jid);
+
+  //! Deny or cancel presence notification deliver to a jid
+  virtual XmppReturnStatus CancelSubscriber(const Jid& jid);
+
+  // XmppIqHandler IMPLEMENTATION ----------------------------------------------
+  virtual void IqResponse(XmppIqCookie cookie, const XmlElement * stanza);
+
+protected:
+  // XmppModuleImpl OVERRIDES --------------------------------------------------
+  virtual bool HandleStanza(const XmlElement *);
+
+  // PRIVATE DATA --------------------------------------------------------------
+private:
+  friend class XmppRosterModule;
+  XmppRosterModuleImpl();
+
+  // Helper functions
+  void DeleteIncomingPresence();
+  void DeleteContacts();
+  XmppReturnStatus SendSubscriptionRequest(const Jid& jid,
+                                           const std::string& type);
+  void InternalSubscriptionRequest(const Jid& jid, const XmlElement* stanza,
+                                   XmppSubscriptionRequestType request_type);
+  void InternalIncomingPresence(const Jid& jid, const XmlElement* stanza);
+  void InternalIncomingPresenceError(const Jid& jid, const XmlElement* stanza);
+  void InternalRosterItems(const XmlElement* stanza);
+
+  // Member data
+  XmppPresenceImpl outgoing_presence_;
+  XmppRosterHandler* roster_handler_;
+
+  typedef std::vector<XmppPresenceImpl*> PresenceVector;
+  typedef std::map<Jid, PresenceVector*> JidPresenceVectorMap;
+  rtc::scoped_ptr<JidPresenceVectorMap> incoming_presence_map_;
+  rtc::scoped_ptr<PresenceVector> incoming_presence_vector_;
+
+  typedef std::vector<XmppRosterContactImpl*> ContactVector;
+  rtc::scoped_ptr<ContactVector> contacts_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPTHREAD_H_
diff --git a/libjingle/xmpp/saslcookiemechanism.h b/libjingle/xmpp/saslcookiemechanism.h
new file mode 100644
index 0000000..7a91246
--- /dev/null
+++ b/libjingle/xmpp/saslcookiemechanism.h
@@ -0,0 +1,69 @@
+/*
+ *  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_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/saslmechanism.h"
+
+namespace buzz {
+
+class SaslCookieMechanism : public SaslMechanism {
+
+public:
+  SaslCookieMechanism(const std::string & mechanism,
+                      const std::string & username,
+                      const std::string & cookie,
+                      const std::string & token_service)
+    : mechanism_(mechanism),
+      username_(username),
+      cookie_(cookie),
+      token_service_(token_service) {}
+
+  SaslCookieMechanism(const std::string & mechanism,
+                      const std::string & username,
+                      const std::string & cookie)
+    : mechanism_(mechanism),
+      username_(username),
+      cookie_(cookie),
+      token_service_("") {}
+
+  virtual std::string GetMechanismName() { return mechanism_; }
+
+  virtual XmlElement * StartSaslAuth() {
+    // send initial request
+    XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+    el->AddAttr(QN_MECHANISM, mechanism_);
+    if (!token_service_.empty()) {
+      el->AddAttr(QN_GOOGLE_AUTH_SERVICE, token_service_);
+    }
+
+    std::string credential;
+    credential.append("\0", 1);
+    credential.append(username_);
+    credential.append("\0", 1);
+    credential.append(cookie_);
+    el->AddText(Base64Encode(credential));
+    return el;
+  }
+
+private:
+  std::string mechanism_;
+  std::string username_;
+  std::string cookie_;
+  std::string token_service_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
diff --git a/libjingle/xmpp/saslhandler.h b/libjingle/xmpp/saslhandler.h
new file mode 100644
index 0000000..f2e3844
--- /dev/null
+++ b/libjingle/xmpp/saslhandler.h
@@ -0,0 +1,42 @@
+/*
+ *  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_LIBJINGLE_XMPP_SASLHANDLER_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
+
+#include <string>
+#include <vector>
+
+namespace buzz {
+
+class XmlElement;
+class SaslMechanism;
+
+// Creates mechanisms to deal with a given mechanism
+class SaslHandler {
+
+public:
+  
+  // Intended to be subclassed
+  virtual ~SaslHandler() {}
+
+  // Should pick the best method according to this handler
+  // returns the empty string if none are suitable
+  virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0;
+
+  // Creates a SaslMechanism for the given mechanism name (you own it
+  // once you get it).
+  // If not handled, return NULL.
+  virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
diff --git a/libjingle/xmpp/saslmechanism.cc b/libjingle/xmpp/saslmechanism.cc
new file mode 100644
index 0000000..b4d6e9b
--- /dev/null
+++ b/libjingle/xmpp/saslmechanism.cc
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/saslmechanism.h"
+#include "webrtc/base/base64.h"
+
+using rtc::Base64;
+
+namespace buzz {
+
+XmlElement *
+SaslMechanism::StartSaslAuth() {
+  return new XmlElement(QN_SASL_AUTH, true);
+}
+
+XmlElement *
+SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) {
+  return new XmlElement(QN_SASL_ABORT, true);
+}
+
+void
+SaslMechanism::HandleSaslSuccess(const XmlElement * success) {
+}
+
+void
+SaslMechanism::HandleSaslFailure(const XmlElement * failure) {
+}
+
+std::string
+SaslMechanism::Base64Encode(const std::string & plain) {
+  return Base64::Encode(plain);
+}
+
+std::string
+SaslMechanism::Base64Decode(const std::string & encoded) {
+  return Base64::Decode(encoded, Base64::DO_LAX);
+}
+
+std::string
+SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) {
+  std::string result;
+  Base64::EncodeFromArray(plain, length, &result);
+  return result;
+}
+
+}
diff --git a/libjingle/xmpp/saslmechanism.h b/libjingle/xmpp/saslmechanism.h
new file mode 100644
index 0000000..9c392e5
--- /dev/null
+++ b/libjingle/xmpp/saslmechanism.h
@@ -0,0 +1,57 @@
+/*
+ *  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_LIBJINGLE_XMPP_SASLMECHANISM_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
+
+#include <string>
+
+namespace buzz {
+
+class XmlElement;
+
+
+// Defines a mechnanism to do SASL authentication.
+// Subclass instances should have a self-contained way to present
+// credentials.
+class SaslMechanism {
+
+public:
+  
+  // Intended to be subclassed
+  virtual ~SaslMechanism() {}
+
+  // Should return the name of the SASL mechanism, e.g., "PLAIN"
+  virtual std::string GetMechanismName() = 0;
+
+  // Should generate the initial "auth" request.  Default is just <auth/>.
+  virtual XmlElement * StartSaslAuth();
+
+  // Should respond to a SASL "<challenge>" request.  Default is
+  // to abort (for mechanisms that do not do challenge-response)
+  virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge);
+
+  // Notification of a SASL "<success>".  Sometimes information
+  // is passed on success.
+  virtual void HandleSaslSuccess(const XmlElement * success);
+
+  // Notification of a SASL "<failure>".  Sometimes information
+  // for the user is passed on failure.
+  virtual void HandleSaslFailure(const XmlElement * failure);
+
+protected:
+  static std::string Base64Encode(const std::string & plain);
+  static std::string Base64Decode(const std::string & encoded);
+  static std::string Base64EncodeFromArray(const char * plain, size_t length);
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
diff --git a/libjingle/xmpp/saslplainmechanism.h b/libjingle/xmpp/saslplainmechanism.h
new file mode 100644
index 0000000..8e162e2
--- /dev/null
+++ b/libjingle/xmpp/saslplainmechanism.h
@@ -0,0 +1,48 @@
+/*
+ *  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_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
+#define WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
+
+#include "webrtc/libjingle/xmpp/saslmechanism.h"
+#include "webrtc/base/cryptstring.h"
+
+namespace buzz {
+
+class SaslPlainMechanism : public SaslMechanism {
+
+public:
+  SaslPlainMechanism(const buzz::Jid user_jid, const rtc::CryptString & password) :
+    user_jid_(user_jid), password_(password) {}
+
+  virtual std::string GetMechanismName() { return "PLAIN"; }
+
+  virtual XmlElement * StartSaslAuth() {
+    // send initial request
+    XmlElement * el = new XmlElement(QN_SASL_AUTH, true);
+    el->AddAttr(QN_MECHANISM, "PLAIN");
+
+    rtc::FormatCryptString credential;
+    credential.Append("\0", 1);
+    credential.Append(user_jid_.node());
+    credential.Append("\0", 1);
+    credential.Append(&password_);
+    el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength()));
+    return el;
+  }
+
+private:
+  Jid user_jid_;
+  rtc::CryptString password_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
diff --git a/libjingle/xmpp/util_unittest.cc b/libjingle/xmpp/util_unittest.cc
new file mode 100644
index 0000000..330ab48
--- /dev/null
+++ b/libjingle/xmpp/util_unittest.cc
@@ -0,0 +1,109 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/util_unittest.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/gunit.h"
+
+namespace buzz {
+
+void XmppTestHandler::WriteOutput(const char * bytes, size_t len) {
+  output_ << std::string(bytes, len);
+}
+
+void XmppTestHandler::StartTls(const std::string & cname) {
+  output_ << "[START-TLS " << cname << "]";
+}
+
+void XmppTestHandler::CloseConnection() {
+  output_ << "[CLOSED]";
+}
+
+void XmppTestHandler::OnStateChange(int state) {
+  switch (static_cast<XmppEngine::State>(state)) {
+  case XmppEngine::STATE_START:
+    session_ << "[START]";
+    break;
+  case XmppEngine::STATE_OPENING:
+    session_ << "[OPENING]";
+    break;
+  case XmppEngine::STATE_OPEN:
+    session_ << "[OPEN]";
+    break;
+  case XmppEngine::STATE_CLOSED:
+    session_ << "[CLOSED]";
+    switch (engine_->GetError(NULL)) {
+    case XmppEngine::ERROR_NONE:
+      // do nothing
+      break;
+    case XmppEngine::ERROR_XML:
+      session_ << "[ERROR-XML]";
+      break;
+    case XmppEngine::ERROR_STREAM:
+      session_ << "[ERROR-STREAM]";
+      break;
+    case XmppEngine::ERROR_VERSION:
+      session_ << "[ERROR-VERSION]";
+      break;
+    case XmppEngine::ERROR_UNAUTHORIZED:
+      session_ << "[ERROR-UNAUTHORIZED]";
+      break;
+    case XmppEngine::ERROR_TLS:
+      session_ << "[ERROR-TLS]";
+      break;
+    case XmppEngine::ERROR_AUTH:
+      session_ << "[ERROR-AUTH]";
+      break;
+    case XmppEngine::ERROR_BIND:
+      session_ << "[ERROR-BIND]";
+      break;
+    case XmppEngine::ERROR_CONNECTION_CLOSED:
+      session_ << "[ERROR-CONNECTION-CLOSED]";
+      break;
+    case XmppEngine::ERROR_DOCUMENT_CLOSED:
+      session_ << "[ERROR-DOCUMENT-CLOSED]";
+      break;
+    default:
+      break;
+    }
+    break;
+  default:
+    break;
+  }
+}
+
+bool XmppTestHandler::HandleStanza(const XmlElement * stanza) {
+  stanza_ << stanza->Str();
+  return true;
+}
+
+std::string XmppTestHandler::OutputActivity() {
+  std::string result = output_.str();
+  output_.str("");
+  return result;
+}
+
+std::string XmppTestHandler::SessionActivity() {
+  std::string result = session_.str();
+  session_.str("");
+  return result;
+}
+
+std::string XmppTestHandler::StanzaActivity() {
+  std::string result = stanza_.str();
+  stanza_.str("");
+  return result;
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/util_unittest.h b/libjingle/xmpp/util_unittest.h
new file mode 100644
index 0000000..38009fb
--- /dev/null
+++ b/libjingle/xmpp/util_unittest.h
@@ -0,0 +1,58 @@
+/*
+ *  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_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
+#define WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
+
+#include <sstream>
+#include <string>
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+
+namespace buzz {
+
+// This class captures callbacks from engine.
+class XmppTestHandler : public XmppOutputHandler,  public XmppSessionHandler,
+                        public XmppStanzaHandler {
+ public:
+  explicit XmppTestHandler(XmppEngine* engine) : engine_(engine) {}
+  virtual ~XmppTestHandler() {}
+
+  void SetEngine(XmppEngine* engine);
+
+  // Output handler
+  virtual void WriteOutput(const char * bytes, size_t len);
+  virtual void StartTls(const std::string & cname);
+  virtual void CloseConnection();
+
+  // Session handler
+  virtual void OnStateChange(int state);
+
+  // Stanza handler
+  virtual bool HandleStanza(const XmlElement* stanza);
+
+  std::string OutputActivity();
+  std::string SessionActivity();
+  std::string StanzaActivity();
+
+ private:
+  XmppEngine* engine_;
+  std::stringstream output_;
+  std::stringstream session_;
+  std::stringstream stanza_;
+};
+
+}  // namespace buzz
+
+inline std::ostream& operator<<(std::ostream& os, const buzz::Jid& jid) {
+  os << jid.Str();
+  return os;
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
diff --git a/libjingle/xmpp/xmpp.gyp b/libjingle/xmpp/xmpp.gyp
new file mode 100644
index 0000000..35755d6
--- /dev/null
+++ b/libjingle/xmpp/xmpp.gyp
@@ -0,0 +1,141 @@
+# 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.
+
+{
+  'includes': [ '../../build/common.gypi', ],
+  'targets': [
+    {
+      'target_name': 'rtc_xmpp',
+      'type': 'static_library',
+      'dependencies': [
+        '<(webrtc_root)/base/base.gyp:webrtc_base',
+        '<(webrtc_root)/libjingle/xmllite/xmllite.gyp:rtc_xmllite',
+        '<(DEPTH)/third_party/expat/expat.gyp:expat',
+      ],
+      'defines': [
+        'FEATURE_ENABLE_SSL',
+      ],
+      'cflags_cc!': [
+        '-Wnon-virtual-dtor',
+      ],
+      'export_dependent_settings': [
+        '<(DEPTH)/third_party/expat/expat.gyp:expat',
+      ],
+      'sources': [
+        'asyncsocket.h',
+        'chatroommodule.h',
+        'chatroommoduleimpl.cc',
+        'constants.cc',
+        'constants.h',
+        'discoitemsquerytask.cc',
+        'discoitemsquerytask.h',
+        'hangoutpubsubclient.cc',
+        'hangoutpubsubclient.h',
+        'iqtask.cc',
+        'iqtask.h',
+        'jid.cc',
+        'jid.h',
+        'module.h',
+        'moduleimpl.cc',
+        'moduleimpl.h',
+        'mucroomconfigtask.cc',
+        'mucroomconfigtask.h',
+        'mucroomdiscoverytask.cc',
+        'mucroomdiscoverytask.h',
+        'mucroomlookuptask.cc',
+        'mucroomlookuptask.h',
+        'mucroomuniquehangoutidtask.cc',
+        'mucroomuniquehangoutidtask.h',
+        'pingtask.cc',
+        'pingtask.h',
+        'plainsaslhandler.h',
+        'presenceouttask.cc',
+        'presenceouttask.h',
+        'presencereceivetask.cc',
+        'presencereceivetask.h',
+        'presencestatus.cc',
+        'presencestatus.h',
+        'prexmppauth.h',
+        'pubsub_task.cc',
+        'pubsub_task.h',
+        'pubsubclient.cc',
+        'pubsubclient.h',
+        'pubsubstateclient.cc',
+        'pubsubstateclient.h',
+        'pubsubtasks.cc',
+        'pubsubtasks.h',
+        'receivetask.cc',
+        'receivetask.h',
+        'rostermodule.h',
+        'rostermoduleimpl.cc',
+        'rostermoduleimpl.h',
+        'saslcookiemechanism.h',
+        'saslhandler.h',
+        'saslmechanism.cc',
+        'saslmechanism.h',
+        'saslplainmechanism.h',
+        'xmppauth.cc',
+        'xmppauth.h',
+        'xmppclient.cc',
+        'xmppclient.h',
+        'xmppclientsettings.h',
+        'xmppengine.h',
+        'xmppengineimpl.cc',
+        'xmppengineimpl.h',
+        'xmppengineimpl_iq.cc',
+        'xmpplogintask.cc',
+        'xmpplogintask.h',
+        'xmpppump.cc',
+        'xmpppump.h',
+        'xmppsocket.cc',
+        'xmppsocket.h',
+        'xmppstanzaparser.cc',
+        'xmppstanzaparser.h',
+        'xmpptask.cc',
+        'xmpptask.h',
+        'xmppthread.cc',
+        'xmppthread.h',
+      ],
+      'direct_dependent_settings': {
+        'cflags_cc!': [
+          '-Wnon-virtual-dtor',
+        ],
+        'defines': [
+          'FEATURE_ENABLE_SSL',
+          'FEATURE_ENABLE_VOICEMAIL',
+        ],
+      },
+      'conditions': [
+        ['build_with_chromium==0', {
+          'defines': [
+            'FEATURE_ENABLE_VOICEMAIL',
+            'FEATURE_ENABLE_PSTN',
+          ],
+        }],
+        ['os_posix==1', {
+          'configurations': {
+            'Debug_Base': {
+              'defines': [
+                # Chromium's build/common.gypi defines this for all posix
+                # _except_ for ios & mac.  We want it there as well, e.g.
+                # because ASSERT and friends trigger off of it.
+                '_DEBUG',
+              ],
+            },
+          }
+        }],
+        ['OS=="android"', {
+          'cflags!': [
+            '-Wextra',
+            '-Wall',
+          ],
+        }],
+      ],
+    }],
+}
+  
diff --git a/libjingle/xmpp/xmpp_tests.gypi b/libjingle/xmpp/xmpp_tests.gypi
new file mode 100644
index 0000000..f1dec1c
--- /dev/null
+++ b/libjingle/xmpp/xmpp_tests.gypi
@@ -0,0 +1,37 @@
+# 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.
+
+{
+  'includes': [ '../../build/common.gypi', ],
+  'targets': [
+    {
+      'target_name': 'rtc_xmpp_unittest',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'sources': [
+          'fakexmppclient.h',
+          'hangoutpubsubclient_unittest.cc',
+          'jid_unittest.cc',
+          'mucroomconfigtask_unittest.cc',
+          'mucroomdiscoverytask_unittest.cc',
+          'mucroomlookuptask_unittest.cc',
+          'mucroomuniquehangoutidtask_unittest.cc',
+          'pingtask_unittest.cc',
+          'pubsubclient_unittest.cc',
+          'pubsubtasks_unittest.cc',
+          'util_unittest.cc',
+          'util_unittest.h',
+          'xmppengine_unittest.cc',
+          'xmpplogintask_unittest.cc',
+          'xmppstanzaparser_unittest.cc',
+        ],
+      },
+    },
+  ],
+}
+  
diff --git a/libjingle/xmpp/xmppauth.cc b/libjingle/xmpp/xmppauth.cc
new file mode 100644
index 0000000..a3d2f67
--- /dev/null
+++ b/libjingle/xmpp/xmppauth.cc
@@ -0,0 +1,88 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/xmppauth.h"
+
+#include <algorithm>
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/saslcookiemechanism.h"
+#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
+
+XmppAuth::XmppAuth() : done_(false) {
+}
+
+XmppAuth::~XmppAuth() {
+}
+
+void XmppAuth::StartPreXmppAuth(const buzz::Jid& jid,
+                                const rtc::SocketAddress& server,
+                                const rtc::CryptString& pass,
+                                const std::string& auth_mechanism,
+                                const std::string& auth_token) {
+  jid_ = jid;
+  passwd_ = pass;
+  auth_mechanism_ = auth_mechanism;
+  auth_token_ = auth_token;
+  done_ = true;
+
+  SignalAuthDone();
+}
+
+static bool contains(const std::vector<std::string>& strings,
+                     const std::string& string) {
+  return std::find(strings.begin(), strings.end(), string) != strings.end();
+}
+
+std::string XmppAuth::ChooseBestSaslMechanism(
+    const std::vector<std::string>& mechanisms,
+    bool encrypted) {
+  // First try Oauth2.
+  if (GetAuthMechanism() == buzz::AUTH_MECHANISM_OAUTH2 &&
+      contains(mechanisms, buzz::AUTH_MECHANISM_OAUTH2)) {
+    return buzz::AUTH_MECHANISM_OAUTH2;
+  }
+
+  // A token is the weakest auth - 15s, service-limited, so prefer it.
+  if (GetAuthMechanism() == buzz::AUTH_MECHANISM_GOOGLE_TOKEN &&
+      contains(mechanisms, buzz::AUTH_MECHANISM_GOOGLE_TOKEN)) {
+    return buzz::AUTH_MECHANISM_GOOGLE_TOKEN;
+  }
+
+  // A cookie is the next weakest - 14 days.
+  if (GetAuthMechanism() == buzz::AUTH_MECHANISM_GOOGLE_COOKIE &&
+      contains(mechanisms, buzz::AUTH_MECHANISM_GOOGLE_COOKIE)) {
+    return buzz::AUTH_MECHANISM_GOOGLE_COOKIE;
+  }
+
+  // As a last resort, use plain authentication.
+  if (contains(mechanisms, buzz::AUTH_MECHANISM_PLAIN)) {
+    return buzz::AUTH_MECHANISM_PLAIN;
+  }
+
+  // No good mechanism found
+  return "";
+}
+
+buzz::SaslMechanism* XmppAuth::CreateSaslMechanism(
+    const std::string& mechanism) {
+  if (mechanism == buzz::AUTH_MECHANISM_OAUTH2) {
+    return new buzz::SaslCookieMechanism(
+        mechanism, jid_.Str(), auth_token_, "oauth2");
+  } else if (mechanism == buzz::AUTH_MECHANISM_GOOGLE_TOKEN) {
+    return new buzz::SaslCookieMechanism(mechanism, jid_.Str(), auth_token_);
+  // } else if (mechanism == buzz::AUTH_MECHANISM_GOOGLE_COOKIE) {
+  //   return new buzz::SaslCookieMechanism(mechanism, jid.Str(), sid_);
+  } else if (mechanism == buzz::AUTH_MECHANISM_PLAIN) {
+    return new buzz::SaslPlainMechanism(jid_, passwd_);
+  } else {
+    return NULL;
+  }
+}
diff --git a/libjingle/xmpp/xmppauth.h b/libjingle/xmpp/xmppauth.h
new file mode 100644
index 0000000..dd363d1
--- /dev/null
+++ b/libjingle/xmpp/xmppauth.h
@@ -0,0 +1,61 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPAUTH_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPAUTH_H_
+
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/prexmppauth.h"
+#include "webrtc/libjingle/xmpp/saslhandler.h"
+#include "webrtc/base/cryptstring.h"
+#include "webrtc/base/sigslot.h"
+
+class XmppAuth: public buzz::PreXmppAuth {
+public:
+  XmppAuth();
+  virtual ~XmppAuth();
+
+  // TODO: Just have one "secret" that is either pass or
+  // token?
+  virtual void StartPreXmppAuth(const buzz::Jid& jid,
+                                const rtc::SocketAddress& server,
+                                const rtc::CryptString& pass,
+                                const std::string& auth_mechanism,
+                                const std::string& auth_token);
+
+  virtual bool IsAuthDone() const { return done_; }
+  virtual bool IsAuthorized() const { return true; }
+  virtual bool HadError() const { return false; }
+  virtual int  GetError() const { return 0; }
+  virtual buzz::CaptchaChallenge GetCaptchaChallenge() const {
+      return buzz::CaptchaChallenge();
+  }
+  virtual std::string GetAuthMechanism() const { return auth_mechanism_; }
+  virtual std::string GetAuthToken() const { return auth_token_; }
+
+  virtual std::string ChooseBestSaslMechanism(
+      const std::vector<std::string>& mechanisms,
+      bool encrypted);
+
+  virtual buzz::SaslMechanism * CreateSaslMechanism(
+      const std::string& mechanism);
+
+private:
+  buzz::Jid jid_;
+  rtc::CryptString passwd_;
+  std::string auth_mechanism_;
+  std::string auth_token_;
+  bool done_;
+};
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPAUTH_H_
+
diff --git a/libjingle/xmpp/xmppclient.cc b/libjingle/xmpp/xmppclient.cc
new file mode 100644
index 0000000..7c2a5e6
--- /dev/null
+++ b/libjingle/xmpp/xmppclient.cc
@@ -0,0 +1,424 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/plainsaslhandler.h"
+#include "webrtc/libjingle/xmpp/prexmppauth.h"
+#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/stringutils.h"
+#include "xmpptask.h"
+
+namespace buzz {
+
+class XmppClient::Private :
+    public sigslot::has_slots<>,
+    public XmppSessionHandler,
+    public XmppOutputHandler {
+public:
+
+  explicit Private(XmppClient* client) :
+    client_(client),
+    socket_(),
+    engine_(),
+    proxy_port_(0),
+    pre_engine_error_(XmppEngine::ERROR_NONE),
+    pre_engine_subcode_(0),
+    signal_closed_(false),
+    allow_plain_(false) {}
+
+  virtual ~Private() {
+    // We need to disconnect from socket_ before engine_ is destructed (by
+    // the auto-generated destructor code).
+    ResetSocket();
+  }
+
+  // the owner
+  XmppClient* const client_;
+
+  // the two main objects
+  rtc::scoped_ptr<AsyncSocket> socket_;
+  rtc::scoped_ptr<XmppEngine> engine_;
+  rtc::scoped_ptr<PreXmppAuth> pre_auth_;
+  rtc::CryptString pass_;
+  std::string auth_mechanism_;
+  std::string auth_token_;
+  rtc::SocketAddress server_;
+  std::string proxy_host_;
+  int proxy_port_;
+  XmppEngine::Error pre_engine_error_;
+  int pre_engine_subcode_;
+  CaptchaChallenge captcha_challenge_;
+  bool signal_closed_;
+  bool allow_plain_;
+
+  void ResetSocket() {
+    if (socket_) {
+      socket_->SignalConnected.disconnect(this);
+      socket_->SignalRead.disconnect(this);
+      socket_->SignalClosed.disconnect(this);
+      socket_.reset(NULL);
+    }
+  }
+
+  // implementations of interfaces
+  void OnStateChange(int state);
+  void WriteOutput(const char* bytes, size_t len);
+  void StartTls(const std::string& domainname);
+  void CloseConnection();
+
+  // slots for socket signals
+  void OnSocketConnected();
+  void OnSocketRead();
+  void OnSocketClosed();
+};
+
+bool IsTestServer(const std::string& server_name,
+                  const std::string& test_server_domain) {
+  return (!test_server_domain.empty() &&
+          rtc::ends_with(server_name.c_str(),
+                               test_server_domain.c_str()));
+}
+
+XmppReturnStatus XmppClient::Connect(
+    const XmppClientSettings& settings,
+    const std::string& lang, AsyncSocket* socket, PreXmppAuth* pre_auth) {
+  if (socket == NULL)
+    return XMPP_RETURN_BADARGUMENT;
+  if (d_->socket_)
+    return XMPP_RETURN_BADSTATE;
+
+  d_->socket_.reset(socket);
+
+  d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected);
+  d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead);
+  d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed);
+
+  d_->engine_.reset(XmppEngine::Create());
+  d_->engine_->SetSessionHandler(d_.get());
+  d_->engine_->SetOutputHandler(d_.get());
+  if (!settings.resource().empty()) {
+    d_->engine_->SetRequestedResource(settings.resource());
+  }
+  d_->engine_->SetTls(settings.use_tls());
+
+  // The talk.google.com server returns a certificate with common-name:
+  //   CN="gmail.com" for @gmail.com accounts,
+  //   CN="googlemail.com" for @googlemail.com accounts,
+  //   CN="talk.google.com" for other accounts (such as @example.com),
+  // so we tweak the tls server setting for those other accounts to match the
+  // returned certificate CN of "talk.google.com".
+  // For other servers, we leave the strings empty, which causes the jid's
+  // domain to be used.  We do the same for gmail.com and googlemail.com as the
+  // returned CN matches the account domain in those cases.
+  std::string server_name = settings.server().HostAsURIString();
+  if (server_name == buzz::STR_TALK_GOOGLE_COM ||
+      server_name == buzz::STR_TALKX_L_GOOGLE_COM ||
+      server_name == buzz::STR_XMPP_GOOGLE_COM ||
+      server_name == buzz::STR_XMPPX_L_GOOGLE_COM ||
+      IsTestServer(server_name, settings.test_server_domain())) {
+    if (settings.host() != STR_GMAIL_COM &&
+        settings.host() != STR_GOOGLEMAIL_COM) {
+      d_->engine_->SetTlsServer("", STR_TALK_GOOGLE_COM);
+    }
+  }
+
+  // Set language
+  d_->engine_->SetLanguage(lang);
+
+  d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY));
+
+  d_->pass_ = settings.pass();
+  d_->auth_mechanism_ = settings.auth_mechanism();
+  d_->auth_token_ = settings.auth_token();
+  d_->server_ = settings.server();
+  d_->proxy_host_ = settings.proxy_host();
+  d_->proxy_port_ = settings.proxy_port();
+  d_->allow_plain_ = settings.allow_plain();
+  d_->pre_auth_.reset(pre_auth);
+
+  return XMPP_RETURN_OK;
+}
+
+XmppEngine::State XmppClient::GetState() const {
+  if (!d_->engine_)
+    return XmppEngine::STATE_NONE;
+  return d_->engine_->GetState();
+}
+
+XmppEngine::Error XmppClient::GetError(int* subcode) {
+  if (subcode) {
+    *subcode = 0;
+  }
+  if (!d_->engine_)
+    return XmppEngine::ERROR_NONE;
+  if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE) {
+    if (subcode) {
+      *subcode = d_->pre_engine_subcode_;
+    }
+    return d_->pre_engine_error_;
+  }
+  return d_->engine_->GetError(subcode);
+}
+
+const XmlElement* XmppClient::GetStreamError() {
+  if (!d_->engine_) {
+    return NULL;
+  }
+  return d_->engine_->GetStreamError();
+}
+
+CaptchaChallenge XmppClient::GetCaptchaChallenge() {
+  if (!d_->engine_)
+    return CaptchaChallenge();
+  return d_->captcha_challenge_;
+}
+
+std::string XmppClient::GetAuthMechanism() {
+  if (!d_->engine_)
+    return "";
+  return d_->auth_mechanism_;
+}
+
+std::string XmppClient::GetAuthToken() {
+  if (!d_->engine_)
+    return "";
+  return d_->auth_token_;
+}
+
+int XmppClient::ProcessStart() {
+  // Should not happen, but was observed in crash reports
+  if (!d_->socket_) {
+    LOG(LS_ERROR) << "socket_ already reset";
+    return STATE_DONE;
+  }
+
+  if (d_->pre_auth_) {
+    d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone);
+    d_->pre_auth_->StartPreXmppAuth(
+        d_->engine_->GetUser(), d_->server_, d_->pass_,
+        d_->auth_mechanism_, d_->auth_token_);
+    d_->pass_.Clear(); // done with this;
+    return STATE_PRE_XMPP_LOGIN;
+  }
+  else {
+    d_->engine_->SetSaslHandler(new PlainSaslHandler(
+              d_->engine_->GetUser(), d_->pass_, d_->allow_plain_));
+    d_->pass_.Clear(); // done with this;
+    return STATE_START_XMPP_LOGIN;
+  }
+}
+
+void XmppClient::OnAuthDone() {
+  Wake();
+}
+
+int XmppClient::ProcessTokenLogin() {
+  // Should not happen, but was observed in crash reports
+  if (!d_->socket_) {
+    LOG(LS_ERROR) << "socket_ already reset";
+    return STATE_DONE;
+  }
+
+  // Don't know how this could happen, but crash reports show it as NULL
+  if (!d_->pre_auth_) {
+    d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+    EnsureClosed();
+    return STATE_ERROR;
+  }
+
+  // Wait until pre authentication is done is done
+  if (!d_->pre_auth_->IsAuthDone())
+    return STATE_BLOCKED;
+
+  if (!d_->pre_auth_->IsAuthorized()) {
+    // maybe split out a case when gaia is down?
+    if (d_->pre_auth_->HadError()) {
+      d_->pre_engine_error_ = XmppEngine::ERROR_AUTH;
+      d_->pre_engine_subcode_ = d_->pre_auth_->GetError();
+    }
+    else {
+      d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED;
+      d_->pre_engine_subcode_ = 0;
+      d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge();
+    }
+    d_->pre_auth_.reset(NULL); // done with this
+    EnsureClosed();
+    return STATE_ERROR;
+  }
+
+  // Save auth token as a result
+
+  d_->auth_mechanism_ = d_->pre_auth_->GetAuthMechanism();
+  d_->auth_token_ = d_->pre_auth_->GetAuthToken();
+
+  // transfer ownership of pre_auth_ to engine
+  d_->engine_->SetSaslHandler(d_->pre_auth_.release());
+  return STATE_START_XMPP_LOGIN;
+}
+
+int XmppClient::ProcessStartXmppLogin() {
+  // Should not happen, but was observed in crash reports
+  if (!d_->socket_) {
+    LOG(LS_ERROR) << "socket_ already reset";
+    return STATE_DONE;
+  }
+
+  // Done with pre-connect tasks - connect!
+  if (!d_->socket_->Connect(d_->server_)) {
+    EnsureClosed();
+    return STATE_ERROR;
+  }
+
+  return STATE_RESPONSE;
+}
+
+int XmppClient::ProcessResponse() {
+  // Hang around while we are connected.
+  if (!delivering_signal_ &&
+      (!d_->engine_ || d_->engine_->GetState() == XmppEngine::STATE_CLOSED))
+    return STATE_DONE;
+  return STATE_BLOCKED;
+}
+
+XmppReturnStatus XmppClient::Disconnect() {
+  if (!d_->socket_)
+    return XMPP_RETURN_BADSTATE;
+  Abort();
+  d_->engine_->Disconnect();
+  d_->ResetSocket();
+  return XMPP_RETURN_OK;
+}
+
+XmppClient::XmppClient(TaskParent* parent)
+    : XmppTaskParentInterface(parent),
+      delivering_signal_(false),
+      valid_(false) {
+  d_.reset(new Private(this));
+  valid_ = true;
+}
+
+XmppClient::~XmppClient() {
+  valid_ = false;
+}
+
+const Jid& XmppClient::jid() const {
+  return d_->engine_->FullJid();
+}
+
+
+std::string XmppClient::NextId() {
+  return d_->engine_->NextId();
+}
+
+XmppReturnStatus XmppClient::SendStanza(const XmlElement* stanza) {
+  return d_->engine_->SendStanza(stanza);
+}
+
+XmppReturnStatus XmppClient::SendStanzaError(
+    const XmlElement* old_stanza, XmppStanzaError xse,
+    const std::string& message) {
+  return d_->engine_->SendStanzaError(old_stanza, xse, message);
+}
+
+XmppReturnStatus XmppClient::SendRaw(const std::string& text) {
+  return d_->engine_->SendRaw(text);
+}
+
+XmppEngine* XmppClient::engine() {
+  return d_->engine_.get();
+}
+
+void XmppClient::Private::OnSocketConnected() {
+  engine_->Connect();
+}
+
+void XmppClient::Private::OnSocketRead() {
+  char bytes[4096];
+  size_t bytes_read;
+  for (;;) {
+    // Should not happen, but was observed in crash reports
+    if (!socket_) {
+      LOG(LS_ERROR) << "socket_ already reset";
+      return;
+    }
+
+    if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) {
+      // TODO: deal with error information
+      return;
+    }
+
+    if (bytes_read == 0)
+      return;
+
+//#ifdef _DEBUG
+    client_->SignalLogInput(bytes, static_cast<int>(bytes_read));
+//#endif
+
+    engine_->HandleInput(bytes, bytes_read);
+  }
+}
+
+void XmppClient::Private::OnSocketClosed() {
+  int code = socket_->GetError();
+  engine_->ConnectionClosed(code);
+}
+
+void XmppClient::Private::OnStateChange(int state) {
+  if (state == XmppEngine::STATE_CLOSED) {
+    client_->EnsureClosed();
+  }
+  else {
+    client_->SignalStateChange((XmppEngine::State)state);
+  }
+  client_->Wake();
+}
+
+void XmppClient::Private::WriteOutput(const char* bytes, size_t len) {
+//#ifdef _DEBUG
+  client_->SignalLogOutput(bytes, static_cast<int>(len));
+//#endif
+
+  socket_->Write(bytes, len);
+  // TODO: deal with error information
+}
+
+void XmppClient::Private::StartTls(const std::string& domain) {
+#if defined(FEATURE_ENABLE_SSL)
+  socket_->StartTls(domain);
+#endif
+}
+
+void XmppClient::Private::CloseConnection() {
+  socket_->Close();
+}
+
+void XmppClient::AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) {
+  d_->engine_->AddStanzaHandler(task, level);
+}
+
+void XmppClient::RemoveXmppTask(XmppTask* task) {
+  d_->engine_->RemoveStanzaHandler(task);
+}
+
+void XmppClient::EnsureClosed() {
+  if (!d_->signal_closed_) {
+    d_->signal_closed_ = true;
+    delivering_signal_ = true;
+    SignalStateChange(XmppEngine::STATE_CLOSED);
+    delivering_signal_ = false;
+  }
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/xmppclient.h b/libjingle/xmpp/xmppclient.h
new file mode 100644
index 0000000..7b9eb7a
--- /dev/null
+++ b/libjingle/xmpp/xmppclient.h
@@ -0,0 +1,148 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPCLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
+
+#include <string>
+#include "webrtc/libjingle/xmpp/asyncsocket.h"
+#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "webrtc/base/basicdefs.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/task.h"
+
+namespace buzz {
+
+class PreXmppAuth;
+class CaptchaChallenge;
+
+// Just some non-colliding number.  Could have picked "1".
+#define XMPP_CLIENT_TASK_CODE 0x366c1e47
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPCLIENT
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task first.  XmppClient is a parent task for XmppTasks.
+//
+// XmppClient is a task which is designed to be the parent task for
+// all tasks that depend on a single Xmpp connection.  If you want to,
+// for example, listen for subscription requests forever, then your
+// listener should be a task that is a child of the XmppClient that owns
+// the connection you are using.  XmppClient has all the utility methods
+// that basically drill through to XmppEngine.
+//
+// XmppClient is just a wrapper for XmppEngine, and if I were writing it
+// all over again, I would make XmppClient == XmppEngine.  Why?
+// XmppEngine needs tasks too, for example it has an XmppLoginTask which
+// should just be the same kind of Task instead of an XmppEngine specific
+// thing.  It would help do certain things like GAIA auth cleaner.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppClient : public XmppTaskParentInterface,
+                   public XmppClientInterface,
+                   public sigslot::has_slots<>
+{
+public:
+  explicit XmppClient(rtc::TaskParent * parent);
+  virtual ~XmppClient();
+
+  XmppReturnStatus Connect(const XmppClientSettings & settings,
+                           const std::string & lang,
+                           AsyncSocket * socket,
+                           PreXmppAuth * preauth);
+
+  virtual int ProcessStart();
+  virtual int ProcessResponse();
+  XmppReturnStatus Disconnect();
+
+  sigslot::signal1<XmppEngine::State> SignalStateChange;
+  XmppEngine::Error GetError(int *subcode);
+
+  // When there is a <stream:error> stanza, return the stanza
+  // so that they can be handled.
+  const XmlElement *GetStreamError();
+
+  // When there is an authentication error, we may have captcha info
+  // that the user can use to unlock their account
+  CaptchaChallenge GetCaptchaChallenge();
+
+  // When authentication is successful, this returns the service token
+  // (if we used GAIA authentication)
+  std::string GetAuthMechanism();
+  std::string GetAuthToken();
+
+  XmppReturnStatus SendRaw(const std::string & text);
+
+  XmppEngine* engine();
+
+  sigslot::signal2<const char *, int> SignalLogInput;
+  sigslot::signal2<const char *, int> SignalLogOutput;
+
+  // As XmppTaskParentIntreface
+  virtual XmppClientInterface* GetClient() { return this; }
+
+  // As XmppClientInterface
+  virtual XmppEngine::State GetState() const;
+  virtual const Jid& jid() const;
+  virtual std::string NextId();
+  virtual XmppReturnStatus SendStanza(const XmlElement *stanza);
+  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+                                           XmppStanzaError code,
+                                           const std::string & text);
+  virtual void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel);
+  virtual void RemoveXmppTask(XmppTask *);
+
+ private:
+  friend class XmppTask;
+
+  void OnAuthDone();
+
+  // Internal state management
+  enum {
+    STATE_PRE_XMPP_LOGIN = STATE_NEXT,
+    STATE_START_XMPP_LOGIN = STATE_NEXT + 1,
+  };
+  int Process(int state) {
+    switch (state) {
+      case STATE_PRE_XMPP_LOGIN: return ProcessTokenLogin();
+      case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin();
+      default: return Task::Process(state);
+    }
+  }
+
+  std::string GetStateName(int state) const {
+    switch (state) {
+      case STATE_PRE_XMPP_LOGIN:      return "PRE_XMPP_LOGIN";
+      case STATE_START_XMPP_LOGIN:  return "START_XMPP_LOGIN";
+      default: return Task::GetStateName(state);
+    }
+  }
+
+  int ProcessTokenLogin();
+  int ProcessStartXmppLogin();
+  void EnsureClosed();
+
+  class Private;
+  friend class Private;
+  rtc::scoped_ptr<Private> d_;
+
+  bool delivering_signal_;
+  bool valid_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
diff --git a/libjingle/xmpp/xmppclientsettings.h b/libjingle/xmpp/xmppclientsettings.h
new file mode 100644
index 0000000..5b7572a
--- /dev/null
+++ b/libjingle/xmpp/xmppclientsettings.h
@@ -0,0 +1,111 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
+
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/cryptstring.h"
+
+namespace buzz {
+
+class XmppUserSettings {
+ public:
+  XmppUserSettings()
+    : use_tls_(buzz::TLS_DISABLED),
+      allow_plain_(false) {
+  }
+
+  void set_user(const std::string& user) { user_ = user; }
+  void set_host(const std::string& host) { host_ = host; }
+  void set_pass(const rtc::CryptString& pass) { pass_ = pass; }
+  void set_auth_token(const std::string& mechanism,
+                      const std::string& token) {
+    auth_mechanism_ = mechanism;
+    auth_token_ = token;
+  }
+  void set_resource(const std::string& resource) { resource_ = resource; }
+  void set_use_tls(const TlsOptions use_tls) { use_tls_ = use_tls; }
+  void set_allow_plain(bool f) { allow_plain_ = f; }
+  void set_test_server_domain(const std::string& test_server_domain) {
+    test_server_domain_ = test_server_domain;
+  }
+  void set_token_service(const std::string& token_service) {
+    token_service_ = token_service;
+  }
+
+  const std::string& user() const { return user_; }
+  const std::string& host() const { return host_; }
+  const rtc::CryptString& pass() const { return pass_; }
+  const std::string& auth_mechanism() const { return auth_mechanism_; }
+  const std::string& auth_token() const { return auth_token_; }
+  const std::string& resource() const { return resource_; }
+  TlsOptions use_tls() const { return use_tls_; }
+  bool allow_plain() const { return allow_plain_; }
+  const std::string& test_server_domain() const { return test_server_domain_; }
+  const std::string& token_service() const { return token_service_; }
+
+ private:
+  std::string user_;
+  std::string host_;
+  rtc::CryptString pass_;
+  std::string auth_mechanism_;
+  std::string auth_token_;
+  std::string resource_;
+  TlsOptions use_tls_;
+  bool allow_plain_;
+  std::string test_server_domain_;
+  std::string token_service_;
+};
+
+class XmppClientSettings : public XmppUserSettings {
+ public:
+  XmppClientSettings()
+    : protocol_(cricket::PROTO_TCP),
+      proxy_(rtc::PROXY_NONE),
+      proxy_port_(80),
+      use_proxy_auth_(false) {
+  }
+
+  void set_server(const rtc::SocketAddress& server) {
+      server_ = server;
+  }
+  void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; }
+  void set_proxy(rtc::ProxyType f) { proxy_ = f; }
+  void set_proxy_host(const std::string& host) { proxy_host_ = host; }
+  void set_proxy_port(int port) { proxy_port_ = port; };
+  void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; }
+  void set_proxy_user(const std::string& user) { proxy_user_ = user; }
+  void set_proxy_pass(const rtc::CryptString& pass) { proxy_pass_ = pass; }
+
+  const rtc::SocketAddress& server() const { return server_; }
+  cricket::ProtocolType protocol() const { return protocol_; }
+  rtc::ProxyType proxy() const { return proxy_; }
+  const std::string& proxy_host() const { return proxy_host_; }
+  int proxy_port() const { return proxy_port_; }
+  bool use_proxy_auth() const { return use_proxy_auth_; }
+  const std::string& proxy_user() const { return proxy_user_; }
+  const rtc::CryptString& proxy_pass() const { return proxy_pass_; }
+
+ private:
+  rtc::SocketAddress server_;
+  cricket::ProtocolType protocol_;
+  rtc::ProxyType proxy_;
+  std::string proxy_host_;
+  int proxy_port_;
+  bool use_proxy_auth_;
+  std::string proxy_user_;
+  rtc::CryptString proxy_pass_;
+};
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
diff --git a/libjingle/xmpp/xmppengine.h b/libjingle/xmpp/xmppengine.h
new file mode 100644
index 0000000..2bc2453
--- /dev/null
+++ b/libjingle/xmpp/xmppengine.h
@@ -0,0 +1,332 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPENGINE_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
+
+// also part of the API
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+
+
+namespace buzz {
+
+class XmppEngine;
+class SaslHandler;
+typedef void * XmppIqCookie;
+
+//! XMPP stanza error codes.
+//! Used in XmppEngine.SendStanzaError().
+enum XmppStanzaError {
+  XSE_BAD_REQUEST,
+  XSE_CONFLICT,
+  XSE_FEATURE_NOT_IMPLEMENTED,
+  XSE_FORBIDDEN,
+  XSE_GONE,
+  XSE_INTERNAL_SERVER_ERROR,
+  XSE_ITEM_NOT_FOUND,
+  XSE_JID_MALFORMED,
+  XSE_NOT_ACCEPTABLE,
+  XSE_NOT_ALLOWED,
+  XSE_PAYMENT_REQUIRED,
+  XSE_RECIPIENT_UNAVAILABLE,
+  XSE_REDIRECT,
+  XSE_REGISTRATION_REQUIRED,
+  XSE_SERVER_NOT_FOUND,
+  XSE_SERVER_TIMEOUT,
+  XSE_RESOURCE_CONSTRAINT,
+  XSE_SERVICE_UNAVAILABLE,
+  XSE_SUBSCRIPTION_REQUIRED,
+  XSE_UNDEFINED_CONDITION,
+  XSE_UNEXPECTED_REQUEST,
+};
+
+// XmppReturnStatus
+//    This is used by API functions to synchronously return status.
+enum XmppReturnStatus {
+  XMPP_RETURN_OK,
+  XMPP_RETURN_BADARGUMENT,
+  XMPP_RETURN_BADSTATE,
+  XMPP_RETURN_PENDING,
+  XMPP_RETURN_UNEXPECTED,
+  XMPP_RETURN_NOTYETIMPLEMENTED,
+};
+
+// TlsOptions
+//    This is used by API to identify TLS setting.
+enum TlsOptions {
+  TLS_DISABLED,
+  TLS_ENABLED,
+  TLS_REQUIRED
+};
+
+//! Callback for socket output for an XmppEngine connection.
+//! Register via XmppEngine.SetOutputHandler.  An XmppEngine
+//! can call back to this handler while it is processing
+//! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
+class XmppOutputHandler {
+public:
+  virtual ~XmppOutputHandler() {}
+
+  //! Deliver the specified bytes to the XMPP socket.
+  virtual void WriteOutput(const char * bytes, size_t len) = 0;
+
+  //! Initiate TLS encryption on the socket.
+  //! The implementation must verify that the SSL
+  //! certificate matches the given domainname.
+  virtual void StartTls(const std::string & domainname) = 0;
+
+  //! Called when engine wants the connecton closed.
+  virtual void CloseConnection() = 0;
+};
+
+//! Callback to deliver engine state change notifications
+//! to the object managing the engine.
+class XmppSessionHandler {
+public:
+  virtual ~XmppSessionHandler() {}
+  //! Called when engine changes state. Argument is new state.
+  virtual void OnStateChange(int state) = 0;
+};
+
+//! Callback to deliver stanzas to an Xmpp application module.
+//! Register via XmppEngine.SetDefaultSessionHandler or via
+//! XmppEngine.AddSessionHAndler.  
+class XmppStanzaHandler {
+public:
+  virtual ~XmppStanzaHandler() {}
+  //! Process the given stanza.
+  //! The handler must return true if it has handled the stanza.
+  //! A false return value causes the stanza to be passed on to
+  //! the next registered handler.
+  virtual bool HandleStanza(const XmlElement * stanza) = 0;
+};
+
+//! Callback to deliver iq responses (results and errors).
+//! Register while sending an iq via XmppEngine.SendIq.
+//! Iq responses are routed to matching XmppIqHandlers in preference
+//! to sending to any registered SessionHandlers.
+class XmppIqHandler {
+public:
+  virtual ~XmppIqHandler() {}
+  //! Called to handle the iq response.
+  //! The response may be either a result or an error, and will have
+  //! an 'id' that matches the request and a 'from' that matches the
+  //! 'to' of the request.  Called no more than once; once this is
+  //! called, the handler is automatically unregistered.
+  virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
+};
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput.  Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngine {
+public:
+  static XmppEngine * Create();
+  virtual ~XmppEngine() {}
+
+  //! Error codes. See GetError().
+  enum Error {
+    ERROR_NONE = 0,         //!< No error
+    ERROR_XML,              //!< Malformed XML or encoding error
+    ERROR_STREAM,           //!< XMPP stream error - see GetStreamError()
+    ERROR_VERSION,          //!< XMPP version error
+    ERROR_UNAUTHORIZED,     //!< User is not authorized (rejected credentials)
+    ERROR_TLS,              //!< TLS could not be negotiated
+    ERROR_AUTH,             //!< Authentication could not be negotiated
+    ERROR_BIND,             //!< Resource or session binding could not be negotiated
+    ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
+    ERROR_DOCUMENT_CLOSED,  //!< Closed by </stream:stream>
+    ERROR_SOCKET,           //!< Socket error
+    ERROR_NETWORK_TIMEOUT,  //!< Some sort of timeout (eg., we never got the roster)
+    ERROR_MISSING_USERNAME  //!< User has a Google Account but no nickname
+  };
+
+  //! States.  See GetState().
+  enum State {
+    STATE_NONE = 0,        //!< Nonexistent state
+    STATE_START,           //!< Initial state.
+    STATE_OPENING,         //!< Exchanging stream headers, authenticating and so on.
+    STATE_OPEN,            //!< Authenticated and bound.
+    STATE_CLOSED,          //!< Session closed, possibly due to error.
+  };
+
+  // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+  //! Registers the handler for socket output
+  virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
+
+  //! Provides socket input to the engine
+  virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
+
+  //! Advises the engine that the socket has closed
+  virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
+
+  // SESSION SETUP ---------------------------------------------------------
+
+  //! Indicates the (bare) JID for the user to use.
+  virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
+
+  //! Get the login (bare) JID.
+  virtual const Jid & GetUser() = 0;
+
+  //! Provides different methods for credentials for login.
+  //! Takes ownership of this object; deletes when login is done
+  virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
+
+  //! Sets whether TLS will be used within the connection (default true).
+  virtual XmppReturnStatus SetTls(TlsOptions useTls) = 0;
+
+  //! Sets an alternate domain from which we allows TLS certificates.
+  //! This is for use in the case where a we want to allow a proxy to
+  //! serve up its own certificate rather than one owned by the underlying
+  //! domain.
+  virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname, 
+                                        const std::string & proxy_domain) = 0;
+
+  //! Gets whether TLS will be used within the connection.
+  virtual TlsOptions GetTls() = 0;
+
+  //! Sets the request resource name, if any (optional).
+  //! Note that the resource name may be overridden by the server; after
+  //! binding, the actual resource name is available as part of FullJid().
+  virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
+
+  //! Gets the request resource name.
+  virtual const std::string & GetRequestedResource() = 0;
+
+  //! Sets language
+  virtual void SetLanguage(const std::string & lang) = 0;
+
+  // SESSION MANAGEMENT ---------------------------------------------------
+
+  //! Set callback for state changes.
+  virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
+
+  //! Initiates the XMPP connection.
+  //! After supplying connection settings, call this once to initiate,
+  //! (optionally) encrypt, authenticate, and bind the connection.
+  virtual XmppReturnStatus Connect() = 0;
+
+  //! The current engine state.
+  virtual State GetState() = 0;
+
+  //! Returns true if the connection is encrypted (under TLS)
+  virtual bool IsEncrypted() = 0;
+
+  //! The error code.
+  //! Consult this after XmppOutputHandler.OnClose().
+  virtual Error GetError(int *subcode) = 0;
+
+  //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
+  //! Notice the stanza returned is owned by the XmppEngine and
+  //! is deleted when the engine is destroyed.
+  virtual const XmlElement * GetStreamError() = 0;
+
+  //! Closes down the connection.
+  //! Sends CloseConnection to output, and disconnects and registered
+  //! session handlers.  After Disconnect completes, it is guaranteed
+  //! that no further callbacks will be made.
+  virtual XmppReturnStatus Disconnect() = 0;
+
+  // APPLICATION USE -------------------------------------------------------
+
+  enum HandlerLevel {
+    HL_NONE = 0,
+    HL_PEEK,   //!< Sees messages before all other processing; cannot abort
+    HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
+    HL_SENDER, //!< Watches for a type of message from a specific sender
+    HL_TYPE,   //!< Watches a type of message, e.g., all groupchat msgs
+    HL_ALL,    //!< Watches all messages - gets last shot
+    HL_COUNT,  //!< Count of handler levels
+  };
+
+  //! Adds a listener for session events.
+  //! Stanza delivery is chained to session handlers; the first to
+  //! return 'true' is the last to get each stanza.
+  virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
+
+  //! Removes a listener for session events.
+  virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
+
+  //! Sends a stanza to the server.
+  virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
+
+  //! Sends raw text to the server
+  virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
+
+  //! Sends an iq to the server, and registers a callback for the result.
+  //! Returns the cookie passed to the result handler.
+  virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
+                                  XmppIqHandler* iq_handler,
+                                  XmppIqCookie* cookie) = 0;
+
+  //! Unregisters an iq callback handler given its cookie.
+  //! No callback will come to this handler after it's unregistered.
+  virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+                                      XmppIqHandler** iq_handler) = 0;
+
+
+  //! Forms and sends an error in response to the given stanza.
+  //! Swaps to and from, sets type to "error", and adds error information
+  //! based on the passed code.  Text is optional and may be STR_EMPTY.
+  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+                                           XmppStanzaError code,
+                                           const std::string & text) = 0;
+
+  //! The fullly bound JID.
+  //! This JID is only valid after binding has succeeded.  If the value
+  //! is JID_NULL, the binding has not succeeded.
+  virtual const Jid & FullJid() = 0;
+
+  //! The next unused iq id for this connection.
+  //! Call this when building iq stanzas, to ensure that each iq
+  //! gets its own unique id.
+  virtual std::string NextId() = 0;
+
+};
+
+}
+
+
+// Move these to a better location
+
+#define XMPP_FAILED(x)                      \
+  ( (x) == buzz::XMPP_RETURN_OK ? false : true)   \
+
+
+#define XMPP_SUCCEEDED(x)                   \
+  ( (x) == buzz::XMPP_RETURN_OK ? true : false)   \
+
+#define IFR(x)                        \
+  do {                                \
+    xmpp_status = (x);                \
+    if (XMPP_FAILED(xmpp_status)) {   \
+      return xmpp_status;             \
+    }                                 \
+  } while (false)                     \
+
+
+#define IFC(x)                        \
+  do {                                \
+    xmpp_status = (x);                \
+    if (XMPP_FAILED(xmpp_status)) {   \
+      goto Cleanup;                   \
+    }                                 \
+  } while (false)                     \
+
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
diff --git a/libjingle/xmpp/xmppengine_unittest.cc b/libjingle/xmpp/xmppengine_unittest.cc
new file mode 100644
index 0000000..7af151b
--- /dev/null
+++ b/libjingle/xmpp/xmppengine_unittest.cc
@@ -0,0 +1,325 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/plainsaslhandler.h"
+#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
+#include "webrtc/libjingle/xmpp/util_unittest.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/gunit.h"
+
+using buzz::Jid;
+using buzz::QName;
+using buzz::XmlElement;
+using buzz::XmppEngine;
+using buzz::XmppIqCookie;
+using buzz::XmppIqHandler;
+using buzz::XmppTestHandler;
+using buzz::QN_ID;
+using buzz::QN_IQ;
+using buzz::QN_TYPE;
+using buzz::QN_ROSTER_QUERY;
+using buzz::XMPP_RETURN_OK;
+using buzz::XMPP_RETURN_BADARGUMENT;
+
+// XmppEngineTestIqHandler
+//    This class grabs the response to an IQ stanza and stores it in a string.
+class XmppEngineTestIqHandler : public XmppIqHandler {
+ public:
+  virtual void IqResponse(XmppIqCookie, const XmlElement * stanza) {
+    ss_ << stanza->Str();
+  }
+
+  std::string IqResponseActivity() {
+    std::string result = ss_.str();
+    ss_.str("");
+    return result;
+  }
+
+ private:
+  std::stringstream ss_;
+};
+
+class XmppEngineTest : public testing::Test {
+ public:
+  XmppEngine* engine() { return engine_.get(); }
+  XmppTestHandler* handler() { return handler_.get(); }
+  virtual void SetUp() {
+    engine_.reset(XmppEngine::Create());
+    handler_.reset(new XmppTestHandler(engine_.get()));
+
+    Jid jid("david@my-server");
+    rtc::InsecureCryptStringImpl pass;
+    pass.password() = "david";
+    engine_->SetSessionHandler(handler_.get());
+    engine_->SetOutputHandler(handler_.get());
+    engine_->AddStanzaHandler(handler_.get());
+    engine_->SetUser(jid);
+    engine_->SetSaslHandler(
+        new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true));
+  }
+  virtual void TearDown() {
+    handler_.reset();
+    engine_.reset();
+  }
+  void RunLogin();
+
+ private:
+  rtc::scoped_ptr<XmppEngine> engine_;
+  rtc::scoped_ptr<XmppTestHandler> handler_;
+};
+
+void XmppEngineTest::RunLogin() {
+  // Connect
+  EXPECT_EQ(XmppEngine::STATE_START, engine()->GetState());
+  engine()->Connect();
+  EXPECT_EQ(XmppEngine::STATE_OPENING, engine()->GetState());
+
+  EXPECT_EQ("[OPENING]", handler_->SessionActivity());
+
+  EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" "
+           "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+           "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+
+  std::string input =
+    "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+    "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+    "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  input =
+    "<stream:features>"
+      "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>"
+        "<required/>"
+      "</starttls>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+    "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
+      handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("[START-TLS my-server]"
+           "<stream:stream to=\"my-server\" xml:lang=\"*\" "
+           "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+           "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<stream:stream id=\"01234567\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  input =
+    "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+    "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" "
+      "auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>",
+      handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<stream:stream id=\"01234567\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  input = "<stream:features>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
+          "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
+          "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<iq type=\"set\" id=\"0\">"
+           "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>",
+           handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<iq type='result' id='0'>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>"
+          "david@my-server/test</jid></bind></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<iq type=\"set\" id=\"1\">"
+           "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>",
+           handler_->OutputActivity());
+
+  EXPECT_EQ("", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+
+  input = "<iq type='result' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[OPEN]", handler_->SessionActivity());
+  EXPECT_EQ("", handler_->StanzaActivity());
+  EXPECT_EQ(Jid("david@my-server/test"), engine()->FullJid());
+}
+
+// TestSuccessfulLogin()
+//    This function simply tests to see if a login works.  This includes
+//    encryption and authentication
+TEST_F(XmppEngineTest, TestSuccessfulLoginAndDisconnect) {
+  RunLogin();
+  engine()->Disconnect();
+  EXPECT_EQ("</stream:stream>[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppEngineTest, TestSuccessfulLoginAndConnectionClosed) {
+  RunLogin();
+  engine()->ConnectionClosed(0);
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-CONNECTION-CLOSED]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+
+// TestNotXmpp()
+//    This tests the error case when connecting to a non XMPP service
+TEST_F(XmppEngineTest, TestNotXmpp) {
+  // Connect
+  engine()->Connect();
+  EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler()->OutputActivity());
+
+  // Send garbage response (courtesy of apache)
+  std::string input = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[OPENING][CLOSED][ERROR-XML]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+// TestPassthrough()
+//    This tests that arbitrary stanzas can be passed to the server through
+//    the engine.
+TEST_F(XmppEngineTest, TestPassthrough) {
+  // Queue up an app stanza
+  XmlElement application_stanza(QName("test", "app-stanza"));
+  application_stanza.AddText("this-is-a-test");
+  engine()->SendStanza(&application_stanza);
+
+  // Do the whole login handshake
+  RunLogin();
+
+  EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test"
+          "</test:app-stanza>", handler()->OutputActivity());
+
+  // do another stanza
+  XmlElement roster_get(QN_IQ);
+  roster_get.AddAttr(QN_TYPE, "get");
+  roster_get.AddAttr(QN_ID, engine()->NextId());
+  roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+  engine()->SendStanza(&roster_get);
+  EXPECT_EQ("<iq type=\"get\" id=\"2\"><query xmlns=\"jabber:iq:roster\"/>"
+          "</iq>", handler()->OutputActivity());
+
+  // now say the server ends the stream
+  engine()->HandleInput("</stream:stream>", 16);
+  EXPECT_EQ("[CLOSED][ERROR-DOCUMENT-CLOSED]", handler()->SessionActivity());
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+// TestIqCallback()
+//    This tests the routing of Iq stanzas and responses.
+TEST_F(XmppEngineTest, TestIqCallback) {
+  XmppEngineTestIqHandler iq_response;
+  XmppIqCookie cookie;
+
+  // Do the whole login handshake
+  RunLogin();
+
+  // Build an iq request
+  XmlElement roster_get(QN_IQ);
+  roster_get.AddAttr(QN_TYPE, "get");
+  roster_get.AddAttr(QN_ID, engine()->NextId());
+  roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true));
+  engine()->SendIq(&roster_get, &iq_response, &cookie);
+  EXPECT_EQ("<iq type=\"get\" id=\"2\"><query xmlns=\"jabber:iq:roster\"/>"
+          "</iq>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+  EXPECT_EQ("", iq_response.IqResponseActivity());
+
+  // now say the server responds to the iq
+  std::string input = "<iq type='result' id='2'>"
+                      "<query xmlns='jabber:iq:roster'><item>foo</item>"
+                      "</query></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+  EXPECT_EQ("<cli:iq type=\"result\" id=\"2\" xmlns:cli=\"jabber:client\">"
+          "<query xmlns=\"jabber:iq:roster\"><item>foo</item></query>"
+          "</cli:iq>", iq_response.IqResponseActivity());
+
+  EXPECT_EQ(XMPP_RETURN_BADARGUMENT, engine()->RemoveIqHandler(cookie, NULL));
+
+  // Do it again with another id to test cancel
+  roster_get.SetAttr(QN_ID, engine()->NextId());
+  engine()->SendIq(&roster_get, &iq_response, &cookie);
+  EXPECT_EQ("<iq type=\"get\" id=\"3\"><query xmlns=\"jabber:iq:roster\"/>"
+          "</iq>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+  EXPECT_EQ("", iq_response.IqResponseActivity());
+
+  // cancel the handler this time
+  EXPECT_EQ(XMPP_RETURN_OK, engine()->RemoveIqHandler(cookie, NULL));
+
+  // now say the server responds to the iq: the iq handler should not get it.
+  input = "<iq type='result' id='3'><query xmlns='jabber:iq:roster'><item>bar"
+          "</item></query></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("<cli:iq type=\"result\" id=\"3\" xmlns:cli=\"jabber:client\">"
+          "<query xmlns=\"jabber:iq:roster\"><item>bar</item></query>"
+          "</cli:iq>", handler()->StanzaActivity());
+  EXPECT_EQ("", iq_response.IqResponseActivity());
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+}
diff --git a/libjingle/xmpp/xmppengineimpl.cc b/libjingle/xmpp/xmppengineimpl.cc
new file mode 100644
index 0000000..e77a1d9
--- /dev/null
+++ b/libjingle/xmpp/xmppengineimpl.cc
@@ -0,0 +1,446 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/xmppengineimpl.h"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmllite/xmlprinter.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/saslhandler.h"
+#include "webrtc/libjingle/xmpp/xmpplogintask.h"
+#include "webrtc/base/common.h"
+
+namespace buzz {
+
+XmppEngine* XmppEngine::Create() {
+  return new XmppEngineImpl();
+}
+
+
+XmppEngineImpl::XmppEngineImpl()
+    : stanza_parse_handler_(this),
+      stanza_parser_(&stanza_parse_handler_),
+      engine_entered_(0),
+      password_(),
+      requested_resource_(STR_EMPTY),
+      tls_option_(buzz::TLS_REQUIRED),
+      login_task_(new XmppLoginTask(this)),
+      next_id_(0),
+      state_(STATE_START),
+      encrypted_(false),
+      error_code_(ERROR_NONE),
+      subcode_(0),
+      stream_error_(),
+      raised_reset_(false),
+      output_handler_(NULL),
+      session_handler_(NULL),
+      iq_entries_(new IqEntryVector()),
+      sasl_handler_(),
+      output_(new std::stringstream()) {
+  for (int i = 0; i < HL_COUNT; i+= 1) {
+    stanza_handlers_[i].reset(new StanzaHandlerVector());
+  }
+
+  // Add XMPP namespaces to XML namespaces stack.
+  xmlns_stack_.AddXmlns("stream", "http://etherx.jabber.org/streams");
+  xmlns_stack_.AddXmlns("", "jabber:client");
+}
+
+XmppEngineImpl::~XmppEngineImpl() {
+  DeleteIqCookies();
+}
+
+XmppReturnStatus XmppEngineImpl::SetOutputHandler(
+    XmppOutputHandler* output_handler) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  output_handler_ = output_handler;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetSessionHandler(
+    XmppSessionHandler* session_handler) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  session_handler_ = session_handler;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::HandleInput(
+    const char* bytes, size_t len) {
+  if (state_ < STATE_OPENING || state_ > STATE_OPEN)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  // TODO: The return value of the xml parser is not checked.
+  stanza_parser_.Parse(bytes, len, false);
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::ConnectionClosed(int subcode) {
+  if (state_ != STATE_CLOSED) {
+    EnterExit ee(this);
+    // If told that connection closed and not already closed,
+    // then connection was unpexectedly dropped.
+    if (subcode) {
+      SignalError(ERROR_SOCKET, subcode);
+    } else {
+      SignalError(ERROR_CONNECTION_CLOSED, 0);  // no subcode
+    }
+  }
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetTls(TlsOptions use_tls) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+  tls_option_ = use_tls;
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetTlsServer(
+    const std::string& tls_server_hostname,
+    const std::string& tls_server_domain) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  tls_server_hostname_ = tls_server_hostname;
+  tls_server_domain_= tls_server_domain;
+
+  return XMPP_RETURN_OK;
+}
+
+TlsOptions XmppEngineImpl::GetTls() {
+  return tls_option_;
+}
+
+XmppReturnStatus XmppEngineImpl::SetUser(const Jid& jid) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  user_jid_ = jid;
+
+  return XMPP_RETURN_OK;
+}
+
+const Jid& XmppEngineImpl::GetUser() {
+  return user_jid_;
+}
+
+XmppReturnStatus XmppEngineImpl::SetSaslHandler(SaslHandler* sasl_handler) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  sasl_handler_.reset(sasl_handler);
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SetRequestedResource(
+    const std::string& resource) {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  requested_resource_ = resource;
+
+  return XMPP_RETURN_OK;
+}
+
+const std::string& XmppEngineImpl::GetRequestedResource() {
+  return requested_resource_;
+}
+
+XmppReturnStatus XmppEngineImpl::AddStanzaHandler(
+    XmppStanzaHandler* stanza_handler,
+    XmppEngine::HandlerLevel level) {
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+
+  stanza_handlers_[level]->push_back(stanza_handler);
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::RemoveStanzaHandler(
+    XmppStanzaHandler* stanza_handler) {
+  bool found = false;
+
+  for (int level = 0; level < HL_COUNT; level += 1) {
+    StanzaHandlerVector::iterator new_end =
+      std::remove(stanza_handlers_[level]->begin(),
+      stanza_handlers_[level]->end(),
+      stanza_handler);
+
+    if (new_end != stanza_handlers_[level]->end()) {
+      stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end());
+      found = true;
+    }
+  }
+
+  if (!found)
+    return XMPP_RETURN_BADARGUMENT;
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::Connect() {
+  if (state_ != STATE_START)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  // get the login task started
+  state_ = STATE_OPENING;
+  if (login_task_) {
+    login_task_->IncomingStanza(NULL, false);
+    if (login_task_->IsDone())
+      login_task_.reset();
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SendStanza(const XmlElement* element) {
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  if (login_task_) {
+    // still handshaking - then outbound stanzas are queued
+    login_task_->OutgoingStanza(element);
+  } else {
+    // handshake done - send straight through
+    InternalSendStanza(element);
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+XmppReturnStatus XmppEngineImpl::SendRaw(const std::string& text) {
+  if (state_ == STATE_CLOSED || login_task_)
+    return XMPP_RETURN_BADSTATE;
+
+  EnterExit ee(this);
+
+  (*output_) << text;
+
+  return XMPP_RETURN_OK;
+}
+
+std::string XmppEngineImpl::NextId() {
+  std::stringstream ss;
+  ss << next_id_++;
+  return ss.str();
+}
+
+XmppReturnStatus XmppEngineImpl::Disconnect() {
+  if (state_ != STATE_CLOSED) {
+    EnterExit ee(this);
+    if (state_ == STATE_OPEN)
+      *output_ << "</stream:stream>";
+    state_ = STATE_CLOSED;
+  }
+
+  return XMPP_RETURN_OK;
+}
+
+void XmppEngineImpl::IncomingStart(const XmlElement* start) {
+  if (HasError() || raised_reset_)
+    return;
+
+  if (login_task_) {
+    // start-stream should go to login task
+    login_task_->IncomingStanza(start, true);
+    if (login_task_->IsDone())
+      login_task_.reset();
+  }
+  else {
+    // if not logging in, it's an error to see a start
+    SignalError(ERROR_XML, 0);
+  }
+}
+
+void XmppEngineImpl::IncomingStanza(const XmlElement* stanza) {
+  if (HasError() || raised_reset_)
+    return;
+
+  if (stanza->Name() == QN_STREAM_ERROR) {
+    // Explicit XMPP stream error
+    SignalStreamError(stanza);
+  } else if (login_task_) {
+    // Handle login handshake
+    login_task_->IncomingStanza(stanza, false);
+    if (login_task_->IsDone())
+      login_task_.reset();
+  } else if (HandleIqResponse(stanza)) {
+    // iq is handled by above call
+  } else {
+    // give every "peek" handler a shot at all stanzas
+    for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) {
+      (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza);
+    }
+
+    // give other handlers a shot in precedence order, stopping after handled
+    for (int level = HL_SINGLE; level <= HL_ALL; level += 1) {
+      for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) {
+        if ((*stanza_handlers_[level])[i]->HandleStanza(stanza))
+          return;
+      }
+    }
+
+    // If nobody wants to handle a stanza then send back an error.
+    // Only do this for IQ stanzas as messages should probably just be dropped
+    // and presence stanzas should certainly be dropped.
+    std::string type = stanza->Attr(QN_TYPE);
+    if (stanza->Name() == QN_IQ &&
+        !(type == "error" || type == "result")) {
+      SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY);
+    }
+  }
+}
+
+void XmppEngineImpl::IncomingEnd(bool isError) {
+  if (HasError() || raised_reset_)
+    return;
+
+  SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED, 0);
+}
+
+void XmppEngineImpl::InternalSendStart(const std::string& to) {
+  std::string hostname = tls_server_hostname_;
+  if (hostname.empty())
+    hostname = to;
+
+  // If not language is specified, the spec says use *
+  std::string lang = lang_;
+  if (lang.length() == 0)
+    lang = "*";
+
+  // send stream-beginning
+  // note, we put a \r\n at tne end fo the first line to cause non-XMPP
+  // line-oriented servers (e.g., Apache) to reveal themselves more quickly.
+  *output_ << "<stream:stream to=\"" << hostname << "\" "
+           << "xml:lang=\"" << lang << "\" "
+           << "version=\"1.0\" "
+           << "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+           << "xmlns=\"jabber:client\">\r\n";
+}
+
+void XmppEngineImpl::InternalSendStanza(const XmlElement* element) {
+  // It should really never be necessary to set a FROM attribute on a stanza.
+  // It is implied by the bind on the stream and if you get it wrong
+  // (by flipping from/to on a message?) the server will close the stream.
+  ASSERT(!element->HasAttr(QN_FROM));
+
+  XmlPrinter::PrintXml(output_.get(), element, &xmlns_stack_);
+}
+
+std::string XmppEngineImpl::ChooseBestSaslMechanism(
+    const std::vector<std::string>& mechanisms, bool encrypted) {
+  return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted);
+}
+
+SaslMechanism* XmppEngineImpl::GetSaslMechanism(const std::string& name) {
+  return sasl_handler_->CreateSaslMechanism(name);
+}
+
+void XmppEngineImpl::SignalBound(const Jid& fullJid) {
+  if (state_ == STATE_OPENING) {
+    bound_jid_ = fullJid;
+    state_ = STATE_OPEN;
+  }
+}
+
+void XmppEngineImpl::SignalStreamError(const XmlElement* stream_error) {
+  if (state_ != STATE_CLOSED) {
+    stream_error_.reset(new XmlElement(*stream_error));
+    SignalError(ERROR_STREAM, 0);
+  }
+}
+
+void XmppEngineImpl::SignalError(Error error_code, int sub_code) {
+  if (state_ != STATE_CLOSED) {
+    error_code_ = error_code;
+    subcode_ = sub_code;
+    state_ = STATE_CLOSED;
+  }
+}
+
+bool XmppEngineImpl::HasError() {
+  return error_code_ != ERROR_NONE;
+}
+
+void XmppEngineImpl::StartTls(const std::string& domain) {
+  if (output_handler_) {
+    // As substitute for the real (login jid's) domain, we permit
+    // verifying a tls_server_domain_ instead, if one was passed.
+    // This allows us to avoid running a proxy that needs to handle
+    // valuable certificates.
+    output_handler_->StartTls(
+      tls_server_domain_.empty() ? domain : tls_server_domain_);
+    encrypted_ = true;
+  }
+}
+
+XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
+    : engine_(engine),
+      state_(engine->state_) {
+  engine->engine_entered_ += 1;
+}
+
+XmppEngineImpl::EnterExit::~EnterExit()  {
+ XmppEngineImpl* engine = engine_;
+
+ engine->engine_entered_ -= 1;
+
+ bool closing = (engine->state_ != state_ &&
+       engine->state_ == STATE_CLOSED);
+ bool flushing = closing || (engine->engine_entered_ == 0);
+
+ if (engine->output_handler_ && flushing) {
+   std::string output = engine->output_->str();
+   if (output.length() > 0)
+     engine->output_handler_->WriteOutput(output.c_str(), output.length());
+   engine->output_->str("");
+
+   if (closing) {
+     engine->output_handler_->CloseConnection();
+     engine->output_handler_ = 0;
+   }
+ }
+
+ if (engine->engine_entered_)
+   return;
+
+ if (engine->raised_reset_) {
+   engine->stanza_parser_.Reset();
+   engine->raised_reset_ = false;
+ }
+
+ if (engine->session_handler_) {
+   if (engine->state_ != state_)
+     engine->session_handler_->OnStateChange(engine->state_);
+   // Note: Handling of OnStateChange(CLOSED) should allow for the
+   // deletion of the engine, so no members should be accessed
+   // after this line.
+ }
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/xmppengineimpl.h b/libjingle/xmpp/xmppengineimpl.h
new file mode 100644
index 0000000..c322596
--- /dev/null
+++ b/libjingle/xmpp/xmppengineimpl.h
@@ -0,0 +1,265 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
+
+#include <sstream>
+#include <vector>
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmppstanzaparser.h"
+
+namespace buzz {
+
+class XmppLoginTask;
+class XmppEngine;
+class XmppIqEntry;
+class SaslHandler;
+class SaslMechanism;
+
+//! The XMPP connection engine.
+//! This engine implements the client side of the 'core' XMPP protocol.
+//! To use it, register an XmppOutputHandler to handle socket output
+//! and pass socket input to HandleInput.  Then application code can
+//! set up the connection with a user, password, and other settings,
+//! and then call Connect() to initiate the connection.
+//! An application can listen for events and receive stanzas by
+//! registering an XmppStanzaHandler via AddStanzaHandler().
+class XmppEngineImpl : public XmppEngine {
+ public:
+  XmppEngineImpl();
+  virtual ~XmppEngineImpl();
+
+  // SOCKET INPUT AND OUTPUT ------------------------------------------------
+
+  //! Registers the handler for socket output
+  virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh);
+
+  //! Provides socket input to the engine
+  virtual XmppReturnStatus HandleInput(const char* bytes, size_t len);
+
+  //! Advises the engine that the socket has closed
+  virtual XmppReturnStatus ConnectionClosed(int subcode);
+
+  // SESSION SETUP ---------------------------------------------------------
+
+  //! Indicates the (bare) JID for the user to use.
+  virtual XmppReturnStatus SetUser(const Jid& jid);
+
+  //! Get the login (bare) JID.
+  virtual const Jid& GetUser();
+
+  //! Indicates the autentication to use.  Takes ownership of the object.
+  virtual XmppReturnStatus SetSaslHandler(SaslHandler* sasl_handler);
+
+  //! Sets whether TLS will be used within the connection (default true).
+  virtual XmppReturnStatus SetTls(TlsOptions use_tls);
+
+  //! Sets an alternate domain from which we allows TLS certificates.
+  //! This is for use in the case where a we want to allow a proxy to
+  //! serve up its own certificate rather than one owned by the underlying
+  //! domain.
+  virtual XmppReturnStatus SetTlsServer(const std::string& proxy_hostname,
+                                        const std::string& proxy_domain);
+
+  //! Gets whether TLS will be used within the connection.
+  virtual TlsOptions GetTls();
+
+  //! Sets the request resource name, if any (optional).
+  //! Note that the resource name may be overridden by the server; after
+  //! binding, the actual resource name is available as part of FullJid().
+  virtual XmppReturnStatus SetRequestedResource(const std::string& resource);
+
+  //! Gets the request resource name.
+  virtual const std::string& GetRequestedResource();
+
+  //! Sets language
+  virtual void SetLanguage(const std::string& lang) {
+    lang_ = lang;
+  }
+
+  // SESSION MANAGEMENT ---------------------------------------------------
+
+  //! Set callback for state changes.
+  virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler);
+
+  //! Initiates the XMPP connection.
+  //! After supplying connection settings, call this once to initiate,
+  //! (optionally) encrypt, authenticate, and bind the connection.
+  virtual XmppReturnStatus Connect();
+
+  //! The current engine state.
+  virtual State GetState() { return state_; }
+
+  //! Returns true if the connection is encrypted (under TLS)
+  virtual bool IsEncrypted() { return encrypted_; }
+
+  //! The error code.
+  //! Consult this after XmppOutputHandler.OnClose().
+  virtual Error GetError(int *subcode) {
+     if (subcode) {
+       *subcode = subcode_;
+     }
+     return error_code_;
+  }
+
+  //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
+  //! Notice the stanza returned is owned by the XmppEngine and
+  //! is deleted when the engine is destroyed.
+  virtual const XmlElement* GetStreamError() { return stream_error_.get(); }
+
+  //! Closes down the connection.
+  //! Sends CloseConnection to output, and disconnects and registered
+  //! session handlers.  After Disconnect completes, it is guaranteed
+  //! that no further callbacks will be made.
+  virtual XmppReturnStatus Disconnect();
+
+  // APPLICATION USE -------------------------------------------------------
+
+  //! Adds a listener for session events.
+  //! Stanza delivery is chained to session handlers; the first to
+  //! return 'true' is the last to get each stanza.
+  virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler,
+                                            XmppEngine::HandlerLevel level);
+
+  //! Removes a listener for session events.
+  virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler);
+
+  //! Sends a stanza to the server.
+  virtual XmppReturnStatus SendStanza(const XmlElement* stanza);
+
+  //! Sends raw text to the server
+  virtual XmppReturnStatus SendRaw(const std::string& text);
+
+  //! Sends an iq to the server, and registers a callback for the result.
+  //! Returns the cookie passed to the result handler.
+  virtual XmppReturnStatus SendIq(const XmlElement* stanza,
+                                  XmppIqHandler* iq_handler,
+                                  XmppIqCookie* cookie);
+
+  //! Unregisters an iq callback handler given its cookie.
+  //! No callback will come to this handler after it's unregistered.
+  virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
+                                      XmppIqHandler** iq_handler);
+
+  //! Forms and sends an error in response to the given stanza.
+  //! Swaps to and from, sets type to "error", and adds error information
+  //! based on the passed code.  Text is optional and may be STR_EMPTY.
+  virtual XmppReturnStatus SendStanzaError(const XmlElement* pelOriginal,
+                                           XmppStanzaError code,
+                                           const std::string& text);
+
+  //! The fullly bound JID.
+  //! This JID is only valid after binding has succeeded.  If the value
+  //! is JID_NULL, the binding has not succeeded.
+  virtual const Jid& FullJid() { return bound_jid_; }
+
+  //! The next unused iq id for this connection.
+  //! Call this when building iq stanzas, to ensure that each iq
+  //! gets its own unique id.
+  virtual std::string NextId();
+
+ private:
+  friend class XmppLoginTask;
+  friend class XmppIqEntry;
+
+  void IncomingStanza(const XmlElement *stanza);
+  void IncomingStart(const XmlElement *stanza);
+  void IncomingEnd(bool isError);
+
+  void InternalSendStart(const std::string& domainName);
+  void InternalSendStanza(const XmlElement* stanza);
+  std::string ChooseBestSaslMechanism(
+      const std::vector<std::string>& mechanisms, bool encrypted);
+  SaslMechanism* GetSaslMechanism(const std::string& name);
+  void SignalBound(const Jid& fullJid);
+  void SignalStreamError(const XmlElement* streamError);
+  void SignalError(Error errorCode, int subCode);
+  bool HasError();
+  void DeleteIqCookies();
+  bool HandleIqResponse(const XmlElement* element);
+  void StartTls(const std::string& domain);
+  void RaiseReset() { raised_reset_ = true; }
+
+  class StanzaParseHandler : public XmppStanzaParseHandler {
+   public:
+    StanzaParseHandler(XmppEngineImpl* outer) : outer_(outer) {}
+    virtual ~StanzaParseHandler() {}
+
+    virtual void StartStream(const XmlElement* stream) {
+      outer_->IncomingStart(stream);
+    }
+    virtual void Stanza(const XmlElement* stanza) {
+      outer_->IncomingStanza(stanza);
+    }
+    virtual void EndStream() {
+      outer_->IncomingEnd(false);
+    }
+    virtual void XmlError() {
+      outer_->IncomingEnd(true);
+    }
+
+   private:
+    XmppEngineImpl* const outer_;
+  };
+
+  class EnterExit {
+   public:
+    EnterExit(XmppEngineImpl* engine);
+    ~EnterExit();
+   private:
+    XmppEngineImpl* engine_;
+    State state_;
+  };
+
+  friend class StanzaParseHandler;
+  friend class EnterExit;
+
+  StanzaParseHandler stanza_parse_handler_;
+  XmppStanzaParser stanza_parser_;
+
+  // state
+  int engine_entered_;
+  Jid user_jid_;
+  std::string password_;
+  std::string requested_resource_;
+  TlsOptions tls_option_;
+  std::string tls_server_hostname_;
+  std::string tls_server_domain_;
+  rtc::scoped_ptr<XmppLoginTask> login_task_;
+  std::string lang_;
+
+  int next_id_;
+  Jid bound_jid_;
+  State state_;
+  bool encrypted_;
+  Error error_code_;
+  int subcode_;
+  rtc::scoped_ptr<XmlElement> stream_error_;
+  bool raised_reset_;
+  XmppOutputHandler* output_handler_;
+  XmppSessionHandler* session_handler_;
+
+  XmlnsStack xmlns_stack_;
+
+  typedef std::vector<XmppStanzaHandler*> StanzaHandlerVector;
+  rtc::scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT];
+
+  typedef std::vector<XmppIqEntry*> IqEntryVector;
+  rtc::scoped_ptr<IqEntryVector> iq_entries_;
+
+  rtc::scoped_ptr<SaslHandler> sasl_handler_;
+
+  rtc::scoped_ptr<std::stringstream> output_;
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
diff --git a/libjingle/xmpp/xmppengineimpl_iq.cc b/libjingle/xmpp/xmppengineimpl_iq.cc
new file mode 100644
index 0000000..23b9fc4
--- /dev/null
+++ b/libjingle/xmpp/xmppengineimpl_iq.cc
@@ -0,0 +1,260 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <algorithm>
+#include <vector>
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/xmppengineimpl.h"
+#include "webrtc/base/common.h"
+
+namespace buzz {
+
+class XmppIqEntry {
+  XmppIqEntry(const std::string & id, const std::string & to,
+               XmppEngine * pxce, XmppIqHandler * iq_handler) :
+    id_(id),
+    to_(to),
+    engine_(pxce),
+    iq_handler_(iq_handler) {
+  }
+
+private:
+  friend class XmppEngineImpl;
+
+  const std::string id_;
+  const std::string to_;
+  XmppEngine * const engine_;
+  XmppIqHandler * const iq_handler_;
+};
+
+
+XmppReturnStatus
+XmppEngineImpl::SendIq(const XmlElement * element, XmppIqHandler * iq_handler,
+  XmppIqCookie* cookie) {
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+  if (NULL == iq_handler)
+    return XMPP_RETURN_BADARGUMENT;
+  if (!element || element->Name() != QN_IQ)
+    return XMPP_RETURN_BADARGUMENT;
+
+  const std::string& type = element->Attr(QN_TYPE);
+  if (type != "get" && type != "set")
+    return XMPP_RETURN_BADARGUMENT;
+
+  if (!element->HasAttr(QN_ID))
+    return XMPP_RETURN_BADARGUMENT;
+  const std::string& id = element->Attr(QN_ID);
+
+  XmppIqEntry * iq_entry = new XmppIqEntry(id,
+                                              element->Attr(QN_TO),
+                                              this, iq_handler);
+  iq_entries_->push_back(iq_entry);
+  SendStanza(element);
+
+  if (cookie)
+    *cookie = iq_entry;
+
+  return XMPP_RETURN_OK;
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::RemoveIqHandler(XmppIqCookie cookie,
+    XmppIqHandler ** iq_handler) {
+
+  std::vector<XmppIqEntry*, std::allocator<XmppIqEntry*> >::iterator pos;
+
+  pos = std::find(iq_entries_->begin(),
+                  iq_entries_->end(),
+                  reinterpret_cast<XmppIqEntry*>(cookie));
+
+  if (pos == iq_entries_->end())
+    return XMPP_RETURN_BADARGUMENT;
+
+  XmppIqEntry* entry = *pos;
+  iq_entries_->erase(pos);
+  if (iq_handler)
+    *iq_handler = entry->iq_handler_;
+  delete entry;
+
+  return XMPP_RETURN_OK;
+}
+
+void
+XmppEngineImpl::DeleteIqCookies() {
+  for (size_t i = 0; i < iq_entries_->size(); i += 1) {
+    XmppIqEntry * iq_entry_ = (*iq_entries_)[i];
+    (*iq_entries_)[i] = NULL;
+    delete iq_entry_;
+  }
+  iq_entries_->clear();
+}
+
+static void
+AecImpl(XmlElement * error_element, const QName & name,
+        const char * type, const char * code) {
+  error_element->AddElement(new XmlElement(QN_ERROR));
+  error_element->AddAttr(QN_CODE, code, 1);
+  error_element->AddAttr(QN_TYPE, type, 1);
+  error_element->AddElement(new XmlElement(name, true), 1);
+}
+
+
+static void
+AddErrorCode(XmlElement * error_element, XmppStanzaError code) {
+  switch (code) {
+    case XSE_BAD_REQUEST:
+      AecImpl(error_element, QN_STANZA_BAD_REQUEST, "modify", "400");
+      break;
+    case XSE_CONFLICT:
+      AecImpl(error_element, QN_STANZA_CONFLICT, "cancel", "409");
+      break;
+    case XSE_FEATURE_NOT_IMPLEMENTED:
+      AecImpl(error_element, QN_STANZA_FEATURE_NOT_IMPLEMENTED,
+              "cancel", "501");
+      break;
+    case XSE_FORBIDDEN:
+      AecImpl(error_element, QN_STANZA_FORBIDDEN, "auth", "403");
+      break;
+    case XSE_GONE:
+      AecImpl(error_element, QN_STANZA_GONE, "modify", "302");
+      break;
+    case XSE_INTERNAL_SERVER_ERROR:
+      AecImpl(error_element, QN_STANZA_INTERNAL_SERVER_ERROR, "wait", "500");
+      break;
+    case XSE_ITEM_NOT_FOUND:
+      AecImpl(error_element, QN_STANZA_ITEM_NOT_FOUND, "cancel", "404");
+      break;
+    case XSE_JID_MALFORMED:
+      AecImpl(error_element, QN_STANZA_JID_MALFORMED, "modify", "400");
+      break;
+    case XSE_NOT_ACCEPTABLE:
+      AecImpl(error_element, QN_STANZA_NOT_ACCEPTABLE, "cancel", "406");
+      break;
+    case XSE_NOT_ALLOWED:
+      AecImpl(error_element, QN_STANZA_NOT_ALLOWED, "cancel", "405");
+      break;
+    case XSE_PAYMENT_REQUIRED:
+      AecImpl(error_element, QN_STANZA_PAYMENT_REQUIRED, "auth", "402");
+      break;
+    case XSE_RECIPIENT_UNAVAILABLE:
+      AecImpl(error_element, QN_STANZA_RECIPIENT_UNAVAILABLE, "wait", "404");
+      break;
+    case XSE_REDIRECT:
+      AecImpl(error_element, QN_STANZA_REDIRECT, "modify", "302");
+      break;
+    case XSE_REGISTRATION_REQUIRED:
+      AecImpl(error_element, QN_STANZA_REGISTRATION_REQUIRED, "auth", "407");
+      break;
+    case XSE_SERVER_NOT_FOUND:
+      AecImpl(error_element, QN_STANZA_REMOTE_SERVER_NOT_FOUND,
+              "cancel", "404");
+      break;
+    case XSE_SERVER_TIMEOUT:
+      AecImpl(error_element, QN_STANZA_REMOTE_SERVER_TIMEOUT, "wait", "502");
+      break;
+    case XSE_RESOURCE_CONSTRAINT:
+      AecImpl(error_element, QN_STANZA_RESOURCE_CONSTRAINT, "wait", "500");
+      break;
+    case XSE_SERVICE_UNAVAILABLE:
+      AecImpl(error_element, QN_STANZA_SERVICE_UNAVAILABLE, "cancel", "503");
+      break;
+    case XSE_SUBSCRIPTION_REQUIRED:
+      AecImpl(error_element, QN_STANZA_SUBSCRIPTION_REQUIRED, "auth", "407");
+      break;
+    case XSE_UNDEFINED_CONDITION:
+      AecImpl(error_element, QN_STANZA_UNDEFINED_CONDITION, "wait", "500");
+      break;
+    case XSE_UNEXPECTED_REQUEST:
+      AecImpl(error_element, QN_STANZA_UNEXPECTED_REQUEST, "wait", "400");
+      break;
+  }
+}
+
+
+XmppReturnStatus
+XmppEngineImpl::SendStanzaError(const XmlElement * element_original,
+                                XmppStanzaError code,
+                                const std::string & text) {
+
+  if (state_ == STATE_CLOSED)
+    return XMPP_RETURN_BADSTATE;
+
+  XmlElement error_element(element_original->Name());
+  error_element.AddAttr(QN_TYPE, "error");
+
+  // copy attrs, copy 'from' to 'to' and strip 'from'
+  for (const XmlAttr * attribute = element_original->FirstAttr();
+       attribute; attribute = attribute->NextAttr()) {
+    QName name = attribute->Name();
+    if (name == QN_TO)
+      continue; // no need to put a from attr.  Server will stamp stanza
+    else if (name == QN_FROM)
+      name = QN_TO;
+    else if (name == QN_TYPE)
+      continue;
+    error_element.AddAttr(name, attribute->Value());
+  }
+
+  // copy children
+  for (const XmlChild * child = element_original->FirstChild();
+       child;
+       child = child->NextChild()) {
+    if (child->IsText()) {
+      error_element.AddText(child->AsText()->Text());
+    } else {
+      error_element.AddElement(new XmlElement(*(child->AsElement())));
+    }
+  }
+
+  // add error information
+  AddErrorCode(&error_element, code);
+  if (text != STR_EMPTY) {
+    XmlElement * text_element = new XmlElement(QN_STANZA_TEXT, true);
+    text_element->AddText(text);
+    error_element.AddElement(text_element);
+  }
+
+  SendStanza(&error_element);
+
+  return XMPP_RETURN_OK;
+}
+
+
+bool
+XmppEngineImpl::HandleIqResponse(const XmlElement * element) {
+  if (iq_entries_->empty())
+    return false;
+  if (element->Name() != QN_IQ)
+    return false;
+  std::string type = element->Attr(QN_TYPE);
+  if (type != "result" && type != "error")
+    return false;
+  if (!element->HasAttr(QN_ID))
+    return false;
+  std::string id = element->Attr(QN_ID);
+  std::string from = element->Attr(QN_FROM);
+
+  for (std::vector<XmppIqEntry *>::iterator it = iq_entries_->begin();
+       it != iq_entries_->end(); it += 1) {
+    XmppIqEntry * iq_entry = *it;
+    if (iq_entry->id_ == id && iq_entry->to_ == from) {
+      iq_entries_->erase(it);
+      iq_entry->iq_handler_->IqResponse(iq_entry, element);
+      delete iq_entry;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+}
diff --git a/libjingle/xmpp/xmpplogintask.cc b/libjingle/xmpp/xmpplogintask.cc
new file mode 100644
index 0000000..f5745cd
--- /dev/null
+++ b/libjingle/xmpp/xmpplogintask.cc
@@ -0,0 +1,380 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/xmpplogintask.h"
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/saslmechanism.h"
+#include "webrtc/libjingle/xmpp/xmppengineimpl.h"
+#include "webrtc/base/base64.h"
+#include "webrtc/base/common.h"
+
+using rtc::ConstantLabel;
+
+namespace buzz {
+
+#ifdef _DEBUG
+const ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
+  KLABEL(LOGINSTATE_INIT),
+  KLABEL(LOGINSTATE_STREAMSTART_SENT),
+  KLABEL(LOGINSTATE_STARTED_XMPP),
+  KLABEL(LOGINSTATE_TLS_INIT),
+  KLABEL(LOGINSTATE_AUTH_INIT),
+  KLABEL(LOGINSTATE_BIND_INIT),
+  KLABEL(LOGINSTATE_TLS_REQUESTED),
+  KLABEL(LOGINSTATE_SASL_RUNNING),
+  KLABEL(LOGINSTATE_BIND_REQUESTED),
+  KLABEL(LOGINSTATE_SESSION_REQUESTED),
+  KLABEL(LOGINSTATE_DONE),
+  LASTLABEL
+};
+#endif  // _DEBUG
+XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
+  pctx_(pctx),
+  authNeeded_(true),
+  allowNonGoogleLogin_(true),
+  state_(LOGINSTATE_INIT),
+  pelStanza_(NULL),
+  isStart_(false),
+  iqId_(STR_EMPTY),
+  pelFeatures_(),
+  fullJid_(STR_EMPTY),
+  streamId_(STR_EMPTY),
+  pvecQueuedStanzas_(new std::vector<XmlElement *>()),
+  sasl_mech_() {
+}
+
+XmppLoginTask::~XmppLoginTask() {
+  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
+    delete (*pvecQueuedStanzas_)[i];
+}
+
+void
+XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
+  pelStanza_ = element;
+  isStart_ = isStart;
+  Advance();
+  pelStanza_ = NULL;
+  isStart_ = false;
+}
+
+const XmlElement *
+XmppLoginTask::NextStanza() {
+  const XmlElement * result = pelStanza_;
+  pelStanza_ = NULL;
+  return result;
+}
+
+bool
+XmppLoginTask::Advance() {
+
+  for (;;) {
+
+    const XmlElement * element = NULL;
+
+#if _DEBUG
+    LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
+      << rtc::ErrorName(state_, LOGINTASK_STATES);
+#endif  // _DEBUG
+
+    switch (state_) {
+
+      case LOGINSTATE_INIT: {
+        pctx_->RaiseReset();
+        pelFeatures_.reset(NULL);
+
+        // The proper domain to verify against is the real underlying
+        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
+        // also allows matching against a proxy domain instead, if it is told
+        // to do so - see the implementation of XmppEngineImpl::StartTls and
+        // XmppEngine::SetTlsServerDomain to see how you can use that feature
+        pctx_->InternalSendStart(pctx_->user_jid_.domain());
+        state_ = LOGINSTATE_STREAMSTART_SENT;
+        break;
+      }
+
+      case LOGINSTATE_STREAMSTART_SENT: {
+        if (NULL == (element = NextStanza()))
+          return true;
+
+        if (!isStart_ || !HandleStartStream(element))
+          return Failure(XmppEngine::ERROR_VERSION);
+
+        state_ = LOGINSTATE_STARTED_XMPP;
+        return true;
+      }
+
+      case LOGINSTATE_STARTED_XMPP: {
+        if (NULL == (element = NextStanza()))
+          return true;
+
+        if (!HandleFeatures(element))
+          return Failure(XmppEngine::ERROR_VERSION);
+
+        bool tls_present = (GetFeature(QN_TLS_STARTTLS) != NULL);
+        // Error if TLS required but not present.
+        if (pctx_->tls_option_ == buzz::TLS_REQUIRED && !tls_present) {
+          return Failure(XmppEngine::ERROR_TLS);
+        }
+        // Use TLS if required or enabled, and also available
+        if ((pctx_->tls_option_ == buzz::TLS_REQUIRED ||
+            pctx_->tls_option_ == buzz::TLS_ENABLED) && tls_present) {
+          state_ = LOGINSTATE_TLS_INIT;
+          continue;
+        }
+
+        if (authNeeded_) {
+          state_ = LOGINSTATE_AUTH_INIT;
+          continue;
+        }
+
+        state_ = LOGINSTATE_BIND_INIT;
+        continue;
+      }
+
+      case LOGINSTATE_TLS_INIT: {
+        const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
+        if (!pelTls)
+          return Failure(XmppEngine::ERROR_TLS);
+
+        XmlElement el(QN_TLS_STARTTLS, true);
+        pctx_->InternalSendStanza(&el);
+        state_ = LOGINSTATE_TLS_REQUESTED;
+        continue;
+      }
+
+      case LOGINSTATE_TLS_REQUESTED: {
+        if (NULL == (element = NextStanza()))
+          return true;
+        if (element->Name() != QN_TLS_PROCEED)
+          return Failure(XmppEngine::ERROR_TLS);
+
+        // The proper domain to verify against is the real underlying
+        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
+        // also allows matching against a proxy domain instead, if it is told
+        // to do so - see the implementation of XmppEngineImpl::StartTls and
+        // XmppEngine::SetTlsServerDomain to see how you can use that feature
+        pctx_->StartTls(pctx_->user_jid_.domain());
+        pctx_->tls_option_ = buzz::TLS_ENABLED;
+        state_ = LOGINSTATE_INIT;
+        continue;
+      }
+
+      case LOGINSTATE_AUTH_INIT: {
+        const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
+        if (!pelSaslAuth) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+
+        // Collect together the SASL auth mechanisms presented by the server
+        std::vector<std::string> mechanisms;
+        for (const XmlElement * pelMech =
+             pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
+             pelMech;
+             pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
+
+          mechanisms.push_back(pelMech->BodyText());
+        }
+
+        // Given all the mechanisms, choose the best
+        std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
+        if (choice.empty()) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+
+        // No recognized auth mechanism - that's an error
+        sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
+        if (!sasl_mech_) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+
+        // OK, let's start it.
+        XmlElement * auth = sasl_mech_->StartSaslAuth();
+        if (auth == NULL) {
+          return Failure(XmppEngine::ERROR_AUTH);
+        }
+        if (allowNonGoogleLogin_) {
+          // Setting the following two attributes is required to support
+          // non-google ids.
+
+          // Allow login with non-google id accounts.
+          auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true");
+
+          // Allow login with either the non-google id or the friendly email.
+          auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
+        }
+
+        pctx_->InternalSendStanza(auth);
+        delete auth;
+        state_ = LOGINSTATE_SASL_RUNNING;
+        continue;
+      }
+
+      case LOGINSTATE_SASL_RUNNING: {
+        if (NULL == (element = NextStanza()))
+          return true;
+        if (element->Name().Namespace() != NS_SASL)
+          return Failure(XmppEngine::ERROR_AUTH);
+        if (element->Name() == QN_SASL_CHALLENGE) {
+          XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
+          if (response == NULL) {
+            return Failure(XmppEngine::ERROR_AUTH);
+          }
+          pctx_->InternalSendStanza(response);
+          delete response;
+          state_ = LOGINSTATE_SASL_RUNNING;
+          continue;
+        }
+        if (element->Name() != QN_SASL_SUCCESS) {
+          return Failure(XmppEngine::ERROR_UNAUTHORIZED);
+        }
+
+        // Authenticated!
+        authNeeded_ = false;
+        state_ = LOGINSTATE_INIT;
+        continue;
+      }
+
+      case LOGINSTATE_BIND_INIT: {
+        const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
+        const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
+        if (!pelBindFeature || !pelSessionFeature)
+          return Failure(XmppEngine::ERROR_BIND);
+
+        XmlElement iq(QN_IQ);
+        iq.AddAttr(QN_TYPE, "set");
+
+        iqId_ = pctx_->NextId();
+        iq.AddAttr(QN_ID, iqId_);
+        iq.AddElement(new XmlElement(QN_BIND_BIND, true));
+
+        if (pctx_->requested_resource_ != STR_EMPTY) {
+          iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
+          iq.AddText(pctx_->requested_resource_, 2);
+        }
+        pctx_->InternalSendStanza(&iq);
+        state_ = LOGINSTATE_BIND_REQUESTED;
+        continue;
+      }
+
+      case LOGINSTATE_BIND_REQUESTED: {
+        if (NULL == (element = NextStanza()))
+          return true;
+
+        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+          return true;
+
+        if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
+            element->FirstElement()->Name() != QN_BIND_BIND)
+          return Failure(XmppEngine::ERROR_BIND);
+
+        fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
+        if (!fullJid_.IsFull()) {
+          return Failure(XmppEngine::ERROR_BIND);
+        }
+
+        // now request session
+        XmlElement iq(QN_IQ);
+        iq.AddAttr(QN_TYPE, "set");
+
+        iqId_ = pctx_->NextId();
+        iq.AddAttr(QN_ID, iqId_);
+        iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
+        pctx_->InternalSendStanza(&iq);
+
+        state_ = LOGINSTATE_SESSION_REQUESTED;
+        continue;
+      }
+
+      case LOGINSTATE_SESSION_REQUESTED: {
+        if (NULL == (element = NextStanza()))
+          return true;
+        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
+            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
+          return false;
+
+        if (element->Attr(QN_TYPE) != "result")
+          return Failure(XmppEngine::ERROR_BIND);
+
+        pctx_->SignalBound(fullJid_);
+        FlushQueuedStanzas();
+        state_ = LOGINSTATE_DONE;
+        return true;
+      }
+
+      case LOGINSTATE_DONE:
+        return false;
+    }
+  }
+}
+
+bool
+XmppLoginTask::HandleStartStream(const XmlElement *element) {
+
+  if (element->Name() != QN_STREAM_STREAM)
+    return false;
+
+  if (element->Attr(QN_XMLNS) != "jabber:client")
+    return false;
+
+  if (element->Attr(QN_VERSION) != "1.0")
+    return false;
+
+  if (!element->HasAttr(QN_ID))
+    return false;
+
+  streamId_ = element->Attr(QN_ID);
+
+  return true;
+}
+
+bool
+XmppLoginTask::HandleFeatures(const XmlElement *element) {
+  if (element->Name() != QN_STREAM_FEATURES)
+    return false;
+
+  pelFeatures_.reset(new XmlElement(*element));
+  return true;
+}
+
+const XmlElement *
+XmppLoginTask::GetFeature(const QName & name) {
+  return pelFeatures_->FirstNamed(name);
+}
+
+bool
+XmppLoginTask::Failure(XmppEngine::Error reason) {
+  state_ = LOGINSTATE_DONE;
+  pctx_->SignalError(reason, 0);
+  return false;
+}
+
+void
+XmppLoginTask::OutgoingStanza(const XmlElement * element) {
+  XmlElement * pelCopy = new XmlElement(*element);
+  pvecQueuedStanzas_->push_back(pelCopy);
+}
+
+void
+XmppLoginTask::FlushQueuedStanzas() {
+  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
+    pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
+    delete (*pvecQueuedStanzas_)[i];
+  }
+  pvecQueuedStanzas_->clear();
+}
+
+}
diff --git a/libjingle/xmpp/xmpplogintask.h b/libjingle/xmpp/xmpplogintask.h
new file mode 100644
index 0000000..58e0a2f
--- /dev/null
+++ b/libjingle/xmpp/xmpplogintask.h
@@ -0,0 +1,87 @@
+/*
+ *  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_LIBJINGLE_XMPP_LOGINTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace buzz {
+
+class XmlElement;
+class XmppEngineImpl;
+class SaslMechanism;
+
+
+// TODO: Rename to LoginTask.
+class XmppLoginTask {
+
+public:
+  XmppLoginTask(XmppEngineImpl *pctx);
+  ~XmppLoginTask();
+
+  bool IsDone()
+    { return state_ == LOGINSTATE_DONE; }
+  void IncomingStanza(const XmlElement * element, bool isStart);
+  void OutgoingStanza(const XmlElement *element);
+  void set_allow_non_google_login(bool b)
+    { allowNonGoogleLogin_ = b; }
+
+private:
+  enum LoginTaskState {
+    LOGINSTATE_INIT = 0,
+    LOGINSTATE_STREAMSTART_SENT,
+    LOGINSTATE_STARTED_XMPP,
+    LOGINSTATE_TLS_INIT,
+    LOGINSTATE_AUTH_INIT,
+    LOGINSTATE_BIND_INIT,
+    LOGINSTATE_TLS_REQUESTED,
+    LOGINSTATE_SASL_RUNNING,
+    LOGINSTATE_BIND_REQUESTED,
+    LOGINSTATE_SESSION_REQUESTED,
+    LOGINSTATE_DONE,
+  };
+
+  const XmlElement * NextStanza();
+  bool Advance();
+  bool HandleStartStream(const XmlElement * element);
+  bool HandleFeatures(const XmlElement * element);
+  const XmlElement * GetFeature(const QName & name);
+  bool Failure(XmppEngine::Error reason);
+  void FlushQueuedStanzas();
+
+  XmppEngineImpl * pctx_;
+  bool authNeeded_;
+  bool allowNonGoogleLogin_;
+  LoginTaskState state_;
+  const XmlElement * pelStanza_;
+  bool isStart_;
+  std::string iqId_;
+  rtc::scoped_ptr<XmlElement> pelFeatures_;
+  Jid fullJid_;
+  std::string streamId_;
+  rtc::scoped_ptr<std::vector<XmlElement *> > pvecQueuedStanzas_;
+
+  rtc::scoped_ptr<SaslMechanism> sasl_mech_;
+
+#ifdef _DEBUG
+  static const rtc::ConstantLabel LOGINTASK_STATES[];
+#endif  // _DEBUG
+};
+
+}
+
+#endif  //  WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
diff --git a/libjingle/xmpp/xmpplogintask_unittest.cc b/libjingle/xmpp/xmpplogintask_unittest.cc
new file mode 100644
index 0000000..035275f
--- /dev/null
+++ b/libjingle/xmpp/xmpplogintask_unittest.cc
@@ -0,0 +1,621 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/plainsaslhandler.h"
+#include "webrtc/libjingle/xmpp/saslplainmechanism.h"
+#include "webrtc/libjingle/xmpp/util_unittest.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/cryptstring.h"
+#include "webrtc/base/gunit.h"
+
+using buzz::Jid;
+using buzz::QName;
+using buzz::XmlElement;
+using buzz::XmppEngine;
+using buzz::XmppTestHandler;
+
+enum XlttStage {
+  XLTT_STAGE_CONNECT = 0,
+  XLTT_STAGE_STREAMSTART,
+  XLTT_STAGE_TLS_FEATURES,
+  XLTT_STAGE_TLS_PROCEED,
+  XLTT_STAGE_ENCRYPTED_START,
+  XLTT_STAGE_AUTH_FEATURES,
+  XLTT_STAGE_AUTH_SUCCESS,
+  XLTT_STAGE_AUTHENTICATED_START,
+  XLTT_STAGE_BIND_FEATURES,
+  XLTT_STAGE_BIND_SUCCESS,
+  XLTT_STAGE_SESSION_SUCCESS,
+};
+
+class XmppLoginTaskTest : public testing::Test {
+ public:
+  XmppEngine* engine() { return engine_.get(); }
+  XmppTestHandler* handler() { return handler_.get(); }
+  virtual void SetUp() {
+    engine_.reset(XmppEngine::Create());
+    handler_.reset(new XmppTestHandler(engine_.get()));
+
+    Jid jid("david@my-server");
+    rtc::InsecureCryptStringImpl pass;
+    pass.password() = "david";
+    engine_->SetSessionHandler(handler_.get());
+    engine_->SetOutputHandler(handler_.get());
+    engine_->AddStanzaHandler(handler_.get());
+    engine_->SetUser(jid);
+    engine_->SetSaslHandler(
+        new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true));
+  }
+  virtual void TearDown() {
+    handler_.reset();
+    engine_.reset();
+  }
+  void RunPartialLogin(XlttStage startstage, XlttStage endstage);
+  void SetTlsOptions(buzz::TlsOptions option);
+
+ private:
+  rtc::scoped_ptr<XmppEngine> engine_;
+  rtc::scoped_ptr<XmppTestHandler> handler_;
+};
+
+void XmppLoginTaskTest::SetTlsOptions(buzz::TlsOptions option) {
+  engine_->SetTls(option);
+}
+void XmppLoginTaskTest::RunPartialLogin(XlttStage startstage,
+                                        XlttStage endstage) {
+  std::string input;
+
+  switch (startstage) {
+    case XLTT_STAGE_CONNECT: {
+      engine_->Connect();
+      XmlElement appStanza(QName("test", "app-stanza"));
+      appStanza.AddText("this-is-a-test");
+      engine_->SendStanza(&appStanza);
+
+      EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" "
+          "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+      EXPECT_EQ("[OPENING]", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      if (endstage == XLTT_STAGE_CONNECT)
+        return;
+    }
+
+    case XLTT_STAGE_STREAMSTART: {
+      input = "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->OutputActivity());
+      if (endstage == XLTT_STAGE_STREAMSTART)
+        return;
+    }
+
+    case XLTT_STAGE_TLS_FEATURES: {
+      input = "<stream:features>"
+        "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
+       "</stream:features>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_TLS_FEATURES)
+        return;
+    }
+
+    case XLTT_STAGE_TLS_PROCEED: {
+      input = std::string("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("[START-TLS my-server]"
+          "<stream:stream to=\"my-server\" xml:lang=\"*\" "
+          "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+       if (endstage == XLTT_STAGE_TLS_PROCEED)
+        return;
+    }
+
+    case XLTT_STAGE_ENCRYPTED_START: {
+      input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">");
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->OutputActivity());
+      if (endstage == XLTT_STAGE_ENCRYPTED_START)
+        return;
+    }
+
+    case XLTT_STAGE_AUTH_FEATURES: {
+      input = "<stream:features>"
+        "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+          "<mechanism>DIGEST-MD5</mechanism>"
+          "<mechanism>PLAIN</mechanism>"
+        "</mechanisms>"
+       "</stream:features>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+          "mechanism=\"PLAIN\" "
+          "auth:allow-non-google-login=\"true\" "
+          "auth:client-uses-full-bind-result=\"true\" "
+          "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+          ">AGRhdmlkAGRhdmlk</auth>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+       if (endstage == XLTT_STAGE_AUTH_FEATURES)
+        return;
+    }
+
+    case XLTT_STAGE_AUTH_SUCCESS: {
+      input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" "
+          "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+       if (endstage == XLTT_STAGE_AUTH_SUCCESS)
+        return;
+    }
+
+    case XLTT_STAGE_AUTHENTICATED_START: {
+      input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" "
+          "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+          "xmlns=\"jabber:client\">");
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->OutputActivity());
+      if (endstage == XLTT_STAGE_AUTHENTICATED_START)
+        return;
+    }
+
+    case XLTT_STAGE_BIND_FEATURES: {
+      input = "<stream:features>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
+          "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
+        "</stream:features>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<iq type=\"set\" id=\"0\">"
+          "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_BIND_FEATURES)
+        return;
+    }
+
+    case XLTT_STAGE_BIND_SUCCESS: {
+      input = "<iq type='result' id='0'>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
+          "<jid>david@my-server/test</jid></bind></iq>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<iq type=\"set\" id=\"1\">"
+          "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>",
+          handler_->OutputActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      EXPECT_EQ("", handler_->SessionActivity());
+      if (endstage == XLTT_STAGE_BIND_SUCCESS)
+        return;
+    }
+
+    case XLTT_STAGE_SESSION_SUCCESS: {
+      input = "<iq type='result' id='1'/>";
+      engine_->HandleInput(input.c_str(), input.length());
+      EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test"
+          "</test:app-stanza>", handler_->OutputActivity());
+      EXPECT_EQ("[OPEN]", handler_->SessionActivity());
+      EXPECT_EQ("", handler_->StanzaActivity());
+      if (endstage == XLTT_STAGE_SESSION_SUCCESS)
+        return;
+    }
+  }
+}
+
+TEST_F(XmppLoginTaskTest, TestUtf8Good) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT);
+
+  std::string input = "<?xml version='1.0' encoding='UTF-8'?>"
+      "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestNonUtf8Bad) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT);
+
+  std::string input = "<?xml version='1.0' encoding='ISO-8859-1'?>"
+      "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
+      "xmlns:stream=\"http://etherx.jabber.org/streams\" "
+      "xmlns=\"jabber:client\">";
+  engine()->HandleInput(input.c_str(), input.length());
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestNoFeatures) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<iq type='get' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsRequiredNotPresent) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsRequeiredAndPresent) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>"
+        "<required/>"
+      "</starttls>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>X-GOOGLE-TOKEN</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+        "<mechanism>X-OAUTH2</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
+      handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsEnabledNotPresent) {
+  SetTlsOptions(buzz::TLS_ENABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsEnabledAndPresent) {
+  SetTlsOptions(buzz::TLS_ENABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>X-GOOGLE-TOKEN</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+        "<mechanism>X-OAUTH2</mechanism>"
+      "</mechanisms>"
+      "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsDisabledNotPresent) {
+  SetTlsOptions(buzz::TLS_DISABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+    std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>DIGEST-MD5</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+      "</mechanisms>"
+     "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsDisabledAndPresent) {
+  SetTlsOptions(buzz::TLS_DISABLED);
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
+
+  std::string input = "<stream:features>"
+      "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+        "<mechanism>X-GOOGLE-TOKEN</mechanism>"
+        "<mechanism>PLAIN</mechanism>"
+        "<mechanism>X-OAUTH2</mechanism>"
+      "</mechanisms>"
+      "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+      "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
+      "auth:client-uses-full-bind-result=\"true\" "
+      "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
+      ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsFailure) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_FEATURES);
+
+  std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestTlsBadStream) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_PROCEED);
+
+  std::string input = "<wrongtag>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestMissingSaslPlain) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_ENCRYPTED_START);
+
+  std::string input = "<stream:features>"
+        "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+          "<mechanism>DIGEST-MD5</mechanism>"
+        "</mechanisms>"
+       "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-AUTH]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestWrongPassword) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_FEATURES);
+
+  std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-UNAUTHORIZED]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestAuthBadStream) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_SUCCESS);
+
+  std::string input = "<wrongtag>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestMissingBindFeature) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START);
+
+  std::string input = "<stream:features>"
+          "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
+        "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestMissingSessionFeature) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START);
+
+  std::string input = "<stream:features>"
+          "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
+        "</stream:features>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+/* TODO: Handle this case properly inside XmppLoginTask.
+TEST_F(XmppLoginTaskTest, TestBindFailure1) {
+  // check wrong JID
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='result' id='0'>"
+      "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
+      "<jid>davey@my-server/test</jid></bind></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+*/
+
+TEST_F(XmppLoginTaskTest, TestBindFailure2) {
+  // check missing JID
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='result' id='0'>"
+      "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestBindFailure3) {
+  // check plain failure
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='error' id='0'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+  EXPECT_EQ("", handler()->StanzaActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestBindFailure4) {
+  // check wrong id to ignore
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
+
+  std::string input = "<iq type='error' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  // continue after an ignored iq
+  RunPartialLogin(XLTT_STAGE_BIND_SUCCESS, XLTT_STAGE_SESSION_SUCCESS);
+}
+
+TEST_F(XmppLoginTaskTest, TestSessionFailurePlain1) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS);
+
+  std::string input = "<iq type='error' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+  EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
+}
+
+TEST_F(XmppLoginTaskTest, TestSessionFailurePlain2) {
+  RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS);
+
+  // check reverse iq to ignore
+  // TODO: consider queueing or passing through?
+  std::string input = "<iq type='get' id='1'/>";
+  engine()->HandleInput(input.c_str(), input.length());
+
+  EXPECT_EQ("", handler()->OutputActivity());
+  EXPECT_EQ("", handler()->SessionActivity());
+
+  // continue after an ignored iq
+  RunPartialLogin(XLTT_STAGE_SESSION_SUCCESS, XLTT_STAGE_SESSION_SUCCESS);
+}
+
+TEST_F(XmppLoginTaskTest, TestBadXml) {
+  int errorKind = 0;
+  for (XlttStage stage = XLTT_STAGE_CONNECT;
+      stage <= XLTT_STAGE_SESSION_SUCCESS;
+      stage = static_cast<XlttStage>(stage + 1)) {
+    RunPartialLogin(XLTT_STAGE_CONNECT, stage);
+
+    std::string input;
+    switch (errorKind++ % 5) {
+      case 0: input = "&syntax;"; break;
+      case 1: input = "<nons:iq/>"; break;
+      case 2: input = "<iq a='b' a='dupe'/>"; break;
+      case 3: input = "<>"; break;
+      case 4: input = "<iq a='<wrong>'>"; break;
+    }
+
+    engine()->HandleInput(input.c_str(), input.length());
+
+    EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+    EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity());
+
+    TearDown();
+    SetUp();
+  }
+}
+
+TEST_F(XmppLoginTaskTest, TestStreamError) {
+  for (XlttStage stage = XLTT_STAGE_CONNECT;
+      stage <= XLTT_STAGE_SESSION_SUCCESS;
+      stage = static_cast<XlttStage>(stage + 1)) {
+    switch (stage) {
+      case XLTT_STAGE_CONNECT:
+      case XLTT_STAGE_TLS_PROCEED:
+      case XLTT_STAGE_AUTH_SUCCESS:
+        continue;
+      default:
+        break;
+    }
+
+    RunPartialLogin(XLTT_STAGE_CONNECT, stage);
+
+    std::string input = "<stream:error>"
+        "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
+        "<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>"
+        "Some special application diagnostic information!"
+        "</text>"
+        "<escape-your-data xmlns='application-ns'/>"
+        "</stream:error>";
+
+    engine()->HandleInput(input.c_str(), input.length());
+
+    EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
+    EXPECT_EQ("[CLOSED][ERROR-STREAM]", handler()->SessionActivity());
+
+    EXPECT_EQ("<str:error xmlns:str=\"http://etherx.jabber.org/streams\">"
+        "<xml-not-well-formed xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>"
+        "<text xml:lang=\"en\" xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\">"
+        "Some special application diagnostic information!"
+        "</text>"
+        "<escape-your-data xmlns=\"application-ns\"/>"
+        "</str:error>", engine()->GetStreamError()->Str());
+
+    TearDown();
+    SetUp();
+  }
+}
+
diff --git a/libjingle/xmpp/xmpppump.cc b/libjingle/xmpp/xmpppump.cc
new file mode 100644
index 0000000..45259b1
--- /dev/null
+++ b/libjingle/xmpp/xmpppump.cc
@@ -0,0 +1,67 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/xmpppump.h"
+
+#include "webrtc/libjingle/xmpp/xmppauth.h"
+
+namespace buzz {
+
+XmppPump::XmppPump(XmppPumpNotify * notify) {
+  state_ = buzz::XmppEngine::STATE_NONE;
+  notify_ = notify;
+  client_ = new buzz::XmppClient(this);  // NOTE: deleted by TaskRunner
+}
+
+void XmppPump::DoLogin(const buzz::XmppClientSettings & xcs,
+                       buzz::AsyncSocket* socket,
+                       buzz::PreXmppAuth* auth) {
+  OnStateChange(buzz::XmppEngine::STATE_START);
+  if (!AllChildrenDone()) {
+    client_->SignalStateChange.connect(this, &XmppPump::OnStateChange);
+    client_->Connect(xcs, "", socket, auth);
+    client_->Start();
+  }
+}
+
+void XmppPump::DoDisconnect() {
+  if (!AllChildrenDone())
+    client_->Disconnect();
+  OnStateChange(buzz::XmppEngine::STATE_CLOSED);
+}
+
+void XmppPump::OnStateChange(buzz::XmppEngine::State state) {
+  if (state_ == state)
+    return;
+  state_ = state;
+  if (notify_ != NULL)
+    notify_->OnStateChange(state);
+}
+
+void XmppPump::WakeTasks() {
+  rtc::Thread::Current()->Post(this);
+}
+
+int64 XmppPump::CurrentTime() {
+  return (int64)rtc::Time();
+}
+
+void XmppPump::OnMessage(rtc::Message *pmsg) {
+  RunTasks();
+}
+
+buzz::XmppReturnStatus XmppPump::SendStanza(const buzz::XmlElement *stanza) {
+  if (!AllChildrenDone())
+    return client_->SendStanza(stanza);
+  return buzz::XMPP_RETURN_BADSTATE;
+}
+
+}  // namespace buzz
+
diff --git a/libjingle/xmpp/xmpppump.h b/libjingle/xmpp/xmpppump.h
new file mode 100644
index 0000000..8163298
--- /dev/null
+++ b/libjingle/xmpp/xmpppump.h
@@ -0,0 +1,62 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPPUMP_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPPUMP_H_
+
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "webrtc/base/messagequeue.h"
+#include "webrtc/base/taskrunner.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/timeutils.h"
+
+namespace buzz {
+
+// Simple xmpp pump
+
+class XmppPumpNotify {
+public:
+  virtual ~XmppPumpNotify() {}
+  virtual void OnStateChange(buzz::XmppEngine::State state) = 0;
+};
+
+class XmppPump : public rtc::MessageHandler, public rtc::TaskRunner {
+public:
+  XmppPump(buzz::XmppPumpNotify * notify = NULL);
+
+  buzz::XmppClient *client() { return client_; }
+
+  void DoLogin(const buzz::XmppClientSettings & xcs,
+               buzz::AsyncSocket* socket,
+               buzz::PreXmppAuth* auth);
+  void DoDisconnect();
+
+  void OnStateChange(buzz::XmppEngine::State state);
+
+  void WakeTasks();
+
+  int64 CurrentTime();
+
+  void OnMessage(rtc::Message *pmsg);
+
+  buzz::XmppReturnStatus SendStanza(const buzz::XmlElement *stanza);
+
+private:
+  buzz::XmppClient *client_;
+  buzz::XmppEngine::State state_;
+  buzz::XmppPumpNotify *notify_;
+};
+
+}  // namespace buzz
+
+#endif // WEBRTC_LIBJINGLE_XMPP_XMPPPUMP_H_
+
diff --git a/libjingle/xmpp/xmppsocket.cc b/libjingle/xmpp/xmppsocket.cc
new file mode 100644
index 0000000..d67a71f
--- /dev/null
+++ b/libjingle/xmpp/xmppsocket.cc
@@ -0,0 +1,245 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "xmppsocket.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include "webrtc/base/basicdefs.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/thread.h"
+#ifdef FEATURE_ENABLE_SSL
+#include "webrtc/base/ssladapter.h"
+#endif
+
+#ifdef USE_SSLSTREAM
+#include "webrtc/base/socketstream.h"
+#ifdef FEATURE_ENABLE_SSL
+#include "webrtc/base/sslstreamadapter.h"
+#endif  // FEATURE_ENABLE_SSL
+#endif  // USE_SSLSTREAM
+
+namespace buzz {
+
+XmppSocket::XmppSocket(buzz::TlsOptions tls) : cricket_socket_(NULL),
+                                               tls_(tls) {
+  state_ = buzz::AsyncSocket::STATE_CLOSED;
+}
+
+void XmppSocket::CreateCricketSocket(int family) {
+  rtc::Thread* pth = rtc::Thread::Current();
+  if (family == AF_UNSPEC) {
+    family = AF_INET;
+  }
+  rtc::AsyncSocket* socket =
+      pth->socketserver()->CreateAsyncSocket(family, SOCK_STREAM);
+#ifndef USE_SSLSTREAM
+#ifdef FEATURE_ENABLE_SSL
+  if (tls_ != buzz::TLS_DISABLED) {
+    socket = rtc::SSLAdapter::Create(socket);
+  }
+#endif  // FEATURE_ENABLE_SSL
+  cricket_socket_ = socket;
+  cricket_socket_->SignalReadEvent.connect(this, &XmppSocket::OnReadEvent);
+  cricket_socket_->SignalWriteEvent.connect(this, &XmppSocket::OnWriteEvent);
+  cricket_socket_->SignalConnectEvent.connect(this,
+                                              &XmppSocket::OnConnectEvent);
+  cricket_socket_->SignalCloseEvent.connect(this, &XmppSocket::OnCloseEvent);
+#else  // USE_SSLSTREAM
+  cricket_socket_ = socket;
+  stream_ = new rtc::SocketStream(cricket_socket_);
+#ifdef FEATURE_ENABLE_SSL
+  if (tls_ != buzz::TLS_DISABLED)
+    stream_ = rtc::SSLStreamAdapter::Create(stream_);
+#endif  // FEATURE_ENABLE_SSL
+  stream_->SignalEvent.connect(this, &XmppSocket::OnEvent);
+#endif  // USE_SSLSTREAM
+}
+
+XmppSocket::~XmppSocket() {
+  Close();
+#ifndef USE_SSLSTREAM
+  delete cricket_socket_;
+#else  // USE_SSLSTREAM
+  delete stream_;
+#endif  // USE_SSLSTREAM
+}
+
+#ifndef USE_SSLSTREAM
+void XmppSocket::OnReadEvent(rtc::AsyncSocket * socket) {
+  SignalRead();
+}
+
+void XmppSocket::OnWriteEvent(rtc::AsyncSocket * socket) {
+  // Write bytes if there are any
+  while (buffer_.Length() != 0) {
+    int written = cricket_socket_->Send(buffer_.Data(), buffer_.Length());
+    if (written > 0) {
+      buffer_.Consume(written);
+      continue;
+    }
+    if (!cricket_socket_->IsBlocking())
+      LOG(LS_ERROR) << "Send error: " << cricket_socket_->GetError();
+    return;
+  }
+}
+
+void XmppSocket::OnConnectEvent(rtc::AsyncSocket * socket) {
+#if defined(FEATURE_ENABLE_SSL)
+  if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) {
+    state_ = buzz::AsyncSocket::STATE_TLS_OPEN;
+    SignalSSLConnected();
+    OnWriteEvent(cricket_socket_);
+    return;
+  }
+#endif  // !defined(FEATURE_ENABLE_SSL)
+  state_ = buzz::AsyncSocket::STATE_OPEN;
+  SignalConnected();
+}
+
+void XmppSocket::OnCloseEvent(rtc::AsyncSocket * socket, int error) {
+  SignalCloseEvent(error);
+}
+
+#else  // USE_SSLSTREAM
+
+void XmppSocket::OnEvent(rtc::StreamInterface* stream,
+                         int events, int err) {
+  if ((events & rtc::SE_OPEN)) {
+#if defined(FEATURE_ENABLE_SSL)
+    if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) {
+      state_ = buzz::AsyncSocket::STATE_TLS_OPEN;
+      SignalSSLConnected();
+      events |= rtc::SE_WRITE;
+    } else
+#endif
+    {
+      state_ = buzz::AsyncSocket::STATE_OPEN;
+      SignalConnected();
+    }
+  }
+  if ((events & rtc::SE_READ))
+    SignalRead();
+  if ((events & rtc::SE_WRITE)) {
+    // Write bytes if there are any
+    while (buffer_.Length() != 0) {
+      rtc::StreamResult result;
+      size_t written;
+      int error;
+      result = stream_->Write(buffer_.Data(), buffer_.Length(),
+                              &written, &error);
+      if (result == rtc::SR_ERROR) {
+        LOG(LS_ERROR) << "Send error: " << error;
+        return;
+      }
+      if (result == rtc::SR_BLOCK)
+        return;
+      ASSERT(result == rtc::SR_SUCCESS);
+      ASSERT(written > 0);
+      buffer_.Shift(written);
+    }
+  }
+  if ((events & rtc::SE_CLOSE))
+    SignalCloseEvent(err);
+}
+#endif  // USE_SSLSTREAM
+
+buzz::AsyncSocket::State XmppSocket::state() {
+  return state_;
+}
+
+buzz::AsyncSocket::Error XmppSocket::error() {
+  return buzz::AsyncSocket::ERROR_NONE;
+}
+
+int XmppSocket::GetError() {
+  return 0;
+}
+
+bool XmppSocket::Connect(const rtc::SocketAddress& addr) {
+  if (cricket_socket_ == NULL) {
+    CreateCricketSocket(addr.family());
+  }
+  if (cricket_socket_->Connect(addr) < 0) {
+    return cricket_socket_->IsBlocking();
+  }
+  return true;
+}
+
+bool XmppSocket::Read(char * data, size_t len, size_t* len_read) {
+#ifndef USE_SSLSTREAM
+  int read = cricket_socket_->Recv(data, len);
+  if (read > 0) {
+    *len_read = (size_t)read;
+    return true;
+  }
+#else  // USE_SSLSTREAM
+  rtc::StreamResult result = stream_->Read(data, len, len_read, NULL);
+  if (result == rtc::SR_SUCCESS)
+    return true;
+#endif  // USE_SSLSTREAM
+  return false;
+}
+
+bool XmppSocket::Write(const char * data, size_t len) {
+  buffer_.WriteBytes(data, len);
+#ifndef USE_SSLSTREAM
+  OnWriteEvent(cricket_socket_);
+#else  // USE_SSLSTREAM
+  OnEvent(stream_, rtc::SE_WRITE, 0);
+#endif  // USE_SSLSTREAM
+  return true;
+}
+
+bool XmppSocket::Close() {
+  if (state_ != buzz::AsyncSocket::STATE_OPEN)
+    return false;
+#ifndef USE_SSLSTREAM
+  if (cricket_socket_->Close() == 0) {
+    state_ = buzz::AsyncSocket::STATE_CLOSED;
+    SignalClosed();
+    return true;
+  }
+  return false;
+#else  // USE_SSLSTREAM
+  state_ = buzz::AsyncSocket::STATE_CLOSED;
+  stream_->Close();
+  SignalClosed();
+  return true;
+#endif  // USE_SSLSTREAM
+}
+
+bool XmppSocket::StartTls(const std::string & domainname) {
+#if defined(FEATURE_ENABLE_SSL)
+  if (tls_ == buzz::TLS_DISABLED)
+    return false;
+#ifndef USE_SSLSTREAM
+  rtc::SSLAdapter* ssl_adapter =
+    static_cast<rtc::SSLAdapter *>(cricket_socket_);
+  if (ssl_adapter->StartSSL(domainname.c_str(), false) != 0)
+    return false;
+#else  // USE_SSLSTREAM
+  rtc::SSLStreamAdapter* ssl_stream =
+    static_cast<rtc::SSLStreamAdapter *>(stream_);
+  if (ssl_stream->StartSSLWithServer(domainname.c_str()) != 0)
+    return false;
+#endif  // USE_SSLSTREAM
+  state_ = buzz::AsyncSocket::STATE_TLS_CONNECTING;
+  return true;
+#else  // !defined(FEATURE_ENABLE_SSL)
+  return false;
+#endif  // !defined(FEATURE_ENABLE_SSL)
+}
+
+}  // namespace buzz
+
diff --git a/libjingle/xmpp/xmppsocket.h b/libjingle/xmpp/xmppsocket.h
new file mode 100644
index 0000000..527b23a
--- /dev/null
+++ b/libjingle/xmpp/xmppsocket.h
@@ -0,0 +1,72 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPSOCKET_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPSOCKET_H_
+
+#include "webrtc/libjingle/xmpp/asyncsocket.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/asyncsocket.h"
+#include "webrtc/base/bytebuffer.h"
+#include "webrtc/base/sigslot.h"
+
+// The below define selects the SSLStreamAdapter implementation for
+// SSL, as opposed to the SSLAdapter socket adapter.
+// #define USE_SSLSTREAM 
+
+namespace rtc {
+  class StreamInterface;
+  class SocketAddress;
+};
+extern rtc::AsyncSocket* cricket_socket_;
+
+namespace buzz {
+
+class XmppSocket : public buzz::AsyncSocket, public sigslot::has_slots<> {
+public:
+  XmppSocket(buzz::TlsOptions tls);
+  ~XmppSocket();
+
+  virtual buzz::AsyncSocket::State state();
+  virtual buzz::AsyncSocket::Error error();
+  virtual int GetError();
+
+  virtual bool Connect(const rtc::SocketAddress& addr);
+  virtual bool Read(char * data, size_t len, size_t* len_read);
+  virtual bool Write(const char * data, size_t len);
+  virtual bool Close();
+  virtual bool StartTls(const std::string & domainname);
+
+  sigslot::signal1<int> SignalCloseEvent;
+
+private:
+  void CreateCricketSocket(int family);
+#ifndef USE_SSLSTREAM
+  void OnReadEvent(rtc::AsyncSocket * socket);
+  void OnWriteEvent(rtc::AsyncSocket * socket);
+  void OnConnectEvent(rtc::AsyncSocket * socket);
+  void OnCloseEvent(rtc::AsyncSocket * socket, int error);
+#else  // USE_SSLSTREAM
+  void OnEvent(rtc::StreamInterface* stream, int events, int err);
+#endif  // USE_SSLSTREAM
+
+  rtc::AsyncSocket * cricket_socket_;
+#ifdef USE_SSLSTREAM
+  rtc::StreamInterface *stream_;
+#endif  // USE_SSLSTREAM
+  buzz::AsyncSocket::State state_;
+  rtc::ByteBuffer buffer_;
+  buzz::TlsOptions tls_;
+};
+
+}  // namespace buzz
+
+#endif // WEBRTC_LIBJINGLE_XMPP_XMPPSOCKET_H_
+
diff --git a/libjingle/xmpp/xmppstanzaparser.cc b/libjingle/xmpp/xmppstanzaparser.cc
new file mode 100644
index 0000000..035bb0b
--- /dev/null
+++ b/libjingle/xmpp/xmppstanzaparser.cc
@@ -0,0 +1,89 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/xmppstanzaparser.h"
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/common.h"
+#ifdef EXPAT_RELATIVE_PATH
+#include "expat.h"
+#else
+#include "third_party/expat/v2_0_1/Source/lib/expat.h"
+#endif
+
+namespace buzz {
+
+XmppStanzaParser::XmppStanzaParser(XmppStanzaParseHandler *psph) :
+  psph_(psph),
+  innerHandler_(this),
+  parser_(&innerHandler_),
+  depth_(0),
+  builder_() {
+}
+
+void
+XmppStanzaParser::Reset() {
+  parser_.Reset();
+  depth_ = 0;
+  builder_.Reset();
+}
+
+void
+XmppStanzaParser::IncomingStartElement(
+    XmlParseContext * pctx, const char * name, const char ** atts) {
+  if (depth_++ == 0) {
+    XmlElement * pelStream = XmlBuilder::BuildElement(pctx, name, atts);
+    if (pelStream == NULL) {
+      pctx->RaiseError(XML_ERROR_SYNTAX);
+      return;
+    }
+    psph_->StartStream(pelStream);
+    delete pelStream;
+    return;
+  }
+
+  builder_.StartElement(pctx, name, atts);
+}
+
+void
+XmppStanzaParser::IncomingCharacterData(
+    XmlParseContext * pctx, const char * text, int len) {
+  if (depth_ > 1) {
+    builder_.CharacterData(pctx, text, len);
+  }
+}
+
+void
+XmppStanzaParser::IncomingEndElement(
+    XmlParseContext * pctx, const char * name) {
+  if (--depth_ == 0) {
+    psph_->EndStream();
+    return;
+  }
+
+  builder_.EndElement(pctx, name);
+
+  if (depth_ == 1) {
+    XmlElement *element = builder_.CreateElement();
+    psph_->Stanza(element);
+    delete element;
+  }
+}
+
+void
+XmppStanzaParser::IncomingError(
+    XmlParseContext * pctx, XML_Error errCode) {
+  RTC_UNUSED(pctx);
+  RTC_UNUSED(errCode);
+  psph_->XmlError();
+}
+
+}
diff --git a/libjingle/xmpp/xmppstanzaparser.h b/libjingle/xmpp/xmppstanzaparser.h
new file mode 100644
index 0000000..3ad052e
--- /dev/null
+++ b/libjingle/xmpp/xmppstanzaparser.h
@@ -0,0 +1,80 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
+
+#include "webrtc/libjingle/xmllite/xmlbuilder.h"
+#include "webrtc/libjingle/xmllite/xmlparser.h"
+
+
+namespace buzz {
+
+class XmlElement;
+
+class XmppStanzaParseHandler {
+public:
+  virtual ~XmppStanzaParseHandler() {}
+  virtual void StartStream(const XmlElement * pelStream) = 0;
+  virtual void Stanza(const XmlElement * pelStanza) = 0;
+  virtual void EndStream() = 0;
+  virtual void XmlError() = 0;
+};
+
+class XmppStanzaParser {
+public:
+  XmppStanzaParser(XmppStanzaParseHandler *psph);
+  bool Parse(const char * data, size_t len, bool isFinal)
+    { return parser_.Parse(data, len, isFinal); }
+  void Reset();
+
+private:
+  class ParseHandler : public XmlParseHandler {
+  public:
+    ParseHandler(XmppStanzaParser * outer) : outer_(outer) {}
+    virtual void StartElement(XmlParseContext * pctx,
+               const char * name, const char ** atts)
+      { outer_->IncomingStartElement(pctx, name, atts); }
+    virtual void EndElement(XmlParseContext * pctx,
+               const char * name)
+      { outer_->IncomingEndElement(pctx, name); }
+    virtual void CharacterData(XmlParseContext * pctx,
+               const char * text, int len)
+      { outer_->IncomingCharacterData(pctx, text, len); }
+    virtual void Error(XmlParseContext * pctx,
+               XML_Error errCode)
+      { outer_->IncomingError(pctx, errCode); }
+  private:
+    XmppStanzaParser * const outer_;
+  };
+
+  friend class ParseHandler;
+
+  void IncomingStartElement(XmlParseContext * pctx,
+               const char * name, const char ** atts);
+  void IncomingEndElement(XmlParseContext * pctx,
+               const char * name);
+  void IncomingCharacterData(XmlParseContext * pctx,
+               const char * text, int len);
+  void IncomingError(XmlParseContext * pctx,
+               XML_Error errCode);
+
+  XmppStanzaParseHandler * psph_;
+  ParseHandler innerHandler_;
+  XmlParser parser_;
+  int depth_;
+  XmlBuilder builder_;
+
+ };
+
+
+}
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
diff --git a/libjingle/xmpp/xmppstanzaparser_unittest.cc b/libjingle/xmpp/xmppstanzaparser_unittest.cc
new file mode 100644
index 0000000..65fcac9
--- /dev/null
+++ b/libjingle/xmpp/xmppstanzaparser_unittest.cc
@@ -0,0 +1,175 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/xmppstanzaparser.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/gunit.h"
+
+using buzz::QName;
+using buzz::XmlElement;
+using buzz::XmppStanzaParser;
+using buzz::XmppStanzaParseHandler;
+
+class XmppStanzaParserTestHandler : public XmppStanzaParseHandler {
+ public:
+  virtual void StartStream(const XmlElement * element) {
+    ss_ << "START" << element->Str();
+  }
+  virtual void Stanza(const XmlElement * element) {
+    ss_ << "STANZA" << element->Str();
+  }
+  virtual void EndStream() {
+    ss_ << "END";
+  }
+  virtual void XmlError() {
+    ss_ << "ERROR";
+  }
+
+  std::string Str() {
+    return ss_.str();
+  }
+
+  std::string StrClear() {
+    std::string result = ss_.str();
+    ss_.str("");
+    return result;
+  }
+
+ private:
+  std::stringstream ss_;
+};
+
+
+TEST(XmppStanzaParserTest, TestTrivial) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<trivial/>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<trivial/>END", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestStanzaAtATime) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xmlns:stream='str'>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+
+  fragment = "<message type='foo'><body>hello</body></message>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">"
+      "<c:body>hello</c:body></c:message>", handler.StrClear());
+
+  fragment = " SOME TEXT TO IGNORE ";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "<iq type='set' id='123'><abc xmlns='def'/></iq>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:iq type=\"set\" id=\"123\" xmlns:c=\"j:c\">"
+      "<abc xmlns=\"def\"/></c:iq>", handler.StrClear());
+
+  fragment = "</stream:stream>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("END", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestFragmentedStanzas) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xml";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "ns:stream='str'><message type='foo'><body>hel";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+
+  fragment = "lo</body></message> IGNORE ME <iq type='set' id='123'>"
+      "<abc xmlns='def'/></iq></st";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">"
+      "<c:body>hello</c:body></c:message>STANZA<c:iq type=\"set\" id=\"123\" "
+      "xmlns:c=\"j:c\"><abc xmlns=\"def\"/></c:iq>", handler.StrClear());
+
+  fragment = "ream:stream>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("END", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestReset) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xml";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  parser.Reset();
+  fragment = "<stream:stream id='abc' xmlns='j:c' xml";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("", handler.StrClear());
+
+  fragment = "ns:stream='str'><message type='foo'><body>hel";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+  parser.Reset();
+
+  fragment = "<stream:stream id='abc' xmlns='j:c' xmlns:stream='str'>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" "
+      "xmlns:stream=\"str\"/>", handler.StrClear());
+
+  fragment = "<message type='foo'><body>hello</body></message>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">"
+      "<c:body>hello</c:body></c:message>", handler.StrClear());
+}
+
+TEST(XmppStanzaParserTest, TestError) {
+  XmppStanzaParserTestHandler handler;
+  XmppStanzaParser parser(&handler);
+  std::string fragment;
+
+  fragment = "<-foobar/>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("ERROR", handler.StrClear());
+
+  parser.Reset();
+  fragment = "<stream:stream/>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("ERROR", handler.StrClear());
+  parser.Reset();
+
+  fragment = "ns:stream='str'><message type='foo'><body>hel";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("ERROR", handler.StrClear());
+  parser.Reset();
+
+  fragment = "<stream:stream xmlns:stream='st' xmlns='jc'>"
+      "<foo/><bar><st:foobar/></bar>";
+  parser.Parse(fragment.c_str(), fragment.length(), false);
+  EXPECT_EQ("START<stream:stream xmlns:stream=\"st\" xmlns=\"jc\"/>STANZA"
+      "<jc:foo xmlns:jc=\"jc\"/>ERROR", handler.StrClear());
+}
diff --git a/libjingle/xmpp/xmpptask.cc b/libjingle/xmpp/xmpptask.cc
new file mode 100644
index 0000000..0906705
--- /dev/null
+++ b/libjingle/xmpp/xmpptask.cc
@@ -0,0 +1,158 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace buzz {
+
+XmppClientInterface::XmppClientInterface() {
+}
+
+XmppClientInterface::~XmppClientInterface() {
+}
+
+XmppTask::XmppTask(XmppTaskParentInterface* parent,
+                   XmppEngine::HandlerLevel level)
+    : XmppTaskBase(parent), stopped_(false) {
+#ifdef _DEBUG
+  debug_force_timeout_ = false;
+#endif
+
+  id_ = GetClient()->NextId();
+  GetClient()->AddXmppTask(this, level);
+  GetClient()->SignalDisconnected.connect(this, &XmppTask::OnDisconnect);
+}
+
+XmppTask::~XmppTask() {
+  StopImpl();
+}
+
+void XmppTask::StopImpl() {
+  while (NextStanza() != NULL) {}
+  if (!stopped_) {
+    GetClient()->RemoveXmppTask(this);
+    GetClient()->SignalDisconnected.disconnect(this);
+    stopped_ = true;
+  }
+}
+
+XmppReturnStatus XmppTask::SendStanza(const XmlElement* stanza) {
+  if (stopped_)
+    return XMPP_RETURN_BADSTATE;
+  return GetClient()->SendStanza(stanza);
+}
+
+XmppReturnStatus XmppTask::SendStanzaError(const XmlElement* element_original,
+                                           XmppStanzaError code,
+                                           const std::string& text) {
+  if (stopped_)
+    return XMPP_RETURN_BADSTATE;
+  return GetClient()->SendStanzaError(element_original, code, text);
+}
+
+void XmppTask::Stop() {
+  StopImpl();
+  Task::Stop();
+}
+
+void XmppTask::OnDisconnect() {
+  Error();
+}
+
+void XmppTask::QueueStanza(const XmlElement* stanza) {
+#ifdef _DEBUG
+  if (debug_force_timeout_)
+    return;
+#endif
+
+  stanza_queue_.push_back(new XmlElement(*stanza));
+  Wake();
+}
+
+const XmlElement* XmppTask::NextStanza() {
+  XmlElement* result = NULL;
+  if (!stanza_queue_.empty()) {
+    result = stanza_queue_.front();
+    stanza_queue_.pop_front();
+  }
+  next_stanza_.reset(result);
+  return result;
+}
+
+XmlElement* XmppTask::MakeIq(const std::string& type,
+                             const buzz::Jid& to,
+                             const std::string& id) {
+  XmlElement* result = new XmlElement(QN_IQ);
+  if (!type.empty())
+    result->AddAttr(QN_TYPE, type);
+  if (!to.IsEmpty())
+    result->AddAttr(QN_TO, to.Str());
+  if (!id.empty())
+    result->AddAttr(QN_ID, id);
+  return result;
+}
+
+XmlElement* XmppTask::MakeIqResult(const XmlElement * query) {
+  XmlElement* result = new XmlElement(QN_IQ);
+  result->AddAttr(QN_TYPE, STR_RESULT);
+  if (query->HasAttr(QN_FROM)) {
+    result->AddAttr(QN_TO, query->Attr(QN_FROM));
+  }
+  result->AddAttr(QN_ID, query->Attr(QN_ID));
+  return result;
+}
+
+bool XmppTask::MatchResponseIq(const XmlElement* stanza,
+                               const Jid& to,
+                               const std::string& id) {
+  if (stanza->Name() != QN_IQ)
+    return false;
+
+  if (stanza->Attr(QN_ID) != id)
+    return false;
+
+  return MatchStanzaFrom(stanza, to);
+}
+
+bool XmppTask::MatchStanzaFrom(const XmlElement* stanza,
+                               const Jid& to) {
+  Jid from(stanza->Attr(QN_FROM));
+  if (from == to)
+    return true;
+
+  // We address the server as "", check if we are doing so here.
+  if (!to.IsEmpty())
+    return false;
+
+  // It is legal for the server to identify itself with "domain" or
+  // "myself@domain"
+  Jid me = GetClient()->jid();
+  return (from == Jid(me.domain())) || (from == me.BareJid());
+}
+
+bool XmppTask::MatchRequestIq(const XmlElement* stanza,
+                              const std::string& type,
+                              const QName& qn) {
+  if (stanza->Name() != QN_IQ)
+    return false;
+
+  if (stanza->Attr(QN_TYPE) != type)
+    return false;
+
+  if (stanza->FirstNamed(qn) == NULL)
+    return false;
+
+  return true;
+}
+
+}
diff --git a/libjingle/xmpp/xmpptask.h b/libjingle/xmpp/xmpptask.h
new file mode 100644
index 0000000..e27b265
--- /dev/null
+++ b/libjingle/xmpp/xmpptask.h
@@ -0,0 +1,172 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPTASK_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
+
+#include <deque>
+#include <string>
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/task.h"
+#include "webrtc/base/taskparent.h"
+
+namespace buzz {
+
+/////////////////////////////////////////////////////////////////////
+//
+// XMPPTASK
+//
+/////////////////////////////////////////////////////////////////////
+//
+// See Task and XmppClient first.
+//
+// XmppTask is a task that is designed to go underneath XmppClient and be
+// useful there.  It has a way of finding its XmppClient parent so you
+// can have it nested arbitrarily deep under an XmppClient and it can
+// still find the XMPP services.
+//
+// Tasks register themselves to listen to particular kinds of stanzas
+// that are sent out by the client.  Rather than processing stanzas
+// right away, they should decide if they own the sent stanza,
+// and if so, queue it and Wake() the task, or if a stanza does not belong
+// to you, return false right away so the next XmppTask can take a crack.
+// This technique (synchronous recognize, but asynchronous processing)
+// allows you to have arbitrary logic for recognizing stanzas yet still,
+// for example, disconnect a client while processing a stanza -
+// without reentrancy problems.
+//
+/////////////////////////////////////////////////////////////////////
+
+class XmppTask;
+
+// XmppClientInterface is an abstract interface for sending and
+// handling stanzas.  It can be implemented for unit tests or
+// different network environments.  It will usually be implemented by
+// XmppClient.
+class XmppClientInterface {
+ public:
+  XmppClientInterface();
+  virtual ~XmppClientInterface();
+
+  virtual XmppEngine::State GetState() const = 0;
+  virtual const Jid& jid() const = 0;
+  virtual std::string NextId() = 0;
+  virtual XmppReturnStatus SendStanza(const XmlElement* stanza) = 0;
+  virtual XmppReturnStatus SendStanzaError(const XmlElement* original_stanza,
+                                           XmppStanzaError error_code,
+                                           const std::string& message) = 0;
+  virtual void AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) = 0;
+  virtual void RemoveXmppTask(XmppTask* task) = 0;
+  sigslot::signal0<> SignalDisconnected;
+
+  DISALLOW_EVIL_CONSTRUCTORS(XmppClientInterface);
+};
+
+// XmppTaskParentInterface is the interface require for any parent of
+// an XmppTask.  It needs, for example, a way to get an
+// XmppClientInterface.
+
+// We really ought to inherit from a TaskParentInterface, but we tried
+// that and it's way too complicated to change
+// Task/TaskParent/TaskRunner.  For now, this works.
+class XmppTaskParentInterface : public rtc::Task {
+ public:
+  explicit XmppTaskParentInterface(rtc::TaskParent* parent)
+      : Task(parent) {
+  }
+  virtual ~XmppTaskParentInterface() {}
+
+  virtual XmppClientInterface* GetClient() = 0;
+
+  DISALLOW_EVIL_CONSTRUCTORS(XmppTaskParentInterface);
+};
+
+class XmppTaskBase : public XmppTaskParentInterface {
+ public:
+  explicit XmppTaskBase(XmppTaskParentInterface* parent)
+      : XmppTaskParentInterface(parent),
+        parent_(parent) {
+  }
+  virtual ~XmppTaskBase() {}
+
+  virtual XmppClientInterface* GetClient() {
+    return parent_->GetClient();
+  }
+
+ protected:
+  XmppTaskParentInterface* parent_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(XmppTaskBase);
+};
+
+class XmppTask : public XmppTaskBase,
+                 public XmppStanzaHandler,
+                 public sigslot::has_slots<>
+{
+ public:
+  XmppTask(XmppTaskParentInterface* parent,
+           XmppEngine::HandlerLevel level = XmppEngine::HL_NONE);
+  virtual ~XmppTask();
+
+  std::string task_id() const { return id_; }
+  void set_task_id(std::string id) { id_ = id; }
+
+#ifdef _DEBUG
+  void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; }
+#endif
+
+  virtual bool HandleStanza(const XmlElement* stanza) { return false; }
+
+ protected:
+  XmppReturnStatus SendStanza(const XmlElement* stanza);
+  XmppReturnStatus SetResult(const std::string& code);
+  XmppReturnStatus SendStanzaError(const XmlElement* element_original,
+                                   XmppStanzaError code,
+                                   const std::string& text);
+
+  virtual void Stop();
+  virtual void OnDisconnect();
+
+  virtual void QueueStanza(const XmlElement* stanza);
+  const XmlElement* NextStanza();
+
+  bool MatchStanzaFrom(const XmlElement* stanza, const Jid& match_jid);
+
+  bool MatchResponseIq(const XmlElement* stanza, const Jid& to,
+                       const std::string& task_id);
+
+  static bool MatchRequestIq(const XmlElement* stanza, const std::string& type,
+                             const QName& qn);
+  static XmlElement *MakeIqResult(const XmlElement* query);
+  static XmlElement *MakeIq(const std::string& type,
+                            const Jid& to, const std::string& task_id);
+
+  // Returns true if the task is under the specified rate limit and updates the
+  // rate limit accordingly
+  bool VerifyTaskRateLimit(const std::string task_name, int max_count,
+                           int per_x_seconds);
+
+private:
+  void StopImpl();
+
+  bool stopped_;
+  std::deque<XmlElement*> stanza_queue_;
+  rtc::scoped_ptr<XmlElement> next_stanza_;
+  std::string id_;
+
+#ifdef _DEBUG
+  bool debug_force_timeout_;
+#endif
+};
+
+}  // namespace buzz
+
+#endif // WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
diff --git a/libjingle/xmpp/xmppthread.cc b/libjingle/xmpp/xmppthread.cc
new file mode 100644
index 0000000..faf2164
--- /dev/null
+++ b/libjingle/xmpp/xmppthread.cc
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/xmppthread.h"
+
+#include "webrtc/libjingle/xmpp/xmppauth.h"
+#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+
+namespace buzz {
+namespace {
+
+const uint32 MSG_LOGIN = 1;
+const uint32 MSG_DISCONNECT = 2;
+
+struct LoginData: public rtc::MessageData {
+  LoginData(const buzz::XmppClientSettings& s) : xcs(s) {}
+  virtual ~LoginData() {}
+
+  buzz::XmppClientSettings xcs;
+};
+
+} // namespace
+
+XmppThread::XmppThread() {
+  pump_ = new buzz::XmppPump(this);
+}
+
+XmppThread::~XmppThread() {
+  Stop();
+  delete pump_;
+}
+
+void XmppThread::ProcessMessages(int cms) {
+  rtc::Thread::ProcessMessages(cms);
+}
+
+void XmppThread::Login(const buzz::XmppClientSettings& xcs) {
+  Post(this, MSG_LOGIN, new LoginData(xcs));
+}
+
+void XmppThread::Disconnect() {
+  Post(this, MSG_DISCONNECT);
+}
+
+void XmppThread::OnStateChange(buzz::XmppEngine::State state) {
+}
+
+void XmppThread::OnMessage(rtc::Message* pmsg) {
+  if (pmsg->message_id == MSG_LOGIN) {
+    ASSERT(pmsg->pdata != NULL);
+    LoginData* data = reinterpret_cast<LoginData*>(pmsg->pdata);
+    pump_->DoLogin(data->xcs, new XmppSocket(buzz::TLS_DISABLED),
+        new XmppAuth());
+    delete data;
+  } else if (pmsg->message_id == MSG_DISCONNECT) {
+    pump_->DoDisconnect();
+  } else {
+    ASSERT(false);
+  }
+}
+
+}  // namespace buzz
diff --git a/libjingle/xmpp/xmppthread.h b/libjingle/xmpp/xmppthread.h
new file mode 100644
index 0000000..8017925
--- /dev/null
+++ b/libjingle/xmpp/xmppthread.h
@@ -0,0 +1,45 @@
+/*
+ *  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_LIBJINGLE_XMPP_XMPPTHREAD_H_
+#define WEBRTC_LIBJINGLE_XMPP_XMPPTHREAD_H_
+
+#include "webrtc/libjingle/xmpp/xmppclientsettings.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpppump.h"
+#include "webrtc/libjingle/xmpp/xmppsocket.h"
+#include "webrtc/base/thread.h"
+
+namespace buzz {
+
+class XmppThread:
+    public rtc::Thread, buzz::XmppPumpNotify, rtc::MessageHandler {
+public:
+  XmppThread();
+  ~XmppThread();
+
+  buzz::XmppClient* client() { return pump_->client(); }
+
+  void ProcessMessages(int cms);
+
+  void Login(const buzz::XmppClientSettings & xcs);
+  void Disconnect();
+
+private:
+  buzz::XmppPump* pump_;
+
+  void OnStateChange(buzz::XmppEngine::State state);
+  void OnMessage(rtc::Message* pmsg);
+};
+
+}  // namespace buzz
+
+#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPTHREAD_H_
+
diff --git a/modules/CNG.target.darwin-arm.mk b/modules/CNG.target.darwin-arm.mk
index 8aa231f..325b032 100644
--- a/modules/CNG.target.darwin-arm.mk
+++ b/modules/CNG.target.darwin-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.darwin-arm64.mk b/modules/CNG.target.darwin-arm64.mk
index ef2a722..a294979 100644
--- a/modules/CNG.target.darwin-arm64.mk
+++ b/modules/CNG.target.darwin-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.darwin-mips.mk b/modules/CNG.target.darwin-mips.mk
index c74926f..28d9930 100644
--- a/modules/CNG.target.darwin-mips.mk
+++ b/modules/CNG.target.darwin-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.darwin-mips64.mk b/modules/CNG.target.darwin-mips64.mk
new file mode 100644
index 0000000..d8277d9
--- /dev/null
+++ b/modules/CNG.target.darwin-mips64.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_CNG_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.c \
+	third_party/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_CNG_gyp
+
+# Alias gyp target name.
+.PHONY: CNG
+CNG: third_party_webrtc_modules_CNG_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/CNG.target.darwin-x86.mk b/modules/CNG.target.darwin-x86.mk
index 0701555..a23265d 100644
--- a/modules/CNG.target.darwin-x86.mk
+++ b/modules/CNG.target.darwin-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.darwin-x86_64.mk b/modules/CNG.target.darwin-x86_64.mk
index 49f0ee1..f7d133f 100644
--- a/modules/CNG.target.darwin-x86_64.mk
+++ b/modules/CNG.target.darwin-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.linux-arm.mk b/modules/CNG.target.linux-arm.mk
index 8aa231f..325b032 100644
--- a/modules/CNG.target.linux-arm.mk
+++ b/modules/CNG.target.linux-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.linux-arm64.mk b/modules/CNG.target.linux-arm64.mk
index ef2a722..a294979 100644
--- a/modules/CNG.target.linux-arm64.mk
+++ b/modules/CNG.target.linux-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.linux-mips.mk b/modules/CNG.target.linux-mips.mk
index c74926f..28d9930 100644
--- a/modules/CNG.target.linux-mips.mk
+++ b/modules/CNG.target.linux-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.linux-mips64.mk b/modules/CNG.target.linux-mips64.mk
new file mode 100644
index 0000000..d8277d9
--- /dev/null
+++ b/modules/CNG.target.linux-mips64.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_CNG_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.c \
+	third_party/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_CNG_gyp
+
+# Alias gyp target name.
+.PHONY: CNG
+CNG: third_party_webrtc_modules_CNG_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/CNG.target.linux-x86.mk b/modules/CNG.target.linux-x86.mk
index 0701555..a23265d 100644
--- a/modules/CNG.target.linux-x86.mk
+++ b/modules/CNG.target.linux-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/CNG.target.linux-x86_64.mk b/modules/CNG.target.linux-x86_64.mk
index 49f0ee1..f7d133f 100644
--- a/modules/CNG.target.linux-x86_64.mk
+++ b/modules/CNG.target.linux-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.darwin-arm.mk b/modules/G711.target.darwin-arm.mk
index 9e5001b..b8317a4 100644
--- a/modules/G711.target.darwin-arm.mk
+++ b/modules/G711.target.darwin-arm.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -87,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +210,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -225,6 +232,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.darwin-arm64.mk b/modules/G711.target.darwin-arm64.mk
index 0391470..5985ed5 100644
--- a/modules/G711.target.darwin-arm64.mk
+++ b/modules/G711.target.darwin-arm64.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -76,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -192,10 +200,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.darwin-mips.mk b/modules/G711.target.darwin-mips.mk
index 2b57aea..cfa4437 100644
--- a/modules/G711.target.darwin-mips.mk
+++ b/modules/G711.target.darwin-mips.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -81,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +218,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.darwin-mips64.mk b/modules/G711.target.darwin-mips64.mk
new file mode 100644
index 0000000..dd204ad
--- /dev/null
+++ b/modules/G711.target.darwin-mips64.mk
@@ -0,0 +1,271 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_G711_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_G711_gyp
+
+# Alias gyp target name.
+.PHONY: G711
+G711: third_party_webrtc_modules_G711_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/G711.target.darwin-x86.mk b/modules/G711.target.darwin-x86.mk
index 6bbab2a..ac39ccb 100644
--- a/modules/G711.target.darwin-x86.mk
+++ b/modules/G711.target.darwin-x86.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -82,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.darwin-x86_64.mk b/modules/G711.target.darwin-x86_64.mk
index e027881..33f38be 100644
--- a/modules/G711.target.darwin-x86_64.mk
+++ b/modules/G711.target.darwin-x86_64.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -81,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.linux-arm.mk b/modules/G711.target.linux-arm.mk
index 9e5001b..b8317a4 100644
--- a/modules/G711.target.linux-arm.mk
+++ b/modules/G711.target.linux-arm.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -87,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +210,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -225,6 +232,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.linux-arm64.mk b/modules/G711.target.linux-arm64.mk
index 0391470..5985ed5 100644
--- a/modules/G711.target.linux-arm64.mk
+++ b/modules/G711.target.linux-arm64.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -76,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -192,10 +200,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.linux-mips.mk b/modules/G711.target.linux-mips.mk
index 2b57aea..cfa4437 100644
--- a/modules/G711.target.linux-mips.mk
+++ b/modules/G711.target.linux-mips.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -81,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +218,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.linux-mips64.mk b/modules/G711.target.linux-mips64.mk
new file mode 100644
index 0000000..dd204ad
--- /dev/null
+++ b/modules/G711.target.linux-mips64.mk
@@ -0,0 +1,271 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_G711_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_G711_gyp
+
+# Alias gyp target name.
+.PHONY: G711
+G711: third_party_webrtc_modules_G711_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/G711.target.linux-x86.mk b/modules/G711.target.linux-x86.mk
index 6bbab2a..ac39ccb 100644
--- a/modules/G711.target.linux-x86.mk
+++ b/modules/G711.target.linux-x86.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -82,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G711.target.linux-x86_64.mk b/modules/G711.target.linux-x86_64.mk
index e027881..33f38be 100644
--- a/modules/G711.target.linux-x86_64.mk
+++ b/modules/G711.target.linux-x86_64.mk
@@ -18,13 +18,15 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
 	third_party/webrtc/modules/audio_coding/codecs/g711/g711_interface.c \
-	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c
+	third_party/webrtc/modules/audio_coding/codecs/g711/g711.c \
+	third_party/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
 
 
 # Flags passed to both C and C++ files.
@@ -81,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.darwin-arm.mk b/modules/G722.target.darwin-arm.mk
index ec53ae5..30b1a06 100644
--- a/modules/G722.target.darwin-arm.mk
+++ b/modules/G722.target.darwin-arm.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -206,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -226,6 +231,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.darwin-arm64.mk b/modules/G722.target.darwin-arm64.mk
index bab6cb8..5b94da1 100644
--- a/modules/G722.target.darwin-arm64.mk
+++ b/modules/G722.target.darwin-arm64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -90,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -180,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -193,10 +199,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.darwin-mips.mk b/modules/G722.target.darwin-mips.mk
index ff5f97b..a8ea043 100644
--- a/modules/G722.target.darwin-mips.mk
+++ b/modules/G722.target.darwin-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -212,6 +217,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.darwin-mips64.mk b/modules/G722.target.darwin-mips64.mk
new file mode 100644
index 0000000..e6985ee
--- /dev/null
+++ b/modules/G722.target.darwin-mips64.mk
@@ -0,0 +1,270 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_G722_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/g722/g722_interface.c \
+	third_party/webrtc/modules/audio_coding/codecs/g722/g722_encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/g722/g722_decode.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_G722_gyp
+
+# Alias gyp target name.
+.PHONY: G722
+G722: third_party_webrtc_modules_G722_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/G722.target.darwin-x86.mk b/modules/G722.target.darwin-x86.mk
index 7a276d6..94c4bb7 100644
--- a/modules/G722.target.darwin-x86.mk
+++ b/modules/G722.target.darwin-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.darwin-x86_64.mk b/modules/G722.target.darwin-x86_64.mk
index 589efac..118ec03 100644
--- a/modules/G722.target.darwin-x86_64.mk
+++ b/modules/G722.target.darwin-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.linux-arm.mk b/modules/G722.target.linux-arm.mk
index ec53ae5..30b1a06 100644
--- a/modules/G722.target.linux-arm.mk
+++ b/modules/G722.target.linux-arm.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -206,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -226,6 +231,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.linux-arm64.mk b/modules/G722.target.linux-arm64.mk
index bab6cb8..5b94da1 100644
--- a/modules/G722.target.linux-arm64.mk
+++ b/modules/G722.target.linux-arm64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -90,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -180,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -193,10 +199,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.linux-mips.mk b/modules/G722.target.linux-mips.mk
index ff5f97b..a8ea043 100644
--- a/modules/G722.target.linux-mips.mk
+++ b/modules/G722.target.linux-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -212,6 +217,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.linux-mips64.mk b/modules/G722.target.linux-mips64.mk
new file mode 100644
index 0000000..e6985ee
--- /dev/null
+++ b/modules/G722.target.linux-mips64.mk
@@ -0,0 +1,270 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_G722_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/g722/g722_interface.c \
+	third_party/webrtc/modules/audio_coding/codecs/g722/g722_encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/g722/g722_decode.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_G722_gyp
+
+# Alias gyp target name.
+.PHONY: G722
+G722: third_party_webrtc_modules_G722_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/G722.target.linux-x86.mk b/modules/G722.target.linux-x86.mk
index 7a276d6..94c4bb7 100644
--- a/modules/G722.target.linux-x86.mk
+++ b/modules/G722.target.linux-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/G722.target.linux-x86_64.mk b/modules/G722.target.linux-x86_64.mk
index 589efac..118ec03 100644
--- a/modules/G722.target.linux-x86_64.mk
+++ b/modules/G722.target.linux-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.darwin-arm.mk b/modules/PCM16B.target.darwin-arm.mk
index e4b94cd..404a489 100644
--- a/modules/PCM16B.target.darwin-arm.mk
+++ b/modules/PCM16B.target.darwin-arm.mk
@@ -86,11 +86,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.darwin-arm64.mk b/modules/PCM16B.target.darwin-arm64.mk
index dc883bc..6db1b5e 100644
--- a/modules/PCM16B.target.darwin-arm64.mk
+++ b/modules/PCM16B.target.darwin-arm64.mk
@@ -75,11 +75,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -88,10 +90,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.darwin-mips.mk b/modules/PCM16B.target.darwin-mips.mk
index b4a9f92..5aac061 100644
--- a/modules/PCM16B.target.darwin-mips.mk
+++ b/modules/PCM16B.target.darwin-mips.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.darwin-mips64.mk b/modules/PCM16B.target.darwin-mips64.mk
new file mode 100644
index 0000000..7a37a0c
--- /dev/null
+++ b/modules/PCM16B.target.darwin-mips64.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_PCM16B_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_PCM16B_gyp
+
+# Alias gyp target name.
+.PHONY: PCM16B
+PCM16B: third_party_webrtc_modules_PCM16B_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/PCM16B.target.darwin-x86.mk b/modules/PCM16B.target.darwin-x86.mk
index 31cae40..2345cbb 100644
--- a/modules/PCM16B.target.darwin-x86.mk
+++ b/modules/PCM16B.target.darwin-x86.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.darwin-x86_64.mk b/modules/PCM16B.target.darwin-x86_64.mk
index fd77326..21ab87f 100644
--- a/modules/PCM16B.target.darwin-x86_64.mk
+++ b/modules/PCM16B.target.darwin-x86_64.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.linux-arm.mk b/modules/PCM16B.target.linux-arm.mk
index e4b94cd..404a489 100644
--- a/modules/PCM16B.target.linux-arm.mk
+++ b/modules/PCM16B.target.linux-arm.mk
@@ -86,11 +86,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.linux-arm64.mk b/modules/PCM16B.target.linux-arm64.mk
index dc883bc..6db1b5e 100644
--- a/modules/PCM16B.target.linux-arm64.mk
+++ b/modules/PCM16B.target.linux-arm64.mk
@@ -75,11 +75,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -88,10 +90,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.linux-mips.mk b/modules/PCM16B.target.linux-mips.mk
index b4a9f92..5aac061 100644
--- a/modules/PCM16B.target.linux-mips.mk
+++ b/modules/PCM16B.target.linux-mips.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.linux-mips64.mk b/modules/PCM16B.target.linux-mips64.mk
new file mode 100644
index 0000000..7a37a0c
--- /dev/null
+++ b/modules/PCM16B.target.linux-mips64.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_PCM16B_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_PCM16B_gyp
+
+# Alias gyp target name.
+.PHONY: PCM16B
+PCM16B: third_party_webrtc_modules_PCM16B_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/PCM16B.target.linux-x86.mk b/modules/PCM16B.target.linux-x86.mk
index 31cae40..2345cbb 100644
--- a/modules/PCM16B.target.linux-x86.mk
+++ b/modules/PCM16B.target.linux-x86.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/PCM16B.target.linux-x86_64.mk b/modules/PCM16B.target.linux-x86_64.mk
index fd77326..21ab87f 100644
--- a/modules/PCM16B.target.linux-x86_64.mk
+++ b/modules/PCM16B.target.linux-x86_64.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn
index d6cdf0e..547f15f 100644
--- a/modules/audio_coding/BUILD.gn
+++ b/modules/audio_coding/BUILD.gn
@@ -147,7 +147,9 @@
 
 source_set("g711") {
   sources = [
+    "codecs/g711/include/audio_encoder_pcm.h",
     "codecs/g711/include/g711_interface.h",
+    "codecs/g711/audio_encoder_pcm.cc",
     "codecs/g711/g711_interface.c",
     "codecs/g711/g711.c",
     "codecs/g711/g711.h",
@@ -606,6 +608,8 @@
 
 source_set("webrtc_opus") {
   sources = [
+    "codecs/opus/audio_encoder_opus.cc",
+    "codecs/opus/interface/audio_encoder_opus.h",
     "codecs/opus/interface/opus_interface.h",
     "codecs/opus/opus_inst.h",
     "codecs/opus/opus_interface.c",
diff --git a/modules/audio_coding/codecs/audio_encoder.h b/modules/audio_coding/codecs/audio_encoder.h
index 1569caf..45c0a85 100644
--- a/modules/audio_coding/codecs/audio_encoder.h
+++ b/modules/audio_coding/codecs/audio_encoder.h
@@ -12,7 +12,6 @@
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
 
 #include <algorithm>
-#include <limits>
 
 #include "webrtc/base/checks.h"
 #include "webrtc/typedefs.h"
@@ -28,39 +27,48 @@
   // Accepts one 10 ms block of input audio (i.e., sample_rate_hz() / 100 *
   // num_channels() samples). Multi-channel audio must be sample-interleaved.
   // If successful, the encoder produces zero or more bytes of output in
-  // |encoded|, and returns the number of bytes. In case of error, -1 is
-  // returned. It is an error for the encoder to attempt to produce more than
-  // |max_encoded_bytes| bytes of output.
-  ssize_t Encode(uint32_t timestamp,
-                 const int16_t* audio,
-                 size_t num_samples,
-                 size_t max_encoded_bytes,
-                 uint8_t* encoded,
-                 uint32_t* encoded_timestamp) {
-    CHECK_EQ(num_samples,
-             static_cast<size_t>(sample_rate_hz() / 100 * num_channels()));
-    ssize_t num_bytes =
-        Encode(timestamp, audio, max_encoded_bytes, encoded, encoded_timestamp);
-    CHECK_LE(num_bytes,
-             static_cast<ssize_t>(std::min(
-                 max_encoded_bytes,
-                 static_cast<size_t>(std::numeric_limits<ssize_t>::max()))));
-    return num_bytes;
+  // |encoded|, and provides the number of encoded bytes in |encoded_bytes|.
+  // In case of error, false is returned, otherwise true. It is an error for the
+  // encoder to attempt to produce more than |max_encoded_bytes| bytes of
+  // output.
+  bool Encode(uint32_t timestamp,
+              const int16_t* audio,
+              size_t num_samples_per_channel,
+              size_t max_encoded_bytes,
+              uint8_t* encoded,
+              size_t* encoded_bytes,
+              uint32_t* encoded_timestamp) {
+    CHECK_EQ(num_samples_per_channel,
+             static_cast<size_t>(sample_rate_hz() / 100));
+    bool ret = Encode(timestamp,
+                      audio,
+                      max_encoded_bytes,
+                      encoded,
+                      encoded_bytes,
+                      encoded_timestamp);
+    CHECK_LE(*encoded_bytes, max_encoded_bytes);
+    return ret;
   }
 
-  // Returns the input sample rate in Hz, the number of input channels, and the
-  // number of 10 ms frames the encoder puts in one output packet. These are
-  // constants set at instantiation time.
+  // Return the input sample rate in Hz and the number of input channels.
+  // These are constants set at instantiation time.
   virtual int sample_rate_hz() const = 0;
   virtual int num_channels() const = 0;
-  virtual int num_10ms_frames_per_packet() const = 0;
+
+  // Returns the number of 10 ms frames the encoder will put in the next
+  // packet. This value may only change when Encode() outputs a packet; i.e.,
+  // the encoder may vary the number of 10 ms frames from packet to packet, but
+  // it must decide the length of the next packet no later than when outputting
+  // the preceding packet.
+  virtual int Num10MsFramesInNextPacket() const = 0;
 
  protected:
-  virtual ssize_t Encode(uint32_t timestamp,
-                         const int16_t* audio,
-                         size_t max_encoded_bytes,
-                         uint8_t* encoded,
-                         uint32_t* encoded_timestamp) = 0;
+  virtual bool Encode(uint32_t timestamp,
+                      const int16_t* audio,
+                      size_t max_encoded_bytes,
+                      uint8_t* encoded,
+                      size_t* encoded_bytes,
+                      uint32_t* encoded_timestamp) = 0;
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
new file mode 100644
index 0000000..6454e93
--- /dev/null
+++ b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -0,0 +1,98 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h"
+
+#include <limits>
+
+#include "webrtc/modules/audio_coding/codecs/g711/include/g711_interface.h"
+
+namespace webrtc {
+
+namespace {
+int16_t NumSamplesPerFrame(int num_channels,
+                           int frame_size_ms,
+                           int sample_rate_hz) {
+  int samples_per_frame = num_channels * frame_size_ms * sample_rate_hz / 1000;
+  CHECK_LE(samples_per_frame, std::numeric_limits<int16_t>::max())
+      << "Frame size too large.";
+  return static_cast<int16_t>(samples_per_frame);
+}
+}  // namespace
+
+AudioEncoderPcm::AudioEncoderPcm(const Config& config)
+    : num_channels_(config.num_channels),
+      num_10ms_frames_per_packet_(config.frame_size_ms / 10),
+      full_frame_samples_(NumSamplesPerFrame(num_channels_,
+                                             config.frame_size_ms,
+                                             kSampleRateHz)),
+      first_timestamp_in_buffer_(0) {
+  CHECK_EQ(config.frame_size_ms % 10, 0)
+      << "Frame size must be an integer multiple of 10 ms.";
+  speech_buffer_.reserve(full_frame_samples_);
+}
+
+AudioEncoderPcm::~AudioEncoderPcm() {
+}
+
+int AudioEncoderPcm::sample_rate_hz() const {
+  return kSampleRateHz;
+}
+int AudioEncoderPcm::num_channels() const {
+  return num_channels_;
+}
+int AudioEncoderPcm::Num10MsFramesInNextPacket() const {
+  return num_10ms_frames_per_packet_;
+}
+
+bool AudioEncoderPcm::Encode(uint32_t timestamp,
+                             const int16_t* audio,
+                             size_t max_encoded_bytes,
+                             uint8_t* encoded,
+                             size_t* encoded_bytes,
+                             uint32_t* encoded_timestamp) {
+  const int num_samples = sample_rate_hz() / 100 * num_channels();
+  if (speech_buffer_.empty()) {
+    first_timestamp_in_buffer_ = timestamp;
+  }
+  for (int i = 0; i < num_samples; ++i) {
+    speech_buffer_.push_back(audio[i]);
+  }
+  if (speech_buffer_.size() < static_cast<size_t>(full_frame_samples_)) {
+    *encoded_bytes = 0;
+    return true;
+  }
+  CHECK_EQ(speech_buffer_.size(), static_cast<size_t>(full_frame_samples_));
+  int16_t ret = EncodeCall(&speech_buffer_[0], full_frame_samples_, encoded);
+  speech_buffer_.clear();
+  *encoded_timestamp = first_timestamp_in_buffer_;
+  if (ret < 0)
+    return false;
+  *encoded_bytes = static_cast<size_t>(ret);
+  return true;
+}
+
+int16_t AudioEncoderPcmA::EncodeCall(const int16_t* audio,
+                                     size_t input_len,
+                                     uint8_t* encoded) {
+  return WebRtcG711_EncodeA(const_cast<int16_t*>(audio),
+                            static_cast<int16_t>(input_len),
+                            reinterpret_cast<int16_t*>(encoded));
+}
+
+int16_t AudioEncoderPcmU::EncodeCall(const int16_t* audio,
+                                     size_t input_len,
+                                     uint8_t* encoded) {
+  return WebRtcG711_EncodeU(const_cast<int16_t*>(audio),
+                            static_cast<int16_t>(input_len),
+                            reinterpret_cast<int16_t*>(encoded));
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_coding/codecs/g711/g711.gypi b/modules/audio_coding/codecs/g711/g711.gypi
index c39b4af..2b637cf 100644
--- a/modules/audio_coding/codecs/g711/g711.gypi
+++ b/modules/audio_coding/codecs/g711/g711.gypi
@@ -23,9 +23,11 @@
       },
       'sources': [
         'include/g711_interface.h',
+        'include/audio_encoder_pcm.h',
         'g711_interface.c',
         'g711.c',
         'g711.h',
+        'audio_encoder_pcm.cc',
       ],
     },
   ], # targets
diff --git a/modules/audio_coding/codecs/g711/g711_interface.c b/modules/audio_coding/codecs/g711/g711_interface.c
index 134c1e4..ec726c5 100644
--- a/modules/audio_coding/codecs/g711/g711_interface.c
+++ b/modules/audio_coding/codecs/g711/g711_interface.c
@@ -12,16 +12,12 @@
 #include "g711_interface.h"
 #include "webrtc/typedefs.h"
 
-int16_t WebRtcG711_EncodeA(void* state,
-                           int16_t* speechIn,
+int16_t WebRtcG711_EncodeA(int16_t* speechIn,
                            int16_t len,
                            int16_t* encoded) {
   int n;
   uint16_t tempVal, tempVal2;
 
-  // Set and discard to avoid getting warnings
-  (void)(state = NULL);
-
   // Sanity check of input length
   if (len < 0) {
     return (-1);
@@ -50,16 +46,12 @@
   return (len);
 }
 
-int16_t WebRtcG711_EncodeU(void* state,
-                           int16_t* speechIn,
+int16_t WebRtcG711_EncodeU(int16_t* speechIn,
                            int16_t len,
                            int16_t* encoded) {
   int n;
   uint16_t tempVal;
 
-  // Set and discard to avoid getting warnings
-  (void)(state = NULL);
-
   // Sanity check of input length
   if (len < 0) {
     return (-1);
@@ -86,17 +78,13 @@
   return (len);
 }
 
-int16_t WebRtcG711_DecodeA(void* state,
-                           int16_t* encoded,
+int16_t WebRtcG711_DecodeA(int16_t* encoded,
                            int16_t len,
                            int16_t* decoded,
                            int16_t* speechType) {
   int n;
   uint16_t tempVal;
 
-  // Set and discard to avoid getting warnings
-  (void)(state = NULL);
-
   // Sanity check of input length
   if (len < 0) {
     return (-1);
@@ -123,17 +111,13 @@
   return (len);
 }
 
-int16_t WebRtcG711_DecodeU(void* state,
-                           int16_t* encoded,
+int16_t WebRtcG711_DecodeU(int16_t* encoded,
                            int16_t len,
                            int16_t* decoded,
                            int16_t* speechType) {
   int n;
   uint16_t tempVal;
 
-  // Set and discard to avoid getting warnings
-  (void)(state = NULL);
-
   // Sanity check of input length
   if (len < 0) {
     return (-1);
@@ -160,10 +144,8 @@
   return (len);
 }
 
-int WebRtcG711_DurationEst(void* state,
-                           const uint8_t* payload,
+int WebRtcG711_DurationEst(const uint8_t* payload,
                            int payload_length_bytes) {
-  (void) state;
   (void) payload;
   /* G.711 is one byte per sample, so we can just return the number of bytes. */
   return payload_length_bytes;
diff --git a/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h b/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
new file mode 100644
index 0000000..f668296
--- /dev/null
+++ b/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_G711_INCLUDE_AUDIO_ENCODER_PCM_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_G711_INCLUDE_AUDIO_ENCODER_PCM_H_
+
+#include <vector>
+
+#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+
+namespace webrtc {
+
+class AudioEncoderPcm : public AudioEncoder {
+ public:
+  struct Config {
+    Config() : frame_size_ms(20), num_channels(1) {}
+
+    int frame_size_ms;
+    int num_channels;
+  };
+
+  explicit AudioEncoderPcm(const Config& config);
+
+  virtual ~AudioEncoderPcm();
+
+  virtual int sample_rate_hz() const OVERRIDE;
+  virtual int num_channels() const OVERRIDE;
+  virtual int Num10MsFramesInNextPacket() const OVERRIDE;
+
+ protected:
+  virtual bool Encode(uint32_t timestamp,
+                      const int16_t* audio,
+                      size_t max_encoded_bytes,
+                      uint8_t* encoded,
+                      size_t* encoded_bytes,
+                      uint32_t* encoded_timestamp) OVERRIDE;
+
+  virtual int16_t EncodeCall(const int16_t* audio,
+                             size_t input_len,
+                             uint8_t* encoded) = 0;
+
+ private:
+  static const int kSampleRateHz = 8000;
+  const int num_channels_;
+  const int num_10ms_frames_per_packet_;
+  const int16_t full_frame_samples_;
+  std::vector<int16_t> speech_buffer_;
+  uint32_t first_timestamp_in_buffer_;
+};
+
+class AudioEncoderPcmA : public AudioEncoderPcm {
+ public:
+  explicit AudioEncoderPcmA(const Config& config) : AudioEncoderPcm(config) {}
+
+ protected:
+  virtual int16_t EncodeCall(const int16_t* audio,
+                             size_t input_len,
+                             uint8_t* encoded) OVERRIDE;
+};
+
+class AudioEncoderPcmU : public AudioEncoderPcm {
+ public:
+  explicit AudioEncoderPcmU(const Config& config) : AudioEncoderPcm(config) {}
+
+ protected:
+  virtual int16_t EncodeCall(const int16_t* audio,
+                             size_t input_len,
+                             uint8_t* encoded) OVERRIDE;
+};
+
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_G711_INCLUDE_AUDIO_ENCODER_PCM_H_
diff --git a/modules/audio_coding/codecs/g711/include/g711_interface.h b/modules/audio_coding/codecs/g711/include/g711_interface.h
index 83357e4..545ca3e 100644
--- a/modules/audio_coding/codecs/g711/include/g711_interface.h
+++ b/modules/audio_coding/codecs/g711/include/g711_interface.h
@@ -28,8 +28,6 @@
  * Input speech length has be of any length.
  *
  * Input:
- *      - state              : Dummy state to make this codec look more like
- *                             other codecs
  *      - speechIn           : Input speech vector
  *      - len                : Samples in speechIn
  *
@@ -40,8 +38,7 @@
  *                             -1 - Error
  */
 
-int16_t WebRtcG711_EncodeA(void* state,
-                           int16_t* speechIn,
+int16_t WebRtcG711_EncodeA(int16_t* speechIn,
                            int16_t len,
                            int16_t* encoded);
 
@@ -52,8 +49,6 @@
  * Input speech length has be of any length.
  *
  * Input:
- *      - state              : Dummy state to make this codec look more like
- *                             other codecs
  *      - speechIn           : Input speech vector
  *      - len                : Samples in speechIn
  *
@@ -64,8 +59,7 @@
  *                             -1 - Error
  */
 
-int16_t WebRtcG711_EncodeU(void* state,
-                           int16_t* speechIn,
+int16_t WebRtcG711_EncodeU(int16_t* speechIn,
                            int16_t len,
                            int16_t* encoded);
 
@@ -75,8 +69,6 @@
  * This function decodes a packet G711 A-law frame.
  *
  * Input:
- *      - state              : Dummy state to make this codec look more like
- *                             other codecs
  *      - encoded            : Encoded data
  *      - len                : Bytes in encoded vector
  *
@@ -90,8 +82,7 @@
  *                             -1 - Error
  */
 
-int16_t WebRtcG711_DecodeA(void* state,
-                           int16_t* encoded,
+int16_t WebRtcG711_DecodeA(int16_t* encoded,
                            int16_t len,
                            int16_t* decoded,
                            int16_t* speechType);
@@ -102,8 +93,6 @@
  * This function decodes a packet G711 U-law frame.
  *
  * Input:
- *      - state              : Dummy state to make this codec look more like
- *                             other codecs
  *      - encoded            : Encoded data
  *      - len                : Bytes in encoded vector
  *
@@ -117,8 +106,7 @@
  *                             -1 - Error
  */
 
-int16_t WebRtcG711_DecodeU(void* state,
-                           int16_t* encoded,
+int16_t WebRtcG711_DecodeU(int16_t* encoded,
                            int16_t len,
                            int16_t* decoded,
                            int16_t* speechType);
@@ -129,8 +117,6 @@
  * This function estimates the duration of a G711 packet in samples.
  *
  * Input:
- *      - state              : Dummy state to make this codec look more like
- *                             other codecs
  *      - payload            : Encoded data
  *      - payloadLengthBytes : Bytes in encoded vector
  *
@@ -139,8 +125,7 @@
  *                             byte per sample.
  */
 
-int WebRtcG711_DurationEst(void* state,
-                           const uint8_t* payload,
+int WebRtcG711_DurationEst(const uint8_t* payload,
                            int payload_length_bytes);
 
 /**********************************************************************
diff --git a/modules/audio_coding/codecs/g711/test/testG711.cc b/modules/audio_coding/codecs/g711/test/testG711.cc
index 95a0246..76950fa 100644
--- a/modules/audio_coding/codecs/g711/test/testG711.cc
+++ b/modules/audio_coding/codecs/g711/test/testG711.cc
@@ -127,7 +127,7 @@
     /* G.711 encoding */
     if (!strcmp(law, "A")) {
       /* A-law encoding */
-      stream_len = WebRtcG711_EncodeA(NULL, shortdata, framelength, streamdata);
+      stream_len = WebRtcG711_EncodeA(shortdata, framelength, streamdata);
       if (argc == 6) {
         /* Write bits to file */
         if (fwrite(streamdata, sizeof(unsigned char), stream_len, bitp) !=
@@ -135,11 +135,11 @@
           return -1;
         }
       }
-      err = WebRtcG711_DecodeA(NULL, streamdata, stream_len, decoded,
+      err = WebRtcG711_DecodeA(streamdata, stream_len, decoded,
                                speechType);
     } else if (!strcmp(law, "u")) {
       /* u-law encoding */
-      stream_len = WebRtcG711_EncodeU(NULL, shortdata, framelength, streamdata);
+      stream_len = WebRtcG711_EncodeU(shortdata, framelength, streamdata);
       if (argc == 6) {
         /* Write bits to file */
         if (fwrite(streamdata, sizeof(unsigned char), stream_len, bitp) !=
@@ -147,8 +147,7 @@
           return -1;
         }
       }
-      err = WebRtcG711_DecodeU(NULL, streamdata, stream_len, decoded,
-                               speechType);
+      err = WebRtcG711_DecodeU(streamdata, stream_len, decoded, speechType);
     } else {
       printf("Wrong law mode\n");
       exit(1);
diff --git a/modules/audio_coding/codecs/ilbc/cb_construct.c b/modules/audio_coding/codecs/ilbc/cb_construct.c
index 808451f..04a59e1 100644
--- a/modules/audio_coding/codecs/ilbc/cb_construct.c
+++ b/modules/audio_coding/codecs/ilbc/cb_construct.c
@@ -60,7 +60,7 @@
     a32 += WEBRTC_SPL_MUL_16_16(*gainPtr++, cbvec1[j]);
     a32 += WEBRTC_SPL_MUL_16_16(*gainPtr, cbvec2[j]);
     gainPtr -= 2;
-    decvector[j] = (int16_t) WEBRTC_SPL_RSHIFT_W32(a32 + 8192, 14);
+    decvector[j] = (int16_t)((a32 + 8192) >> 14);
   }
 
   return;
diff --git a/modules/audio_coding/codecs/ilbc/cb_mem_energy.c b/modules/audio_coding/codecs/ilbc/cb_mem_energy.c
index f883287..50ad0ad 100644
--- a/modules/audio_coding/codecs/ilbc/cb_mem_energy.c
+++ b/modules/audio_coding/codecs/ilbc/cb_mem_energy.c
@@ -54,7 +54,7 @@
   /* Normalize the energy and store the number of shifts */
   energyShifts[0] = (int16_t)WebRtcSpl_NormW32(energy);
   tmp32 = WEBRTC_SPL_LSHIFT_W32(energy, energyShifts[0]);
-  energyW16[0] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32, 16);
+  energyW16[0] = (int16_t)(tmp32 >> 16);
 
   /* Compute the energy of the rest of the cb memory
    * by step wise adding and subtracting the next
@@ -70,7 +70,7 @@
   /* Normalize the energy and store the number of shifts */
   energyShifts[base_size] = (int16_t)WebRtcSpl_NormW32(energy);
   tmp32 = WEBRTC_SPL_LSHIFT_W32(energy, energyShifts[base_size]);
-  energyW16[base_size] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32, 16);
+  energyW16[base_size] = (int16_t)(tmp32 >> 16);
 
   ppi = filteredCB + lMem - 1 - lTarget;
   ppo = filteredCB + lMem - 1;
diff --git a/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.c b/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.c
index 29f499f..e5fb81c 100644
--- a/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.c
+++ b/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.c
@@ -60,7 +60,7 @@
     /* Normalize the energy and store the number of shifts */
     (*enShPtr) = (int16_t)WebRtcSpl_NormW32(energy);
     tmp32 = WEBRTC_SPL_LSHIFT_W32(energy, (*enShPtr));
-    (*enPtr) = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32, 16);
+    *enPtr = (int16_t)(tmp32 >> 16);
     enShPtr++;
     enPtr++;
   }
diff --git a/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.c b/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.c
index a2bc9b8..4c7332a 100644
--- a/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.c
+++ b/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.c
@@ -47,7 +47,7 @@
        operation on the edge samples */
     tmp  = WEBRTC_SPL_MUL_16_16(*ppi, *ppi);
     tmp -= WEBRTC_SPL_MUL_16_16(*ppo, *ppo);
-    energy += WEBRTC_SPL_RSHIFT_W32(tmp, scale);
+    energy += tmp >> scale;
     energy = WEBRTC_SPL_MAX(energy, 0);
 
     ppi--;
@@ -60,6 +60,6 @@
     *eSh_ptr++ = shft;
 
     tmp = WEBRTC_SPL_LSHIFT_W32(energy, shft);
-    *eW16_ptr++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp, 16);
+    *eW16_ptr++ = (int16_t)(tmp >> 16);
   }
 }
diff --git a/modules/audio_coding/codecs/ilbc/cb_search_core.c b/modules/audio_coding/codecs/ilbc/cb_search_core.c
index c2299d5..a511422 100644
--- a/modules/audio_coding/codecs/ilbc/cb_search_core.c
+++ b/modules/audio_coding/codecs/ilbc/cb_search_core.c
@@ -66,7 +66,7 @@
   for (i=0;i<range;i++) {
     /* Calculate cDot*cDot and put the result in a int16_t */
     tmp32 = WEBRTC_SPL_LSHIFT_W32(*cDotPtr,sh);
-    tmp16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32,16);
+    tmp16 = (int16_t)(tmp32 >> 16);
     cDotSqW16 = (int16_t)(((int32_t)(tmp16)*(tmp16))>>16);
 
     /* Calculate the criteria (cDot*cDot/energy) */
diff --git a/modules/audio_coding/codecs/ilbc/cb_update_best_index.c b/modules/audio_coding/codecs/ilbc/cb_update_best_index.c
index 88ea199..9e32437 100644
--- a/modules/audio_coding/codecs/ilbc/cb_update_best_index.c
+++ b/modules/audio_coding/codecs/ilbc/cb_update_best_index.c
@@ -51,8 +51,7 @@
      calculate the gain and store this index as the new best one
   */
 
-  if (WEBRTC_SPL_RSHIFT_W32(CritNew, shNew)>
-      WEBRTC_SPL_RSHIFT_W32((*CritMax),shOld)) {
+  if ((CritNew >> shNew) > (*CritMax >> shOld)) {
 
     tmp16 = (int16_t)WebRtcSpl_NormW32(cDotNew);
     tmp16 = 16 - tmp16;
diff --git a/modules/audio_coding/codecs/ilbc/chebyshev.c b/modules/audio_coding/codecs/ilbc/chebyshev.c
index b49dd79..6174c9d 100644
--- a/modules/audio_coding/codecs/ilbc/chebyshev.c
+++ b/modules/audio_coding/codecs/ilbc/chebyshev.c
@@ -46,8 +46,8 @@
     tmp2W32 = tmp1W32;
 
     /* Split b1 (in tmp1W32) into a high and low part */
-    b1_high = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp1W32, 16);
-    b1_low = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp1W32-WEBRTC_SPL_LSHIFT_W32(((int32_t)b1_high),16), 1);
+    b1_high = (int16_t)(tmp1W32 >> 16);
+    b1_low = (int16_t)((tmp1W32 - ((int32_t)b1_high << 16)) >> 1);
 
     /* Calculate 2*x*b1-b2+f[i] */
     tmp1W32 = WEBRTC_SPL_LSHIFT_W32( (WEBRTC_SPL_MUL_16_16(b1_high, x) +
@@ -61,8 +61,8 @@
   }
 
   /* Split b1 (in tmp1W32) into a high and low part */
-  b1_high = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp1W32, 16);
-  b1_low = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp1W32-WEBRTC_SPL_LSHIFT_W32(((int32_t)b1_high),16), 1);
+  b1_high = (int16_t)(tmp1W32 >> 16);
+  b1_low = (int16_t)((tmp1W32 - ((int32_t)b1_high << 16)) >> 1);
 
   /* tmp1W32 = x*b1 - b2 + f[i]/2 */
   tmp1W32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(b1_high, x), 1) +
@@ -77,6 +77,6 @@
   } else if (tmp1W32<((int32_t)-33554432)) {
     return(WEBRTC_SPL_WORD16_MIN);
   } else {
-    return((int16_t)WEBRTC_SPL_RSHIFT_W32(tmp1W32, 10));
+    return (int16_t)(tmp1W32 >> 10);
   }
 }
diff --git a/modules/audio_coding/codecs/ilbc/do_plc.c b/modules/audio_coding/codecs/ilbc/do_plc.c
index c0f5368..4d233e3 100644
--- a/modules/audio_coding/codecs/ilbc/do_plc.c
+++ b/modules/audio_coding/codecs/ilbc/do_plc.c
@@ -262,11 +262,11 @@
 
       /* mix noise and pitch repeatition */
 
-      PLCresidual[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tot_gain,
-                                                                (int16_t)WEBRTC_SPL_RSHIFT_W32( (WEBRTC_SPL_MUL_16_16(pitchfact, PLCresidual[i]) +
-                                                                                                       WEBRTC_SPL_MUL_16_16((32767-pitchfact), randvec[i]) + 16384),
-                                                                                                      15),
-                                                                15);
+      PLCresidual[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
+          tot_gain,
+          (pitchfact * PLCresidual[i] + (32767 - pitchfact) * randvec[i] +
+              16384) >> 15,
+          15);
 
       /* Shifting down the result one step extra to ensure that no overflow
          will occur */
diff --git a/modules/audio_coding/codecs/ilbc/get_lsp_poly.c b/modules/audio_coding/codecs/ilbc/get_lsp_poly.c
index d44380f..2b0fe2b 100644
--- a/modules/audio_coding/codecs/ilbc/get_lsp_poly.c
+++ b/modules/audio_coding/codecs/ilbc/get_lsp_poly.c
@@ -64,8 +64,8 @@
     for(j=i; j>1; j--)
     {
       /* Compute f[j] = f[j] + tmp*f[j-1] + f[j-2]; */
-      high = (int16_t)WEBRTC_SPL_RSHIFT_W32(fPtr[-1], 16);
-      low = (int16_t)WEBRTC_SPL_RSHIFT_W32(fPtr[-1]-WEBRTC_SPL_LSHIFT_W32(((int32_t)high),16), 1);
+      high = (int16_t)(fPtr[-1] >> 16);
+      low = (int16_t)((fPtr[-1] - ((int32_t)high << 16)) >> 1);
 
       tmpW32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(high, (*lspPtr)), 2) +
           WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16_RSFT(low, (*lspPtr), 15), 2);
diff --git a/modules/audio_coding/codecs/ilbc/hp_input.c b/modules/audio_coding/codecs/ilbc/hp_input.c
index 48bd7c4..40c35eb 100644
--- a/modules/audio_coding/codecs/ilbc/hp_input.c
+++ b/modules/audio_coding/codecs/ilbc/hp_input.c
@@ -65,7 +65,7 @@
     tmpW32b = WEBRTC_SPL_SAT((int32_t)268435455, tmpW32b, (int32_t)-268435456);
 
     /* Convert back to Q0 and multiply with 0.5 */
-    signal[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32b, 13);
+    signal[i] = (int16_t)(tmpW32b >> 13);
 
     /* Update state (filtered part) */
     y[2] = y[0];
diff --git a/modules/audio_coding/codecs/ilbc/hp_output.c b/modules/audio_coding/codecs/ilbc/hp_output.c
index 432fdee..e1de829 100644
--- a/modules/audio_coding/codecs/ilbc/hp_output.c
+++ b/modules/audio_coding/codecs/ilbc/hp_output.c
@@ -65,7 +65,7 @@
     tmpW32b = WEBRTC_SPL_SAT((int32_t)67108863, tmpW32b, (int32_t)-67108864);
 
     /* Convert back to Q0 and multiply with 2 */
-    signal[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32b, 11);
+    signal[i] = (int16_t)(tmpW32b >> 11);
 
     /* Update state (filtered part) */
     y[2] = y[0];
diff --git a/modules/audio_coding/codecs/ilbc/interpolate.c b/modules/audio_coding/codecs/ilbc/interpolate.c
index b6ea201..d0869a5 100644
--- a/modules/audio_coding/codecs/ilbc/interpolate.c
+++ b/modules/audio_coding/codecs/ilbc/interpolate.c
@@ -39,9 +39,7 @@
 
   invcoef = 16384 - coef; /* 16384 = 1.0 (Q14)*/
   for (i = 0; i < length; i++) {
-    out[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(
-        (WEBRTC_SPL_MUL_16_16(coef, in1[i]) + WEBRTC_SPL_MUL_16_16(invcoef, in2[i]))+8192,
-        14);
+    out[i] = (int16_t)((coef * in1[i] + invcoef * in2[i] + 8192) >> 14);
   }
 
   return;
diff --git a/modules/audio_coding/codecs/ilbc/lsf_to_lsp.c b/modules/audio_coding/codecs/ilbc/lsf_to_lsp.c
index 579fdcf..078a0fc 100644
--- a/modules/audio_coding/codecs/ilbc/lsf_to_lsp.c
+++ b/modules/audio_coding/codecs/ilbc/lsf_to_lsp.c
@@ -54,7 +54,7 @@
 
     /* Calculate linear approximation */
     tmpW32 = WEBRTC_SPL_MUL_16_16(WebRtcIlbcfix_kCosDerivative[k], diff);
-    lsp[i] = WebRtcIlbcfix_kCos[k]+(int16_t)(WEBRTC_SPL_RSHIFT_W32(tmpW32, 12));
+    lsp[i] = WebRtcIlbcfix_kCos[k] + (int16_t)(tmpW32 >> 12);
   }
 
   return;
diff --git a/modules/audio_coding/codecs/ilbc/lsf_to_poly.c b/modules/audio_coding/codecs/ilbc/lsf_to_poly.c
index acc5ac8..c3a34ca 100644
--- a/modules/audio_coding/codecs/ilbc/lsf_to_poly.c
+++ b/modules/audio_coding/codecs/ilbc/lsf_to_poly.c
@@ -71,10 +71,10 @@
   for (i=5; i>0; i--)
   {
     tmpW32 = (*f1ptr) + (*f2ptr);
-    (*a1ptr) = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32+4096),13);
+    *a1ptr = (int16_t)((tmpW32 + 4096) >> 13);
 
     tmpW32 = (*f1ptr) - (*f2ptr);
-    (*a2ptr) = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32+4096),13);
+    *a2ptr = (int16_t)((tmpW32 + 4096) >> 13);
 
     a1ptr++;
     a2ptr--;
diff --git a/modules/audio_coding/codecs/ilbc/poly_to_lsp.c b/modules/audio_coding/codecs/ilbc/poly_to_lsp.c
index e194e8f..74bb1b7 100644
--- a/modules/audio_coding/codecs/ilbc/poly_to_lsp.c
+++ b/modules/audio_coding/codecs/ilbc/poly_to_lsp.c
@@ -56,8 +56,10 @@
   (*f1ptr) = 1024; /* 1.0 in Q10 */
   (*f2ptr) = 1024; /* 1.0 in Q10 */
   for (i = 0; i < 5; i++) {
-    (*(f1ptr+1)) = (int16_t)(WEBRTC_SPL_RSHIFT_W32(((int32_t)(*a_i_ptr)+(*a_10mi_ptr)), 2) - (*f1ptr));
-    (*(f2ptr+1)) = (int16_t)(WEBRTC_SPL_RSHIFT_W32(((int32_t)(*a_i_ptr)-(*a_10mi_ptr)), 2) + (*f2ptr));
+    *(f1ptr + 1) =
+        (int16_t)((((int32_t)(*a_i_ptr) + *a_10mi_ptr) >> 2) - *f1ptr);
+    *(f2ptr + 1) =
+        (int16_t)((((int32_t)(*a_i_ptr) - *a_10mi_ptr) >> 2) + *f2ptr);
     a_i_ptr++;
     a_10mi_ptr--;
     f1ptr++;
diff --git a/modules/audio_coding/codecs/ilbc/refiner.c b/modules/audio_coding/codecs/ilbc/refiner.c
index fed3394..e96ae26 100644
--- a/modules/audio_coding/codecs/ilbc/refiner.c
+++ b/modules/audio_coding/codecs/ilbc/refiner.c
@@ -81,7 +81,7 @@
 
   if (scalefact>0) {
     for (i=0;i<corrdim;i++) {
-      corrVec[i]=(int16_t)WEBRTC_SPL_RSHIFT_W32(corrVecTemp[i], scalefact);
+      corrVec[i] = (int16_t)(corrVecTemp[i] >> scalefact);
     }
   } else {
     for (i=0;i<corrdim;i++) {
diff --git a/modules/audio_coding/codecs/ilbc/smooth.c b/modules/audio_coding/codecs/ilbc/smooth.c
index c975098..3d59c52 100644
--- a/modules/audio_coding/codecs/ilbc/smooth.c
+++ b/modules/audio_coding/codecs/ilbc/smooth.c
@@ -101,7 +101,7 @@
   } else {
     /* crit = 0.05 * w00 (Result in Q-6) */
     crit = WEBRTC_SPL_SHIFT_W32(
-        WEBRTC_SPL_MUL(ENH_A0, WEBRTC_SPL_RSHIFT_W32(w00prim, 14)),
+        WEBRTC_SPL_MUL(ENH_A0, w00prim >> 14),
         -(6-scale+scale1));
   }
 
@@ -139,7 +139,7 @@
       endiff = (w11w00-w10w10);
       endiff = WEBRTC_SPL_MAX(0, endiff);
       /* denom is in Q16 */
-      denom = WebRtcSpl_DivW32W16(endiff, (int16_t)WEBRTC_SPL_RSHIFT_W32(w00w00, 16));
+      denom = WebRtcSpl_DivW32W16(endiff, (int16_t)(w00w00 >> 16));
     } else {
       denom = 65536;
     }
@@ -151,10 +151,10 @@
 
       if (scale>0) {
         /* denomW16 is in Q(16+scale) */
-        denomW16=(int16_t)WEBRTC_SPL_RSHIFT_W32(denom, scale);
+        denomW16 = (int16_t)(denom >> scale);
 
         /* num in Q(34-scale) */
-        num=WEBRTC_SPL_RSHIFT_W32(ENH_A0_MINUS_A0A0DIV4, scale);
+        num = ENH_A0_MINUS_A0A0DIV4 >> scale;
       } else {
         /* denomW16 is in Q16 */
         denomW16=(int16_t)denom;
@@ -174,8 +174,8 @@
       scale = bitsw00-scale2-15;
 
       if (scale>0) {
-        w10prim=WEBRTC_SPL_RSHIFT_W32(w10prim, scale);
-        w00prim=WEBRTC_SPL_RSHIFT_W32(w00prim, scale);
+        w10prim >>= scale;
+        w00prim >>= scale;
       }
 
       if ((w00prim>0)&&(w10prim>0)) {
@@ -187,7 +187,7 @@
           B_W32 = (int32_t)1073741824 - (int32_t)ENH_A0DIV2 -
               WEBRTC_SPL_MUL(A, w11_div_w00);
         }
-        B = (int16_t)WEBRTC_SPL_RSHIFT_W32(B_W32, 16); /* B in Q14 */
+        B = (int16_t)(B_W32 >> 16);  /* B in Q14. */
       } else {
         /* No smoothing */
         A = 0;
diff --git a/modules/audio_coding/codecs/ilbc/smooth_out_data.c b/modules/audio_coding/codecs/ilbc/smooth_out_data.c
index cf3b30a..622af7b 100644
--- a/modules/audio_coding/codecs/ilbc/smooth_out_data.c
+++ b/modules/audio_coding/codecs/ilbc/smooth_out_data.c
@@ -31,8 +31,7 @@
   int32_t errs;
 
   for(i=0;i<80;i++) {
-    odata[i]= (int16_t)WEBRTC_SPL_RSHIFT_W32(
-        (WEBRTC_SPL_MUL_16_16(C, surround[i])+1024), 11);
+    odata[i]= (int16_t)((C * surround[i] + 1024) >> 11);
   }
 
   errs=0;
diff --git a/modules/audio_coding/codecs/ilbc/sort_sq.c b/modules/audio_coding/codecs/ilbc/sort_sq.c
index dcfd8bd..c51bf6d 100644
--- a/modules/audio_coding/codecs/ilbc/sort_sq.c
+++ b/modules/audio_coding/codecs/ilbc/sort_sq.c
@@ -40,7 +40,7 @@
       i++;
     }
 
-    if (x > WEBRTC_SPL_RSHIFT_W32(( (int32_t)cb[i] + cb[i - 1] + 1),1)) {
+    if (x > (((int32_t)cb[i] + cb[i - 1] + 1) >> 1)) {
       *index = i;
       *xq = cb[i];
     } else {
diff --git a/modules/audio_coding/codecs/ilbc/window32_w32.c b/modules/audio_coding/codecs/ilbc/window32_w32.c
index 9ff1be3..ef5357e 100644
--- a/modules/audio_coding/codecs/ilbc/window32_w32.c
+++ b/modules/audio_coding/codecs/ilbc/window32_w32.c
@@ -42,15 +42,15 @@
    */
   for (i = 0; i < N; i++) {
     /* Extract higher bytes */
-    x_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(x[i], 16);
-    y_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(y[i], 16);
+    x_hi = (int16_t)(x[i] >> 16);
+    y_hi = (int16_t)(y[i] >> 16);
 
     /* Extract lower bytes, defined as (w32 - hi<<16)>>1 */
     temp = WEBRTC_SPL_LSHIFT_W32((int32_t)x_hi, 16);
-    x_low = (int16_t) WEBRTC_SPL_RSHIFT_W32((x[i] - temp), 1);
+    x_low = (int16_t)((x[i] - temp) >> 1);
 
     temp = WEBRTC_SPL_LSHIFT_W32((int32_t)y_hi, 16);
-    y_low = (int16_t) WEBRTC_SPL_RSHIFT_W32((y[i] - temp), 1);
+    y_low = (int16_t)((y[i] - temp) >> 1);
 
     /* Calculate z by a 32 bit multiplication using both low and high from x and y */
     temp = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(x_hi, y_hi), 1);
diff --git a/modules/audio_coding/codecs/ilbc/xcorr_coef.c b/modules/audio_coding/codecs/ilbc/xcorr_coef.c
index eb7f828..38af71f 100644
--- a/modules/audio_coding/codecs/ilbc/xcorr_coef.c
+++ b/modules/audio_coding/codecs/ilbc/xcorr_coef.c
@@ -131,9 +131,7 @@
     pos+=step;
 
     /* Do a +/- to get the next energy */
-    Energy += step*(WEBRTC_SPL_RSHIFT_W32(
-        ((int32_t)(*rp_end)*(*rp_end)) - ((int32_t)(*rp_beg)*(*rp_beg)),
-        shifts));
+    Energy += step * ((*rp_end * *rp_end - *rp_beg * *rp_beg) >> shifts);
     rp_beg+=step;
     rp_end+=step;
   }
diff --git a/modules/audio_coding/codecs/isac/fix/source/arith_routines.c b/modules/audio_coding/codecs/isac/fix/source/arith_routines.c
index 38eecb7..5925d68 100644
--- a/modules/audio_coding/codecs/isac/fix/source/arith_routines.c
+++ b/modules/audio_coding/codecs/isac/fix/source/arith_routines.c
@@ -72,11 +72,10 @@
     }
     /* write remaining data to bitstream, if "full == 0" first byte has data */
     if (streamData->full == 0) {
-      *streamPtr++ += (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24);
+      *streamPtr++ += (uint16_t)(streamData->streamval >> 24);
       streamData->full = 1;
     } else {
-      *streamPtr = (uint16_t) WEBRTC_SPL_LSHIFT_W32(
-          WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24), 8);
+      *streamPtr = (uint16_t)((streamData->streamval >> 24) << 8);
       streamData->full = 0;
     }
   }
@@ -111,11 +110,10 @@
     }
     /* write remaining data (2 bytes) to bitstream */
     if (streamData->full) {
-      *streamPtr++ = (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 16);
+      *streamPtr++ = (uint16_t)(streamData->streamval >> 16);
     } else {
-      *streamPtr++ |= (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24);
-      *streamPtr = (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 8)
-          & 0xFF00;
+      *streamPtr++ |= (uint16_t)(streamData->streamval >> 24);
+      *streamPtr = (uint16_t)(streamData->streamval >> 8) & 0xFF00;
     }
   }
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c b/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c
index b88bc1f..83f36fe 100644
--- a/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c
+++ b/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c
@@ -65,7 +65,7 @@
 
     /* update interval */
     W_upper_LSB = W_upper & 0x0000FFFF;
-    W_upper_MSB = WEBRTC_SPL_RSHIFT_W32(W_upper, 16);
+    W_upper_MSB = W_upper >> 16;
     W_lower = WEBRTC_SPL_UMUL(W_upper_MSB, cdfLo);
     W_lower += ((W_upper_LSB * cdfLo) >> 16);
     W_upper = WEBRTC_SPL_UMUL(W_upper_MSB, cdfHi);
@@ -103,11 +103,10 @@
     {
       W_upper = WEBRTC_SPL_LSHIFT_W32(W_upper, 8);
       if (streamData->full == 0) {
-        *streamPtr++ += (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24);
+        *streamPtr++ += (uint16_t)(streamData->streamval >> 24);
         streamData->full = 1;
       } else {
-        *streamPtr = (uint16_t) WEBRTC_SPL_LSHIFT_W32(
-            WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24), 8);
+        *streamPtr = (uint16_t)((streamData->streamval >> 24) << 8);
         streamData->full = 0;
       }
 
@@ -185,7 +184,7 @@
   {
     /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
     W_upper_LSB = W_upper & 0x0000FFFF;
-    W_upper_MSB = WEBRTC_SPL_RSHIFT_W32(W_upper, 16);
+    W_upper_MSB = W_upper >> 16;
 
     /* start halfway the cdf range */
     sizeTmp = *cdfSize++ / 2;
diff --git a/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c b/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c
index 27f582a..5c7df47 100644
--- a/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c
+++ b/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c
@@ -71,7 +71,7 @@
   /* Find index for x-value */
   qtmp1 = WEBRTC_SPL_SAT(kHistEdges[50],xinQ15,kHistEdges[0]);
   ind = WEBRTC_SPL_MUL(5, qtmp1 - kHistEdges[0]);
-  ind =  WEBRTC_SPL_RSHIFT_W32(ind, 16);
+  ind >>= 16;
 
   /* Calculate corresponding y-value ans return*/
   qtmp1 = qtmp1 - kHistEdges[ind];
@@ -300,7 +300,7 @@
       candQ7 = - *dataQ7 + 64;
       cdfTmp = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8));
 
-      W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB);
+      W_tmp = (uint32_t)cdfTmp * W_upper_MSB;
       W_tmp += ((uint32_t)cdfTmp * (uint32_t)W_upper_LSB) >> 16;
 
       if (streamVal > W_tmp)
@@ -309,7 +309,7 @@
         candQ7 += 128;
         cdfTmp = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8));
 
-        W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB);
+        W_tmp = (uint32_t)cdfTmp * W_upper_MSB;
         W_tmp += ((uint32_t)cdfTmp * (uint32_t)W_upper_LSB) >> 16;
 
         while (streamVal > W_tmp)
@@ -319,7 +319,7 @@
           cdfTmp = WebRtcIsacfix_Piecewise(
               WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8));
 
-          W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB);
+          W_tmp = (uint32_t)cdfTmp * W_upper_MSB;
           W_tmp += ((uint32_t)cdfTmp * (uint32_t)W_upper_LSB) >> 16;
 
           /* error check */
@@ -338,7 +338,7 @@
         candQ7 -= 128;
         cdfTmp = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8));
 
-        W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB);
+        W_tmp = (uint32_t)cdfTmp * W_upper_MSB;
         W_tmp += ((uint32_t)cdfTmp * (uint32_t)W_upper_LSB) >> 16;
 
         while ( !(streamVal > W_tmp) )
@@ -348,7 +348,7 @@
           cdfTmp = WebRtcIsacfix_Piecewise(
               WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8));
 
-          W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB);
+          W_tmp = (uint32_t)cdfTmp * W_upper_MSB;
           W_tmp += ((uint32_t)cdfTmp * (uint32_t)W_upper_LSB) >> 16;
 
           /* error check */
diff --git a/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c b/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c
index 7012e8d..63797d2 100644
--- a/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c
+++ b/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c
@@ -200,8 +200,8 @@
     }
 
     /* kBitsByteSec is in Q15 */
-    recRtpRate = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(kBitsByteSec,
-                                                                     (int32_t)pksize), 15) + bweStr->recHeaderRate;
+    recRtpRate = (int16_t)((kBitsByteSec * pksize) >> 15) +
+        bweStr->recHeaderRate;
 
   } else {
     /* If frameSize changed since last call, from 60 to 30, recalculate some values */
@@ -215,8 +215,8 @@
     }
 
     /* kBitsByteSec is in Q14 */
-    recRtpRate = (uint16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(kBitsByteSec,
-                                                                      (int32_t)pksize), 14) + bweStr->recHeaderRate;
+    recRtpRate = (uint16_t)((kBitsByteSec * pksize) >> 14) +
+        bweStr->recHeaderRate;
   }
 
 
@@ -293,7 +293,7 @@
 
           if ( reductionFactor != 0 ) {
             bweStr->recBwInv = WEBRTC_SPL_MUL((int32_t)bweStr->recBwInv, (int32_t)reductionFactor);
-            bweStr->recBwInv = WEBRTC_SPL_RSHIFT_W32((int32_t)bweStr->recBwInv, 13);
+            bweStr->recBwInv = (int32_t)bweStr->recBwInv >> 13;
 
           } else {
             static const uint32_t kInitRate = INIT_BN_EST + INIT_HDR_RATE;
@@ -345,8 +345,8 @@
         }
       }
 
-      if ((bweStr->prevRtpRate > WEBRTC_SPL_RSHIFT_W32((int32_t) bweStr->recBwAvg, 5)) &&
-          (recRtpRate > WEBRTC_SPL_RSHIFT_W32((int32_t)bweStr->recBwAvg, 5)) &&
+      if ((bweStr->prevRtpRate > (int32_t)bweStr->recBwAvg >> 5) &&
+          (recRtpRate > (int32_t)bweStr->recBwAvg >> 5) &&
           !bweStr->inWaitPeriod) {
 
         /* test if still in initiation period and increment counter */
@@ -356,7 +356,7 @@
         } else {
           /* weight decreases with number of updates, 1/countUpdates in Q13  */
           weight = (uint16_t) WebRtcSpl_DivW32W16(
-              (int32_t)(8192 + WEBRTC_SPL_RSHIFT_W32((int32_t) bweStr->countUpdates, 1)),
+              8192 + (bweStr->countUpdates >> 1),
               (int16_t)bweStr->countUpdates);
         }
 
@@ -374,8 +374,8 @@
 
         /* compute inverse receiving rate for last packet, in Q19 */
         numBytesInv = (uint16_t) WebRtcSpl_DivW32W16(
-            (int32_t)(524288 + WEBRTC_SPL_RSHIFT_W32(((int32_t)pksize + HEADER_SIZE), 1)),
-            (int16_t)(pksize + HEADER_SIZE));
+            524288 + ((pksize + HEADER_SIZE) >> 1),
+            pksize + HEADER_SIZE);
 
         /* 8389 is  ~ 1/128000 in Q30 */
         byteSecondsPerBit = WEBRTC_SPL_MUL_16_16(arrTimeDiff, 8389);
@@ -445,12 +445,12 @@
         arrTimeNoiseAbs = arrTimeNoise;
 
         /* long term averaged absolute jitter, Q15 */
-        weight = WEBRTC_SPL_RSHIFT_W32(weight, 3);
+        weight >>= 3;
         bweStr->recJitter = WEBRTC_SPL_MUL(weight, WEBRTC_SPL_LSHIFT_W32(arrTimeNoiseAbs, 5))
             +  WEBRTC_SPL_MUL(1024 - weight, bweStr->recJitter);
 
         /* remove the fractional portion */
-        bweStr->recJitter = WEBRTC_SPL_RSHIFT_W32(bweStr->recJitter, 10);
+        bweStr->recJitter >>= 10;
 
         /* Maximum jitter is 10 msec in Q15 */
         if (bweStr->recJitter > (int32_t)327680) {
@@ -461,7 +461,7 @@
         /* Calculation in Q13 products in Q23 */
         bweStr->recJitterShortTermAbs = WEBRTC_SPL_MUL(51, WEBRTC_SPL_LSHIFT_W32(arrTimeNoiseAbs, 3)) +
             WEBRTC_SPL_MUL(973, bweStr->recJitterShortTermAbs);
-        bweStr->recJitterShortTermAbs = WEBRTC_SPL_RSHIFT_W32(bweStr->recJitterShortTermAbs , 10);
+        bweStr->recJitterShortTermAbs >>= 10;
 
         /* short term averaged jitter */
         /* Calculation in Q13 products in Q23 */
@@ -470,10 +470,10 @@
 
         if (bweStr->recJitterShortTerm < 0) {
           temp = -bweStr->recJitterShortTerm;
-          temp = WEBRTC_SPL_RSHIFT_W32(temp, 12);
+          temp >>= 12;
           bweStr->recJitterShortTerm = -temp;
         } else {
-          bweStr->recJitterShortTerm = WEBRTC_SPL_RSHIFT_W32(bweStr->recJitterShortTerm, 12);
+          bweStr->recJitterShortTerm >>= 12;
         }
       }
     }
@@ -558,7 +558,7 @@
     /* sendMaxDelayAvg = 0.9 * sendMaxDelayAvg + 0.1 * MAX_ISAC_MD */
     bweStr->sendMaxDelayAvg = WEBRTC_SPL_MUL(461, bweStr->sendMaxDelayAvg) +
         WEBRTC_SPL_MUL(51, WEBRTC_SPL_LSHIFT_W32((int32_t)MAX_ISAC_MD, 9));
-    bweStr->sendMaxDelayAvg = WEBRTC_SPL_RSHIFT_W32(bweStr->sendMaxDelayAvg, 9);
+    bweStr->sendMaxDelayAvg >>= 9;
 
   } else {
     RateInd = Index;
@@ -566,7 +566,7 @@
     /* sendMaxDelayAvg = 0.9 * sendMaxDelayAvg + 0.1 * MIN_ISAC_MD */
     bweStr->sendMaxDelayAvg = WEBRTC_SPL_MUL(461, bweStr->sendMaxDelayAvg) +
         WEBRTC_SPL_MUL(51, WEBRTC_SPL_LSHIFT_W32((int32_t)MIN_ISAC_MD,9));
-    bweStr->sendMaxDelayAvg = WEBRTC_SPL_RSHIFT_W32(bweStr->sendMaxDelayAvg, 9);
+    bweStr->sendMaxDelayAvg >>= 9;
 
   }
 
@@ -644,7 +644,7 @@
   /* 0.9 times recBwAvgQ in Q16 */
   /* 461/512 - 25/65536 =0.900009 */
   tempTerm1 = WEBRTC_SPL_MUL(bweStr->recBwAvgQ, 25);
-  tempTerm1 = WEBRTC_SPL_RSHIFT_W32(tempTerm1, 7);
+  tempTerm1 >>= 7;
   tempTermX = WEBRTC_SPL_UMUL(461, bweStr->recBwAvgQ) - tempTerm1;
 
   /* rate in Q16 */
@@ -667,7 +667,7 @@
   tempTermX += KQRate01[rateInd];
 
   /* Shift back to Q7 */
-  bweStr->recBwAvgQ = WEBRTC_SPL_RSHIFT_W32(tempTermX, 9);
+  bweStr->recBwAvgQ = tempTermX >> 9;
 
   /* Count consecutive received bandwidth above 28000 kbps (28000 in Q7 = 3584000) */
   /* If 66 high estimates in a row, set highSpeedRec to one */
@@ -700,13 +700,13 @@
     tempTerm1 = tempTermX + tempMin;
 
     /* update quantized average, shift back to Q9 */
-    bweStr->recMaxDelayAvgQ = WEBRTC_SPL_RSHIFT_W32(tempTerm1, 9);
+    bweStr->recMaxDelayAvgQ = tempTerm1 >> 9;
   } else {
     maxDelayBit = 12;
     tempTerm1 =  tempTermX + tempMax;
 
     /* update quantized average, shift back to Q9 */
-    bweStr->recMaxDelayAvgQ = WEBRTC_SPL_RSHIFT_W32(tempTerm1, 9);
+    bweStr->recMaxDelayAvgQ = tempTerm1 >> 9;
   }
 
   /* Return bandwitdh and jitter index (0..23) */
@@ -727,39 +727,41 @@
   rec_jitter_short_term_abs_inv = 0x80000000u / bweStr->recJitterShortTermAbs;
 
   /* Q27 = 9 + 18 */
-  jitter_sign = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(bweStr->recJitterShortTerm, 4), (int32_t)rec_jitter_short_term_abs_inv);
+  jitter_sign = (bweStr->recJitterShortTerm >> 4) *
+      rec_jitter_short_term_abs_inv;
 
   if (jitter_sign < 0) {
     temp = -jitter_sign;
-    temp = WEBRTC_SPL_RSHIFT_W32(temp, 19);
+    temp >>= 19;
     jitter_sign = -temp;
   } else {
-    jitter_sign = WEBRTC_SPL_RSHIFT_W32(jitter_sign, 19);
+    jitter_sign >>= 19;
   }
 
   /* adjust bw proportionally to negative average jitter sign */
   //bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign);
   //Q8 -> Q16 .15 +.15 * jitter^2 first term is .15 in Q16 latter term is Q8*Q8*Q8
   //38 in Q8 ~.15 9830 in Q16 ~.15
-  temp = 9830  + WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL(38, WEBRTC_SPL_MUL(jitter_sign, jitter_sign))), 8);
+  temp = 9830 + ((38 * jitter_sign * jitter_sign) >> 8);
 
   if (jitter_sign < 0) {
     temp = WEBRTC_SPL_MUL(jitter_sign, temp);
     temp = -temp;
-    temp = WEBRTC_SPL_RSHIFT_W32(temp, 8);
+    temp >>= 8;
     bw_adjust = (uint32_t)65536 + temp; /* (1 << 16) + temp; */
   } else {
-    bw_adjust = (uint32_t)65536 - WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(jitter_sign, temp), 8);/* (1 << 16) - ((jitter_sign * temp) >> 8); */
+    /* (1 << 16) - ((jitter_sign * temp) >> 8); */
+    bw_adjust = 65536 - ((jitter_sign * temp) >> 8);
   }
 
   //make sure following multiplication won't overflow
   //bw adjust now Q14
-  bw_adjust = WEBRTC_SPL_RSHIFT_W32(bw_adjust, 2);//see if good resolution is maintained
+  bw_adjust >>= 2;  // See if good resolution is maintained.
 
   /* adjust Rate if jitter sign is mostly constant */
   recBw = WEBRTC_SPL_UMUL(bweStr->recBw, bw_adjust);
 
-  recBw = WEBRTC_SPL_RSHIFT_W32(recBw, 14);
+  recBw >>= 14;
 
   /* limit range of bottle neck rate */
   if (recBw < MIN_ISAC_BW) {
@@ -774,9 +776,7 @@
 /* Returns the mmax delay (in ms) */
 int16_t WebRtcIsacfix_GetDownlinkMaxDelay(const BwEstimatorstr *bweStr)
 {
-  int16_t recMaxDelay;
-
-  recMaxDelay = (int16_t)  WEBRTC_SPL_RSHIFT_W32(bweStr->recMaxDelay, 15);
+  int16_t recMaxDelay = (int16_t)(bweStr->recMaxDelay >> 15);
 
   /* limit range of jitter estimate */
   if (recMaxDelay < MIN_ISAC_MD) {
@@ -810,9 +810,7 @@
 /* Returns the max delay value from the other side in ms */
 int16_t WebRtcIsacfix_GetUplinkMaxDelay(const BwEstimatorstr *bweStr)
 {
-  int16_t send_max_delay;
-
-  send_max_delay = (int16_t) WEBRTC_SPL_RSHIFT_W32(bweStr->sendMaxDelayAvg, 9);
+  int16_t send_max_delay = (int16_t)(bweStr->sendMaxDelayAvg >> 9);
 
   /* limit range of jitter estimate */
   if (send_max_delay < MIN_ISAC_MD) {
@@ -858,17 +856,19 @@
           (((512 - 512 / BURST_LEN) * DelayBuildUp) >> 9)) {
         /* max bps derived from BottleNeck and DelayBuildUp values */
         inv_Q12 = 4096 / (BURST_LEN * FrameSamples);
-        MinRate = WEBRTC_SPL_MUL(512 + WEBRTC_SPL_MUL(SAMPLES_PER_MSEC, WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(DelayBuildUp, inv_Q12), 3)), BottleNeck);
+        MinRate = (512 + SAMPLES_PER_MSEC * ((DelayBuildUp * inv_Q12) >> 3)) *
+            BottleNeck;
       } else {
         /* max bps derived from StillBuffered and DelayBuildUp values */
         inv_Q12 = 4096 / FrameSamples;
         if (DelayBuildUp > State->StillBuffered) {
-          MinRate = WEBRTC_SPL_MUL(512 + WEBRTC_SPL_MUL(SAMPLES_PER_MSEC, WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(DelayBuildUp - State->StillBuffered, inv_Q12), 3)), BottleNeck);
+          MinRate = (512 + SAMPLES_PER_MSEC * (((DelayBuildUp -
+              State->StillBuffered) * inv_Q12) >> 3)) * BottleNeck;
         } else if ((den = WEBRTC_SPL_MUL(SAMPLES_PER_MSEC, (State->StillBuffered - DelayBuildUp))) >= FrameSamples) {
           /* MinRate will be negative here */
           MinRate = 0;
         } else {
-          MinRate = WEBRTC_SPL_MUL((512 - WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(den, inv_Q12), 3)), BottleNeck);
+          MinRate = (512 - ((den * inv_Q12) >> 3)) * BottleNeck;
         }
         //if (MinRate < 1.04 * BottleNeck)
         //    MinRate = 1.04 * BottleNeck;
@@ -886,7 +886,7 @@
   /* convert rate from bits/second to bytes/packet */
   //round and shift before conversion
   MinRate += 256;
-  MinRate = WEBRTC_SPL_RSHIFT_W32(MinRate, 9);
+  MinRate >>= 9;
   MinBytes = MinRate * FrameSamples / FS8;
 
   /* StreamSize will be adjusted if less than MinBytes */
diff --git a/modules/audio_coding/codecs/isac/fix/source/decode.c b/modules/audio_coding/codecs/isac/fix/source/decode.c
index 263f88a..fb9c7be 100644
--- a/modules/audio_coding/codecs/isac/fix/source/decode.c
+++ b/modules/audio_coding/codecs/isac/fix/source/decode.c
@@ -54,7 +54,7 @@
   int16_t AvgPitchGain_Q12;
 
   int16_t tmp_1, tmp_2;
-  int32_t tmp32a, tmp32b;
+  int32_t tmp32a;
   int16_t gainQ13;
 
 
@@ -113,7 +113,8 @@
     WebRtcIsacfix_Spec2Time(Vector_Word16_1, Vector_Word16_2, Vector_Word32_1, Vector_Word32_2);
 
     for (k=0; k<FRAMESAMPLES/2; k++) {
-      Vector_Word16_1[k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(Vector_Word32_1[k]+64, 7); //Q16 -> Q9
+      // Q16 -> Q9.
+      Vector_Word16_1[k] = (int16_t)((Vector_Word32_1[k] + 64) >> 7);
     }
 
     /* ----  If this is recovery frame ---- */
@@ -176,8 +177,7 @@
     /* reduce gain to compensate for pitch enhancer */
     /* gain = 1.0f - 0.45f * AvgPitchGain; */
     tmp32a = WEBRTC_SPL_MUL_16_16_RSFT(AvgPitchGain_Q12, 29, 0); // Q18
-    tmp32b = 262144 - tmp32a;  // Q18
-    gainQ13 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q13
+    gainQ13 = (int16_t)((262144 - tmp32a) >> 5);  // Q18 -> Q13.
 
     for (k = 0; k < FRAMESAMPLES/2; k++)
     {
diff --git a/modules/audio_coding/codecs/isac/fix/source/decode_plc.c b/modules/audio_coding/codecs/isac/fix/source/decode_plc.c
index 2099dc4..51344c2 100644
--- a/modules/audio_coding/codecs/isac/fix/source/decode_plc.c
+++ b/modules/audio_coding/codecs/isac/fix/source/decode_plc.c
@@ -71,7 +71,7 @@
     o = WEBRTC_SPL_SAT((int32_t)lim, o, (int32_t)-lim);
 
     /* o should be in the range of int16_t */
-    o = WEBRTC_SPL_RSHIFT_W32( o, rshift );
+    o >>= rshift;
 
     /* decay the output signal; this is specific to plc */
     *Out++ = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT( (int16_t)o, decay, 15); // ((o + (int32_t)2048) >> 12);
@@ -97,7 +97,7 @@
   int16_t frac;
 
   zeros=WebRtcSpl_NormU32(x);
-  frac=(int16_t)WEBRTC_SPL_RSHIFT_W32(((uint32_t)WEBRTC_SPL_LSHIFT_W32(x, zeros)&0x7FFFFFFF), 23);
+  frac = (int16_t)(((x << zeros) & 0x7FFFFFFF) >> 23);
 
   /* log2(magn(i)) */
   return ((31 - zeros) << 8) + frac;
@@ -145,7 +145,7 @@
                            WEBRTC_SPL_MUL_16_16_RSFT( in, 983, 12) );
       /* b = x^2 / 2 {in Q15} so a shift of 16 is required to
          be in correct domain and one more for the division by 2 */
-      *B = (int16_t)WEBRTC_SPL_RSHIFT_W32( WEBRTC_SPL_MUL_16_16( x, x ) + 0x00010000, 17 );
+      *B = (int16_t)((x * x + 0x00010000) >> 17);
       *A = WEBRTC_SPL_WORD16_MAX - *B;
     }
     else
@@ -164,7 +164,7 @@
                            WEBRTC_SPL_MUL_16_16_RSFT( in, 983, 12) );
       /* b = x^2 / 2 {in Q15} so a shift of 16 is required to
          be in correct domain and one more for the division by 2 */
-      *A = (int16_t)WEBRTC_SPL_RSHIFT_W32( WEBRTC_SPL_MUL_16_16( x, x ) + 0x00010000, 17 );
+      *A = (int16_t)((x * x + 0x00010000) >> 17);
       *B = WEBRTC_SPL_WORD16_MAX - *A;
 
     }
@@ -501,14 +501,13 @@
     rshift = 0;
     while( maxCoeff > WEBRTC_SPL_WORD16_MAX )
     {
-      maxCoeff = WEBRTC_SPL_RSHIFT_W32(maxCoeff, 1);
+      maxCoeff >>= 1;
       rshift++;
     }
     for( i = 0; i < NOISE_FILTER_LEN; i++ ) {
-      Vector_Word16_1[ FRAMESAMPLES_HALF - NOISE_FILTER_LEN + i] =
-          (int16_t)WEBRTC_SPL_RSHIFT_W32(
-              (ISACdec_obj->plcstr_obj).prevHP[
-                  PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN + i], rshift);
+      Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN + i] =(int16_t)(
+          ISACdec_obj->plcstr_obj.prevHP[PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN +
+                                         i] >> rshift);
     }
     (ISACdec_obj->plcstr_obj).decayCoeffNoise = plc_filterma_Fast(
         Vector_Word16_2,
diff --git a/modules/audio_coding/codecs/isac/fix/source/encode.c b/modules/audio_coding/codecs/isac/fix/source/encode.c
index 0998545..2c63c02 100644
--- a/modules/audio_coding/codecs/isac/fix/source/encode.c
+++ b/modules/audio_coding/codecs/isac/fix/source/encode.c
@@ -194,7 +194,8 @@
     }
     return status;
   }
-  AvgPitchGain_Q12 = WEBRTC_SPL_RSHIFT_W32(PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3], 2);
+  AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] +
+      PitchGains_Q12[2] + PitchGains_Q12[3]) >> 2;
 
   /* find coefficients for perceptual pre-filters */
   WebRtcIsacfix_GetLpcCoef(LPandHP, HP16a+QLOOKAHEAD, &ISACenc_obj->maskfiltstr_obj,
diff --git a/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c b/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c
index c1b4abb..869db75 100644
--- a/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c
+++ b/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c
@@ -72,13 +72,7 @@
 
 */
 static __inline int32_t CalcLrIntQ(int32_t fixVal, int16_t qDomain) {
-  int32_t intgr;
-  int32_t roundVal;
-
-  roundVal = WEBRTC_SPL_LSHIFT_W32((int32_t)1, qDomain-1);
-  intgr = WEBRTC_SPL_RSHIFT_W32(fixVal+roundVal, qDomain);
-
-  return intgr;
+  return (fixVal + (1 << (qDomain - 1))) >> qDomain;
 }
 
 /*
@@ -154,10 +148,10 @@
     ax = -ax;
     axINT = 1 + (ax >> 8);  //Q0
     axFRAC = 0x00FF - (ax&0x00FF);
-    exp16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(32768, axINT); //Q15
+    exp16 = (int16_t)(32768 >> axINT);  // Q15
     axFRAC = axFRAC+256; //Q8
     exp = WEBRTC_SPL_MUL_16_16(exp16, axFRAC); // Q15*Q8 = Q23
-    exp = WEBRTC_SPL_RSHIFT_W32(exp, 6); //Q17
+    exp >>= 6;  // Q17
   }
 
   return exp;
@@ -173,8 +167,8 @@
   int k, n;
 
   for (k = 0; k < FRAMESAMPLES/8; k++) {
-    summ[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] + PSpecQ12[FRAMESAMPLES/4-1 - k] + 16, 5);
-    diff[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] - PSpecQ12[FRAMESAMPLES/4-1 - k] + 16, 5);
+    summ[k] = (PSpecQ12[k] + PSpecQ12[FRAMESAMPLES / 4 - 1 - k] + 16) >> 5;
+    diff[k] = (PSpecQ12[k] - PSpecQ12[FRAMESAMPLES / 4 - 1 - k] + 16) >> 5;
   }
 
   sum = 2;
@@ -185,14 +179,14 @@
   for (k = 0; k < AR_ORDER; k += 2) {
     sum = 0;
     for (n = 0; n < FRAMESAMPLES/8; n++)
-      sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], diff[n]) + 256, 9);
+      sum += (WebRtcIsacfix_kCos[k][n] * diff[n] + 256) >> 9;
     CorrQ7[k+1] = sum;
   }
 
   for (k=1; k<AR_ORDER; k+=2) {
     sum = 0;
     for (n = 0; n < FRAMESAMPLES/8; n++)
-      sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], summ[n]) + 256, 9);
+      sum += (WebRtcIsacfix_kCos[k][n] * summ[n] + 256) >> 9;
     CorrQ7[k+1] = sum;
   }
 }
@@ -213,12 +207,12 @@
   sum = 0;
   for (n = 0; n < AR_ORDER+1; n++)
     sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]);    /* Q24 */
-  sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), 65) + 32768, 16);    /* result in Q8 */
-  CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, gainQ10) + 256, 9);
+  sum = ((sum >> 6) * 65 + 32768) >> 16;  /* Result in Q8. */
+  CorrQ11[0] = (sum * gainQ10 + 256) >> 9;
 
   /* To avoid overflow, we shift down gainQ10 if it is large. We will not lose any precision */
   if(gainQ10>400000){
-    tmpGain = WEBRTC_SPL_RSHIFT_W32(gainQ10, 3);
+    tmpGain = gainQ10 >> 3;
     round = 32;
     shftVal = 6;
   } else {
@@ -231,8 +225,8 @@
     sum = 16384;
     for (n = k; n < AR_ORDER+1; n++)
       sum += WEBRTC_SPL_MUL(ARCoefQ12[n-k], ARCoefQ12[n]);  /* Q24 */
-    sum = WEBRTC_SPL_RSHIFT_W32(sum, 15);
-    CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round, shftVal);
+    sum >>= 15;
+    CorrQ11[k] = (sum * tmpGain + round) >> shftVal;
   }
   sum = WEBRTC_SPL_LSHIFT_W32(CorrQ11[0], 7);
   for (n = 0; n < FRAMESAMPLES/8; n++)
@@ -240,7 +234,7 @@
 
   for (k = 1; k < AR_ORDER; k += 2) {
     for (n = 0; n < FRAMESAMPLES/8; n++)
-      CurveQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], CorrQ11[k+1]) + 2, 2);
+      CurveQ16[n] += (WebRtcIsacfix_kCos[k][n] * CorrQ11[k + 1] + 2) >> 2;
   }
 
   CS_ptrQ9 = WebRtcIsacfix_kCos[0];
@@ -256,11 +250,11 @@
     shftVal = 0;
 
   for (n = 0; n < FRAMESAMPLES/8; n++)
-    diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2);
+    diffQ16[n] = (CS_ptrQ9[n] * (CorrQ11[1] >> shftVal) + 2) >> 2;
   for (k = 2; k < AR_ORDER; k += 2) {
     CS_ptrQ9 = WebRtcIsacfix_kCos[k];
     for (n = 0; n < FRAMESAMPLES/8; n++)
-      diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k+1], shftVal)) + 2, 2);
+      diffQ16[n] += (CS_ptrQ9[n] * (CorrQ11[k + 1] >> shftVal) + 2) >> 2;
   }
 
   for (k=0; k<FRAMESAMPLES/8; k++) {
@@ -286,12 +280,12 @@
   sum = 0;
   for (n = 0; n < AR_ORDER+1; n++)
     sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]);    /* Q24 */
-  sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), 65) + 32768, 16);    /* result in Q8 */
-  CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, gainQ10) + 256, 9);
+  sum = ((sum >> 6) * 65 + 32768) >> 16;  /* Result in Q8. */
+  CorrQ11[0] = (sum * gainQ10 + 256) >> 9;
 
   /* To avoid overflow, we shift down gainQ10 if it is large. We will not lose any precision */
   if(gainQ10>400000){
-    tmpGain = WEBRTC_SPL_RSHIFT_W32(gainQ10, 3);
+    tmpGain = gainQ10 >> 3;
     round = 32;
     shftVal = 6;
   } else {
@@ -304,8 +298,8 @@
     sum = 16384;
     for (n = k; n < AR_ORDER+1; n++)
       sum += WEBRTC_SPL_MUL(ARCoefQ12[n-k], ARCoefQ12[n]);  /* Q24 */
-    sum = WEBRTC_SPL_RSHIFT_W32(sum, 15);
-    CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round, shftVal);
+    sum >>= 15;
+    CorrQ11[k] = (sum * tmpGain + round) >> shftVal;
   }
   sum = WEBRTC_SPL_LSHIFT_W32(CorrQ11[0], 7);
   for (n = 0; n < FRAMESAMPLES/8; n++)
@@ -329,11 +323,11 @@
     shftVal = 0;
 
   for (n = 0; n < FRAMESAMPLES/8; n++)
-    diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2);
+    diffQ16[n] = (CS_ptrQ9[n] * (CorrQ11[1] >> shftVal) + 2) >> 2;
   for (k = 2; k < AR_ORDER; k += 2) {
     CS_ptrQ9 = WebRtcIsacfix_kCos[k];
     for (n = 0; n < FRAMESAMPLES/8; n++)
-      diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k+1], shftVal)) + 2, 2);
+      diffQ16[n] += (CS_ptrQ9[n] * (CorrQ11[k + 1] >> shftVal) + 2) >> 2;
   }
 
   in_sqrt = summQ16[0] + WEBRTC_SPL_LSHIFT_W32(diffQ16[0], shftVal);
@@ -399,13 +393,13 @@
       seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515;
 
       /* fixed-point dither sample between -64 and 64 (Q7) */
-      dither1_Q7 = (int16_t)WEBRTC_SPL_RSHIFT_W32((int32_t)seed + 16777216, 25); // * 128/4294967295
+      dither1_Q7 = (int16_t)(((int32_t)seed + 16777216) >> 25);
 
       /* new random unsigned int32_t */
       seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515;
 
       /* fixed-point dither sample between -64 and 64 */
-      dither2_Q7 = (int16_t)WEBRTC_SPL_RSHIFT_W32(seed + 16777216, 25);
+      dither2_Q7 = (int16_t)((seed + 16777216) >> 25);
 
       shft = (int16_t)(WEBRTC_SPL_RSHIFT_U32(seed, 25) & 15);
       if (shft < 5)
@@ -439,12 +433,12 @@
       seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515;
 
       /* fixed-point dither sample between -64 and 64 */
-      dither1_Q7 = (int16_t)WEBRTC_SPL_RSHIFT_W32((int32_t)seed + 16777216, 25);
+      dither1_Q7 = (int16_t)(((int32_t)seed + 16777216) >> 25);
 
       /* dither sample is placed in either even or odd index */
       shft = (int16_t)(WEBRTC_SPL_RSHIFT_U32(seed, 25) & 1);     /* either 0 or 1 */
 
-      bufQ7[k + shft] = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(dither_gain_Q14, dither1_Q7) + 8192, 14);
+      bufQ7[k + shft] = (int16_t)((dither_gain_Q14 * dither1_Q7 + 8192) >> 14);
       bufQ7[k + 1 - shft] = 0;
     }
   }
@@ -501,10 +495,10 @@
     {
       gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((int32_t)30, 10),
                                               (int16_t)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (uint32_t)2195456, 16));
-      *frQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10);
-      *fiQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10);
-      *frQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10);
-      *fiQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10);
+      *frQ7++ = (int16_t)((data[k] * gainQ10 + 512) >> 10);
+      *fiQ7++ = (int16_t)((data[k + 1] * gainQ10 + 512) >> 10);
+      *frQ7++ = (int16_t)((data[k + 2] * gainQ10 + 512) >> 10);
+      *fiQ7++ = (int16_t)((data[k + 3] * gainQ10 + 512) >> 10);
     }
   }
   else
@@ -513,10 +507,10 @@
     {
       gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((int32_t)36, 10),
                                               (int16_t)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (uint32_t)2654208, 16));
-      *frQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10);
-      *fiQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10);
-      *frQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10);
-      *fiQ7++ = (int16_t)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10);
+      *frQ7++ = (int16_t)((data[k] * gainQ10 + 512) >> 10);
+      *fiQ7++ = (int16_t)((data[k + 1] * gainQ10 + 512) >> 10);
+      *frQ7++ = (int16_t)((data[k + 2] * gainQ10 + 512) >> 10);
+      *fiQ7++ = (int16_t)((data[k + 3] * gainQ10 + 512) >> 10);
     }
   }
 
@@ -584,7 +578,7 @@
       CorrQ7_norm[k] = WEBRTC_SPL_LSHIFT_W32(CorrQ7[k], lft_shft);
   } else {
     for (k=0; k<AR_ORDER+1; k++)
-      CorrQ7_norm[k] = WEBRTC_SPL_RSHIFT_W32(CorrQ7[k], -lft_shft);
+      CorrQ7_norm[k] = CorrQ7[k] >> -lft_shft;
   }
 
   /* find RC coefficients */
@@ -603,20 +597,22 @@
   nrg = 0;
   for (j = 0; j <= AR_ORDER; j++) {
     for (n = 0; n <= j; n++)
-      nrg += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[j-n], ARCoefQ12[n]) + 256, 9)) + 4, 3);
+      nrg += (ARCoefQ12[j] * ((CorrQ7_norm[j - n] * ARCoefQ12[n] + 256) >> 9) +
+          4) >> 3;
     for (n = j+1; n <= AR_ORDER; n++)
-      nrg += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[n-j], ARCoefQ12[n]) + 256, 9)) + 4, 3);
+      nrg += (ARCoefQ12[j] * ((CorrQ7_norm[n - j] * ARCoefQ12[n] + 256) >> 9) +
+          4) >> 3;
   }
 
   if (lft_shft > 0)
-    nrg = WEBRTC_SPL_RSHIFT_W32(nrg, lft_shft);
+    nrg >>= lft_shft;
   else
     nrg = WEBRTC_SPL_LSHIFT_W32(nrg, -lft_shft);
 
   if(nrg>131072)
     gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES >> 2, nrg);  /* also shifts 31 bits to the left! */
   else
-    gain2_Q10 = WEBRTC_SPL_RSHIFT_W32(FRAMESAMPLES, 2);
+    gain2_Q10 = FRAMESAMPLES >> 2;
 
   /* quantize & code gain2_Q10 */
   if (WebRtcIsacfix_EncodeGain2(&gain2_Q10, streamdata))
@@ -715,20 +711,20 @@
 
   for (k = 0; k < order; k++) {
 
-    larAbsQ11 = (int16_t) WEBRTC_SPL_ABS_W32(WEBRTC_SPL_RSHIFT_W32(larQ17[k]+32,6)); //Q11
+    larAbsQ11 = (int16_t)WEBRTC_SPL_ABS_W32((larQ17[k] + 32) >> 6);  // Q11
 
     if (larAbsQ11<4097) { //2.000012018559 in Q11
       // Q11*Q16>>12 = Q15
       rc = WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24957, 12);
     } else if (larAbsQ11<6393) { //3.121320351712 in Q11
       // (Q11*Q17 + Q13)>>13 = Q15
-      rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 17993) + 130738688), 13);
+      rc = (larAbsQ11 * 17993 + 130738688) >> 13;
     } else if (larAbsQ11<11255) { //5.495270168700 in Q11
       // (Q11*Q19 + Q30)>>15 = Q15
-      rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 16850) + 875329820), 15);
+      rc = (larAbsQ11 * 16850 + 875329820) >> 15;
     } else  {
       // (Q11*Q24>>16 + Q19)>>4 = Q15
-      rc = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24433, 16)) + 515804), 4);
+      rc = (((larAbsQ11 * 24433) >> 16) + 515804) >> 4;
     }
 
     if (larQ17[k]<=0) {
@@ -1020,14 +1016,16 @@
   for (k=0; k<SUBFRAMES; k++) {
 
     /* log gains */
-    sumQQ16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9
+    // Divide by 4 and get Q17 to Q8, i.e. shift 2+9.
+    sumQQ16 = (int16_t)(tmpcoeffs_gQ17[posg] >> 11);
     sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg];
     sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out
     gain_lo_hiQ17[gainpos] = sumQQ; //Q17
     gainpos++;
     posg++;
 
-    sumQQ16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9
+    // Divide by 4 and get Q17 to Q8, i.e. shift 2+9.
+    sumQQ16 = (int16_t)(tmpcoeffs_gQ17[posg] >> 11);
     sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg];
     sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out
     gain_lo_hiQ17[gainpos] = sumQQ; //Q17
@@ -1321,7 +1319,8 @@
   gainpos = 0;
   for (k=0; k<2*SUBFRAMES; k++) {
 
-    sumQQ16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9
+    // Divide by 4 and get Q17 to Q8, i.e. shift 2+9.
+    sumQQ16 = (int16_t)(tmpcoeffs_gQ17[posg] >> 11);
     sumQQ16 += WebRtcIsacfix_kMeansGainQ8[0][posg];
     sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out
     gain_lo_hiQ17[gainpos] = sumQQ; //Q17
@@ -1687,7 +1686,7 @@
   for (k = 0; k < 4; k++)
     meangainQ12 += PitchGain_Q12[k];
 
-  meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2);  // Get average
+  meangainQ12 >>= 2;  // Get average.
 
   /* voicing classificiation */
   if (meangainQ12 <= 819) {                 // mean_gain < 0.2
@@ -1731,21 +1730,21 @@
   CQ11 = WEBRTC_SPL_SHIFT_W32(CQ11,11-shft); // Scale with StepSize, Q11
   for (k=0; k<PITCH_SUBFRAMES; k++) {
     tmp32a =  WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11);
-    tmp16a = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5);
+    tmp16a = (int16_t)(tmp32a >> 5);
     PitchLags_Q7[k] = tmp16a;
   }
 
   CQ10 = mean_val2Q10[index[1]];
   for (k=0; k<PITCH_SUBFRAMES; k++) {
     tmp32b =  (int32_t) WEBRTC_SPL_MUL_16_16_RSFT((int16_t) WebRtcIsacfix_kTransform[1][k], (int16_t) CQ10,10);
-    tmp16c = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5);
+    tmp16c = (int16_t)(tmp32b >> 5);
     PitchLags_Q7[k] += tmp16c;
   }
 
   CQ10 = mean_val4Q10[index[3]];
   for (k=0; k<PITCH_SUBFRAMES; k++) {
     tmp32b =  (int32_t) WEBRTC_SPL_MUL_16_16_RSFT((int16_t) WebRtcIsacfix_kTransform[3][k], (int16_t) CQ10,10);
-    tmp16c = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5);
+    tmp16c = (int16_t)(tmp32b >> 5);
     PitchLags_Q7[k] += tmp16c;
   }
 
@@ -1775,7 +1774,7 @@
   for (k = 0; k < 4; k++)
     meangainQ12 += PitchGain_Q12[k];
 
-  meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2);
+  meangainQ12 >>= 2;
 
   /* Save data for creation of multiple bitstreams */
   if (encData != NULL) {
@@ -1817,7 +1816,7 @@
     CQ17 = WEBRTC_SPL_SHIFT_W32(CQ17,shft); // Scale with StepSize
 
     /* quantize */
-    tmp16b = (int16_t) WEBRTC_SPL_RSHIFT_W32(CQ17 + 65536, 17 );
+    tmp16b = (int16_t)((CQ17 + 65536) >> 17);
     index[k] =  tmp16b;
 
     /* check that the index is not outside the boundaries of the table */
@@ -1837,21 +1836,21 @@
 
   for (k=0; k<PITCH_SUBFRAMES; k++) {
     tmp32a =  WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11); // Q12
-    tmp16a = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5);// Q7
+    tmp16a = (int16_t)(tmp32a >> 5);  // Q7.
     PitchLagsQ7[k] = tmp16a;
   }
 
   CQ10 = mean_val2Q10[index[1]];
   for (k=0; k<PITCH_SUBFRAMES; k++) {
     tmp32b =  (int32_t) WEBRTC_SPL_MUL_16_16_RSFT((int16_t) WebRtcIsacfix_kTransform[1][k], (int16_t) CQ10,10);
-    tmp16c = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7
+    tmp16c = (int16_t)(tmp32b >> 5);  // Q7.
     PitchLagsQ7[k] += tmp16c;
   }
 
   CQ10 = mean_val4Q10[index[3]];
   for (k=0; k<PITCH_SUBFRAMES; k++) {
     tmp32b =  (int32_t) WEBRTC_SPL_MUL_16_16_RSFT((int16_t) WebRtcIsacfix_kTransform[3][k], (int16_t) CQ10,10);
-    tmp16c = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7
+    tmp16c = (int16_t)(tmp32b >> 5);  // Q7.
     PitchLagsQ7[k] += tmp16c;
   }
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/filterbanks.c b/modules/audio_coding/codecs/isac/fix/source/filterbanks.c
index 8be427a..cbaaae8 100644
--- a/modules/audio_coding/codecs/isac/fix/source/filterbanks.c
+++ b/modules/audio_coding/codecs/isac/fix/source/filterbanks.c
@@ -141,7 +141,7 @@
         (WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[2], state1) >> 16);
 #endif
 
-    c = ((int32_t)in) + WEBRTC_SPL_RSHIFT_W32(a1+b1, 7);  // Q0
+    c = in + ((a1 + b1) >> 7);  // Q0.
     io[k] = (int16_t)WebRtcSpl_SatW32ToW16(c);  // Write output as Q0.
 
     c = WEBRTC_SPL_LSHIFT_W32((int32_t)in, 2) - a2 - b2;  // In Q2.
@@ -223,9 +223,9 @@
     int32_t tmp1, tmp2, tmp3;
     tmp1 = (int32_t)tempin_ch1[k]; // Q0 -> Q0
     tmp2 = (int32_t)tempin_ch2[k]; // Q0 -> Q0
-    tmp3 = (int32_t)WEBRTC_SPL_RSHIFT_W32((tmp1 + tmp2), 1);/* low pass signal*/
+    tmp3 = (tmp1 + tmp2) >> 1;  /* Low pass signal. */
     LP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*low pass */
-    tmp3 = (int32_t)WEBRTC_SPL_RSHIFT_W32((tmp1 - tmp2), 1);/* high pass signal*/
+    tmp3 = (tmp1 - tmp2) >> 1;  /* High pass signal. */
     HP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*high pass */
   }
 
@@ -282,9 +282,9 @@
     int32_t tmp1, tmp2, tmp3;
     tmp1 = (int32_t)tempin_ch1[k]; // Q0 -> Q0
     tmp2 = (int32_t)tempin_ch2[k]; // Q0 -> Q0
-    tmp3 = (int32_t)WEBRTC_SPL_RSHIFT_W32((tmp1 + tmp2), 1);/* low pass signal*/
+    tmp3 = (tmp1 + tmp2) >> 1;  /* Low pass signal. */
     LP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*low pass */
-    tmp3 = (int32_t)WEBRTC_SPL_RSHIFT_W32((tmp1 - tmp2), 1);/* high pass signal*/
+    tmp3 = (tmp1 - tmp2) >> 1;  /* High pass signal. */
     HP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*high pass */
   }
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/filters.c b/modules/audio_coding/codecs/isac/fix/source/filters.c
index cf92a4d..2a74fc0 100644
--- a/modules/audio_coding/codecs/isac/fix/source/filters.c
+++ b/modules/audio_coding/codecs/isac/fix/source/filters.c
@@ -76,13 +76,12 @@
       a = WEBRTC_SPL_MUL_16_32_RSFT16(InOut16[n], APSectionFactors[j]); //Q0*Q31=Q31 shifted 16 gives Q15
       a = WEBRTC_SPL_LSHIFT_W32(a, 1); // Q15 -> Q16
       b = WebRtcSpl_AddSatW32(a, FilterState[j]);  //Q16+Q16=Q16
-      a = WEBRTC_SPL_MUL_16_32_RSFT16(
-          (int16_t) WEBRTC_SPL_RSHIFT_W32(b, 16),
-          -APSectionFactors[j]); //Q0*Q31=Q31 shifted 16 gives Q15
+      // |a| in Q15 (Q0*Q31=Q31 shifted 16 gives Q15).
+      a = WEBRTC_SPL_MUL_16_32_RSFT16(b >> 16, -APSectionFactors[j]);
       FilterState[j] = WebRtcSpl_AddSatW32(
           WEBRTC_SPL_LSHIFT_W32(a,1),
           WEBRTC_SPL_LSHIFT_W32((uint32_t)InOut16[n], 16)); // Q15<<1 + Q0<<16 = Q16 + Q16 = Q16
-      InOut16[n] = (int16_t) WEBRTC_SPL_RSHIFT_W32(b, 16); //Save as Q0
+      InOut16[n] = (int16_t)(b >> 16);  // Save as Q0.
     }
   }
 }
@@ -102,7 +101,7 @@
   memcpy(data_vec+1, in, WEBRTC_SPL_MUL_16_16(sizeof(int16_t), (N-1)));
 
 
-  data_vec[0] = (int16_t) WEBRTC_SPL_RSHIFT_W32(state_in[WEBRTC_SPL_MUL_16_16(2, ALLPASSSECTIONS)],16);   //the z^(-1) state
+  data_vec[0] = (int16_t)(state_in[2 * ALLPASSSECTIONS] >> 16);  // z^-1 state.
   state_in[WEBRTC_SPL_MUL_16_16(2, ALLPASSSECTIONS)] = WEBRTC_SPL_LSHIFT_W32((uint32_t)in[N-1],16);
 
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/isacfix.c b/modules/audio_coding/codecs/isac/fix/source/isacfix.c
index 1c1a720..5e8fd4f 100644
--- a/modules/audio_coding/codecs/isac/fix/source/isacfix.c
+++ b/modules/audio_coding/codecs/isac/fix/source/isacfix.c
@@ -345,6 +345,35 @@
   return statusInit;
 }
 
+/* Read the given number of bytes of big-endian 16-bit integers from |src| and
+   write them to |dest| in host endian. If |nbytes| is odd, the number of
+   output elements is rounded up, and the least significant byte of the last
+   element is set to 0. */
+static void read_be16(const uint8_t* src, size_t nbytes, uint16_t* dest) {
+  size_t i;
+  for (i = 0; i < nbytes / 2; ++i)
+    dest[i] = src[2 * i] << 8 | src[2 * i + 1];
+  if (nbytes % 2 == 1)
+    dest[nbytes / 2] = src[nbytes - 1] << 8;
+}
+
+/* Read the given number of bytes of host-endian 16-bit integers from |src| and
+   write them to |dest| in big endian. If |nbytes| is odd, the number of source
+   elements is rounded up (but only the most significant byte of the last
+   element is used), and the number of output bytes written will be
+   nbytes + 1. */
+static void write_be16(const uint16_t* src, size_t nbytes, uint8_t* dest) {
+  size_t i;
+  for (i = 0; i < nbytes / 2; ++i) {
+    dest[2 * i] = src[i] >> 8;
+    dest[2 * i + 1] = src[i];
+  }
+  if (nbytes % 2 == 1) {
+    dest[nbytes - 1] = src[nbytes / 2] >> 8;
+    dest[nbytes] = 0;
+  }
+}
+
 /****************************************************************************
  * WebRtcIsacfix_Encode(...)
  *
@@ -372,10 +401,7 @@
                              uint8_t* encoded)
 {
   ISACFIX_SubStruct *ISAC_inst;
-  int16_t stream_len, stream_len_even;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
+  int16_t stream_len;
 
   /* typecast pointer to rela structure */
   ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst;
@@ -396,29 +422,7 @@
     return -1;
   }
 
-  /* One would think that only even stream lengths would make sense here. We do
-     in fact observe odd lengths, however, and in those cases we copy an extra
-     byte. */
-  stream_len_even = stream_len % 2 == 0 ? stream_len : stream_len + 1;
-
-  /* convert from bytes to int16_t */
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  /* The encoded data vector is supposesd to be big-endian, but our internal
-     representation is little-endian. So byteswap. */
-  for (k = 0; k < stream_len_even / 2; ++k) {
-    uint16_t s = ISAC_inst->ISACenc_obj.bitstr_obj.stream[k];
-    /* In big-endian, we have... */
-    encoded[2 * k] = s >> 8;  /* ...most significant byte at low address... */
-    encoded[2 * k + 1] = s;  /* ...least significant byte at high address. */
-  }
-#else
-  /* The encoded data vector and our internal representation are both
-     big-endian. */
-  memcpy(encoded, ISAC_inst->ISACenc_obj.bitstr_obj.stream, stream_len_even);
-#endif
-
-
-
+  write_be16(ISAC_inst->ISACenc_obj.bitstr_obj.stream, stream_len, encoded);
   return stream_len;
 
 }
@@ -495,20 +499,9 @@
     return -1;
   }
 
-
-  /* convert from bytes to int16_t */
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k=0;k<(stream_len+1)>>1;k++) {
-    encoded[k] = (int16_t)(((uint16_t)(ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] >> 8)
-                                 | (((ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] & 0x00FF) << 8));
-  }
-
-#else
-  WEBRTC_SPL_MEMCPY_W16(encoded, (ISAC_inst->ISACenc_obj.bitstr_obj).stream, (stream_len + 1)>>1);
-#endif
-
-
-
+  write_be16(ISAC_inst->ISACenc_obj.bitstr_obj.stream,
+             stream_len,
+             (uint8_t*)encoded);
   return stream_len;
 }
 #endif  /* WEBRTC_ISAC_FIX_NB_CALLS_ENABLED */
@@ -540,9 +533,6 @@
 {
   ISACFIX_SubStruct *ISAC_inst;
   int16_t stream_len;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
 
   /* typecast pointer to rela structure */
   ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst;
@@ -562,19 +552,8 @@
     return -1;
   }
 
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k=0;k<(stream_len+1)>>1;k++) {
-    ((int16_t*)encoded)[k] = (int16_t)(
-        ((uint16_t)(ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] >> 8) |
-        (((ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] & 0x00FF) << 8));
-  }
-
-#else
-  WEBRTC_SPL_MEMCPY_W16(encoded, (ISAC_inst->ISACenc_obj.bitstr_obj).stream, (stream_len + 1)>>1);
-#endif
-
+  write_be16(ISAC_inst->ISACenc_obj.bitstr_obj.stream, stream_len, encoded);
   return stream_len;
-
 }
 
 
@@ -643,9 +622,6 @@
 {
   ISACFIX_SubStruct *ISAC_inst;
   Bitstr_dec streamdata;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
   int16_t err;
   const int kRequiredEncodedLenBytes = 10;
 
@@ -671,14 +647,7 @@
 
   InitializeDecoderBitstream(packet_size, &streamdata);
 
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k = 0; k < kRequiredEncodedLenBytes / 2; k++) {
-    uint16_t ek = ((const uint16_t*)encoded)[k];
-    streamdata.stream[k] = (uint16_t) ((ek >> 8)|((ek & 0xff) << 8));
-  }
-#else
-  memcpy(streamdata.stream, encoded, kRequiredEncodedLenBytes);
-#endif
+  read_be16(encoded, kRequiredEncodedLenBytes, streamdata.stream);
 
   err = WebRtcIsacfix_EstimateBandwidth(&ISAC_inst->bwestimator_obj,
                                         &streamdata,
@@ -726,9 +695,6 @@
 {
   ISACFIX_SubStruct *ISAC_inst;
   Bitstr_dec streamdata;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
   int16_t err;
   const int kRequiredEncodedLenBytes = 10;
 
@@ -757,14 +723,7 @@
 
   InitializeDecoderBitstream(packet_size, &streamdata);
 
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k = 0; k < kRequiredEncodedLenBytes / 2; k++) {
-    uint16_t ek = ((const uint16_t*)encoded)[k];
-    streamdata.stream[k] = (uint16_t) ((ek >> 8)|((ek & 0xff) <<8 ));
-  }
-#else
-  memcpy(streamdata.stream, encoded, kRequiredEncodedLenBytes);
-#endif
+  read_be16(encoded, kRequiredEncodedLenBytes, streamdata.stream);
 
   err = WebRtcIsacfix_EstimateBandwidth(&ISAC_inst->bwestimator_obj,
                                         &streamdata,
@@ -814,9 +773,6 @@
   /* number of samples (480 or 960), output from decoder */
   /* that were actually used in the encoder/decoder (determined on the fly) */
   int16_t     number_of_samples;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
   int16_t declen = 0;
 
   /* typecast pointer to real structure */
@@ -841,19 +797,7 @@
 
   InitializeDecoderBitstream(len, &ISAC_inst->ISACdec_obj.bitstr_obj);
 
-  /* convert bitstream from int16_t to bytes */
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k=0; k<(len>>1); k++) {
-    uint16_t ek = ((const uint16_t*)encoded)[k];
-    ISAC_inst->ISACdec_obj.bitstr_obj.stream[k] =
-        (uint16_t)((ek >> 8) | ((ek & 0xff) << 8));
-  }
-  if (len & 0x0001)
-    ISAC_inst->ISACdec_obj.bitstr_obj.stream[k] =
-        (uint16_t)((((const uint16_t*)encoded)[k] & 0xff) << 8);
-#else
-  memcpy(ISAC_inst->ISACdec_obj.bitstr_obj.stream, encoded, len);
-#endif
+  read_be16(encoded, len, ISAC_inst->ISACdec_obj.bitstr_obj.stream);
 
   /* added for NetEq purposes (VAD/DTX related) */
   *speechType=1;
@@ -922,9 +866,6 @@
   /* twice the number of samples (480 or 960), output from decoder */
   /* that were actually used in the encoder/decoder (determined on the fly) */
   int16_t     number_of_samples;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
   int16_t declen = 0;
   int16_t dummy[FRAMESAMPLES/2];
 
@@ -950,16 +891,7 @@
 
   InitializeDecoderBitstream(len, &ISAC_inst->ISACdec_obj.bitstr_obj);
 
-  /* convert bitstream from int16_t to bytes */
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k=0; k<(len>>1); k++) {
-    (ISAC_inst->ISACdec_obj.bitstr_obj).stream[k] = (uint16_t) ((encoded[k] >> 8)|((encoded[k] & 0xFF)<<8));
-  }
-  if (len & 0x0001)
-    (ISAC_inst->ISACdec_obj.bitstr_obj).stream[k] = (uint16_t) ((encoded[k] & 0xFF)<<8);
-#else
-  memcpy(ISAC_inst->ISACdec_obj.bitstr_obj.stream, encoded, len);
-#endif
+  read_be16(encoded, len, ISAC_inst->ISACdec_obj.bitstr_obj.stream);
 
   /* added for NetEq purposes (VAD/DTX related) */
   *speechType=1;
@@ -1326,9 +1258,6 @@
                                    int16_t* frameLength)
 {
   Bitstr_dec streamdata;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
   int16_t err;
   const int kRequiredEncodedLenBytes = 10;
 
@@ -1338,14 +1267,7 @@
 
   InitializeDecoderBitstream(encoded_len_bytes, &streamdata);
 
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k = 0; k < kRequiredEncodedLenBytes / 2; k++) {
-    uint16_t ek = ((uint16_t*)encoded)[k];
-    streamdata.stream[k] = (uint16_t)((ek >> 8) | ((ek & 0xff) << 8));
-  }
-#else
-  memcpy(streamdata.stream, encoded, kRequiredEncodedLenBytes);
-#endif
+  read_be16(encoded, kRequiredEncodedLenBytes, streamdata.stream);
 
   /* decode frame length */
   err = WebRtcIsacfix_DecodeFrameLen(&streamdata, frameLength);
@@ -1375,9 +1297,6 @@
                                   int16_t* rateIndex)
 {
   Bitstr_dec streamdata;
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  int k;
-#endif
   int16_t err;
   const int kRequiredEncodedLenBytes = 10;
 
@@ -1387,14 +1306,7 @@
 
   InitializeDecoderBitstream(encoded_len_bytes, &streamdata);
 
-#ifndef WEBRTC_ARCH_BIG_ENDIAN
-  for (k = 0; k < kRequiredEncodedLenBytes / 2; k++) {
-    uint16_t ek = ((uint16_t*)encoded)[k];
-    streamdata.stream[k] = (uint16_t)((ek >> 8) | ((ek & 0xff) << 8));
-  }
-#else
-  memcpy(streamdata.stream, encoded, kRequiredEncodedLenBytes);
-#endif
+  read_be16(encoded, kRequiredEncodedLenBytes, streamdata.stream);
 
   /* decode frame length, needed to get to the rateIndex in the bitstream */
   err = WebRtcIsacfix_DecodeFrameLen(&streamdata, rateIndex);
diff --git a/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi b/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi
index 7bef170..2a36309 100644
--- a/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi
+++ b/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi
@@ -87,7 +87,7 @@
             'pitch_filter_c.c',
           ],
         }],
-        ['target_arch=="mipsel"', {
+        ['target_arch=="mipsel" and mips_arch_variant!="r6"', {
           'sources': [
             'entropy_coding_mips.c',
             'filters_mips.c',
diff --git a/modules/audio_coding/codecs/isac/fix/source/lattice.c b/modules/audio_coding/codecs/isac/fix/source/lattice.c
index 6b3a6bf..6bb987b 100644
--- a/modules/audio_coding/codecs/isac/fix/source/lattice.c
+++ b/modules/audio_coding/codecs/isac/fix/source/lattice.c
@@ -136,7 +136,7 @@
       gain32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[k], gain32); //Q15*Q(17+gain_sh)>>15 = Q(17+gain_sh)
       inv_cthQ16[k] = WebRtcSpl_DivW32W16((int32_t)2147483647, cthQ15[k]); // 1/cth[k] in Q31/Q15 = Q16
     }
-    gain16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(gain32, 16); //Q(1+gain_sh)
+    gain16 = (int16_t)(gain32 >> 16);  // Q(1+gain_sh).
 
     /* normalized lattice filter */
     /*****************************/
@@ -158,7 +158,7 @@
       tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(sthQ15[i-1], stateGQ15[i-1]);//Q15*Q15>>15 = Q15
       tmp32b= fQtmp + tmp32; //Q15+Q15=Q15
       tmp32 = inv_cthQ16[i-1]; //Q16
-      t16a = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32, 16);
+      t16a = (int16_t)(tmp32 >> 16);
       t16b = (int16_t) (tmp32-WEBRTC_SPL_LSHIFT_W32(((int32_t)t16a), 16));
       if (t16b<0) t16a++;
       tmp32 = LATTICE_MUL_32_32_RSFT16(t16a, t16b, tmp32b);
@@ -186,7 +186,7 @@
 
     for(n=0;n<HALF_SUBFRAMELEN;n++)
     {
-      //gain32 = WEBRTC_SPL_RSHIFT_W32(gain32, gain_sh); // Q(17+gain_sh) -> Q17
+      //gain32 >>= gain_sh; // Q(17+gain_sh) -> Q17
       tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(gain16, fQ15vec[n]); //Q(1+gain_sh)*Q15>>16 = Q(gain_sh)
       sh = 9-gain_sh; //number of needed shifts to reach Q9
       t16a = (int16_t) WEBRTC_SPL_SHIFT_W32(tmp32, sh);
@@ -267,7 +267,7 @@
     inv_gain32 = WebRtcSpl_DivW32W16((int32_t)2147483647, den16); // 1/gain in Q31/Q(sh+11) = Q(20-sh)
 
     //initial conditions
-    inv_gain16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(inv_gain32, 2); // 1/gain in Q(20-sh-2) = Q(18-sh)
+    inv_gain16 = (int16_t)(inv_gain32 >> 2);  // 1/gain in Q(20-sh-2) = Q(18-sh)
 
     for (i=0;i<HALF_SUBFRAMELEN;i++)
     {
@@ -281,10 +281,10 @@
 
     for (i=orderCoef-1;i>=0;i--) //get the state of f&g for the first input, for all orders
     {
-      tmp32 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(cthQ15[i],ARfQ0vec[0])) - (WEBRTC_SPL_MUL_16_16(sthQ15[i],stateGQ0[i])) + 16384), 15);
+      tmp32 = (cthQ15[i] * ARfQ0vec[0] - sthQ15[i] * stateGQ0[i] + 16384) >> 15;
       tmpAR = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0
 
-      tmp32 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(sthQ15[i],ARfQ0vec[0])) + (WEBRTC_SPL_MUL_16_16(cthQ15[i], stateGQ0[i])) + 16384), 15);
+      tmp32 = (sthQ15[i] * ARfQ0vec[0] + cthQ15[i] * stateGQ0[i] + 16384) >> 15;
       ARgQ0vec[i+1] = (int16_t)WebRtcSpl_SatW32ToW16(tmp32); // Q0
       ARfQ0vec[0] = tmpAR;
     }
diff --git a/modules/audio_coding/codecs/isac/fix/source/lattice_c.c b/modules/audio_coding/codecs/isac/fix/source/lattice_c.c
index d7d198c..8c53b0b 100644
--- a/modules/audio_coding/codecs/isac/fix/source/lattice_c.c
+++ b/modules/audio_coding/codecs/isac/fix/source/lattice_c.c
@@ -36,10 +36,8 @@
 
     tmpAR = ar_f_Q0[n + 1];
     for (k = order_coef - 1; k >= 0; k--) {
-      tmp32 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(cth_Q15[k], tmpAR))
-              - (WEBRTC_SPL_MUL_16_16(sth_Q15[k], ar_g_Q0[k])) + 16384), 15);
-      tmp32_2 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(sth_Q15[k], tmpAR))
-                + (WEBRTC_SPL_MUL_16_16(cth_Q15[k], ar_g_Q0[k])) + 16384), 15);
+      tmp32 = (cth_Q15[k] * tmpAR - sth_Q15[k] * ar_g_Q0[k] + 16384) >> 15;
+      tmp32_2 = (sth_Q15[k] * tmpAR + cth_Q15[k] * ar_g_Q0[k] + 16384) >> 15;
       tmpAR   = (int16_t)WebRtcSpl_SatW32ToW16(tmp32);
       ar_g_Q0[k + 1] = (int16_t)WebRtcSpl_SatW32ToW16(tmp32_2);
     }
diff --git a/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c b/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c
index dba92f8..555cca0 100644
--- a/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c
+++ b/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c
@@ -39,7 +39,7 @@
 
   for (m=useOrder-1; m>0; m--) {
     tmp_inv_denum32 = ((int32_t) 1073741823) - WEBRTC_SPL_MUL_16_16(k16[m], k16[m]); // (1 - k^2) in Q30
-    tmp_inv_denum16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp_inv_denum32, 15); // (1 - k^2) in Q15
+    tmp_inv_denum16 = (int16_t)(tmp_inv_denum32 >> 15);  // (1 - k^2) in Q15.
 
     for (k=1; k<=m; k++) {
       tmp32b = WEBRTC_SPL_LSHIFT_W32((int32_t)a16[k], 16) -
@@ -49,7 +49,7 @@
     }
 
     for (k=1; k<m; k++) {
-      a16[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32[k], 1); //Q12>>1 => Q11
+      a16[k] = (int16_t)(tmp32[k] >> 1);  // Q12>>1 => Q11
     }
 
     tmp32[m] = WEBRTC_SPL_SAT(4092, tmp32[m], -4092);
@@ -90,8 +90,8 @@
   for (i=order;i>=0;i--) {
     temp1W32 = WEBRTC_SPL_LSHIFT_W32(R[i], norm);
     /* Put R in hi and low format */
-    R_hi[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-    R_low[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[i], 16)), 1);
+    R_hi[i] = (int16_t)(temp1W32 >> 16);
+    R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] << 16)) >> 1);
   }
 
   /* K = A[1] = -R[1] / R[0] */
@@ -106,41 +106,39 @@
   }
 
   /* Put K in hi and low format */
-  K_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-  K_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)K_hi, 16)), 1);
+  K_hi = (int16_t)(temp1W32 >> 16);
+  K_low = (int16_t)((temp1W32 - ((int32_t)K_hi << 16)) >> 1);
 
   /* Store first reflection coefficient */
   K[0] = K_hi;
 
-  temp1W32 = WEBRTC_SPL_RSHIFT_W32(temp1W32, 4);    /* A[1] in Q27      */
+  temp1W32 >>= 4;  /* A[1] in Q27. */
 
   /* Put A[1] in hi and low format */
-  A_hi[1] = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-  A_low[1] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[1], 16)), 1);
+  A_hi[1] = (int16_t)(temp1W32 >> 16);
+  A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] << 16)) >> 1);
 
   /*  Alpha = R[0] * (1-K^2) */
 
-  temp1W32  = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, K_low), 14) +
-                                      WEBRTC_SPL_MUL_16_16(K_hi, K_hi)), 1); /* temp1W32 = k^2 in Q31 */
+  temp1W32  = (((K_hi * K_low) >> 14) + K_hi * K_hi) << 1;  /* = k^2 in Q31 */
 
   temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32);    /* Guard against <0 */
   temp1W32 = (int32_t)0x7fffffffL - temp1W32;    /* temp1W32 = (1 - K[0]*K[0]) in Q31 */
 
   /* Store temp1W32 = 1 - K[0]*K[0] on hi and low format */
-  tmp_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-  tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+  tmp_hi = (int16_t)(temp1W32 >> 16);
+  tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
 
   /* Calculate Alpha in Q31 */
-  temp1W32 = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_hi) +
-                                     WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_low), 15) +
-                                     WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_low[0], tmp_hi), 15) ), 1);
+  temp1W32 = (R_hi[0] * tmp_hi + ((R_hi[0] * tmp_low) >> 15) +
+      ((R_low[0] * tmp_hi) >> 15)) << 1;
 
   /* Normalize Alpha and put it in hi and low format */
 
   Alpha_exp = WebRtcSpl_NormW32(temp1W32);
   temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp);
-  Alpha_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-  Alpha_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)Alpha_hi, 16)), 1);
+  Alpha_hi = (int16_t)(temp1W32 >> 16);
+  Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi<< 16)) >> 1);
 
   /* Perform the iterative calculations in the
      Levinson Durbin algorithm */
@@ -150,7 +148,7 @@
 
     /*                    ----
                           \
-                          temp1W32 =  R[i] + > R[j]*A[i-j]
+        temp1W32 =  R[i] + > R[j]*A[i-j]
                           /
                           ----
                           j=1..i-1
@@ -160,9 +158,9 @@
 
     for(j=1; j<i; j++) {
       /* temp1W32 is in Q31 */
-      temp1W32 += (WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[j], A_hi[i-j]), 1) +
-                   WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[j], A_low[i-j]), 15) +
-                                            WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_low[j], A_hi[i-j]), 15) ), 1));
+      temp1W32 += ((R_hi[j] * A_hi[i - j]) << 1) +
+          ((((R_hi[j] * A_low[i - j]) >> 15) +
+              ((R_low[j] * A_hi[i - j]) >> 15)) << 1);
     }
 
     temp1W32  = WEBRTC_SPL_LSHIFT_W32(temp1W32, 4);
@@ -193,8 +191,8 @@
     }
 
     /* Put K on hi and low format */
-    K_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp3W32, 16);
-    K_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp3W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)K_hi, 16)), 1);
+    K_hi = (int16_t)(temp3W32 >> 16);
+    K_low = (int16_t)((temp3W32 - ((int32_t)K_hi << 16)) >> 1);
 
     /* Store Reflection coefficient in Q15 */
     K[i-1] = K_hi;
@@ -218,45 +216,42 @@
       temp1W32  = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[j],16) +
           WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[j],1);    /* temp1W32 = A[j] in Q27 */
 
-      temp1W32 += WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_MUL_16_16(K_hi, A_hi[i-j]) +
-                                           WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, A_low[i-j]), 15) +
-                                           WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_low, A_hi[i-j]), 15) ), 1); /* temp1W32 += K*A[i-j] in Q27 */
+      temp1W32 += (K_hi * A_hi[i - j] + ((K_hi * A_low[i - j]) >> 15) +
+          ((K_low * A_hi[i - j]) >> 15)) << 1;  // temp1W32 += K*A[i-j] in Q27.
 
       /* Put Anew in hi and low format */
-      A_upd_hi[j] = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-      A_upd_low[j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)A_upd_hi[j], 16)), 1);
+      A_upd_hi[j] = (int16_t)(temp1W32 >> 16);
+      A_upd_low[j] = (int16_t)((temp1W32 - ((int32_t)A_upd_hi[j] << 16)) >> 1);
     }
 
-    temp3W32 = WEBRTC_SPL_RSHIFT_W32(temp3W32, 4);     /* temp3W32 = K in Q27 (Convert from Q31 to Q27) */
+    temp3W32 >>= 4;  /* temp3W32 = K in Q27 (Convert from Q31 to Q27) */
 
     /* Store Anew in hi and low format */
-    A_upd_hi[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp3W32, 16);
-    A_upd_low[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp3W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)A_upd_hi[i], 16)), 1);
+    A_upd_hi[i] = (int16_t)(temp3W32 >> 16);
+    A_upd_low[i] = (int16_t)((temp3W32 - ((int32_t)A_upd_hi[i] << 16)) >> 1);
 
     /*  Alpha = Alpha * (1-K^2) */
 
-    temp1W32  = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, K_low), 14) +
-                                        WEBRTC_SPL_MUL_16_16(K_hi, K_hi)), 1);  /* K*K in Q31 */
+    temp1W32 = (((K_hi * K_low) >> 14) + K_hi * K_hi) << 1;  /* K*K in Q31 */
 
     temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32);      /* Guard against <0 */
     temp1W32 = (int32_t)0x7fffffffL - temp1W32;      /* 1 - K*K  in Q31 */
 
     /* Convert 1- K^2 in hi and low format */
-    tmp_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-    tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+    tmp_hi = (int16_t)(temp1W32 >> 16);
+    tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
 
     /* Calculate Alpha = Alpha * (1-K^2) in Q31 */
-    temp1W32 = WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_hi) +
-                                        WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_low), 15) +
-                                        WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(Alpha_low, tmp_hi), 15)), 1);
+    temp1W32 = (Alpha_hi * tmp_hi + ((Alpha_hi * tmp_low) >> 15) +
+        ((Alpha_low * tmp_hi) >> 15)) << 1;
 
     /* Normalize Alpha and store it on hi and low format */
 
     norm = WebRtcSpl_NormW32(temp1W32);
     temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm);
 
-    Alpha_hi = (int16_t) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
-    Alpha_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((int32_t)Alpha_hi, 16)), 1);
+    Alpha_hi = (int16_t)(temp1W32 >> 16);
+    Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
 
     /* Update the total nomalization of Alpha */
     Alpha_exp = Alpha_exp + norm;
@@ -282,7 +277,7 @@
     temp1W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[i], 16) +
         WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1);
     /* Round and store upper word */
-    A[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32+(int32_t)32768, 16);
+    A[i] = (int16_t)((temp1W32 + 32768) >> 16);
   }
   return(1); /* Stable filters */
 }
@@ -350,7 +345,7 @@
   int16_t frac;
 
   zeros=WebRtcSpl_NormU32(x);
-  frac=(int16_t)WEBRTC_SPL_RSHIFT_W32(((uint32_t)WEBRTC_SPL_LSHIFT_W32(x, zeros)&0x7FFFFFFF), 23);
+  frac = (int16_t)(((x << zeros) & 0x7FFFFFFF) >> 23);
 
   /* log2(x) */
   return ((31 - zeros) << 8) + frac;
@@ -601,9 +596,7 @@
      With 0.35 in Q16 (0.35 ~= 22938/65536.0 = 0.3500061) and varscaleQ14 in Q14,
      we get Q16*Q14>>16 = Q14
   */
-  aaQ14 = (int16_t) WEBRTC_SPL_RSHIFT_W32(
-      (WEBRTC_SPL_MUL_16_16(22938, (8192 + WEBRTC_SPL_RSHIFT_W32(varscaleQ14, 1)))
-       + ((int32_t)32768)), 16);
+  aaQ14 = (int16_t)((22938 * (8192 + (varscaleQ14 >> 1)) + 32768) >> 16);
 
   /* Calculate tmp = (1.0 + aa*aa); in Q12 */
   tmp16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(aaQ14, aaQ14, 15); //Q14*Q14>>15 = Q13
@@ -673,16 +666,16 @@
     /* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */
 
     /* Calculate corrlo2[0] = tmpQQlo * corrlo[0] - 2.0*tmpQQlo * corrlo[1];*/
-    corrlo2QQ[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[0]), 1)- // Q(12+QdomLO-16)>>1 = Q(QdomLO-5)
-        WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, corrloQQ[1]), 2); // 2*Q(14+QdomLO-16)>>3 = Q(QdomLO-2)>>2 = Q(QdomLO-5)
+    // |corrlo2QQ| in Q(QdomLO-5).
+    corrlo2QQ[0] = (WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[0]) >> 1) -
+        (WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, corrloQQ[1]) >> 2);
 
     /* Calculate corrlo2[n] = tmpQQlo * corrlo[n] - tmpQQlo * (corrlo[n-1] + corrlo[n+1]);*/
     for (n = 1; n <= ORDERLO; n++) {
 
-      tmp32 = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n-1], 1) + WEBRTC_SPL_RSHIFT_W32(corrloQQ[n+1], 1); // Q(QdomLO-1)
-      corrlo2QQ[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[n]), 1)- // Q(12+QdomLO-16)>>1 = Q(QdomLO-5)
-          WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, tmp32), 2); // Q(14+QdomLO-1-16)>>2 = Q(QdomLO-3)>>2 = Q(QdomLO-5)
-
+      tmp32 = (corrloQQ[n - 1] >> 1) + (corrloQQ[n + 1] >> 1);  // Q(QdomLO-1).
+      corrlo2QQ[n] = (WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[n]) >> 1) -
+          (WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, tmp32) >> 2);
     }
     QdomLO -= 5;
 
@@ -705,12 +698,12 @@
     /* corrlo2QQ is in Q(QdomLO) and corrhiQQ is in Q(QdomHI) before the following
        code segment, where we want to make sure we get a 1-bit margin */
     for (n = 0; n <= ORDERLO; n++) {
-      corrlo2QQ[n] = WEBRTC_SPL_RSHIFT_W32(corrlo2QQ[n], 1); // Make sure we have a 1-bit margin
+      corrlo2QQ[n] >>= 1;  // Make sure we have a 1-bit margin.
     }
     QdomLO -= 1; // Now, corrlo2QQ is in Q(QdomLO), with a 1-bit margin
 
     for (n = 0; n <= ORDERHI; n++) {
-      corrhiQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], 1); // Make sure we have a 1-bit margin
+      corrhiQQ[n] >>= 1;  // Make sure we have a 1-bit margin.
     }
     QdomHI -= 1; // Now, corrhiQQ is in Q(QdomHI), with a 1-bit margin
 
@@ -738,7 +731,7 @@
           // Shift |alpha| as much as possible without overflow the number of
           // times required to get |tmp| in QdomLO.
           tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha << 6, tmp);
-          tmpCorr = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n], sh-shMem-6);
+          tmpCorr = corrloQQ[n] >> (sh - shMem - 6);
           tmp = tmp + tmpCorr;
           maskdata->CorrBufLoQQ[n] = tmp;
           newQdomLO = QdomLO-(sh-shMem-6);
@@ -759,7 +752,7 @@
     if( newQdomLO!=QdomLO) {
       for (n = 0; n <= ORDERLO; n++) {
         if (maskdata->CorrBufLoQdom[n] != newQdomLO)
-          corrloQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n], maskdata->CorrBufLoQdom[n]-newQdomLO);
+          corrloQQ[n] >>= maskdata->CorrBufLoQdom[n] - newQdomLO;
       }
       QdomLO = newQdomLO;
     }
@@ -795,7 +788,7 @@
           // Shift |alpha| as much as possible without overflow the number of
           // times required to get |tmp| in QdomHI.
           tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha << 6, tmp);
-          tmpCorr = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], sh-shMem-6);
+          tmpCorr = corrhiQQ[n] >> (sh - shMem - 6);
           tmp = tmp + tmpCorr;
           maskdata->CorrBufHiQQ[n] = tmp;
           newQdomHI = QdomHI-(sh-shMem-6);
@@ -816,7 +809,7 @@
     if( newQdomHI!=QdomHI) {
       for (n = 0; n <= ORDERHI; n++) {
         if (maskdata->CorrBufHiQdom[n] != newQdomHI)
-          corrhiQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], maskdata->CorrBufHiQdom[n]-newQdomHI);
+          corrhiQQ[n] >>= maskdata->CorrBufHiQdom[n] - newQdomHI;
       }
       QdomHI = newQdomHI;
     }
@@ -867,7 +860,7 @@
     WebRtcSpl_AToK_JSK(a_LOQ11, ORDERLO, rcQ15_lo);
 
     if (sh_lo & 0x0001) {
-      res_nrgQQ=WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1);
+      res_nrgQQ >>= 1;
       sh_lo-=1;
     }
 
@@ -916,7 +909,7 @@
     WebRtcSpl_LpcToReflCoef(polyHI, ORDERHI, rcQ15_hi);
 
     if (sh_hi & 0x0001) {
-      res_nrgQQ=WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1);
+      res_nrgQQ >>= 1;
       sh_hi-=1;
     }
 
@@ -930,9 +923,9 @@
       /* hi_coeff = varscale * S_N_R / (sqrt_nrg + varscale * H_T_H); */
 
       //tmp32a=WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, H_T_HQ19, 17);  // Q14
-      tmp32a=WEBRTC_SPL_RSHIFT_W32((int32_t) varscaleQ14,1);  // H_T_HQ19=65536 (16-17=-1)
+      tmp32a = varscaleQ14 >> 1;  // H_T_HQ19=65536 (16-17=-1)
 
-      ssh= WEBRTC_SPL_RSHIFT_W32(sh_hi, 1);  // sqrt_nrg is in Qssh
+      ssh = sh_hi >> 1;  // |sqrt_nrg| is in Qssh.
       sh = ssh - 14;
       tmp32b = WEBRTC_SPL_SHIFT_W32(tmp32a, sh); // Q14->Qssh
       tmp32c = sqrt_nrg + tmp32b;  // Qssh  (denominator)
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c
index bdb54bb..a315c47 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c
@@ -32,7 +32,7 @@
   int16_t frac;
 
   zeros=WebRtcSpl_NormU32(x);
-  frac=(int16_t)WEBRTC_SPL_RSHIFT_W32(((uint32_t)(WEBRTC_SPL_LSHIFT_W32(x, zeros))&0x7FFFFFFF), 23);
+  frac = (int16_t)(((x << zeros) & 0x7FFFFFFF) >> 23);
   /* log2(magn(i)) */
 
   lg2= (WEBRTC_SPL_LSHIFT_W32((31-zeros), 8)+frac);
@@ -77,7 +77,7 @@
     /* t in Q31, without signs */
     t32 = WebRtcSpl_DivResultInQ31(nom32 * sign1, den32 * sign2);
 
-    t16=(int16_t)WEBRTC_SPL_RSHIFT_W32(t32, 23);  /* Q8 */
+    t16 = (int16_t)(t32 >> 23);  /* Q8 */
     t16=t16*sign1*sign2;        /* t in Q8 with signs */
 
     *y = x[0]+t16;          /* Q8 */
@@ -327,7 +327,7 @@
 
   /* Bias towards constant pitch */
   tmp32a = lagsQ8[0] - PITCH_MIN_LAG_Q8;
-  ratq = WEBRTC_SPL_RSHIFT_W32(tmp32a, 1) + OFFSET_Q8;
+  ratq = (tmp32a >> 1) + OFFSET_Q8;
 
   for (k = 1; k <= PITCH_LAG_SPAN2; k++)
   {
@@ -335,7 +335,7 @@
     tmp32b = (int32_t) (WEBRTC_SPL_LSHIFT_W32(tmp32a, 1)) - ratq; // Q8
     tmp32c = WEBRTC_SPL_MUL_16_16_RSFT((int16_t) tmp32b, (int16_t) tmp32b, 8); // Q8
 
-    tmp32b = (int32_t)tmp32c + (int32_t)WEBRTC_SPL_RSHIFT_W32(ratq, 1);
+    tmp32b = tmp32c + (ratq >> 1);
         // (k-r)^2 + 0.5 * r  Q8
     tmp32c = WebRtcIsacfix_Log2Q8((uint32_t)tmp32a) - 2048;
         // offset 8*2^8 , log2(0.5*k) Q8
@@ -343,7 +343,7 @@
         // offset 8*2^8 , log2(0.5*k) Q8
     tmp32e =  tmp32c - tmp32d;
 
-    cv2q[k] += WEBRTC_SPL_RSHIFT_W32(tmp32e, 1);
+    cv2q[k] += tmp32e >> 1;
 
   }
 
@@ -401,12 +401,10 @@
     lagsQ8[3] = lagsQ8[0];
   }
 
-  lagsQ7[0]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[0], 1);
-  lagsQ7[1]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[1], 1);
-  lagsQ7[2]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[2], 1);
-  lagsQ7[3]=(int16_t) WEBRTC_SPL_RSHIFT_W32(lagsQ8[3], 1);
-
-
+  lagsQ7[0] = (int16_t)(lagsQ8[0] >> 1);
+  lagsQ7[1] = (int16_t)(lagsQ8[1] >> 1);
+  lagsQ7[2] = (int16_t)(lagsQ8[2] >> 1);
+  lagsQ7[3] = (int16_t)(lagsQ8[3] >> 1);
 }
 
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c
index 82155d2..b3f9f2f 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c
@@ -44,8 +44,7 @@
                                         scaling);  // Q0
   }
   logcorQ8 += PITCH_LAG_SPAN2 - 1;
-  lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32);    // Q8
-  lys = WEBRTC_SPL_RSHIFT_W32(lys, 1);  //sqrt(ysum);
+  lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32) >> 1; // Q8, sqrt(ysum)
   if (csum32 > 0) {
     lcs = WebRtcIsacfix_Log2Q8((uint32_t)csum32);  // 2log(csum) in Q8
     if (lcs > (lys + oneQ8)) {          // csum/sqrt(ysum) > 2 in Q8
@@ -105,8 +104,7 @@
 
     logcorQ8--;
 
-    lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32);  // Q8
-    lys = WEBRTC_SPL_RSHIFT_W32(lys, 1);  //sqrt(ysum);
+    lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32) >> 1; // Q8, sqrt(ysum)
 
     if (csum32 > 0) {
       lcs = WebRtcIsacfix_Log2Q8((uint32_t)csum32);  // 2log(csum) in Q8
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_mips.c b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_mips.c
index fa426e9..2ce4888 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_mips.c
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_mips.c
@@ -86,8 +86,7 @@
     );
   }
   logcorQ8 += PITCH_LAG_SPAN2 - 1;
-  lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32); // Q8
-  lys = WEBRTC_SPL_RSHIFT_W32(lys, 1); //sqrt(ysum);
+  lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32) >> 1; // Q8, sqrt(ysum)
   if (csum32 > 0) {
     lcs = WebRtcIsacfix_Log2Q8((uint32_t)csum32);  // 2log(csum) in Q8
     if (lcs > (lys + oneQ8)) {  // csum/sqrt(ysum) > 2 in Q8
@@ -180,8 +179,7 @@
     );
 
     logcorQ8--;
-    lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32); // Q8
-    lys = WEBRTC_SPL_RSHIFT_W32(lys, 1); //sqrt(ysum);
+    lys = WebRtcIsacfix_Log2Q8((uint32_t)ysum32) >> 1; // Q8, sqrt(ysum)
     if (csum32 > 0) {
       lcs = WebRtcIsacfix_Log2Q8((uint32_t)csum32); // 2log(csum) in Q8
       if (lcs > (lys + oneQ8)) { // csum/sqrt(ysum) > 2
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c b/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c
index ca810a5..d27daf3 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c
@@ -53,7 +53,7 @@
   int32_t roundVal;
 
   roundVal = WEBRTC_SPL_LSHIFT_W32((int32_t)1,  qDomain - 1);
-  intgr = WEBRTC_SPL_RSHIFT_W32(fixVal + roundVal, qDomain);
+  intgr = (fixVal + roundVal) >> qDomain;
 
   return intgr;
 }
@@ -132,8 +132,7 @@
       indW32 = CalcLrIntQ(curLagQ7, 7);
       tmpW32 = WEBRTC_SPL_LSHIFT_W32(indW32, 7);
       tmpW32 -= curLagQ7;
-      frcQQ = WEBRTC_SPL_RSHIFT_W32(tmpW32, 4);
-      frcQQ += 4;
+      frcQQ = (tmpW32 >> 4) + 4;
 
       if (frcQQ == PITCH_FRACS) {
         frcQQ = 0;
@@ -228,19 +227,17 @@
 
         tmp2W32 = WEBRTC_SPL_MUL_16_32_RSFT14(indatQ0[ind], tmpW32);
         tmpW32 += 8192;
-        tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 14);
+        tmpW16 = (int16_t)(tmpW32 >> 14);
         tmpW32 = WEBRTC_SPL_MUL_16_16(tmpW16, tmpW16);
 
         if ((tmp2W32 > 1073700000) || (csum1QQ > 1073700000) ||
             (tmpW32 > 1073700000) || (esumxQQ > 1073700000)) {  // 2^30
           scale++;
-          csum1QQ = WEBRTC_SPL_RSHIFT_W32(csum1QQ, 1);
-          esumxQQ = WEBRTC_SPL_RSHIFT_W32(esumxQQ, 1);
+          csum1QQ >>= 1;
+          esumxQQ >>= 1;
         }
-        tmp2W32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, scale);
-        csum1QQ += tmp2W32;
-        tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmpW32, scale);
-        esumxQQ += tmpW32;
+        csum1QQ += tmp2W32 >> scale;
+        esumxQQ += tmpW32 >> scale;
 
         ind++;
         pos++;
@@ -252,7 +249,7 @@
       tmp2W32 = WebRtcSpl_DivResultInQ31(csum1QQ, esumxQQ);
 
       // Gain should be half the correlation.
-      tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, 20);
+      tmpW32 = tmp2W32 >> 20;
     } else {
       tmpW32 = 4096;
     }
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c b/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c
index 5b1b3f1..2f3fb4b 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c
@@ -41,7 +41,7 @@
     /* Saturate to avoid overflow in tmpW16. */
     tmpW32 = WEBRTC_SPL_SAT(536862719, tmpW32, -536879104);
     tmpW32 += 8192;
-    tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 14);
+    tmpW16 = (int16_t)(tmpW32 >> 14);
 
     /* Shift low pass filter state. */
     memmove(&inputState[1], &inputState[0],
@@ -60,7 +60,7 @@
     /* Saturate to avoid overflow in tmpW16. */
     tmpW32 = WEBRTC_SPL_SAT(1073725439, tmpW32, -1073758208);
     tmpW32 += 16384;
-    tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 15);
+    tmpW16 = (int16_t)(tmpW32 >> 15);
 
     /* Subtract from input and update buffer. */
     tmpW32 = inputBuf[*index2] - WEBRTC_SPL_MUL_16_16(sign, tmpW16);
@@ -71,4 +71,3 @@
     (*index2)++;
   }
 }
-
diff --git a/modules/audio_coding/codecs/isac/fix/source/transform.c b/modules/audio_coding/codecs/isac/fix/source/transform.c
index 24ccc82..e675e15 100644
--- a/modules/audio_coding/codecs/isac/fix/source/transform.c
+++ b/modules/audio_coding/codecs/isac/fix/source/transform.c
@@ -45,10 +45,11 @@
   for (k = 0; k < FRAMESAMPLES/2; k++) {
     tmp1rQ14 = WebRtcIsacfix_kCosTab1[k];
     tmp1iQ14 = WebRtcIsacfix_kSinTab1[k];
-    xrQ16 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(tmp1rQ14, inre1Q9[k]) + WEBRTC_SPL_MUL_16_16(tmp1iQ14, inre2Q9[k]), 7);
-    xiQ16 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(tmp1rQ14, inre2Q9[k]) - WEBRTC_SPL_MUL_16_16(tmp1iQ14, inre1Q9[k]), 7);
-    tmpreQ16[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xrQ16)+4, 3); // (Q16*Q19>>16)>>3 = Q16
-    tmpimQ16[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xiQ16)+4, 3); // (Q16*Q19>>16)>>3 = Q16
+    xrQ16 = (tmp1rQ14 * inre1Q9[k] + tmp1iQ14 * inre2Q9[k]) >> 7;
+    xiQ16 = (tmp1rQ14 * inre2Q9[k] - tmp1iQ14 * inre1Q9[k]) >> 7;
+    // Q-domains below: (Q16*Q19>>16)>>3 = Q16
+    tmpreQ16[k] = (WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xrQ16) + 4) >> 3;
+    tmpimQ16[k] = (WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xiQ16) + 4) >> 3;
   }
 
 
@@ -71,8 +72,8 @@
   } else {
     int32_t round = WEBRTC_SPL_LSHIFT_W32((int32_t)1, -sh-1);
     for (k=0; k<FRAMESAMPLES/2; k++) {
-      inre1Q9[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmpreQ16[k]+round, -sh); //Q(16+sh)
-      inre2Q9[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmpimQ16[k]+round, -sh); //Q(16+sh)
+      inre1Q9[k] = (int16_t)((tmpreQ16[k] + round) >> -sh);  // Q(16+sh)
+      inre2Q9[k] = (int16_t)((tmpimQ16[k] + round) >> -sh);  // Q(16+sh)
     }
   }
 
@@ -82,8 +83,8 @@
   //"Fastest" vectors
   if (sh>=0) {
     for (k=0; k<FRAMESAMPLES/2; k++) {
-      tmpreQ16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inre1Q9[k], sh); //Q(16+sh) -> Q16
-      tmpimQ16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inre2Q9[k], sh); //Q(16+sh) -> Q16
+      tmpreQ16[k] = inre1Q9[k] >> sh;  // Q(16+sh) -> Q16
+      tmpimQ16[k] = inre2Q9[k] >> sh;  // Q(16+sh) -> Q16
     }
   } else {
     for (k=0; k<FRAMESAMPLES/2; k++) {
@@ -103,12 +104,14 @@
     tmp1iQ14 = WebRtcIsacfix_kSinTab2[k];
     v1Q16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, xrQ16) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, xiQ16);
     v2Q16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, xrQ16) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, xiQ16);
-    outreQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(v1Q16, 9);
-    outimQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(v2Q16, 9);
+    outreQ7[k] = (int16_t)(v1Q16 >> 9);
+    outimQ7[k] = (int16_t)(v2Q16 >> 9);
     v1Q16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, yrQ16) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, yiQ16);
     v2Q16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, yrQ16) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, yiQ16);
-    outreQ7[FRAMESAMPLES/2 - 1 - k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(v1Q16, 9); //CalcLrIntQ(v1Q16, 9);
-    outimQ7[FRAMESAMPLES/2 - 1 - k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(v2Q16, 9); //CalcLrIntQ(v2Q16, 9);
+    // CalcLrIntQ(v1Q16, 9);
+    outreQ7[FRAMESAMPLES / 2 - 1 - k] = (int16_t)(v1Q16 >> 9);
+    // CalcLrIntQ(v2Q16, 9);
+    outimQ7[FRAMESAMPLES / 2 - 1 - k] = (int16_t)(v2Q16 >> 9);
 
   }
 }
@@ -166,8 +169,8 @@
   } else {
     int32_t round = WEBRTC_SPL_LSHIFT_W32((int32_t)1, -sh-1);
     for (k=0; k<240; k++) {
-      inreQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(outre1Q16[k]+round, -sh); //Q(16+sh)
-      inimQ7[k] = (int16_t) WEBRTC_SPL_RSHIFT_W32(outre2Q16[k]+round, -sh); //Q(16+sh)
+      inreQ7[k] = (int16_t)((outre1Q16[k] + round) >> -sh);  // Q(16+sh)
+      inimQ7[k] = (int16_t)((outre2Q16[k] + round) >> -sh);  // Q(16+sh)
     }
   }
 
@@ -176,8 +179,8 @@
   //"Fastest" vectors
   if (sh>=0) {
     for (k=0; k<240; k++) {
-      outre1Q16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inreQ7[k], sh); //Q(16+sh) -> Q16
-      outre2Q16[k] = WEBRTC_SPL_RSHIFT_W32((int32_t)inimQ7[k], sh); //Q(16+sh) -> Q16
+      outre1Q16[k] = inreQ7[k] >> sh;  // Q(16+sh) -> Q16
+      outre2Q16[k] = inimQ7[k] >> sh;  // Q(16+sh) -> Q16
     }
   } else {
     for (k=0; k<240; k++) {
diff --git a/modules/audio_coding/codecs/isac/main/source/entropy_coding.c b/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
index 9ae69a0..6cd3310 100644
--- a/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
+++ b/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
@@ -106,14 +106,13 @@
   for (n = 0; n < AR_ORDER + 1; n++) {
     sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]);   /* Q24 */
   }
-  sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6),
-                                             65) + 32768, 16); /* Q8 */
-  CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, gainQ10) + 256, 9);
+  sum = ((sum >> 6) * 65 + 32768) >> 16;  /* Q8 */
+  CorrQ11[0] = (sum * gainQ10 + 256) >> 9;
 
   /* To avoid overflow, we shift down gainQ10 if it is large.
    * We will not lose any precision */
   if (gainQ10 > 400000) {
-    tmpGain = WEBRTC_SPL_RSHIFT_W32(gainQ10, 3);
+    tmpGain = gainQ10 >> 3;
     round = 32;
     shftVal = 6;
   } else {
@@ -126,9 +125,8 @@
     sum = 16384;
     for (n = k; n < AR_ORDER + 1; n++)
       sum += WEBRTC_SPL_MUL(ARCoefQ12[n - k], ARCoefQ12[n]); /* Q24 */
-    sum = WEBRTC_SPL_RSHIFT_W32(sum, 15);
-    CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round,
-                                       shftVal);
+    sum >>= 15;
+    CorrQ11[k] = (sum * tmpGain + round) >> shftVal;
   }
   sum = WEBRTC_SPL_LSHIFT_W32(CorrQ11[0], 7);
   for (n = 0; n < FRAMESAMPLES / 8; n++) {
@@ -136,8 +134,7 @@
   }
   for (k = 1; k < AR_ORDER; k += 2) {
     for (n = 0; n < FRAMESAMPLES / 8; n++) {
-      CurveQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(
-          WebRtcIsac_kCos[k][n], CorrQ11[k + 1]) + 2, 2);
+      CurveQ16[n] += (WebRtcIsac_kCos[k][n] * CorrQ11[k + 1] + 2) >> 2;
     }
   }
 
@@ -155,14 +152,12 @@
     shftVal = 0;
   }
   for (n = 0; n < FRAMESAMPLES / 8; n++) {
-    diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(
-        CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2);
+    diffQ16[n] = (CS_ptrQ9[n] * (CorrQ11[1] >> shftVal) + 2) >> 2;
   }
   for (k = 2; k < AR_ORDER; k += 2) {
     CS_ptrQ9 = WebRtcIsac_kCos[k];
     for (n = 0; n < FRAMESAMPLES / 8; n++) {
-      diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(
-          CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k + 1], shftVal)) + 2, 2);
+      diffQ16[n] += (CS_ptrQ9[n] * (CorrQ11[k + 1] >> shftVal) + 2) >> 2;
     }
   }
 
diff --git a/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc b/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc
index 567ec85..ffdcc0c 100644
--- a/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc
+++ b/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc
@@ -448,7 +448,7 @@
     {
 		printf("  Error iSAC Cannot write file %s.\n", outname);
         cout << flush;
-        getchar();
+        getc(stdin);
 		exit(1);
 	}
 	if(VADusage)
diff --git a/modules/audio_coding/codecs/isac/main/test/simpleKenny.c b/modules/audio_coding/codecs/isac/main/test/simpleKenny.c
index 1e752a1..d10b4ad 100644
--- a/modules/audio_coding/codecs/isac/main/test/simpleKenny.c
+++ b/modules/audio_coding/codecs/isac/main/test/simpleKenny.c
@@ -383,7 +383,7 @@
 					// exit if returned with error
 					//errType=WebRtcIsac_GetErrorCode(ISAC_main_inst);
 					fprintf(stderr,"\nError in encoder\n");
-					getchar();
+					getc(stdin);
 					exit(EXIT_FAILURE);
 				}
 
@@ -479,7 +479,7 @@
 			{
 				//errType=WebRtcIsac_GetErrorCode(ISAC_main_inst);
 				fprintf(stderr,"\nError in decoder.\n");
-				getchar();
+				getc(stdin);
 				exit(1);
 			}
 
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
new file mode 100644
index 0000000..6349b5c
--- /dev/null
+++ b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -0,0 +1,104 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
+
+#include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
+
+namespace webrtc {
+
+namespace {
+
+// We always encode at 48 kHz.
+const int kSampleRateHz = 48000;
+
+int DivExact(int a, int b) {
+  CHECK_EQ(a % b, 0);
+  return a / b;
+}
+
+int16_t ClampInt16(size_t x) {
+  return static_cast<int16_t>(
+      std::min(x, static_cast<size_t>(std::numeric_limits<int16_t>::max())));
+}
+
+int16_t CastInt16(size_t x) {
+  DCHECK_LE(x, static_cast<size_t>(std::numeric_limits<int16_t>::max()));
+  return static_cast<int16_t>(x);
+}
+
+}  // namespace
+
+AudioEncoderOpus::Config::Config() : frame_size_ms(20), num_channels(1) {}
+
+bool AudioEncoderOpus::Config::IsOk() const {
+  if (frame_size_ms <= 0 || frame_size_ms % 10 != 0)
+    return false;
+  if (num_channels <= 0)
+    return false;
+  return true;
+}
+
+AudioEncoderOpus::AudioEncoderOpus(const Config& config)
+    : num_10ms_frames_per_packet_(DivExact(config.frame_size_ms, 10)),
+      num_channels_(config.num_channels),
+      samples_per_10ms_frame_(DivExact(kSampleRateHz, 100) * num_channels_) {
+  CHECK(config.IsOk());
+  input_buffer_.reserve(num_10ms_frames_per_packet_ * samples_per_10ms_frame_);
+  CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, num_channels_));
+}
+
+AudioEncoderOpus::~AudioEncoderOpus() {
+  CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
+}
+
+int AudioEncoderOpus::sample_rate_hz() const {
+  return kSampleRateHz;
+}
+
+int AudioEncoderOpus::num_channels() const {
+  return num_channels_;
+}
+
+int AudioEncoderOpus::Num10MsFramesInNextPacket() const {
+  return num_10ms_frames_per_packet_;
+}
+
+bool AudioEncoderOpus::Encode(uint32_t timestamp,
+                              const int16_t* audio,
+                              size_t max_encoded_bytes,
+                              uint8_t* encoded,
+                              size_t* encoded_bytes,
+                              uint32_t* encoded_timestamp) {
+  if (input_buffer_.empty())
+    first_timestamp_in_buffer_ = timestamp;
+  input_buffer_.insert(input_buffer_.end(), audio,
+                       audio + samples_per_10ms_frame_);
+  if (input_buffer_.size() < (static_cast<size_t>(num_10ms_frames_per_packet_) *
+                              samples_per_10ms_frame_)) {
+    *encoded_bytes = 0;
+    return true;
+  }
+  CHECK_EQ(input_buffer_.size(),
+           static_cast<size_t>(num_10ms_frames_per_packet_) *
+           samples_per_10ms_frame_);
+  int16_t r = WebRtcOpus_Encode(
+      inst_, &input_buffer_[0],
+      DivExact(CastInt16(input_buffer_.size()), num_channels_),
+      ClampInt16(max_encoded_bytes), encoded);
+  input_buffer_.clear();
+  if (r < 0)
+    return false;
+  *encoded_bytes = r;
+  *encoded_timestamp = first_timestamp_in_buffer_;
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h b/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
new file mode 100644
index 0000000..e2e5c73
--- /dev/null
+++ b/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INTERFACE_AUDIO_ENCODER_OPUS_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INTERFACE_AUDIO_ENCODER_OPUS_H_
+
+#include <vector>
+
+#include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+
+namespace webrtc {
+
+class AudioEncoderOpus : public AudioEncoder {
+ public:
+  struct Config {
+    Config();
+    bool IsOk() const;
+    int frame_size_ms;
+    int num_channels;
+  };
+
+  explicit AudioEncoderOpus(const Config& config);
+  virtual ~AudioEncoderOpus() OVERRIDE;
+
+  virtual int sample_rate_hz() const OVERRIDE;
+  virtual int num_channels() const OVERRIDE;
+  virtual int Num10MsFramesInNextPacket() const OVERRIDE;
+
+ protected:
+  virtual bool Encode(uint32_t timestamp,
+                      const int16_t* audio,
+                      size_t max_encoded_bytes,
+                      uint8_t* encoded,
+                      size_t* encoded_bytes,
+                      uint32_t* encoded_timestamp) OVERRIDE;
+
+ private:
+  const int num_10ms_frames_per_packet_;
+  const int num_channels_;
+  const int samples_per_10ms_frame_;
+  std::vector<int16_t> input_buffer_;
+  OpusEncInst* inst_;
+  uint32_t first_timestamp_in_buffer_;
+};
+
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INTERFACE_AUDIO_ENCODER_OPUS_H_
diff --git a/modules/audio_coding/codecs/opus/opus.gypi b/modules/audio_coding/codecs/opus/opus.gypi
index 89f0a54..b537285 100644
--- a/modules/audio_coding/codecs/opus/opus.gypi
+++ b/modules/audio_coding/codecs/opus/opus.gypi
@@ -27,6 +27,8 @@
         '<(webrtc_root)',
       ],
       'sources': [
+        'audio_encoder_opus.cc',
+        'interface/audio_encoder_opus.h',
         'interface/opus_interface.h',
         'opus_inst.h',
         'opus_interface.c',
diff --git a/modules/audio_coding/codecs/pcm16b/include/pcm16b.h b/modules/audio_coding/codecs/pcm16b/include/pcm16b.h
index 9c96b83..86b32fe 100644
--- a/modules/audio_coding/codecs/pcm16b/include/pcm16b.h
+++ b/modules/audio_coding/codecs/pcm16b/include/pcm16b.h
@@ -73,8 +73,7 @@
  * Returned value    : Samples in speechOut16b
  */
 
-int16_t WebRtcPcm16b_DecodeW16(void *inst,
-                               int16_t *speechIn16b,
+int16_t WebRtcPcm16b_DecodeW16(int16_t *speechIn16b,
                                int16_t length_bytes,
                                int16_t *speechOut16b,
                                int16_t* speechType);
diff --git a/modules/audio_coding/codecs/pcm16b/pcm16b.c b/modules/audio_coding/codecs/pcm16b/pcm16b.c
index af6720f..2c6bea6 100644
--- a/modules/audio_coding/codecs/pcm16b/pcm16b.c
+++ b/modules/audio_coding/codecs/pcm16b/pcm16b.c
@@ -61,8 +61,7 @@
 
 
 /* Decoder with int16_t Input instead of char when the int16_t Encoder is used */
-int16_t WebRtcPcm16b_DecodeW16(void *inst,
-                               int16_t *speechIn16b,
+int16_t WebRtcPcm16b_DecodeW16(int16_t *speechIn16b,
                                int16_t length_bytes,
                                int16_t *speechOut16b,
                                int16_t* speechType)
@@ -80,9 +79,6 @@
 
     *speechType=1;
 
-    // Avoid warning.
-    (void)(inst = NULL);
-
     return length_bytes >> 1;
 }
 
diff --git a/modules/audio_coding/codecs/tools/audio_codec_speed_tests.gypi b/modules/audio_coding/codecs/tools/audio_codec_speed_tests.gypi
index 6503a51..a9a5bb9 100644
--- a/modules/audio_coding/codecs/tools/audio_codec_speed_tests.gypi
+++ b/modules/audio_coding/codecs/tools/audio_codec_speed_tests.gypi
@@ -55,7 +55,6 @@
           ],
           'includes': [
             '../../../../build/isolate.gypi',
-            'audio_codec_speed_tests.isolate',
           ],
           'sources': [
             'audio_codec_speed_tests.isolate',
diff --git a/modules/audio_coding/codecs/tools/audio_codec_speed_tests.isolate b/modules/audio_coding/codecs/tools/audio_codec_speed_tests.isolate
index 8c5a2bd..ed7599d 100644
--- a/modules/audio_coding/codecs/tools/audio_codec_speed_tests.isolate
+++ b/modules/audio_coding/codecs/tools/audio_codec_speed_tests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/resources/',
           '<(DEPTH)/data/',
         ],
@@ -21,19 +21,14 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/audio_codec_speed_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_touched': [
+        'files': [
           '<(DEPTH)/DEPS',
-        ],
-        'isolate_dependency_tracked': [
           '<(DEPTH)/resources/audio_coding/music_stereo_48kHz.pcm',
           '<(DEPTH)/resources/audio_coding/speech_mono_16kHz.pcm',
           '<(DEPTH)/resources/audio_coding/speech_mono_32_48kHz.pcm',
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/audio_codec_speed_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/modules/audio_coding/main/acm2/acm_isac.cc b/modules/audio_coding/main/acm2/acm_isac.cc
index 6ee2682..bc20c96 100644
--- a/modules/audio_coding/main/acm2/acm_isac.cc
+++ b/modules/audio_coding/main/acm2/acm_isac.cc
@@ -262,8 +262,7 @@
 #endif
 
 ACMISAC::ACMISAC(int16_t codec_id)
-    : AudioDecoder(ACMCodecDB::neteq_decoders_[codec_id]),
-      codec_inst_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
+    : codec_inst_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
       is_enc_initialized_(false),
       isac_coding_mode_(CHANNEL_INDEPENDENT),
       enforce_frame_size_(false),
diff --git a/modules/audio_coding/main/acm2/acm_pcma.cc b/modules/audio_coding/main/acm2/acm_pcma.cc
index 548e8fd..41d4d08 100644
--- a/modules/audio_coding/main/acm2/acm_pcma.cc
+++ b/modules/audio_coding/main/acm2/acm_pcma.cc
@@ -27,7 +27,7 @@
 int16_t ACMPCMA::InternalEncode(uint8_t* bitstream,
                                 int16_t* bitstream_len_byte) {
   *bitstream_len_byte = WebRtcG711_EncodeA(
-      NULL, &in_audio_[in_audio_ix_read_], frame_len_smpl_ * num_channels_,
+      &in_audio_[in_audio_ix_read_], frame_len_smpl_ * num_channels_,
       reinterpret_cast<int16_t*>(bitstream));
   // Increment the read index this tell the caller that how far
   // we have gone forward in reading the audio buffer.
diff --git a/modules/audio_coding/main/acm2/acm_pcmu.cc b/modules/audio_coding/main/acm2/acm_pcmu.cc
index 5c03236..4f16062 100644
--- a/modules/audio_coding/main/acm2/acm_pcmu.cc
+++ b/modules/audio_coding/main/acm2/acm_pcmu.cc
@@ -27,7 +27,7 @@
 int16_t ACMPCMU::InternalEncode(uint8_t* bitstream,
                                 int16_t* bitstream_len_byte) {
   *bitstream_len_byte = WebRtcG711_EncodeU(
-      NULL, &in_audio_[in_audio_ix_read_], frame_len_smpl_ * num_channels_,
+      &in_audio_[in_audio_ix_read_], frame_len_smpl_ * num_channels_,
       reinterpret_cast<int16_t*>(bitstream));
 
   // Increment the read index this tell the caller that how far
diff --git a/modules/audio_coding/main/acm2/acm_receiver.cc b/modules/audio_coding/main/acm2/acm_receiver.cc
index 0c7e6c7..0744754 100644
--- a/modules/audio_coding/main/acm2/acm_receiver.cc
+++ b/modules/audio_coding/main/acm2/acm_receiver.cc
@@ -122,11 +122,14 @@
       last_audio_decoder_(-1),  // Invalid value.
       previous_audio_activity_(AudioFrame::kVadPassive),
       current_sample_rate_hz_(config.neteq_config.sample_rate_hz),
+      audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
+      last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
       nack_(),
       nack_enabled_(false),
       neteq_(NetEq::Create(config.neteq_config)),
       vad_enabled_(true),
       clock_(config.clock),
+      resampled_last_output_frame_(true),
       av_sync_(false),
       initial_delay_manager_(),
       missing_packets_sync_stream_(),
@@ -143,6 +146,9 @@
     neteq_->EnableVad();
   else
     neteq_->DisableVad();
+
+  memset(audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples);
+  memset(last_audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples);
 }
 
 AcmReceiver::~AcmReceiver() {
@@ -342,7 +348,6 @@
 
 int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) {
   enum NetEqOutputType type;
-  int16_t* ptr_audio_buffer = audio_frame->data_;
   int samples_per_channel;
   int num_channels;
   bool return_silence = false;
@@ -359,18 +364,6 @@
       initial_delay_manager_->LatePackets(timestamp_now,
                                           late_packets_sync_stream_.get());
     }
-
-    if (!return_silence) {
-      // This is our initial guess regarding whether a resampling will be
-      // required. It is based on previous sample rate of netEq. Most often,
-      // this is a correct guess, however, in case that incoming payload changes
-      // the resampling might might be needed. By doing so, we avoid an
-      // unnecessary memcpy().
-      if (desired_freq_hz != -1 &&
-          current_sample_rate_hz_ != desired_freq_hz) {
-        ptr_audio_buffer = audio_buffer_;
-      }
-    }
   }
 
   // If |late_packets_sync_stream_| is allocated then we have been in AV-sync
@@ -381,17 +374,19 @@
       return 0;
   }
 
+  // Accessing members, take the lock.
+  CriticalSectionScoped lock(crit_sect_.get());
+
+  // Always write the output to |audio_buffer_| first.
   if (neteq_->GetAudio(AudioFrame::kMaxDataSizeSamples,
-                       ptr_audio_buffer,
+                       audio_buffer_.get(),
                        &samples_per_channel,
-                       &num_channels, &type) != NetEq::kOK) {
+                       &num_channels,
+                       &type) != NetEq::kOK) {
     LOG_FERR0(LS_ERROR, "AcmReceiver::GetAudio") << "NetEq Failed.";
     return -1;
   }
 
-  // Accessing members, take the lock.
-  CriticalSectionScoped lock(crit_sect_.get());
-
   // Update NACK.
   int decoded_sequence_num = 0;
   uint32_t decoded_timestamp = 0;
@@ -409,45 +404,53 @@
   bool need_resampling = (desired_freq_hz != -1) &&
       (current_sample_rate_hz_ != desired_freq_hz);
 
-  if (ptr_audio_buffer == audio_buffer_) {
-    // Data is written to local buffer.
-    if (need_resampling) {
-      samples_per_channel =
-          resampler_.Resample10Msec(audio_buffer_,
-                                    current_sample_rate_hz_,
-                                    desired_freq_hz,
-                                    num_channels,
-                                    AudioFrame::kMaxDataSizeSamples,
-                                    audio_frame->data_);
-      if (samples_per_channel < 0) {
-        LOG_FERR0(LS_ERROR, "AcmReceiver::GetAudio") << "Resampler Failed.";
-        return -1;
-      }
-    } else {
-      // We might end up here ONLY if codec is changed.
-      memcpy(audio_frame->data_, audio_buffer_, samples_per_channel *
-             num_channels * sizeof(int16_t));
-    }
-  } else {
-    // Data is written into |audio_frame|.
-    if (need_resampling) {
-      // We might end up here ONLY if codec is changed.
-      samples_per_channel =
-          resampler_.Resample10Msec(audio_frame->data_,
-                                    current_sample_rate_hz_,
-                                    desired_freq_hz,
-                                    num_channels,
-                                    AudioFrame::kMaxDataSizeSamples,
-                                    audio_buffer_);
-      if (samples_per_channel < 0) {
-        LOG_FERR0(LS_ERROR, "AcmReceiver::GetAudio") << "Resampler Failed.";
-        return -1;
-      }
-      memcpy(audio_frame->data_, audio_buffer_, samples_per_channel *
-             num_channels * sizeof(int16_t));
+  if (need_resampling && !resampled_last_output_frame_) {
+    // Prime the resampler with the last frame.
+    int16_t temp_output[AudioFrame::kMaxDataSizeSamples];
+    samples_per_channel =
+        resampler_.Resample10Msec(last_audio_buffer_.get(),
+                                  current_sample_rate_hz_,
+                                  desired_freq_hz,
+                                  num_channels,
+                                  AudioFrame::kMaxDataSizeSamples,
+                                  temp_output);
+    if (samples_per_channel < 0) {
+      LOG_FERR0(LS_ERROR, "AcmReceiver::GetAudio")
+          << "Resampling last_audio_buffer_ failed.";
+      return -1;
     }
   }
 
+  // The audio in |audio_buffer_| is tansferred to |audio_frame_| below, either
+  // through resampling, or through straight memcpy.
+  // TODO(henrik.lundin) Glitches in the output may appear if the output rate
+  // from NetEq changes. See WebRTC issue 3923.
+  if (need_resampling) {
+    samples_per_channel =
+        resampler_.Resample10Msec(audio_buffer_.get(),
+                                  current_sample_rate_hz_,
+                                  desired_freq_hz,
+                                  num_channels,
+                                  AudioFrame::kMaxDataSizeSamples,
+                                  audio_frame->data_);
+    if (samples_per_channel < 0) {
+      LOG_FERR0(LS_ERROR, "AcmReceiver::GetAudio")
+          << "Resampling audio_buffer_ failed.";
+      return -1;
+    }
+    resampled_last_output_frame_ = true;
+  } else {
+    resampled_last_output_frame_ = false;
+    // We might end up here ONLY if codec is changed.
+    memcpy(audio_frame->data_,
+           audio_buffer_.get(),
+           samples_per_channel * num_channels * sizeof(int16_t));
+  }
+
+  // Swap buffers, so that the current audio is stored in |last_audio_buffer_|
+  // for next time.
+  audio_buffer_.swap(last_audio_buffer_);
+
   audio_frame->num_channels_ = num_channels;
   audio_frame->samples_per_channel_ = samples_per_channel;
   audio_frame->sample_rate_hz_ = samples_per_channel * 100;
diff --git a/modules/audio_coding/main/acm2/acm_receiver.h b/modules/audio_coding/main/acm2/acm_receiver.h
index 94ea5b0..6d31b9a 100644
--- a/modules/audio_coding/main/acm2/acm_receiver.h
+++ b/modules/audio_coding/main/acm2/acm_receiver.h
@@ -334,7 +334,8 @@
   ACMResampler resampler_ GUARDED_BY(crit_sect_);
   // Used in GetAudio, declared as member to avoid allocating every 10ms.
   // TODO(henrik.lundin) Stack-allocate in GetAudio instead?
-  int16_t audio_buffer_[AudioFrame::kMaxDataSizeSamples] GUARDED_BY(crit_sect_);
+  scoped_ptr<int16_t[]> audio_buffer_ GUARDED_BY(crit_sect_);
+  scoped_ptr<int16_t[]> last_audio_buffer_ GUARDED_BY(crit_sect_);
   scoped_ptr<Nack> nack_ GUARDED_BY(crit_sect_);
   bool nack_enabled_ GUARDED_BY(crit_sect_);
   CallStatistics call_stats_ GUARDED_BY(crit_sect_);
@@ -342,6 +343,7 @@
   Decoder decoders_[ACMCodecDB::kMaxNumCodecs];
   bool vad_enabled_;
   Clock* clock_;  // TODO(henrik.lundin) Make const if possible.
+  bool resampled_last_output_frame_ GUARDED_BY(crit_sect_);
 
   // Indicates if a non-zero initial delay is set, and the receiver is in
   // AV-sync mode.
diff --git a/modules/audio_coding/main/acm2/audio_coding_module.gypi b/modules/audio_coding/main/acm2/audio_coding_module.gypi
index d746a80..8dfdb56 100644
--- a/modules/audio_coding/main/acm2/audio_coding_module.gypi
+++ b/modules/audio_coding/main/acm2/audio_coding_module.gypi
@@ -162,7 +162,7 @@
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(webrtc_root)/test/test.gyp:test_support',
             '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
           ],
           'sources': [
@@ -180,7 +180,7 @@
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(webrtc_root)/test/test.gyp:test_support',
             '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
           ],
           'sources': [
diff --git a/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc b/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
index 7ffcac7..d9ed32c 100644
--- a/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
+++ b/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
@@ -1034,7 +1034,7 @@
   Run(16000, 16000, 1000);
 }
 
-TEST_F(AcmSwitchingOutputFrequencyOldApi, DISABLED_Toggle16KhzTo32Khz) {
+TEST_F(AcmSwitchingOutputFrequencyOldApi, Toggle16KhzTo32Khz) {
   Run(16000, 32000, 1000);
 }
 
@@ -1042,7 +1042,7 @@
   Run(32000, 16000, 1000);
 }
 
-TEST_F(AcmSwitchingOutputFrequencyOldApi, DISABLED_Toggle16KhzTo8Khz) {
+TEST_F(AcmSwitchingOutputFrequencyOldApi, Toggle16KhzTo8Khz) {
   Run(16000, 8000, 1000);
 }
 
diff --git a/modules/audio_coding/main/test/APITest.cc b/modules/audio_coding/main/test/APITest.cc
index 82940fa..b6e4714 100644
--- a/modules/audio_coding/main/test/APITest.cc
+++ b/modules/audio_coding/main/test/APITest.cc
@@ -503,7 +503,7 @@
       break;
     default:
       fprintf(stderr, "Wrong Test Number\n");
-      getchar();
+      getc(stdin);
       exit(1);
   }
 }
diff --git a/modules/audio_coding/neteq/audio_decoder.cc b/modules/audio_coding/neteq/audio_decoder.cc
index 0fdaa44..04a74ee 100644
--- a/modules/audio_coding/neteq/audio_decoder.cc
+++ b/modules/audio_coding/neteq/audio_decoder.cc
@@ -51,8 +51,6 @@
   return false;
 }
 
-NetEqDecoder AudioDecoder::codec_type() const { return codec_type_; }
-
 bool AudioDecoder::CodecSupported(NetEqDecoder codec_type) {
   switch (codec_type) {
     case kDecoderPCMu:
@@ -197,26 +195,24 @@
       return new AudioDecoderIsacFix;
 #elif defined(WEBRTC_CODEC_ISAC)
     case kDecoderISAC:
-      return new AudioDecoderIsac;
-#endif
-#ifdef WEBRTC_CODEC_ISAC
+      return new AudioDecoderIsac(16000);
     case kDecoderISACswb:
-      return new AudioDecoderIsacSwb;
     case kDecoderISACfb:
-      return new AudioDecoderIsacFb;
+      return new AudioDecoderIsac(32000);
 #endif
 #ifdef WEBRTC_CODEC_PCM16
     case kDecoderPCM16B:
     case kDecoderPCM16Bwb:
     case kDecoderPCM16Bswb32kHz:
     case kDecoderPCM16Bswb48kHz:
-      return new AudioDecoderPcm16B(codec_type);
+      return new AudioDecoderPcm16B;
     case kDecoderPCM16B_2ch:
     case kDecoderPCM16Bwb_2ch:
     case kDecoderPCM16Bswb32kHz_2ch:
     case kDecoderPCM16Bswb48kHz_2ch:
+      return new AudioDecoderPcm16BMultiCh(2);
     case kDecoderPCM16B_5ch:
-      return new AudioDecoderPcm16BMultiCh(codec_type);
+      return new AudioDecoderPcm16BMultiCh(5);
 #endif
 #ifdef WEBRTC_CODEC_G722
     case kDecoderG722:
@@ -226,19 +222,21 @@
 #endif
 #ifdef WEBRTC_CODEC_CELT
     case kDecoderCELT_32:
+      return new AudioDecoderCelt(1);
     case kDecoderCELT_32_2ch:
-      return new AudioDecoderCelt(codec_type);
+      return new AudioDecoderCelt(2);
 #endif
 #ifdef WEBRTC_CODEC_OPUS
     case kDecoderOpus:
+      return new AudioDecoderOpus(1);
     case kDecoderOpus_2ch:
-      return new AudioDecoderOpus(codec_type);
+      return new AudioDecoderOpus(2);
 #endif
     case kDecoderCNGnb:
     case kDecoderCNGwb:
     case kDecoderCNGswb32kHz:
     case kDecoderCNGswb48kHz:
-      return new AudioDecoderCng(codec_type);
+      return new AudioDecoderCng;
     case kDecoderRED:
     case kDecoderAVT:
     case kDecoderArbitrary:
diff --git a/modules/audio_coding/neteq/audio_decoder_impl.cc b/modules/audio_coding/neteq/audio_decoder_impl.cc
index 661f2b1..07b1b4b 100644
--- a/modules/audio_coding/neteq/audio_decoder_impl.cc
+++ b/modules/audio_coding/neteq/audio_decoder_impl.cc
@@ -13,6 +13,7 @@
 #include <assert.h>
 #include <string.h>  // memmove
 
+#include "webrtc/base/checks.h"
 #ifdef WEBRTC_CODEC_CELT
 #include "webrtc/modules/audio_coding/codecs/celt/include/celt_interface.h"
 #endif
@@ -44,7 +45,7 @@
                               int16_t* decoded, SpeechType* speech_type) {
   int16_t temp_type = 1;  // Default is speech.
   int16_t ret = WebRtcG711_DecodeU(
-      state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+      reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
       static_cast<int16_t>(encoded_len), decoded, &temp_type);
   *speech_type = ConvertSpeechType(temp_type);
   return ret;
@@ -61,7 +62,7 @@
                               int16_t* decoded, SpeechType* speech_type) {
   int16_t temp_type = 1;  // Default is speech.
   int16_t ret = WebRtcG711_DecodeA(
-      state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+      reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
       static_cast<int16_t>(encoded_len), decoded, &temp_type);
   *speech_type = ConvertSpeechType(temp_type);
   return ret;
@@ -75,19 +76,13 @@
 
 // PCM16B
 #ifdef WEBRTC_CODEC_PCM16
-AudioDecoderPcm16B::AudioDecoderPcm16B(enum NetEqDecoder type)
-    : AudioDecoder(type) {
-  assert(type == kDecoderPCM16B ||
-         type == kDecoderPCM16Bwb ||
-         type == kDecoderPCM16Bswb32kHz ||
-         type == kDecoderPCM16Bswb48kHz);
-}
+AudioDecoderPcm16B::AudioDecoderPcm16B() {}
 
 int AudioDecoderPcm16B::Decode(const uint8_t* encoded, size_t encoded_len,
                                int16_t* decoded, SpeechType* speech_type) {
   int16_t temp_type = 1;  // Default is speech.
   int16_t ret = WebRtcPcm16b_DecodeW16(
-      state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+      reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
       static_cast<int16_t>(encoded_len), decoded, &temp_type);
   *speech_type = ConvertSpeechType(temp_type);
   return ret;
@@ -99,29 +94,15 @@
   return static_cast<int>(encoded_len / (2 * channels_));
 }
 
-AudioDecoderPcm16BMultiCh::AudioDecoderPcm16BMultiCh(
-    enum NetEqDecoder type)
-    : AudioDecoderPcm16B(kDecoderPCM16B) {  // This will be changed below.
-  codec_type_ = type;  // Changing to actual type here.
-  switch (codec_type_) {
-    case kDecoderPCM16B_2ch:
-    case kDecoderPCM16Bwb_2ch:
-    case kDecoderPCM16Bswb32kHz_2ch:
-    case kDecoderPCM16Bswb48kHz_2ch:
-      channels_ = 2;
-      break;
-    case kDecoderPCM16B_5ch:
-      channels_ = 5;
-      break;
-    default:
-      assert(false);
-  }
+AudioDecoderPcm16BMultiCh::AudioDecoderPcm16BMultiCh(int num_channels) {
+  DCHECK(num_channels > 0);
+  channels_ = num_channels;
 }
 #endif
 
 // iLBC
 #ifdef WEBRTC_CODEC_ILBC
-AudioDecoderIlbc::AudioDecoderIlbc() : AudioDecoder(kDecoderILBC) {
+AudioDecoderIlbc::AudioDecoderIlbc() {
   WebRtcIlbcfix_DecoderCreate(reinterpret_cast<iLBC_decinst_t**>(&state_));
 }
 
@@ -152,9 +133,11 @@
 
 // iSAC float
 #ifdef WEBRTC_CODEC_ISAC
-AudioDecoderIsac::AudioDecoderIsac() : AudioDecoder(kDecoderISAC) {
+AudioDecoderIsac::AudioDecoderIsac(int decode_sample_rate_hz) {
+  DCHECK(decode_sample_rate_hz == 16000 || decode_sample_rate_hz == 32000);
   WebRtcIsac_Create(reinterpret_cast<ISACStruct**>(&state_));
-  WebRtcIsac_SetDecSampRate(static_cast<ISACStruct*>(state_), 16000);
+  WebRtcIsac_SetDecSampRate(static_cast<ISACStruct*>(state_),
+                            decode_sample_rate_hz);
 }
 
 AudioDecoderIsac::~AudioDecoderIsac() {
@@ -209,22 +192,11 @@
 int AudioDecoderIsac::ErrorCode() {
   return WebRtcIsac_GetErrorCode(static_cast<ISACStruct*>(state_));
 }
-
-// iSAC SWB
-AudioDecoderIsacSwb::AudioDecoderIsacSwb() : AudioDecoderIsac() {
-  codec_type_ = kDecoderISACswb;
-  WebRtcIsac_SetDecSampRate(static_cast<ISACStruct*>(state_), 32000);
-}
-
-// iSAC FB
-AudioDecoderIsacFb::AudioDecoderIsacFb() : AudioDecoderIsacSwb() {
-  codec_type_ = kDecoderISACfb;
-}
 #endif
 
 // iSAC fix
 #ifdef WEBRTC_CODEC_ISACFX
-AudioDecoderIsacFix::AudioDecoderIsacFix() : AudioDecoder(kDecoderISAC) {
+AudioDecoderIsacFix::AudioDecoderIsacFix() {
   WebRtcIsacfix_Create(reinterpret_cast<ISACFIX_MainStruct**>(&state_));
 }
 
@@ -266,7 +238,7 @@
 
 // G.722
 #ifdef WEBRTC_CODEC_G722
-AudioDecoderG722::AudioDecoderG722() : AudioDecoder(kDecoderG722) {
+AudioDecoderG722::AudioDecoderG722() {
   WebRtcG722_CreateDecoder(reinterpret_cast<G722DecInst**>(&state_));
 }
 
@@ -382,14 +354,9 @@
 
 // CELT
 #ifdef WEBRTC_CODEC_CELT
-AudioDecoderCelt::AudioDecoderCelt(enum NetEqDecoder type)
-    : AudioDecoder(type) {
-  assert(type == kDecoderCELT_32 || type == kDecoderCELT_32_2ch);
-  if (type == kDecoderCELT_32) {
-    channels_ = 1;
-  } else {
-    channels_ = 2;
-  }
+AudioDecoderCelt::AudioDecoderCelt(int num_channels) {
+  DCHECK(num_channels == 1 || num_channels == 2);
+  channels_ = num_channels;
   WebRtcCelt_CreateDec(reinterpret_cast<CELT_decinst_t**>(&state_),
                        static_cast<int>(channels_));
 }
@@ -431,13 +398,9 @@
 
 // Opus
 #ifdef WEBRTC_CODEC_OPUS
-AudioDecoderOpus::AudioDecoderOpus(enum NetEqDecoder type)
-    : AudioDecoder(type) {
-  if (type == kDecoderOpus_2ch) {
-    channels_ = 2;
-  } else {
-    channels_ = 1;
-  }
+AudioDecoderOpus::AudioDecoderOpus(int num_channels) {
+  DCHECK(num_channels == 1 || num_channels == 2);
+  channels_ = num_channels;
   WebRtcOpus_DecoderCreate(reinterpret_cast<OpusDecInst**>(&state_),
                            static_cast<int>(channels_));
 }
@@ -494,10 +457,7 @@
 }
 #endif
 
-AudioDecoderCng::AudioDecoderCng(enum NetEqDecoder type)
-    : AudioDecoder(type) {
-  assert(type == kDecoderCNGnb || type == kDecoderCNGwb ||
-         kDecoderCNGswb32kHz || type == kDecoderCNGswb48kHz);
+AudioDecoderCng::AudioDecoderCng() {
   WebRtcCng_CreateDec(reinterpret_cast<CNG_dec_inst**>(&state_));
   assert(state_);
 }
diff --git a/modules/audio_coding/neteq/audio_decoder_impl.h b/modules/audio_coding/neteq/audio_decoder_impl.h
index 265d660..214392e 100644
--- a/modules/audio_coding/neteq/audio_decoder_impl.h
+++ b/modules/audio_coding/neteq/audio_decoder_impl.h
@@ -26,7 +26,7 @@
 
 class AudioDecoderPcmU : public AudioDecoder {
  public:
-  AudioDecoderPcmU() : AudioDecoder(kDecoderPCMu) {}
+  AudioDecoderPcmU() {}
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
                      int16_t* decoded, SpeechType* speech_type);
   virtual int Init() { return 0; }
@@ -38,7 +38,7 @@
 
 class AudioDecoderPcmA : public AudioDecoder {
  public:
-  AudioDecoderPcmA() : AudioDecoder(kDecoderPCMa) {}
+  AudioDecoderPcmA() {}
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
                      int16_t* decoded, SpeechType* speech_type);
   virtual int Init() { return 0; }
@@ -75,7 +75,7 @@
 // The type is specified in the constructor parameter |type|.
 class AudioDecoderPcm16B : public AudioDecoder {
  public:
-  explicit AudioDecoderPcm16B(enum NetEqDecoder type);
+  AudioDecoderPcm16B();
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
                      int16_t* decoded, SpeechType* speech_type);
   virtual int Init() { return 0; }
@@ -90,7 +90,7 @@
 // of channels is derived from the type.
 class AudioDecoderPcm16BMultiCh : public AudioDecoderPcm16B {
  public:
-  explicit AudioDecoderPcm16BMultiCh(enum NetEqDecoder type);
+  explicit AudioDecoderPcm16BMultiCh(int num_channels);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AudioDecoderPcm16BMultiCh);
@@ -116,7 +116,7 @@
 #ifdef WEBRTC_CODEC_ISAC
 class AudioDecoderIsac : public AudioDecoder {
  public:
-  AudioDecoderIsac();
+  explicit AudioDecoderIsac(int decode_sample_rate_hz);
   virtual ~AudioDecoderIsac();
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
                      int16_t* decoded, SpeechType* speech_type);
@@ -135,22 +135,6 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsac);
 };
-
-class AudioDecoderIsacSwb : public AudioDecoderIsac {
- public:
-  AudioDecoderIsacSwb();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacSwb);
-};
-
-class AudioDecoderIsacFb : public AudioDecoderIsacSwb {
- public:
-  AudioDecoderIsacFb();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacFb);
-};
 #endif
 
 #ifdef WEBRTC_CODEC_ISACFX
@@ -215,7 +199,7 @@
 #ifdef WEBRTC_CODEC_CELT
 class AudioDecoderCelt : public AudioDecoder {
  public:
-  explicit AudioDecoderCelt(enum NetEqDecoder type);
+  explicit AudioDecoderCelt(int num_channels);
   virtual ~AudioDecoderCelt();
 
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
@@ -232,7 +216,7 @@
 #ifdef WEBRTC_CODEC_OPUS
 class AudioDecoderOpus : public AudioDecoder {
  public:
-  explicit AudioDecoderOpus(enum NetEqDecoder type);
+  explicit AudioDecoderOpus(int num_channels);
   virtual ~AudioDecoderOpus();
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
                      int16_t* decoded, SpeechType* speech_type);
@@ -257,7 +241,7 @@
 // specific CngDecoder class could both inherit from that class.
 class AudioDecoderCng : public AudioDecoder {
  public:
-  explicit AudioDecoderCng(enum NetEqDecoder type);
+  explicit AudioDecoderCng();
   virtual ~AudioDecoderCng();
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
                      int16_t* decoded, SpeechType* speech_type) { return -1; }
diff --git a/modules/audio_coding/neteq/audio_decoder_unittest.cc b/modules/audio_coding/neteq/audio_decoder_unittest.cc
index 624e6a4..c95214b 100644
--- a/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -14,56 +14,106 @@
 #include <stdlib.h>
 
 #include <string>
+#include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/common_audio/resampler/include/resampler.h"
 #ifdef WEBRTC_CODEC_CELT
 #include "webrtc/modules/audio_coding/codecs/celt/include/celt_interface.h"
 #endif
 #include "webrtc/modules/audio_coding/codecs/g711/include/g711_interface.h"
+#include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h"
 #include "webrtc/modules/audio_coding/codecs/g722/include/g722_interface.h"
 #include "webrtc/modules/audio_coding/codecs/ilbc/interface/ilbc.h"
 #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h"
-#include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
+#include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
 #include "webrtc/system_wrappers/interface/data_log.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
 #include "webrtc/test/testsupport/fileutils.h"
 
 namespace webrtc {
 
+namespace {
+// The absolute difference between the input and output (the first channel) is
+// compared vs |tolerance|. The parameter |delay| is used to correct for codec
+// delays.
+void CompareInputOutput(const std::vector<int16_t>& input,
+                        const std::vector<int16_t>& output,
+                        size_t num_samples,
+                        size_t channels,
+                        int tolerance,
+                        int delay) {
+  ASSERT_LE(num_samples, input.size());
+  ASSERT_LE(num_samples * channels, output.size());
+  for (unsigned int n = 0; n < num_samples - delay; ++n) {
+    ASSERT_NEAR(input[n], output[channels * n + delay], tolerance)
+        << "Exit test on first diff; n = " << n;
+    DataLog::InsertCell("CodecTest", "input", input[n]);
+    DataLog::InsertCell("CodecTest", "output", output[channels * n]);
+    DataLog::NextRow("CodecTest");
+  }
+}
+
+// The absolute difference between the first two channels in |output| is
+// compared vs |tolerance|.
+void CompareTwoChannels(const std::vector<int16_t>& output,
+                        size_t samples_per_channel,
+                        size_t channels,
+                        int tolerance) {
+  ASSERT_GE(channels, 2u);
+  ASSERT_LE(samples_per_channel * channels, output.size());
+  for (unsigned int n = 0; n < samples_per_channel; ++n)
+    ASSERT_NEAR(output[channels * n], output[channels * n + 1], tolerance)
+        << "Stereo samples differ.";
+}
+
+// Calculates mean-squared error between input and output (the first channel).
+// The parameter |delay| is used to correct for codec delays.
+double MseInputOutput(const std::vector<int16_t>& input,
+                      const std::vector<int16_t>& output,
+                      size_t num_samples,
+                      size_t channels,
+                      int delay) {
+  assert(delay < static_cast<int>(num_samples));
+  assert(num_samples <= input.size());
+  assert(num_samples * channels <= output.size());
+  if (num_samples == 0)
+    return 0.0;
+  double squared_sum = 0.0;
+  for (unsigned int n = 0; n < num_samples - delay; ++n) {
+    squared_sum += (input[n] - output[channels * n + delay]) *
+                   (input[n] - output[channels * n + delay]);
+  }
+  return squared_sum / (num_samples - delay);
+}
+}  // namespace
+
 class AudioDecoderTest : public ::testing::Test {
  protected:
   AudioDecoderTest()
-    : input_fp_(NULL),
-      input_(NULL),
-      encoded_(NULL),
-      decoded_(NULL),
-      frame_size_(0),
-      data_length_(0),
-      encoded_bytes_(0),
-      channels_(1),
-      decoder_(NULL) {
-    input_file_ = webrtc::test::ProjectRootPath() +
-        "resources/audio_coding/testfile32kHz.pcm";
-  }
+      : input_audio_(webrtc::test::ProjectRootPath() +
+                         "resources/audio_coding/testfile32kHz.pcm",
+                     32000),
+        codec_input_rate_hz_(32000),  // Legacy default value.
+        encoded_(NULL),
+        frame_size_(0),
+        data_length_(0),
+        encoded_bytes_(0),
+        channels_(1),
+        output_timestamp_(0),
+        decoder_(NULL) {}
 
   virtual ~AudioDecoderTest() {}
 
   virtual void SetUp() {
+    if (audio_encoder_)
+      codec_input_rate_hz_ = audio_encoder_->sample_rate_hz();
     // Create arrays.
     ASSERT_GT(data_length_, 0u) << "The test must set data_length_ > 0";
-    input_ = new int16_t[data_length_];
     // Longest encoded data is produced by PCM16b with 2 bytes per sample.
     encoded_ = new uint8_t[data_length_ * 2];
-    decoded_ = new int16_t[data_length_ * channels_];
-    // Open input file.
-    input_fp_ = fopen(input_file_.c_str(), "rb");
-    ASSERT_TRUE(input_fp_ != NULL) << "Failed to open file " << input_file_;
-    // Read data to |input_|.
-    ASSERT_EQ(data_length_,
-              fread(input_, sizeof(int16_t), data_length_, input_fp_)) <<
-                  "Could not read enough data from file";
     // Logging to view input and output in Matlab.
     // Use 'gyp -Denable_data_logging=1' to enable logging.
     DataLog::CreateLog();
@@ -75,24 +125,37 @@
   virtual void TearDown() {
     delete decoder_;
     decoder_ = NULL;
-    // Close input file.
-    fclose(input_fp_);
     // Delete arrays.
-    delete [] input_;
-    input_ = NULL;
     delete [] encoded_;
     encoded_ = NULL;
-    delete [] decoded_;
-    decoded_ = NULL;
     // Close log.
     DataLog::ReturnLog();
   }
 
   virtual void InitEncoder() { }
 
-  // This method must be implemented for all tests derived from this class.
-  virtual int EncodeFrame(const int16_t* input, size_t input_len,
-                          uint8_t* output) = 0;
+  // TODO(henrik.lundin) Change return type to size_t once most/all overriding
+  // implementations are gone.
+  virtual int EncodeFrame(const int16_t* input,
+                          size_t input_len_samples,
+                          uint8_t* output) {
+    size_t enc_len_bytes = 0;
+    scoped_ptr<int16_t[]> interleaved_input(
+        new int16_t[channels_ * input_len_samples]);
+    for (int i = 0; i < audio_encoder_->Num10MsFramesInNextPacket(); ++i) {
+      EXPECT_EQ(0u, enc_len_bytes);
+
+      // Duplicate the mono input signal to however many channels the test
+      // wants.
+      test::InputAudioFile::DuplicateInterleaved(
+          input, input_len_samples, channels_, interleaved_input.get());
+
+      EXPECT_TRUE(audio_encoder_->Encode(
+          0, interleaved_input.get(), audio_encoder_->sample_rate_hz() / 100,
+          data_length_ * 2, output, &enc_len_bytes, &output_timestamp_));
+    }
+    return static_cast<int>(enc_len_bytes);
+  }
 
   // Encodes and decodes audio. The absolute difference between the input and
   // output is compared vs |tolerance|, and the mean-squared error is compared
@@ -108,13 +171,23 @@
     encoded_bytes_ = 0u;
     InitEncoder();
     EXPECT_EQ(0, decoder_->Init());
+    std::vector<int16_t> input;
+    std::vector<int16_t> decoded;
     while (processed_samples + frame_size_ <= data_length_) {
-      size_t enc_len = EncodeFrame(&input_[processed_samples], frame_size_,
-                                   &encoded_[encoded_bytes_]);
+      // Extend input vector with |frame_size_|.
+      input.resize(input.size() + frame_size_, 0);
+      // Read from input file.
+      ASSERT_GE(input.size() - processed_samples, frame_size_);
+      ASSERT_TRUE(input_audio_.Read(
+          frame_size_, codec_input_rate_hz_, &input[processed_samples]));
+      size_t enc_len = EncodeFrame(
+          &input[processed_samples], frame_size_, &encoded_[encoded_bytes_]);
+      // Make sure that frame_size_ * channels_ samples are allocated and free.
+      decoded.resize((processed_samples + frame_size_) * channels_, 0);
       AudioDecoder::SpeechType speech_type;
-      size_t dec_len = decoder_->Decode(&encoded_[encoded_bytes_], enc_len,
-                                        &decoded_[processed_samples *
-                                                  channels_],
+      size_t dec_len = decoder_->Decode(&encoded_[encoded_bytes_],
+                                        enc_len,
+                                        &decoded[processed_samples * channels_],
                                         &speech_type);
       EXPECT_EQ(frame_size_ * channels_, dec_len);
       encoded_bytes_ += enc_len;
@@ -126,65 +199,36 @@
     if (expected_bytes) {
       EXPECT_EQ(expected_bytes, encoded_bytes_);
     }
-    CompareInputOutput(processed_samples, tolerance, delay);
+    CompareInputOutput(
+        input, decoded, processed_samples, channels_, tolerance, delay);
     if (channels_ == 2)
-      CompareTwoChannels(processed_samples, channel_diff_tolerance);
-    EXPECT_LE(MseInputOutput(processed_samples, delay), mse);
-  }
-
-  // The absolute difference between the input and output (the first channel) is
-  // compared vs |tolerance|. The parameter |delay| is used to correct for codec
-  // delays.
-  virtual void CompareInputOutput(size_t num_samples, int tolerance,
-                                  int delay) const {
-    assert(num_samples <= data_length_);
-    for (unsigned int n = 0; n < num_samples - delay; ++n) {
-      ASSERT_NEAR(input_[n], decoded_[channels_ * n + delay], tolerance) <<
-          "Exit test on first diff; n = " << n;
-      DataLog::InsertCell("CodecTest", "input", input_[n]);
-      DataLog::InsertCell("CodecTest", "output", decoded_[channels_ * n]);
-      DataLog::NextRow("CodecTest");
-    }
-  }
-
-  // The absolute difference between the two channels in a stereo is compared vs
-  // |tolerance|.
-  virtual void CompareTwoChannels(size_t samples_per_channel,
-                                  int tolerance) const {
-    assert(samples_per_channel <= data_length_);
-    for (unsigned int n = 0; n < samples_per_channel; ++n)
-      ASSERT_NEAR(decoded_[channels_ * n], decoded_[channels_ * n + 1],
-                  tolerance) << "Stereo samples differ.";
-  }
-
-  // Calculates mean-squared error between input and output (the first channel).
-  // The parameter |delay| is used to correct for codec delays.
-  virtual double MseInputOutput(size_t num_samples, int delay) const {
-    assert(num_samples <= data_length_);
-    if (num_samples == 0) return 0.0;
-    double squared_sum = 0.0;
-    for (unsigned int n = 0; n < num_samples - delay; ++n) {
-      squared_sum += (input_[n] - decoded_[channels_ * n + delay]) *
-          (input_[n] - decoded_[channels_ * n + delay]);
-    }
-    return squared_sum / (num_samples - delay);
+      CompareTwoChannels(
+          decoded, processed_samples, channels_, channel_diff_tolerance);
+    EXPECT_LE(
+        MseInputOutput(input, decoded, processed_samples, channels_, delay),
+        mse);
   }
 
   // Encodes a payload and decodes it twice with decoder re-init before each
   // decode. Verifies that the decoded result is the same.
   void ReInitTest() {
-    int16_t* output1 = decoded_;
-    int16_t* output2 = decoded_ + frame_size_;
     InitEncoder();
-    size_t enc_len = EncodeFrame(input_, frame_size_, encoded_);
+    scoped_ptr<int16_t[]> input(new int16_t[frame_size_]);
+    ASSERT_TRUE(
+        input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get()));
+    size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_);
     size_t dec_len;
     AudioDecoder::SpeechType speech_type1, speech_type2;
     EXPECT_EQ(0, decoder_->Init());
-    dec_len = decoder_->Decode(encoded_, enc_len, output1, &speech_type1);
+    scoped_ptr<int16_t[]> output1(new int16_t[frame_size_ * channels_]);
+    dec_len = decoder_->Decode(encoded_, enc_len, output1.get(), &speech_type1);
+    ASSERT_LE(dec_len, frame_size_ * channels_);
     EXPECT_EQ(frame_size_ * channels_, dec_len);
     // Re-init decoder and decode again.
     EXPECT_EQ(0, decoder_->Init());
-    dec_len = decoder_->Decode(encoded_, enc_len, output2, &speech_type2);
+    scoped_ptr<int16_t[]> output2(new int16_t[frame_size_ * channels_]);
+    dec_len = decoder_->Decode(encoded_, enc_len, output2.get(), &speech_type2);
+    ASSERT_LE(dec_len, frame_size_ * channels_);
     EXPECT_EQ(frame_size_ * channels_, dec_len);
     for (unsigned int n = 0; n < frame_size_; ++n) {
       ASSERT_EQ(output1[n], output2[n]) << "Exit test on first diff; n = " << n;
@@ -195,29 +239,33 @@
   // Call DecodePlc and verify that the correct number of samples is produced.
   void DecodePlcTest() {
     InitEncoder();
-    size_t enc_len = EncodeFrame(input_, frame_size_, encoded_);
+    scoped_ptr<int16_t[]> input(new int16_t[frame_size_]);
+    ASSERT_TRUE(
+        input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get()));
+    size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_);
     AudioDecoder::SpeechType speech_type;
     EXPECT_EQ(0, decoder_->Init());
+    scoped_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]);
     size_t dec_len =
-        decoder_->Decode(encoded_, enc_len, decoded_, &speech_type);
+        decoder_->Decode(encoded_, enc_len, output.get(), &speech_type);
     EXPECT_EQ(frame_size_ * channels_, dec_len);
     // Call DecodePlc and verify that we get one frame of data.
     // (Overwrite the output from the above Decode call, but that does not
     // matter.)
-    dec_len = decoder_->DecodePlc(1, decoded_);
+    dec_len = decoder_->DecodePlc(1, output.get());
     EXPECT_EQ(frame_size_ * channels_, dec_len);
   }
 
-  std::string input_file_;
-  FILE* input_fp_;
-  int16_t* input_;
+  test::ResampleInputAudioFile input_audio_;
+  int codec_input_rate_hz_;
   uint8_t* encoded_;
-  int16_t* decoded_;
   size_t frame_size_;
   size_t data_length_;
   size_t encoded_bytes_;
   size_t channels_;
+  uint32_t output_timestamp_;
   AudioDecoder* decoder_;
+  scoped_ptr<AudioEncoder> audio_encoder_;
 };
 
 class AudioDecoderPcmUTest : public AudioDecoderTest {
@@ -226,17 +274,9 @@
     frame_size_ = 160;
     data_length_ = 10 * frame_size_;
     decoder_ = new AudioDecoderPcmU;
-    assert(decoder_);
-  }
-
-  virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
-                          uint8_t* output) {
-    int enc_len_bytes =
-        WebRtcG711_EncodeU(NULL, const_cast<int16_t*>(input),
-                           static_cast<int>(input_len_samples),
-                           reinterpret_cast<int16_t*>(output));
-    EXPECT_EQ(input_len_samples, static_cast<size_t>(enc_len_bytes));
-    return enc_len_bytes;
+    AudioEncoderPcmU::Config config;
+    config.frame_size_ms = static_cast<int>(frame_size_ / 8);
+    audio_encoder_.reset(new AudioEncoderPcmU(config));
   }
 };
 
@@ -246,26 +286,19 @@
     frame_size_ = 160;
     data_length_ = 10 * frame_size_;
     decoder_ = new AudioDecoderPcmA;
-    assert(decoder_);
-  }
-
-  virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
-                          uint8_t* output) {
-    int enc_len_bytes =
-        WebRtcG711_EncodeA(NULL, const_cast<int16_t*>(input),
-                           static_cast<int>(input_len_samples),
-                           reinterpret_cast<int16_t*>(output));
-    EXPECT_EQ(input_len_samples, static_cast<size_t>(enc_len_bytes));
-    return enc_len_bytes;
+    AudioEncoderPcmA::Config config;
+    config.frame_size_ms = static_cast<int>(frame_size_ / 8);
+    audio_encoder_.reset(new AudioEncoderPcmA(config));
   }
 };
 
 class AudioDecoderPcm16BTest : public AudioDecoderTest {
  protected:
   AudioDecoderPcm16BTest() : AudioDecoderTest() {
+    codec_input_rate_hz_ = 8000;
     frame_size_ = 160;
     data_length_ = 10 * frame_size_;
-    decoder_ = new AudioDecoderPcm16B(kDecoderPCM16B);
+    decoder_ = new AudioDecoderPcm16B;
     assert(decoder_);
   }
 
@@ -282,6 +315,7 @@
 class AudioDecoderIlbcTest : public AudioDecoderTest {
  protected:
   AudioDecoderIlbcTest() : AudioDecoderTest() {
+    codec_input_rate_hz_ = 8000;
     frame_size_ = 240;
     data_length_ = 10 * frame_size_;
     decoder_ = new AudioDecoderIlbc;
@@ -311,14 +345,18 @@
   // not return any data. It simply resets a few states and returns 0.
   void DecodePlcTest() {
     InitEncoder();
-    size_t enc_len = EncodeFrame(input_, frame_size_, encoded_);
+    scoped_ptr<int16_t[]> input(new int16_t[frame_size_]);
+    ASSERT_TRUE(
+        input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get()));
+    size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_);
     AudioDecoder::SpeechType speech_type;
     EXPECT_EQ(0, decoder_->Init());
+    scoped_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]);
     size_t dec_len =
-        decoder_->Decode(encoded_, enc_len, decoded_, &speech_type);
+        decoder_->Decode(encoded_, enc_len, output.get(), &speech_type);
     EXPECT_EQ(frame_size_, dec_len);
     // Simply call DecodePlc and verify that we get 0 as return value.
-    EXPECT_EQ(0, decoder_->DecodePlc(1, decoded_));
+    EXPECT_EQ(0, decoder_->DecodePlc(1, output.get()));
   }
 
   iLBC_encinst_t* encoder_;
@@ -327,10 +365,11 @@
 class AudioDecoderIsacFloatTest : public AudioDecoderTest {
  protected:
   AudioDecoderIsacFloatTest() : AudioDecoderTest() {
+    codec_input_rate_hz_ = 16000;
     input_size_ = 160;
     frame_size_ = 480;
     data_length_ = 10 * frame_size_;
-    decoder_ = new AudioDecoderIsac;
+    decoder_ = new AudioDecoderIsac(16000);
     assert(decoder_);
     WebRtcIsac_Create(&encoder_);
     WebRtcIsac_SetEncSampRate(encoder_, 16000);
@@ -364,10 +403,11 @@
 class AudioDecoderIsacSwbTest : public AudioDecoderTest {
  protected:
   AudioDecoderIsacSwbTest() : AudioDecoderTest() {
+    codec_input_rate_hz_ = 32000;
     input_size_ = 320;
     frame_size_ = 960;
     data_length_ = 10 * frame_size_;
-    decoder_ = new AudioDecoderIsacSwb;
+    decoder_ = new AudioDecoderIsac(32000);
     assert(decoder_);
     WebRtcIsac_Create(&encoder_);
     WebRtcIsac_SetEncSampRate(encoder_, 32000);
@@ -398,22 +438,10 @@
   int input_size_;
 };
 
-// This test is identical to AudioDecoderIsacSwbTest, except that it creates
-// an AudioDecoderIsacFb decoder object.
-class AudioDecoderIsacFbTest : public AudioDecoderIsacSwbTest {
- protected:
-  AudioDecoderIsacFbTest() : AudioDecoderIsacSwbTest() {
-    // Delete the |decoder_| that was created by AudioDecoderIsacSwbTest and
-    // create an AudioDecoderIsacFb object instead.
-    delete decoder_;
-    decoder_ = new AudioDecoderIsacFb;
-    assert(decoder_);
-  }
-};
-
 class AudioDecoderIsacFixTest : public AudioDecoderTest {
  protected:
   AudioDecoderIsacFixTest() : AudioDecoderTest() {
+    codec_input_rate_hz_ = 16000;
     input_size_ = 160;
     frame_size_ = 480;
     data_length_ = 10 * frame_size_;
@@ -451,6 +479,7 @@
 class AudioDecoderG722Test : public AudioDecoderTest {
  protected:
   AudioDecoderG722Test() : AudioDecoderTest() {
+    codec_input_rate_hz_ = 16000;
     frame_size_ = 160;
     data_length_ = 10 * frame_size_;
     decoder_ = new AudioDecoderG722;
@@ -593,79 +622,26 @@
 class AudioDecoderOpusTest : public AudioDecoderTest {
  protected:
   AudioDecoderOpusTest() : AudioDecoderTest() {
+    codec_input_rate_hz_ = 48000;
     frame_size_ = 480;
     data_length_ = 10 * frame_size_;
-    decoder_ = new AudioDecoderOpus(kDecoderOpus);
-    assert(decoder_);
-    WebRtcOpus_EncoderCreate(&encoder_, 1);
+    decoder_ = new AudioDecoderOpus(1);
+    AudioEncoderOpus::Config config;
+    config.frame_size_ms = static_cast<int>(frame_size_) / 48;
+    audio_encoder_.reset(new AudioEncoderOpus(config));
   }
-
-  ~AudioDecoderOpusTest() {
-    WebRtcOpus_EncoderFree(encoder_);
-  }
-
-  virtual void SetUp() OVERRIDE {
-    AudioDecoderTest::SetUp();
-    // Upsample from 32 to 48 kHz.
-    // Because Opus is 48 kHz codec but the input file is 32 kHz, so the data
-    // read in |AudioDecoderTest::SetUp| has to be upsampled.
-    // |AudioDecoderTest::SetUp| has read |data_length_| samples, which is more
-    // than necessary after upsampling, so the end of audio that has been read
-    // is unused and the end of the buffer is overwritten by the resampled data.
-    Resampler rs;
-    rs.Reset(32000, 48000, kResamplerSynchronous);
-    const int before_resamp_len_samples = static_cast<int>(data_length_) * 2
-        / 3;
-    int16_t* before_resamp_input = new int16_t[before_resamp_len_samples];
-    memcpy(before_resamp_input, input_,
-           sizeof(int16_t) * before_resamp_len_samples);
-    int resamp_len_samples;
-    EXPECT_EQ(0, rs.Push(before_resamp_input, before_resamp_len_samples,
-                         input_, static_cast<int>(data_length_),
-                         resamp_len_samples));
-    EXPECT_EQ(static_cast<int>(data_length_), resamp_len_samples);
-    delete[] before_resamp_input;
-  }
-
-  virtual void InitEncoder() {}
-
-  virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
-                          uint8_t* output) OVERRIDE {
-    int enc_len_bytes = WebRtcOpus_Encode(encoder_, const_cast<int16_t*>(input),
-        static_cast<int16_t>(input_len_samples),
-        static_cast<int16_t>(data_length_), output);
-    EXPECT_GT(enc_len_bytes, 0);
-    return enc_len_bytes;
-  }
-
-  OpusEncInst* encoder_;
 };
 
 class AudioDecoderOpusStereoTest : public AudioDecoderOpusTest {
  protected:
   AudioDecoderOpusStereoTest() : AudioDecoderOpusTest() {
     channels_ = 2;
-    WebRtcOpus_EncoderFree(encoder_);
     delete decoder_;
-    decoder_ = new AudioDecoderOpus(kDecoderOpus_2ch);
-    assert(decoder_);
-    WebRtcOpus_EncoderCreate(&encoder_, 2);
-  }
-
-  virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
-                          uint8_t* output) OVERRIDE {
-    // Create stereo by duplicating each sample in |input|.
-    const int input_stereo_samples = static_cast<int>(input_len_samples) * 2;
-    int16_t* input_stereo = new int16_t[input_stereo_samples];
-    for (size_t i = 0; i < input_len_samples; i++)
-      input_stereo[i * 2] = input_stereo[i * 2 + 1] = input[i];
-
-    int enc_len_bytes = WebRtcOpus_Encode(
-        encoder_, input_stereo, static_cast<int16_t>(input_len_samples),
-        static_cast<int16_t>(data_length_), output);
-    EXPECT_GT(enc_len_bytes, 0);
-    delete[] input_stereo;
-    return enc_len_bytes;
+    decoder_ = new AudioDecoderOpus(2);
+    AudioEncoderOpus::Config config;
+    config.frame_size_ms = static_cast<int>(frame_size_) / 48;
+    config.num_channels = 2;
+    audio_encoder_.reset(new AudioEncoderOpus(config));
   }
 };
 
@@ -732,17 +708,6 @@
   DecodePlcTest();
 }
 
-TEST_F(AudioDecoderIsacFbTest, EncodeDecode) {
-  int tolerance = 19757;
-  double mse = 8.18e6;
-  int delay = 160;  // Delay from input to output.
-  EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISACswb));
-  EncodeDecodeTest(0, tolerance, mse, delay);
-  ReInitTest();
-  EXPECT_TRUE(decoder_->HasDecodePlc());
-  DecodePlcTest();
-}
-
 TEST_F(AudioDecoderIsacFixTest, DISABLED_EncodeDecode) {
   int tolerance = 11034;
   double mse = 3.46e6;
diff --git a/modules/audio_coding/neteq/audio_decoder_unittests.isolate b/modules/audio_coding/neteq/audio_decoder_unittests.isolate
index e4a18ca..f10b327 100644
--- a/modules/audio_coding/neteq/audio_decoder_unittests.isolate
+++ b/modules/audio_coding/neteq/audio_decoder_unittests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/resources/',
           '<(DEPTH)/data/',
         ],
@@ -21,17 +21,12 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/audio_decoder_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_touched': [
+        'files': [
           '<(DEPTH)/DEPS',
-        ],
-        'isolate_dependency_tracked': [
           '<(DEPTH)/resources/audio_coding/testfile32kHz.pcm',
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/audio_decoder_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/modules/audio_coding/neteq/decision_logic_normal.cc b/modules/audio_coding/neteq/decision_logic_normal.cc
index 9e42204..f238284 100644
--- a/modules/audio_coding/neteq/decision_logic_normal.cc
+++ b/modules/audio_coding/neteq/decision_logic_normal.cc
@@ -67,19 +67,19 @@
     return kNormal;
   }
 
+  const uint32_t five_seconds_samples = 5 * 8000 * fs_mult_;
   // Check if the required packet is available.
   if (target_timestamp == available_timestamp) {
     return ExpectedPacketAvailable(prev_mode, play_dtmf);
-  } else if (IsNewerTimestamp(available_timestamp, target_timestamp)) {
+  } else if (!PacketBuffer::IsObsoleteTimestamp(
+                 available_timestamp, target_timestamp, five_seconds_samples)) {
     return FuturePacketAvailable(sync_buffer, expand, decoder_frame_length,
                                  prev_mode, target_timestamp,
                                  available_timestamp, play_dtmf);
   } else {
     // This implies that available_timestamp < target_timestamp, which can
-    // happen when a new stream or codec is received. Do Expand instead, and
-    // wait for a newer packet to arrive, or for the buffer to flush (resulting
-    // in a master reset).
-    return kExpand;
+    // happen when a new stream or codec is received. Signal for a reset.
+    return kUndefined;
   }
 }
 
diff --git a/modules/audio_coding/neteq/decoder_database_unittest.cc b/modules/audio_coding/neteq/decoder_database_unittest.cc
index 6f49719..1e4e58a 100644
--- a/modules/audio_coding/neteq/decoder_database_unittest.cc
+++ b/modules/audio_coding/neteq/decoder_database_unittest.cc
@@ -189,21 +189,18 @@
   EXPECT_TRUE(changed);
   AudioDecoder* decoder = db.GetActiveDecoder();
   ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
-  EXPECT_EQ(kDecoderPCMu, decoder->codec_type());
 
   // Set the same again. Expect no change.
   EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(0, &changed));
   EXPECT_FALSE(changed);
   decoder = db.GetActiveDecoder();
   ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
-  EXPECT_EQ(kDecoderPCMu, decoder->codec_type());
 
   // Change active decoder.
   EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(103, &changed));
   EXPECT_TRUE(changed);
   decoder = db.GetActiveDecoder();
   ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
-  EXPECT_EQ(kDecoderISAC, decoder->codec_type());
 
   // Remove the active decoder, and verify that the active becomes NULL.
   EXPECT_EQ(DecoderDatabase::kOK, db.Remove(103));
@@ -213,7 +210,6 @@
   EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveCngDecoder(13));
   decoder = db.GetActiveCngDecoder();
   ASSERT_FALSE(decoder == NULL);  // Should get a decoder here.
-  EXPECT_EQ(kDecoderCNGnb, decoder->codec_type());
 
   // Remove the active CNG decoder, and verify that the active becomes NULL.
   EXPECT_EQ(DecoderDatabase::kOK, db.Remove(13));
diff --git a/modules/audio_coding/neteq/expand.cc b/modules/audio_coding/neteq/expand.cc
index 1f46e66..49ea45f 100644
--- a/modules/audio_coding/neteq/expand.cc
+++ b/modules/audio_coding/neteq/expand.cc
@@ -488,7 +488,7 @@
       // Calculate scaled_energy1 / scaled_energy2 in Q13.
       int32_t energy_ratio = WebRtcSpl_DivW32W16(
           WEBRTC_SPL_SHIFT_W32(energy1, -scaled_energy1),
-          WEBRTC_SPL_RSHIFT_W32(energy2, scaled_energy2));
+          energy2 >> scaled_energy2);
       // Calculate sqrt ratio in Q13 (sqrt of en1/en2 in Q26).
       amplitude_ratio = WebRtcSpl_SqrtFloor(energy_ratio << 13);
       // Copy the two vectors and give them the same energy.
diff --git a/modules/audio_coding/neteq/interface/audio_decoder.h b/modules/audio_coding/neteq/interface/audio_decoder.h
index 9a2fb8b..16d78c9 100644
--- a/modules/audio_coding/neteq/interface/audio_decoder.h
+++ b/modules/audio_coding/neteq/interface/audio_decoder.h
@@ -63,12 +63,7 @@
   // Used by PacketDuration below. Save the value -1 for errors.
   enum { kNotImplemented = -2 };
 
-  explicit AudioDecoder(enum NetEqDecoder type)
-    : codec_type_(type),
-      channels_(1),
-      state_(NULL) {
-  }
-
+  AudioDecoder() : channels_(1), state_(NULL) {}
   virtual ~AudioDecoder() {}
 
   // Decodes |encode_len| bytes from |encoded| and writes the result in
@@ -119,8 +114,6 @@
   // Returns true if the packet has FEC and false otherwise.
   virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
 
-  virtual NetEqDecoder codec_type() const;
-
   // Returns the underlying decoder state.
   void* state() { return state_; }
 
@@ -140,7 +133,6 @@
  protected:
   static SpeechType ConvertSpeechType(int16_t type);
 
-  enum NetEqDecoder codec_type_;
   size_t channels_;
   void* state_;
 
diff --git a/modules/audio_coding/neteq/interface/neteq.h b/modules/audio_coding/neteq/interface/neteq.h
index 925cb23..560e77b 100644
--- a/modules/audio_coding/neteq/interface/neteq.h
+++ b/modules/audio_coding/neteq/interface/neteq.h
@@ -248,7 +248,7 @@
 
   // Returns the error code for the last occurred error. If no error has
   // occurred, 0 is returned.
-  virtual int LastError() = 0;
+  virtual int LastError() const = 0;
 
   // Returns the error code last returned by a decoder (audio or comfort noise).
   // When LastError() returns kDecoderErrorCode or kComfortNoiseErrorCode, check
diff --git a/modules/audio_coding/neteq/mock/mock_audio_decoder.h b/modules/audio_coding/neteq/mock/mock_audio_decoder.h
index f3cecc2..95b564d 100644
--- a/modules/audio_coding/neteq/mock/mock_audio_decoder.h
+++ b/modules/audio_coding/neteq/mock/mock_audio_decoder.h
@@ -19,7 +19,7 @@
 
 class MockAudioDecoder : public AudioDecoder {
  public:
-  MockAudioDecoder() : AudioDecoder(kDecoderArbitrary) {}
+  MockAudioDecoder() {}
   virtual ~MockAudioDecoder() { Die(); }
   MOCK_METHOD0(Die, void());
   MOCK_METHOD4(Decode, int(const uint8_t*, size_t, int16_t*,
diff --git a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
index ef5e03e..400c0b0 100644
--- a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
+++ b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
@@ -27,15 +27,13 @@
 // audio_decoder_impl.{cc, h}.
 class ExternalPcm16B : public AudioDecoder {
  public:
-  explicit ExternalPcm16B(enum NetEqDecoder type)
-      : AudioDecoder(type) {
-  }
+  ExternalPcm16B() {}
 
   virtual int Decode(const uint8_t* encoded, size_t encoded_len,
                      int16_t* decoded, SpeechType* speech_type) {
     int16_t temp_type;
     int16_t ret = WebRtcPcm16b_DecodeW16(
-        state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+        reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
         static_cast<int16_t>(encoded_len), decoded, &temp_type);
     *speech_type = ConvertSpeechType(temp_type);
     return ret;
@@ -51,9 +49,7 @@
 // The reason is that we can then track that the correct calls are being made.
 class MockExternalPcm16B : public ExternalPcm16B {
  public:
-  explicit MockExternalPcm16B(enum NetEqDecoder type)
-      : ExternalPcm16B(type),
-        real_(type) {
+  MockExternalPcm16B() {
     // By default, all calls are delegated to the real object.
     ON_CALL(*this, Decode(_, _, _, _))
         .WillByDefault(Invoke(&real_, &ExternalPcm16B::Decode));
@@ -67,8 +63,6 @@
         .WillByDefault(Invoke(&real_, &ExternalPcm16B::IncomingPacket));
     ON_CALL(*this, ErrorCode())
         .WillByDefault(Invoke(&real_, &ExternalPcm16B::ErrorCode));
-    ON_CALL(*this, codec_type())
-        .WillByDefault(Invoke(&real_, &ExternalPcm16B::codec_type));
   }
   virtual ~MockExternalPcm16B() { Die(); }
 
diff --git a/modules/audio_coding/neteq/mock/mock_packet_buffer.h b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
index 74eea6f..0eb7edc 100644
--- a/modules/audio_coding/neteq/mock/mock_packet_buffer.h
+++ b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
@@ -44,7 +44,9 @@
       Packet*(int* discard_count));
   MOCK_METHOD0(DiscardNextPacket,
       int());
-  MOCK_METHOD1(DiscardOldPackets,
+  MOCK_METHOD2(DiscardOldPackets,
+      int(uint32_t timestamp_limit, uint32_t horizon_samples));
+  MOCK_METHOD1(DiscardAllOldPackets,
       int(uint32_t timestamp_limit));
   MOCK_CONST_METHOD0(NumPacketsInBuffer,
       int());
diff --git a/modules/audio_coding/neteq/neteq.gypi b/modules/audio_coding/neteq/neteq.gypi
index 0901615..c68651d 100644
--- a/modules/audio_coding/neteq/neteq.gypi
+++ b/modules/audio_coding/neteq/neteq.gypi
@@ -136,6 +136,7 @@
           'type': '<(gtest_target_type)',
           'dependencies': [
             '<@(codecs)',
+            'neteq_unittest_tools',
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
             '<(webrtc_root)/test/test.gyp:test_support_main',
@@ -170,7 +171,7 @@
           'type': 'static_library',
           'dependencies': [
             'rtp_rtcp',
-            '<(webrtc_root)/test/webrtc_test_common.gyp:webrtc_test_common',
+            '<(webrtc_root)/test/test.gyp:rtp_test_utils',
           ],
           'direct_dependent_settings': {
             'include_dirs': [
@@ -193,6 +194,8 @@
             'tools/packet.cc',
             'tools/packet.h',
             'tools/packet_source.h',
+            'tools/resample_input_audio_file.cc',
+            'tools/resample_input_audio_file.h',
             'tools/rtp_file_source.cc',
             'tools/rtp_file_source.h',
             'tools/rtp_generator.cc',
@@ -222,7 +225,6 @@
               ],
               'includes': [
                 '../../../build/isolate.gypi',
-                'audio_decoder_unittests.isolate',
               ],
               'sources': [
                 'audio_decoder_unittests.isolate',
diff --git a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
index 6a8eafa..d41bc54 100644
--- a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
@@ -47,7 +47,7 @@
         frame_size_ms_(10),
         frame_size_samples_(frame_size_ms_ * samples_per_ms_),
         output_size_samples_(frame_size_ms_ * samples_per_ms_),
-        external_decoder_(new MockExternalPcm16B(kDecoderPCM16Bswb32kHz)),
+        external_decoder_(new MockExternalPcm16B),
         rtp_generator_(new test::RtpGenerator(samples_per_ms_)),
         payload_size_bytes_(0),
         last_send_time_(0),
@@ -241,7 +241,7 @@
     frame_size_samples_ = frame_size_ms_ * samples_per_ms_;
     output_size_samples_ = frame_size_ms_ * samples_per_ms_;
     EXPECT_CALL(*external_decoder_, Die()).Times(1);
-    external_decoder_.reset(new MockExternalPcm16B(kDecoderPCM16B));
+    external_decoder_.reset(new MockExternalPcm16B);
   }
 
   void SetUp() OVERRIDE {
@@ -308,6 +308,8 @@
       case kExpandPhase: {
         if (output_type == kOutputPLCtoCNG) {
           test_state_ = kFadedExpandPhase;
+        } else if (output_type == kOutputNormal) {
+          test_state_ = kRecovered;
         }
         break;
       }
@@ -337,9 +339,14 @@
   }
 
   int NumExpectedDecodeCalls(int num_loops) const OVERRIDE {
-    // Some packets won't be decoded because of the buffer being flushed after
-    // the timestamp jump.
-    return num_loops - (config_.max_packets_in_buffer + 1);
+    // Some packets at the end of the stream won't be decoded. When the jump in
+    // timestamp happens, NetEq will do Expand during one GetAudio call. In the
+    // next call it will decode the packet after the jump, but the net result is
+    // that the delay increased by 1 packet. In another call, a Pre-emptive
+    // Expand operation is performed, leading to delay increase by 1 packet. In
+    // total, the test will end with a 2-packet delay, which results in the 2
+    // last packets not being decoded.
+    return num_loops - 2;
   }
 
   TestStates test_state_;
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index edf618e..f3d1a4f 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -352,7 +352,7 @@
   return true;
 }
 
-int NetEqImpl::LastError() {
+int NetEqImpl::LastError() const {
   CriticalSectionScoped lock(crit_sect_.get());
   return error_code_;
 }
@@ -868,6 +868,10 @@
 
   assert(sync_buffer_.get());
   uint32_t end_timestamp = sync_buffer_->end_timestamp();
+  if (!new_codec_) {
+    const uint32_t five_seconds_samples = 5 * fs_hz_;
+    packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples);
+  }
   const RTPHeader* header = packet_buffer_->NextRtpHeader();
 
   if (decision_logic_->CngRfc3389On() || last_mode_ == kModeRfc3389Cng) {
@@ -884,7 +888,7 @@
       }
       // Check buffer again.
       if (!new_codec_) {
-        packet_buffer_->DiscardOldPackets(end_timestamp);
+        packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_);
       }
       header = packet_buffer_->NextRtpHeader();
     }
@@ -1823,7 +1827,7 @@
     // we could end up in the situation where we never decode anything, since
     // all incoming packets are considered too old but the buffer will also
     // never be flooded and flushed.
-    packet_buffer_->DiscardOldPackets(timestamp_);
+    packet_buffer_->DiscardAllOldPackets(timestamp_);
   }
 
   return extracted_samples;
diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h
index fc2284d..348f483 100644
--- a/modules/audio_coding/neteq/neteq_impl.h
+++ b/modules/audio_coding/neteq/neteq_impl.h
@@ -178,7 +178,7 @@
 
   // Returns the error code for the last occurred error. If no error has
   // occurred, 0 is returned.
-  virtual int LastError() OVERRIDE;
+  virtual int LastError() const OVERRIDE;
 
   // Returns the error code last returned by a decoder (audio or comfort noise).
   // When LastError() returns kDecoderErrorCode or kComfortNoiseErrorCode, check
diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc
index d5676d7..8047fe2 100644
--- a/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -32,9 +32,11 @@
 using ::testing::ReturnNull;
 using ::testing::_;
 using ::testing::SetArgPointee;
+using ::testing::SetArrayArgument;
 using ::testing::InSequence;
 using ::testing::Invoke;
 using ::testing::WithArg;
+using ::testing::Pointee;
 
 namespace webrtc {
 
@@ -422,8 +424,7 @@
   // sample, and then increasing by 1 for each sample.
   class CountingSamplesDecoder : public AudioDecoder {
    public:
-    explicit CountingSamplesDecoder(enum NetEqDecoder type)
-        : AudioDecoder(type), next_value_(1) {}
+    CountingSamplesDecoder() : next_value_(1) {}
 
     // Produce as many samples as input bytes (|encoded_len|).
     virtual int Decode(const uint8_t* encoded,
@@ -446,7 +447,7 @@
 
    private:
     int16_t next_value_;
-  } decoder_(kDecoderPCM16B);
+  } decoder_;
 
   EXPECT_EQ(NetEq::kOK,
             neteq_->RegisterExternalDecoder(
@@ -495,4 +496,95 @@
             static_cast<int>(sync_buffer->FutureLength()));
 }
 
+TEST_F(NetEqImplTest, ReorderedPacket) {
+  UseNoMocks();
+  CreateInstance();
+
+  const uint8_t kPayloadType = 17;   // Just an arbitrary number.
+  const uint32_t kReceiveTime = 17;  // Value doesn't matter for this test.
+  const int kSampleRateHz = 8000;
+  const int kPayloadLengthSamples = 10 * kSampleRateHz / 1000;  // 10 ms.
+  const size_t kPayloadLengthBytes = kPayloadLengthSamples;
+  uint8_t payload[kPayloadLengthBytes] = {0};
+  WebRtcRTPHeader rtp_header;
+  rtp_header.header.payloadType = kPayloadType;
+  rtp_header.header.sequenceNumber = 0x1234;
+  rtp_header.header.timestamp = 0x12345678;
+  rtp_header.header.ssrc = 0x87654321;
+
+  // Create a mock decoder object.
+  MockAudioDecoder mock_decoder;
+  EXPECT_CALL(mock_decoder, Init()).WillRepeatedly(Return(0));
+  EXPECT_CALL(mock_decoder, IncomingPacket(_, kPayloadLengthBytes, _, _, _))
+      .WillRepeatedly(Return(0));
+  int16_t dummy_output[kPayloadLengthSamples] = {0};
+  // The below expectation will make the mock decoder write
+  // |kPayloadLengthSamples| zeros to the output array, and mark it as speech.
+  EXPECT_CALL(mock_decoder, Decode(Pointee(0), kPayloadLengthBytes, _, _))
+      .WillOnce(DoAll(SetArrayArgument<2>(dummy_output,
+                                          dummy_output + kPayloadLengthSamples),
+                      SetArgPointee<3>(AudioDecoder::kSpeech),
+                      Return(kPayloadLengthSamples)));
+  EXPECT_EQ(NetEq::kOK,
+            neteq_->RegisterExternalDecoder(
+                &mock_decoder, kDecoderPCM16B, kPayloadType));
+
+  // Insert one packet.
+  EXPECT_EQ(NetEq::kOK,
+            neteq_->InsertPacket(
+                rtp_header, payload, kPayloadLengthBytes, kReceiveTime));
+
+  // Pull audio once.
+  const int kMaxOutputSize = 10 * kSampleRateHz / 1000;
+  int16_t output[kMaxOutputSize];
+  int samples_per_channel;
+  int num_channels;
+  NetEqOutputType type;
+  EXPECT_EQ(
+      NetEq::kOK,
+      neteq_->GetAudio(
+          kMaxOutputSize, output, &samples_per_channel, &num_channels, &type));
+  ASSERT_EQ(kMaxOutputSize, samples_per_channel);
+  EXPECT_EQ(1, num_channels);
+  EXPECT_EQ(kOutputNormal, type);
+
+  // Insert two more packets. The first one is out of order, and is already too
+  // old, the second one is the expected next packet.
+  rtp_header.header.sequenceNumber -= 1;
+  rtp_header.header.timestamp -= kPayloadLengthSamples;
+  payload[0] = 1;
+  EXPECT_EQ(NetEq::kOK,
+            neteq_->InsertPacket(
+                rtp_header, payload, kPayloadLengthBytes, kReceiveTime));
+  rtp_header.header.sequenceNumber += 2;
+  rtp_header.header.timestamp += 2 * kPayloadLengthSamples;
+  payload[0] = 2;
+  EXPECT_EQ(NetEq::kOK,
+            neteq_->InsertPacket(
+                rtp_header, payload, kPayloadLengthBytes, kReceiveTime));
+
+  // Expect only the second packet to be decoded (the one with "2" as the first
+  // payload byte).
+  EXPECT_CALL(mock_decoder, Decode(Pointee(2), kPayloadLengthBytes, _, _))
+      .WillOnce(DoAll(SetArrayArgument<2>(dummy_output,
+                                          dummy_output + kPayloadLengthSamples),
+                      SetArgPointee<3>(AudioDecoder::kSpeech),
+                      Return(kPayloadLengthSamples)));
+
+  // Pull audio once.
+  EXPECT_EQ(
+      NetEq::kOK,
+      neteq_->GetAudio(
+          kMaxOutputSize, output, &samples_per_channel, &num_channels, &type));
+  ASSERT_EQ(kMaxOutputSize, samples_per_channel);
+  EXPECT_EQ(1, num_channels);
+  EXPECT_EQ(kOutputNormal, type);
+
+  // Now check the packet buffer, and make sure it is empty, since the
+  // out-of-order packet should have been discarded.
+  EXPECT_TRUE(packet_buffer_->Empty());
+
+  EXPECT_CALL(mock_decoder, Die());
+}
+
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq_tests.gypi b/modules/audio_coding/neteq/neteq_tests.gypi
index d134dcd..48cd9eb 100644
--- a/modules/audio_coding/neteq/neteq_tests.gypi
+++ b/modules/audio_coding/neteq/neteq_tests.gypi
@@ -87,7 +87,7 @@
         'neteq_unittest_tools',
         '<(DEPTH)/testing/gtest.gyp:gtest',
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
       ],
       'sources': [
         'tools/rtp_analyze.cc',
diff --git a/modules/audio_coding/neteq/packet_buffer.cc b/modules/audio_coding/neteq/packet_buffer.cc
index 4c48418..816713d 100644
--- a/modules/audio_coding/neteq/packet_buffer.cc
+++ b/modules/audio_coding/neteq/packet_buffer.cc
@@ -216,12 +216,12 @@
   return kOK;
 }
 
-int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit) {
-  while (!Empty() &&
-      timestamp_limit != buffer_.front()->header.timestamp &&
-      static_cast<uint32_t>(timestamp_limit
-                            - buffer_.front()->header.timestamp) <
-                            0xFFFFFFFF / 2) {
+int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
+                                    uint32_t horizon_samples) {
+  while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
+         IsObsoleteTimestamp(buffer_.front()->header.timestamp,
+                             timestamp_limit,
+                             horizon_samples)) {
     if (DiscardNextPacket() != kOK) {
       assert(false);  // Must be ok by design.
     }
diff --git a/modules/audio_coding/neteq/packet_buffer.h b/modules/audio_coding/neteq/packet_buffer.h
index 76c4ddd..b9a1618 100644
--- a/modules/audio_coding/neteq/packet_buffer.h
+++ b/modules/audio_coding/neteq/packet_buffer.h
@@ -95,9 +95,19 @@
   // PacketBuffer::kOK otherwise.
   virtual int DiscardNextPacket();
 
-  // Discards all packets that are (strictly) older than |timestamp_limit|.
+  // Discards all packets that are (strictly) older than timestamp_limit,
+  // but newer than timestamp_limit - horizon_samples. Setting horizon_samples
+  // to zero implies that the horizon is set to half the timestamp range. That
+  // is, if a packet is more than 2^31 timestamps into the future compared with
+  // timestamp_limit (including wrap-around), it is considered old.
   // Returns number of packets discarded.
-  virtual int DiscardOldPackets(uint32_t timestamp_limit);
+  virtual int DiscardOldPackets(uint32_t timestamp_limit,
+                                uint32_t horizon_samples);
+
+  // Discards all packets that are (strictly) older than timestamp_limit.
+  virtual int DiscardAllOldPackets(uint32_t timestamp_limit) {
+    return DiscardOldPackets(timestamp_limit, 0);
+  }
 
   // Returns the number of packets in the buffer, including duplicates and
   // redundant packets.
@@ -125,6 +135,20 @@
   // in |packet_list|.
   static void DeleteAllPackets(PacketList* packet_list);
 
+  // Static method returning true if |timestamp| is older than |timestamp_limit|
+  // but less than |horizon_samples| behind |timestamp_limit|. For instance,
+  // with timestamp_limit = 100 and horizon_samples = 10, a timestamp in the
+  // range (90, 100) is considered obsolete, and will yield true.
+  // Setting |horizon_samples| to 0 is the same as setting it to 2^31, i.e.,
+  // half the 32-bit timestamp range.
+  static bool IsObsoleteTimestamp(uint32_t timestamp,
+                                  uint32_t timestamp_limit,
+                                  uint32_t horizon_samples) {
+    return IsNewerTimestamp(timestamp_limit, timestamp) &&
+           (horizon_samples == 0 ||
+            IsNewerTimestamp(timestamp, timestamp_limit - horizon_samples));
+  }
+
  private:
   size_t max_number_of_packets_;
   PacketList buffer_;
diff --git a/modules/audio_coding/neteq/packet_buffer_unittest.cc b/modules/audio_coding/neteq/packet_buffer_unittest.cc
index 478328c..dc8b68c 100644
--- a/modules/audio_coding/neteq/packet_buffer_unittest.cc
+++ b/modules/audio_coding/neteq/packet_buffer_unittest.cc
@@ -391,7 +391,7 @@
   EXPECT_EQ(NULL, buffer->NextRtpHeader());
   EXPECT_EQ(NULL, buffer->GetNextPacket(NULL));
   EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->DiscardNextPacket());
-  EXPECT_EQ(0, buffer->DiscardOldPackets(0));  // 0 packets discarded.
+  EXPECT_EQ(0, buffer->DiscardAllOldPackets(0));  // 0 packets discarded.
 
   // Insert one packet to make the buffer non-empty.
   packet = gen.NextPacket(payload_len);
@@ -513,4 +513,61 @@
   EXPECT_FALSE(PacketBuffer::DeleteFirstPacket(&list));
 }
 
+namespace {
+void TestIsObsoleteTimestamp(uint32_t limit_timestamp) {
+  // Check with zero horizon, which implies that the horizon is at 2^31, i.e.,
+  // half the timestamp range.
+  static const uint32_t kZeroHorizon = 0;
+  static const uint32_t k2Pow31Minus1 = 0x7FFFFFFF;
+  // Timestamp on the limit is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp, limit_timestamp, kZeroHorizon));
+  // 1 sample behind is old.
+  EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp - 1, limit_timestamp, kZeroHorizon));
+  // 2^31 - 1 samples behind is old.
+  EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp - k2Pow31Minus1, limit_timestamp, kZeroHorizon));
+  // 1 sample ahead is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp + 1, limit_timestamp, kZeroHorizon));
+  // 2^31 samples ahead is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp + (1 << 31), limit_timestamp, kZeroHorizon));
+
+  // Fixed horizon at 10 samples.
+  static const uint32_t kHorizon = 10;
+  // Timestamp on the limit is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp, limit_timestamp, kHorizon));
+  // 1 sample behind is old.
+  EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp - 1, limit_timestamp, kHorizon));
+  // 9 samples behind is old.
+  EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp - 9, limit_timestamp, kHorizon));
+  // 10 samples behind is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp - 10, limit_timestamp, kHorizon));
+  // 2^31 - 1 samples behind is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp - k2Pow31Minus1, limit_timestamp, kHorizon));
+  // 1 sample ahead is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp + 1, limit_timestamp, kHorizon));
+  // 2^31 samples ahead is not old.
+  EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+      limit_timestamp + (1 << 31), limit_timestamp, kHorizon));
+}
+}  // namespace
+
+// Test the IsObsoleteTimestamp method with different limit timestamps.
+TEST(PacketBuffer, IsObsoleteTimestamp) {
+  TestIsObsoleteTimestamp(0);
+  TestIsObsoleteTimestamp(1);
+  TestIsObsoleteTimestamp(0xFFFFFFFF);  // -1 in uint32_t.
+  TestIsObsoleteTimestamp(0x80000000);  // 2^31.
+  TestIsObsoleteTimestamp(0x80000001);  // 2^31 + 1.
+  TestIsObsoleteTimestamp(0x7FFFFFFF);  // 2^31 - 1.
+}
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/test/RTPencode.cc b/modules/audio_coding/neteq/test/RTPencode.cc
index ab338a7..b73e70e 100644
--- a/modules/audio_coding/neteq/test/RTPencode.cc
+++ b/modules/audio_coding/neteq/test/RTPencode.cc
@@ -235,9 +235,6 @@
 #ifdef CODEC_CELT_32
   CELT_encinst_t *CELT32enc_inst[2];
 #endif
-#ifdef CODEC_G711
-    void *G711state[2]={NULL, NULL};
-#endif
 
 
 int main(int argc, char* argv[])
@@ -1602,12 +1599,12 @@
         /* Encode with the selected coder type */
         if (coder==webrtc::kDecoderPCMu) { /*g711 u-law */
 #ifdef CODEC_G711
-            cdlen = WebRtcG711_EncodeU(G711state[k], indata, frameLen, (int16_t*) encoded);
+            cdlen = WebRtcG711_EncodeU(indata, frameLen, (int16_t*) encoded);
 #endif
         }  
         else if (coder==webrtc::kDecoderPCMa) { /*g711 A-law */
 #ifdef CODEC_G711
-            cdlen = WebRtcG711_EncodeA(G711state[k], indata, frameLen, (int16_t*) encoded);
+            cdlen = WebRtcG711_EncodeA(indata, frameLen, (int16_t*) encoded);
         }
 #endif
 #ifdef CODEC_PCM16B
diff --git a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
index 46ef3d0..ef2c0b6 100644
--- a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
+++ b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
@@ -92,6 +92,9 @@
 DEFINE_int32(isac_swb, 104, "RTP payload type for iSAC-swb (32 kHz)");
 static const bool isac_swb_dummy =
     google::RegisterFlagValidator(&FLAGS_isac_swb, &ValidatePayloadType);
+DEFINE_int32(opus, 111, "RTP payload type for Opus");
+static const bool opus_dummy =
+    google::RegisterFlagValidator(&FLAGS_opus, &ValidatePayloadType);
 DEFINE_int32(pcm16b, 93, "RTP payload type for PCM16b-nb (8 kHz)");
 static const bool pcm16b_dummy =
     google::RegisterFlagValidator(&FLAGS_pcm16b, &ValidatePayloadType);
@@ -286,8 +289,24 @@
                               static_cast<int>(payload_len),
                               packet->time_ms() * sample_rate_hz / 1000);
       if (error != NetEq::kOK) {
-        std::cerr << "InsertPacket returned error code " << neteq->LastError()
-                  << std::endl;
+        if (neteq->LastError() == NetEq::kUnknownRtpPayloadType) {
+          std::cerr << "RTP Payload type "
+                    << static_cast<int>(rtp_header.header.payloadType)
+                    << " is unknown." << std::endl;
+          std::cerr << "Use --codec_map to view default mapping." << std::endl;
+          std::cerr << "Use --helpshort for information on how to make custom "
+                       "mappings." << std::endl;
+        } else {
+          std::cerr << "InsertPacket returned error code " << neteq->LastError()
+                    << std::endl;
+          std::cerr << "Header data:" << std::endl;
+          std::cerr << "  PT = "
+                    << static_cast<int>(rtp_header.header.payloadType)
+                    << std::endl;
+          std::cerr << "  SN = " << rtp_header.header.sequenceNumber
+                    << std::endl;
+          std::cerr << "  TS = " << rtp_header.header.timestamp << std::endl;
+        }
       }
 
       // Get next packet from file.
@@ -366,6 +385,8 @@
       return "iSAC";
     case webrtc::kDecoderISACswb:
       return "iSAC-swb (32 kHz)";
+    case webrtc::kDecoderOpus:
+      return "Opus";
     case webrtc::kDecoderPCM16B:
       return "PCM16b-nb (8 kHz)";
     case webrtc::kDecoderPCM16Bwb:
@@ -428,6 +449,12 @@
         " as " << CodecName(webrtc::kDecoderISACswb).c_str() << std::endl;
     exit(1);
   }
+  error = neteq->RegisterPayloadType(webrtc::kDecoderOpus, FLAGS_opus);
+  if (error) {
+    std::cerr << "Cannot register payload type " << FLAGS_opus << " as "
+              << CodecName(webrtc::kDecoderOpus).c_str() << std::endl;
+    exit(1);
+  }
   error = neteq->RegisterPayloadType(webrtc::kDecoderPCM16B, FLAGS_pcm16b);
   if (error) {
     std::cerr << "Cannot register payload type " << FLAGS_pcm16b <<
@@ -514,6 +541,8 @@
       std::endl;
   std::cout << CodecName(webrtc::kDecoderISACswb).c_str() << ": " <<
       FLAGS_isac_swb << std::endl;
+  std::cout << CodecName(webrtc::kDecoderOpus).c_str() << ": " << FLAGS_opus
+            << std::endl;
   std::cout << CodecName(webrtc::kDecoderPCM16B).c_str() << ": " <<
       FLAGS_pcm16b << std::endl;
   std::cout << CodecName(webrtc::kDecoderPCM16Bwb).c_str() << ": " <<
@@ -637,8 +666,8 @@
       payload_type == FLAGS_pcm16b_swb32 ||
       payload_type == FLAGS_cn_swb32) {
     return 32000;
-  } else if (payload_type == FLAGS_pcm16b_swb48 ||
-      payload_type == FLAGS_cn_swb48) {
+  } else if (payload_type == FLAGS_opus || payload_type == FLAGS_pcm16b_swb48 ||
+             payload_type == FLAGS_cn_swb48) {
     return 48000;
   } else if (payload_type == FLAGS_avt ||
       payload_type == FLAGS_red) {
diff --git a/modules/audio_coding/neteq/tools/resample_input_audio_file.cc b/modules/audio_coding/neteq/tools/resample_input_audio_file.cc
new file mode 100644
index 0000000..f391466
--- /dev/null
+++ b/modules/audio_coding/neteq/tools/resample_input_audio_file.cc
@@ -0,0 +1,42 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+namespace test {
+
+bool ResampleInputAudioFile::Read(size_t samples,
+                                  int output_rate_hz,
+                                  int16_t* destination) {
+  const size_t samples_to_read = samples * file_rate_hz_ / output_rate_hz;
+  CHECK_EQ(samples_to_read * output_rate_hz, samples * file_rate_hz_)
+      << "Frame size and sample rates don't add up to an integer.";
+  scoped_ptr<int16_t[]> temp_destination(new int16_t[samples_to_read]);
+  if (!InputAudioFile::Read(samples_to_read, temp_destination.get()))
+    return false;
+  resampler_.ResetIfNeeded(
+      file_rate_hz_, output_rate_hz, kResamplerSynchronous);
+  int output_length = 0;
+  CHECK_EQ(resampler_.Push(temp_destination.get(),
+                           static_cast<int>(samples_to_read),
+                           destination,
+                           static_cast<int>(samples),
+                           output_length),
+           0);
+  CHECK_EQ(static_cast<int>(samples), output_length);
+  return true;
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/resample_input_audio_file.h b/modules/audio_coding/neteq/tools/resample_input_audio_file.h
new file mode 100644
index 0000000..8c02800
--- /dev/null
+++ b/modules/audio_coding/neteq/tools/resample_input_audio_file.h
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RESAMPLE_INPUT_AUDIO_FILE_H_
+#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RESAMPLE_INPUT_AUDIO_FILE_H_
+
+#include <string>
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/common_audio/resampler/include/resampler.h"
+#include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+namespace test {
+
+// Class for handling a looping input audio file with resampling.
+class ResampleInputAudioFile : public InputAudioFile {
+ public:
+  ResampleInputAudioFile(const std::string file_name, int file_rate_hz)
+      : InputAudioFile(file_name), file_rate_hz_(file_rate_hz) {}
+
+  bool Read(size_t samples, int output_rate_hz, int16_t* destination);
+
+ private:
+  const int file_rate_hz_;
+  Resampler resampler_;
+  DISALLOW_COPY_AND_ASSIGN(ResampleInputAudioFile);
+};
+
+}  // namespace test
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RESAMPLE_INPUT_AUDIO_FILE_H_
diff --git a/modules/audio_coding_module.target.darwin-arm.mk b/modules/audio_coding_module.target.darwin-arm.mk
index d197c4d..3257c96 100644
--- a/modules/audio_coding_module.target.darwin-arm.mk
+++ b/modules/audio_coding_module.target.darwin-arm.mk
@@ -114,11 +114,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -135,6 +137,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -248,11 +251,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -269,6 +274,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.darwin-arm64.mk b/modules/audio_coding_module.target.darwin-arm64.mk
index a34666d..ba0c3fc 100644
--- a/modules/audio_coding_module.target.darwin-arm64.mk
+++ b/modules/audio_coding_module.target.darwin-arm64.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -116,11 +118,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -222,11 +226,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -235,11 +241,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.darwin-mips.mk b/modules/audio_coding_module.target.darwin-mips.mk
index 1d8fdfe..aba873a 100644
--- a/modules/audio_coding_module.target.darwin-mips.mk
+++ b/modules/audio_coding_module.target.darwin-mips.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -128,6 +130,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -235,11 +238,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.darwin-mips64.mk b/modules/audio_coding_module.target.darwin-mips64.mk
new file mode 100644
index 0000000..70d3832
--- /dev/null
+++ b/modules/audio_coding_module.target.darwin-mips64.mk
@@ -0,0 +1,328 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_coding_module_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_amr.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_amrwb.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_celt.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_cng.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_dtmf_playout.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g722.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g7221.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g7221c.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g729.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g7291.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_gsmfr.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_ilbc.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_isac.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_opus.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_speex.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_pcm16b.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_pcma.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_pcmu.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_red.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_resampler.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/call_statistics.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/initial_delay_manager.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/nack.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_coding_module_gyp
+
+# Alias gyp target name.
+.PHONY: audio_coding_module
+audio_coding_module: third_party_webrtc_modules_audio_coding_module_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_coding_module.target.darwin-x86.mk b/modules/audio_coding_module.target.darwin-x86.mk
index b0da6df..4b13457 100644
--- a/modules/audio_coding_module.target.darwin-x86.mk
+++ b/modules/audio_coding_module.target.darwin-x86.mk
@@ -109,11 +109,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -127,6 +129,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -234,11 +237,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -252,6 +257,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.darwin-x86_64.mk b/modules/audio_coding_module.target.darwin-x86_64.mk
index ce06a11..d3c7fe2 100644
--- a/modules/audio_coding_module.target.darwin-x86_64.mk
+++ b/modules/audio_coding_module.target.darwin-x86_64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -126,6 +128,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -232,11 +235,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -250,6 +255,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.linux-arm.mk b/modules/audio_coding_module.target.linux-arm.mk
index d197c4d..3257c96 100644
--- a/modules/audio_coding_module.target.linux-arm.mk
+++ b/modules/audio_coding_module.target.linux-arm.mk
@@ -114,11 +114,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -135,6 +137,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -248,11 +251,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -269,6 +274,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.linux-arm64.mk b/modules/audio_coding_module.target.linux-arm64.mk
index a34666d..ba0c3fc 100644
--- a/modules/audio_coding_module.target.linux-arm64.mk
+++ b/modules/audio_coding_module.target.linux-arm64.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -116,11 +118,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -222,11 +226,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -235,11 +241,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.linux-mips.mk b/modules/audio_coding_module.target.linux-mips.mk
index 1d8fdfe..aba873a 100644
--- a/modules/audio_coding_module.target.linux-mips.mk
+++ b/modules/audio_coding_module.target.linux-mips.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -128,6 +130,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -235,11 +238,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.linux-mips64.mk b/modules/audio_coding_module.target.linux-mips64.mk
new file mode 100644
index 0000000..70d3832
--- /dev/null
+++ b/modules/audio_coding_module.target.linux-mips64.mk
@@ -0,0 +1,328 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_coding_module_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_amr.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_amrwb.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_celt.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_cng.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_dtmf_playout.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g722.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g7221.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g7221c.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g729.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_g7291.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_gsmfr.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_ilbc.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_isac.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_opus.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_speex.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_pcm16b.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_pcma.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_pcmu.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_red.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/acm_resampler.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/call_statistics.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/initial_delay_manager.cc \
+	third_party/webrtc/modules/audio_coding/main/acm2/nack.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_coding_module_gyp
+
+# Alias gyp target name.
+.PHONY: audio_coding_module
+audio_coding_module: third_party_webrtc_modules_audio_coding_module_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_coding_module.target.linux-x86.mk b/modules/audio_coding_module.target.linux-x86.mk
index b0da6df..4b13457 100644
--- a/modules/audio_coding_module.target.linux-x86.mk
+++ b/modules/audio_coding_module.target.linux-x86.mk
@@ -109,11 +109,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -127,6 +129,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -234,11 +237,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -252,6 +257,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_coding_module.target.linux-x86_64.mk b/modules/audio_coding_module.target.linux-x86_64.mk
index ce06a11..d3c7fe2 100644
--- a/modules/audio_coding_module.target.linux-x86_64.mk
+++ b/modules/audio_coding_module.target.linux-x86_64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -126,6 +128,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -232,11 +235,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -250,6 +255,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.darwin-arm.mk b/modules/audio_conference_mixer.target.darwin-arm.mk
index d4e718d..75287ab 100644
--- a/modules/audio_conference_mixer.target.darwin-arm.mk
+++ b/modules/audio_conference_mixer.target.darwin-arm.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -110,6 +112,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -209,11 +212,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -229,6 +234,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.darwin-arm64.mk b/modules/audio_conference_mixer.target.darwin-arm64.mk
index 3e63a07..c0efb57 100644
--- a/modules/audio_conference_mixer.target.darwin-arm64.mk
+++ b/modules/audio_conference_mixer.target.darwin-arm64.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -92,10 +94,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -183,11 +187,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -196,10 +202,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.darwin-mips.mk b/modules/audio_conference_mixer.target.darwin-mips.mk
index e410e9f..c11bc92 100644
--- a/modules/audio_conference_mixer.target.darwin-mips.mk
+++ b/modules/audio_conference_mixer.target.darwin-mips.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -103,6 +105,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -196,11 +199,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.darwin-mips64.mk b/modules/audio_conference_mixer.target.darwin-mips64.mk
new file mode 100644
index 0000000..ae70af6
--- /dev/null
+++ b/modules/audio_conference_mixer.target.darwin-mips64.mk
@@ -0,0 +1,274 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_conference_mixer_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.cc \
+	third_party/webrtc/modules/audio_conference_mixer/source/level_indicator.cc \
+	third_party/webrtc/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc \
+	third_party/webrtc/modules/audio_conference_mixer/source/time_scheduler.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_conference_mixer_gyp
+
+# Alias gyp target name.
+.PHONY: audio_conference_mixer
+audio_conference_mixer: third_party_webrtc_modules_audio_conference_mixer_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_conference_mixer.target.darwin-x86.mk b/modules/audio_conference_mixer.target.darwin-x86.mk
index b95f6c9..c37a30b 100644
--- a/modules/audio_conference_mixer.target.darwin-x86.mk
+++ b/modules/audio_conference_mixer.target.darwin-x86.mk
@@ -85,11 +85,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -212,6 +217,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.darwin-x86_64.mk b/modules/audio_conference_mixer.target.darwin-x86_64.mk
index 39a5a64..0fea594 100644
--- a/modules/audio_conference_mixer.target.darwin-x86_64.mk
+++ b/modules/audio_conference_mixer.target.darwin-x86_64.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.linux-arm.mk b/modules/audio_conference_mixer.target.linux-arm.mk
index d4e718d..75287ab 100644
--- a/modules/audio_conference_mixer.target.linux-arm.mk
+++ b/modules/audio_conference_mixer.target.linux-arm.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -110,6 +112,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -209,11 +212,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -229,6 +234,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.linux-arm64.mk b/modules/audio_conference_mixer.target.linux-arm64.mk
index 3e63a07..c0efb57 100644
--- a/modules/audio_conference_mixer.target.linux-arm64.mk
+++ b/modules/audio_conference_mixer.target.linux-arm64.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -92,10 +94,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -183,11 +187,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -196,10 +202,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.linux-mips.mk b/modules/audio_conference_mixer.target.linux-mips.mk
index e410e9f..c11bc92 100644
--- a/modules/audio_conference_mixer.target.linux-mips.mk
+++ b/modules/audio_conference_mixer.target.linux-mips.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -103,6 +105,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -196,11 +199,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.linux-mips64.mk b/modules/audio_conference_mixer.target.linux-mips64.mk
new file mode 100644
index 0000000..ae70af6
--- /dev/null
+++ b/modules/audio_conference_mixer.target.linux-mips64.mk
@@ -0,0 +1,274 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_conference_mixer_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.cc \
+	third_party/webrtc/modules/audio_conference_mixer/source/level_indicator.cc \
+	third_party/webrtc/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc \
+	third_party/webrtc/modules/audio_conference_mixer/source/time_scheduler.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_conference_mixer_gyp
+
+# Alias gyp target name.
+.PHONY: audio_conference_mixer
+audio_conference_mixer: third_party_webrtc_modules_audio_conference_mixer_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_conference_mixer.target.linux-x86.mk b/modules/audio_conference_mixer.target.linux-x86.mk
index b95f6c9..c37a30b 100644
--- a/modules/audio_conference_mixer.target.linux-x86.mk
+++ b/modules/audio_conference_mixer.target.linux-x86.mk
@@ -85,11 +85,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -212,6 +217,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_conference_mixer.target.linux-x86_64.mk b/modules/audio_conference_mixer.target.linux-x86_64.mk
index 39a5a64..0fea594 100644
--- a/modules/audio_conference_mixer.target.linux-x86_64.mk
+++ b/modules/audio_conference_mixer.target.linux-x86_64.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.darwin-arm.mk b/modules/audio_device.target.darwin-arm.mk
index ef5bdaa..0a99c17 100644
--- a/modules/audio_device.target.darwin-arm.mk
+++ b/modules/audio_device.target.darwin-arm.mk
@@ -93,11 +93,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,6 +116,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -219,11 +222,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -240,6 +245,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.darwin-arm64.mk b/modules/audio_device.target.darwin-arm64.mk
index df040e4..78a3fe4 100644
--- a/modules/audio_device.target.darwin-arm64.mk
+++ b/modules/audio_device.target.darwin-arm64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,11 +97,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,11 +212,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.darwin-mips.mk b/modules/audio_device.target.darwin-mips.mk
index f94aea4..7d6d1b3 100644
--- a/modules/audio_device.target.darwin-mips.mk
+++ b/modules/audio_device.target.darwin-mips.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -206,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -226,6 +231,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.darwin-mips64.mk b/modules/audio_device.target.darwin-mips64.mk
new file mode 100644
index 0000000..bf93e62
--- /dev/null
+++ b/modules/audio_device.target.darwin-mips64.mk
@@ -0,0 +1,291 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_device_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_device/audio_device_buffer.cc \
+	third_party/webrtc/modules/audio_device/audio_device_generic.cc \
+	third_party/webrtc/modules/audio_device/audio_device_utility.cc \
+	third_party/webrtc/modules/audio_device/audio_device_impl.cc \
+	third_party/webrtc/modules/audio_device/dummy/audio_device_dummy.cc \
+	third_party/webrtc/modules/audio_device/dummy/audio_device_utility_dummy.cc \
+	third_party/webrtc/modules/audio_device/dummy/file_audio_device.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/dummy \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/android \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/dummy \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/android \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_device_gyp
+
+# Alias gyp target name.
+.PHONY: audio_device
+audio_device: third_party_webrtc_modules_audio_device_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_device.target.darwin-x86.mk b/modules/audio_device.target.darwin-x86.mk
index 4bab701..92c610f 100644
--- a/modules/audio_device.target.darwin-x86.mk
+++ b/modules/audio_device.target.darwin-x86.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.darwin-x86_64.mk b/modules/audio_device.target.darwin-x86_64.mk
index c4e534d..8f05fd2 100644
--- a/modules/audio_device.target.darwin-x86_64.mk
+++ b/modules/audio_device.target.darwin-x86_64.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -105,6 +107,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.linux-arm.mk b/modules/audio_device.target.linux-arm.mk
index ef5bdaa..0a99c17 100644
--- a/modules/audio_device.target.linux-arm.mk
+++ b/modules/audio_device.target.linux-arm.mk
@@ -93,11 +93,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,6 +116,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -219,11 +222,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -240,6 +245,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.linux-arm64.mk b/modules/audio_device.target.linux-arm64.mk
index df040e4..78a3fe4 100644
--- a/modules/audio_device.target.linux-arm64.mk
+++ b/modules/audio_device.target.linux-arm64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,11 +97,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -193,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,11 +212,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.linux-mips.mk b/modules/audio_device.target.linux-mips.mk
index f94aea4..7d6d1b3 100644
--- a/modules/audio_device.target.linux-mips.mk
+++ b/modules/audio_device.target.linux-mips.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -206,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -226,6 +231,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.linux-mips64.mk b/modules/audio_device.target.linux-mips64.mk
new file mode 100644
index 0000000..bf93e62
--- /dev/null
+++ b/modules/audio_device.target.linux-mips64.mk
@@ -0,0 +1,291 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_device_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_device/audio_device_buffer.cc \
+	third_party/webrtc/modules/audio_device/audio_device_generic.cc \
+	third_party/webrtc/modules/audio_device/audio_device_utility.cc \
+	third_party/webrtc/modules/audio_device/audio_device_impl.cc \
+	third_party/webrtc/modules/audio_device/dummy/audio_device_dummy.cc \
+	third_party/webrtc/modules/audio_device/dummy/audio_device_utility_dummy.cc \
+	third_party/webrtc/modules/audio_device/dummy/file_audio_device.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/dummy \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/android \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/dummy \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/android \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_device_gyp
+
+# Alias gyp target name.
+.PHONY: audio_device
+audio_device: third_party_webrtc_modules_audio_device_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_device.target.linux-x86.mk b/modules/audio_device.target.linux-x86.mk
index 4bab701..92c610f 100644
--- a/modules/audio_device.target.linux-x86.mk
+++ b/modules/audio_device.target.linux-x86.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device.target.linux-x86_64.mk b/modules/audio_device.target.linux-x86_64.mk
index c4e534d..8f05fd2 100644
--- a/modules/audio_device.target.linux-x86_64.mk
+++ b/modules/audio_device.target.linux-x86_64.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -105,6 +107,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_DUMMY_AUDIO_BUILD' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_device/audio_device.gypi b/modules/audio_device/audio_device.gypi
index 23f417f..add3be2 100644
--- a/modules/audio_device/audio_device.gypi
+++ b/modules/audio_device/audio_device.gypi
@@ -260,7 +260,6 @@
               ],
               'includes': [
                 '../../build/isolate.gypi',
-                'audio_device_tests.isolate',
               ],
               'sources': [
                 'audio_device_tests.isolate',
diff --git a/modules/audio_device/audio_device_tests.isolate b/modules/audio_device/audio_device_tests.isolate
index ebe8bfb..a3550b7 100644
--- a/modules/audio_device/audio_device_tests.isolate
+++ b/modules/audio_device/audio_device_tests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,13 +21,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/audio_device_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/audio_device_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/modules/audio_device/audio_device_utility.cc b/modules/audio_device/audio_device_utility.cc
index b6c5c48..182329c 100644
--- a/modules/audio_device/audio_device_utility.cc
+++ b/modules/audio_device/audio_device_utility.cc
@@ -82,9 +82,9 @@
 
     // choose enter out of all available keys
 
-    if (getchar() == '\n')
+    if (getc(stdin) == '\n')
     {
-        getchar();
+        getc(stdin);
     }
 
     tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
diff --git a/modules/audio_device/win/audio_device_core_win.cc b/modules/audio_device/win/audio_device_core_win.cc
index 3708c54..bcf1c1b 100644
--- a/modules/audio_device/win/audio_device_core_win.cc
+++ b/modules/audio_device/win/audio_device_core_win.cc
@@ -3893,6 +3893,12 @@
     // This value is fixed during the capturing session.
     //
     UINT32 bufferLength = 0;
+    if (_ptrClientIn == NULL)
+    {
+      WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
+        "input state has been modified before capture loop starts.");
+      return 1;
+    }
     hr = _ptrClientIn->GetBufferSize(&bufferLength);
     EXIT_ON_ERROR(hr);
     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[CAPT] size of buffer       : %u", bufferLength);
@@ -4113,7 +4119,10 @@
 
     // ---------------------------- THREAD LOOP ---------------------------- <<
 
-    hr = _ptrClientIn->Stop();
+    if (_ptrClientIn)
+    {
+        hr = _ptrClientIn->Stop();
+    }
 
 Exit:
     if (FAILED(hr))
diff --git a/modules/audio_processing.target.darwin-arm.mk b/modules/audio_processing.target.darwin-arm.mk
index b963cbf..6764045 100644
--- a/modules/audio_processing.target.darwin-arm.mk
+++ b/modules/audio_processing.target.darwin-arm.mk
@@ -115,11 +115,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -140,6 +142,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -243,11 +246,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -268,6 +273,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.darwin-arm64.mk b/modules/audio_processing.target.darwin-arm64.mk
index 63b3628..ad0582f 100644
--- a/modules/audio_processing.target.darwin-arm64.mk
+++ b/modules/audio_processing.target.darwin-arm64.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -116,6 +118,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -125,6 +128,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -216,11 +220,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -229,6 +235,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -238,6 +245,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.darwin-mips.mk b/modules/audio_processing.target.darwin-mips.mk
index 028bf75..03384ee 100644
--- a/modules/audio_processing.target.darwin-mips.mk
+++ b/modules/audio_processing.target.darwin-mips.mk
@@ -110,11 +110,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -134,6 +136,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -231,11 +234,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.darwin-mips64.mk b/modules/audio_processing.target.darwin-mips64.mk
new file mode 100644
index 0000000..3f0f6ef
--- /dev/null
+++ b/modules/audio_processing.target.darwin-mips64.mk
@@ -0,0 +1,316 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_processing_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_webrtc_modules_audioproc_debug_proto_gyp,,,$(GYP_VAR_PREFIX))/third_party_webrtc_modules_audioproc_debug_proto_gyp.a
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_processing/aec/echo_cancellation.c \
+	third_party/webrtc/modules/audio_processing/aec/aec_core.c \
+	third_party/webrtc/modules/audio_processing/aec/aec_rdft.c \
+	third_party/webrtc/modules/audio_processing/aec/aec_resampler.c \
+	third_party/webrtc/modules/audio_processing/aecm/echo_control_mobile.c \
+	third_party/webrtc/modules/audio_processing/aecm/aecm_core.c \
+	third_party/webrtc/modules/audio_processing/agc/analog_agc.c \
+	third_party/webrtc/modules/audio_processing/agc/digital_agc.c \
+	third_party/webrtc/modules/audio_processing/audio_buffer.cc \
+	third_party/webrtc/modules/audio_processing/audio_processing_impl.cc \
+	third_party/webrtc/modules/audio_processing/echo_cancellation_impl.cc \
+	third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.cc \
+	third_party/webrtc/modules/audio_processing/gain_control_impl.cc \
+	third_party/webrtc/modules/audio_processing/high_pass_filter_impl.cc \
+	third_party/webrtc/modules/audio_processing/level_estimator_impl.cc \
+	third_party/webrtc/modules/audio_processing/noise_suppression_impl.cc \
+	third_party/webrtc/modules/audio_processing/processing_component.cc \
+	third_party/webrtc/modules/audio_processing/rms_level.cc \
+	third_party/webrtc/modules/audio_processing/typing_detection.cc \
+	third_party/webrtc/modules/audio_processing/utility/delay_estimator.c \
+	third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.c \
+	third_party/webrtc/modules/audio_processing/utility/fft4g.c \
+	third_party/webrtc/modules/audio_processing/utility/ring_buffer.c \
+	third_party/webrtc/modules/audio_processing/voice_detection_impl.cc \
+	third_party/webrtc/modules/audio_processing/ns/noise_suppression.c \
+	third_party/webrtc/modules/audio_processing/ns/ns_core.c \
+	third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_AUDIOPROC_DEBUG_DUMP' \
+	'-DWEBRTC_NS_FLOAT' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_AUDIOPROC_DEBUG_DUMP' \
+	'-DWEBRTC_NS_FLOAT' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_processing_gyp
+
+# Alias gyp target name.
+.PHONY: audio_processing
+audio_processing: third_party_webrtc_modules_audio_processing_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_processing.target.darwin-x86.mk b/modules/audio_processing.target.darwin-x86.mk
index b222ded..6840565 100644
--- a/modules/audio_processing.target.darwin-x86.mk
+++ b/modules/audio_processing.target.darwin-x86.mk
@@ -109,11 +109,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -131,6 +133,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -228,11 +231,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -250,6 +255,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.darwin-x86_64.mk b/modules/audio_processing.target.darwin-x86_64.mk
index 37fc518..57c22b8 100644
--- a/modules/audio_processing.target.darwin-x86_64.mk
+++ b/modules/audio_processing.target.darwin-x86_64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -130,6 +132,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -226,11 +229,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -248,6 +253,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.linux-arm.mk b/modules/audio_processing.target.linux-arm.mk
index b963cbf..6764045 100644
--- a/modules/audio_processing.target.linux-arm.mk
+++ b/modules/audio_processing.target.linux-arm.mk
@@ -115,11 +115,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -140,6 +142,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -243,11 +246,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -268,6 +273,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.linux-arm64.mk b/modules/audio_processing.target.linux-arm64.mk
index 63b3628..ad0582f 100644
--- a/modules/audio_processing.target.linux-arm64.mk
+++ b/modules/audio_processing.target.linux-arm64.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -116,6 +118,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -125,6 +128,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -216,11 +220,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -229,6 +235,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -238,6 +245,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.linux-mips.mk b/modules/audio_processing.target.linux-mips.mk
index 028bf75..03384ee 100644
--- a/modules/audio_processing.target.linux-mips.mk
+++ b/modules/audio_processing.target.linux-mips.mk
@@ -110,11 +110,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -134,6 +136,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -231,11 +234,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.linux-mips64.mk b/modules/audio_processing.target.linux-mips64.mk
new file mode 100644
index 0000000..3f0f6ef
--- /dev/null
+++ b/modules/audio_processing.target.linux-mips64.mk
@@ -0,0 +1,316 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audio_processing_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_webrtc_modules_audioproc_debug_proto_gyp,,,$(GYP_VAR_PREFIX))/third_party_webrtc_modules_audioproc_debug_proto_gyp.a
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_processing/aec/echo_cancellation.c \
+	third_party/webrtc/modules/audio_processing/aec/aec_core.c \
+	third_party/webrtc/modules/audio_processing/aec/aec_rdft.c \
+	third_party/webrtc/modules/audio_processing/aec/aec_resampler.c \
+	third_party/webrtc/modules/audio_processing/aecm/echo_control_mobile.c \
+	third_party/webrtc/modules/audio_processing/aecm/aecm_core.c \
+	third_party/webrtc/modules/audio_processing/agc/analog_agc.c \
+	third_party/webrtc/modules/audio_processing/agc/digital_agc.c \
+	third_party/webrtc/modules/audio_processing/audio_buffer.cc \
+	third_party/webrtc/modules/audio_processing/audio_processing_impl.cc \
+	third_party/webrtc/modules/audio_processing/echo_cancellation_impl.cc \
+	third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.cc \
+	third_party/webrtc/modules/audio_processing/gain_control_impl.cc \
+	third_party/webrtc/modules/audio_processing/high_pass_filter_impl.cc \
+	third_party/webrtc/modules/audio_processing/level_estimator_impl.cc \
+	third_party/webrtc/modules/audio_processing/noise_suppression_impl.cc \
+	third_party/webrtc/modules/audio_processing/processing_component.cc \
+	third_party/webrtc/modules/audio_processing/rms_level.cc \
+	third_party/webrtc/modules/audio_processing/typing_detection.cc \
+	third_party/webrtc/modules/audio_processing/utility/delay_estimator.c \
+	third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.c \
+	third_party/webrtc/modules/audio_processing/utility/fft4g.c \
+	third_party/webrtc/modules/audio_processing/utility/ring_buffer.c \
+	third_party/webrtc/modules/audio_processing/voice_detection_impl.cc \
+	third_party/webrtc/modules/audio_processing/ns/noise_suppression.c \
+	third_party/webrtc/modules/audio_processing/ns/ns_core.c \
+	third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_AUDIOPROC_DEBUG_DUMP' \
+	'-DWEBRTC_NS_FLOAT' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_AUDIOPROC_DEBUG_DUMP' \
+	'-DWEBRTC_NS_FLOAT' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audio_processing_gyp
+
+# Alias gyp target name.
+.PHONY: audio_processing
+audio_processing: third_party_webrtc_modules_audio_processing_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audio_processing.target.linux-x86.mk b/modules/audio_processing.target.linux-x86.mk
index b222ded..6840565 100644
--- a/modules/audio_processing.target.linux-x86.mk
+++ b/modules/audio_processing.target.linux-x86.mk
@@ -109,11 +109,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -131,6 +133,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -228,11 +231,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -250,6 +255,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing.target.linux-x86_64.mk b/modules/audio_processing.target.linux-x86_64.mk
index 37fc518..57c22b8 100644
--- a/modules/audio_processing.target.linux-x86_64.mk
+++ b/modules/audio_processing.target.linux-x86_64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -130,6 +132,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -226,11 +229,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -248,6 +253,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing/aec/aec_core.c b/modules/audio_processing/aec/aec_core.c
index 1e217eb..50457d9 100644
--- a/modules/audio_processing/aec/aec_core.c
+++ b/modules/audio_processing/aec/aec_core.c
@@ -1351,7 +1351,7 @@
 #ifdef WEBRTC_AEC_DEBUG_DUMP
 // Open a new Wav file for writing. If it was already open with a different
 // sample frequency, close it first.
-static void ReopenWav(rtc_WavFile** wav_file,
+static void ReopenWav(rtc_WavWriter** wav_file,
                       const char* name,
                       int seq1,
                       int seq2,
diff --git a/modules/audio_processing/aec/aec_core_internal.h b/modules/audio_processing/aec/aec_core_internal.h
index 6adc4d6..5e30366 100644
--- a/modules/audio_processing/aec/aec_core_internal.h
+++ b/modules/audio_processing/aec/aec_core_internal.h
@@ -11,7 +11,7 @@
 #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
 #define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
 
-#include "webrtc/common_audio/wav_writer.h"
+#include "webrtc/common_audio/wav_file.h"
 #include "webrtc/modules/audio_processing/aec/aec_common.h"
 #include "webrtc/modules/audio_processing/aec/aec_core.h"
 #include "webrtc/modules/audio_processing/utility/ring_buffer.h"
@@ -147,10 +147,10 @@
   int debug_dump_count;
 
   RingBuffer* far_time_buf;
-  rtc_WavFile* farFile;
-  rtc_WavFile* nearFile;
-  rtc_WavFile* outFile;
-  rtc_WavFile* outLinearFile;
+  rtc_WavWriter* farFile;
+  rtc_WavWriter* nearFile;
+  rtc_WavWriter* outFile;
+  rtc_WavWriter* outLinearFile;
 #endif
 };
 
diff --git a/modules/audio_processing/audio_buffer.cc b/modules/audio_processing/audio_buffer.cc
index 8aff61c..63d69cf 100644
--- a/modules/audio_processing/audio_buffer.cc
+++ b/modules/audio_processing/audio_buffer.cc
@@ -51,18 +51,11 @@
   return -1;
 }
 
-void StereoToMono(const float* left, const float* right, float* out,
+template <typename T>
+void StereoToMono(const T* left, const T* right, T* out,
                   int samples_per_channel) {
-  for (int i = 0; i < samples_per_channel; ++i) {
+  for (int i = 0; i < samples_per_channel; ++i)
     out[i] = (left[i] + right[i]) / 2;
-  }
-}
-
-void StereoToMono(const int16_t* left, const int16_t* right, int16_t* out,
-                  int samples_per_channel) {
-  for (int i = 0; i < samples_per_channel; ++i) {
-    out[i] = (left[i] + right[i]) >> 1;
-  }
 }
 
 }  // namespace
@@ -114,13 +107,7 @@
   void RefreshI() {
     if (!ivalid_) {
       assert(fvalid_);
-      const float* const float_data = fbuf_.data();
-      int16_t* const int_data = ibuf_.data();
-      const int length = ibuf_.length();
-      for (int i = 0; i < length; ++i)
-        int_data[i] = WEBRTC_SPL_SAT(std::numeric_limits<int16_t>::max(),
-                                     float_data[i],
-                                     std::numeric_limits<int16_t>::min());
+      FloatS16ToS16(fbuf_.data(), ibuf_.length(), ibuf_.data());
       ivalid_ = true;
     }
   }
@@ -228,10 +215,10 @@
     data_ptr = process_buffer_->channels();
   }
 
-  // Convert to int16.
+  // Convert to the S16 range.
   for (int i = 0; i < num_proc_channels_; ++i) {
-    ScaleAndRoundToInt16(data_ptr[i], proc_samples_per_channel_,
-                         channels_->ibuf()->channel(i));
+    FloatToFloatS16(data_ptr[i], proc_samples_per_channel_,
+                    channels_->fbuf()->channel(i));
   }
 }
 
@@ -241,16 +228,15 @@
   assert(samples_per_channel == output_samples_per_channel_);
   assert(ChannelsFromLayout(layout) == num_proc_channels_);
 
-  // Convert to float.
+  // Convert to the float range.
   float* const* data_ptr = data;
   if (output_samples_per_channel_ != proc_samples_per_channel_) {
     // Convert to an intermediate buffer for subsequent resampling.
     data_ptr = process_buffer_->channels();
   }
   for (int i = 0; i < num_proc_channels_; ++i) {
-    ScaleToFloat(channels_->ibuf()->channel(i),
-                 proc_samples_per_channel_,
-                 data_ptr[i]);
+    FloatS16ToFloat(channels_->fbuf()->channel(i), proc_samples_per_channel_,
+                    data_ptr[i]);
   }
 
   // Resample.
@@ -449,12 +435,7 @@
     // Downmix directly; no explicit deinterleaving needed.
     int16_t* downmixed = channels_->ibuf()->channel(0);
     for (int i = 0; i < input_samples_per_channel_; ++i) {
-      // HACK(ajm): The downmixing in the int16_t path is in practice never
-      // called from production code. We do this weird scaling to and from float
-      // to satisfy tests checking for bit-exactness with the float path.
-      float downmix_float = (ScaleToFloat(frame->data_[i * 2]) +
-                             ScaleToFloat(frame->data_[i * 2 + 1])) / 2;
-      downmixed[i] = ScaleAndRoundToInt16(downmix_float);
+      downmixed[i] = (frame->data_[i * 2] + frame->data_[i * 2 + 1]) / 2;
     }
   } else {
     assert(num_proc_channels_ == num_input_channels_);
diff --git a/modules/audio_processing/audio_processing.gypi b/modules/audio_processing/audio_processing.gypi
index ce65f64..2ddcffc 100644
--- a/modules/audio_processing/audio_processing.gypi
+++ b/modules/audio_processing/audio_processing.gypi
@@ -112,7 +112,7 @@
             'ns/nsx_defines.h',
           ],
           'conditions': [
-            ['target_arch=="mipsel"', {
+            ['target_arch=="mipsel" and mips_arch_variant!="r6"', {
               'sources': [
                 'ns/nsx_core_mips.c',
               ],
@@ -139,7 +139,7 @@
         ['(target_arch=="arm" and arm_version==7) or target_arch=="armv7"', {
           'dependencies': ['audio_processing_neon',],
         }],
-        ['target_arch=="mipsel"', {
+        ['target_arch=="mipsel" and mips_arch_variant!="r6"', {
           'sources': [
             'aecm/aecm_core_mips.c',
           ],
diff --git a/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.darwin-arm.mk b/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.darwin-arm.mk
index 16ac388..5cb7370 100644
--- a/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.darwin-arm.mk
+++ b/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.darwin-arm.mk
@@ -112,11 +112,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -224,11 +227,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -244,6 +249,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.linux-arm.mk b/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.linux-arm.mk
index 16ac388..5cb7370 100644
--- a/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.linux-arm.mk
+++ b/modules/audio_processing/gen_aecm_core_neon_offsets_h.target.linux-arm.mk
@@ -112,11 +112,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -224,11 +227,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -244,6 +249,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.darwin-arm.mk b/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.darwin-arm.mk
index e716339..3582a9a 100644
--- a/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.darwin-arm.mk
+++ b/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.darwin-arm.mk
@@ -112,11 +112,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -224,11 +227,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -244,6 +249,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.linux-arm.mk b/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.linux-arm.mk
index e716339..3582a9a 100644
--- a/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.linux-arm.mk
+++ b/modules/audio_processing/gen_nsx_core_neon_offsets_h.target.linux-arm.mk
@@ -112,11 +112,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -224,11 +227,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -244,6 +249,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing/lib_core_neon_offsets.target.darwin-arm.mk b/modules/audio_processing/lib_core_neon_offsets.target.darwin-arm.mk
index 224685c..917720d 100644
--- a/modules/audio_processing/lib_core_neon_offsets.target.darwin-arm.mk
+++ b/modules/audio_processing/lib_core_neon_offsets.target.darwin-arm.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -103,6 +105,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing/lib_core_neon_offsets.target.linux-arm.mk b/modules/audio_processing/lib_core_neon_offsets.target.linux-arm.mk
index 224685c..917720d 100644
--- a/modules/audio_processing/lib_core_neon_offsets.target.linux-arm.mk
+++ b/modules/audio_processing/lib_core_neon_offsets.target.linux-arm.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -103,6 +105,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing/ns/ns_core.c b/modules/audio_processing/ns/ns_core.c
index 2c7c29d..e026c29 100644
--- a/modules/audio_processing/ns/ns_core.c
+++ b/modules/audio_processing/ns/ns_core.c
@@ -8,6 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <assert.h>
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
@@ -18,312 +19,280 @@
 #include "webrtc/modules/audio_processing/ns/windows_private.h"
 #include "webrtc/modules/audio_processing/utility/fft4g.h"
 
-// Set Feature Extraction Parameters
-void WebRtcNs_set_feature_extraction_parameters(NSinst_t* inst) {
-  // bin size of histogram
-  inst->featureExtractionParams.binSizeLrt = 0.1f;
-  inst->featureExtractionParams.binSizeSpecFlat = 0.05f;
-  inst->featureExtractionParams.binSizeSpecDiff = 0.1f;
+// Set Feature Extraction Parameters.
+static void set_feature_extraction_parameters(NSinst_t* self) {
+  // Bin size of histogram.
+  self->featureExtractionParams.binSizeLrt = 0.1f;
+  self->featureExtractionParams.binSizeSpecFlat = 0.05f;
+  self->featureExtractionParams.binSizeSpecDiff = 0.1f;
 
-  // range of histogram over which lrt threshold is computed
-  inst->featureExtractionParams.rangeAvgHistLrt = 1.f;
+  // Range of histogram over which LRT threshold is computed.
+  self->featureExtractionParams.rangeAvgHistLrt = 1.f;
 
-  // scale parameters: multiply dominant peaks of the histograms by scale factor
-  // to obtain thresholds for prior model
-  inst->featureExtractionParams.factor1ModelPars =
-      1.2f;  // for lrt and spectral diff
-  inst->featureExtractionParams.factor2ModelPars =
-      0.9f;  // for spectral_flatness:
-  // used when noise is flatter than speech
+  // Scale parameters: multiply dominant peaks of the histograms by scale factor
+  // to obtain thresholds for prior model.
+  // For LRT and spectral difference.
+  self->featureExtractionParams.factor1ModelPars = 1.2f;
+  // For spectral_flatness: used when noise is flatter than speech.
+  self->featureExtractionParams.factor2ModelPars = 0.9f;
 
-  // peak limit for spectral flatness (varies between 0 and 1)
-  inst->featureExtractionParams.thresPosSpecFlat = 0.6f;
+  // Peak limit for spectral flatness (varies between 0 and 1).
+  self->featureExtractionParams.thresPosSpecFlat = 0.6f;
 
-  // limit on spacing of two highest peaks in histogram: spacing determined by
-  // bin size
-  inst->featureExtractionParams.limitPeakSpacingSpecFlat =
-      2 * inst->featureExtractionParams.binSizeSpecFlat;
-  inst->featureExtractionParams.limitPeakSpacingSpecDiff =
-      2 * inst->featureExtractionParams.binSizeSpecDiff;
+  // Limit on spacing of two highest peaks in histogram: spacing determined by
+  // bin size.
+  self->featureExtractionParams.limitPeakSpacingSpecFlat =
+      2 * self->featureExtractionParams.binSizeSpecFlat;
+  self->featureExtractionParams.limitPeakSpacingSpecDiff =
+      2 * self->featureExtractionParams.binSizeSpecDiff;
 
-  // limit on relevance of second peak:
-  inst->featureExtractionParams.limitPeakWeightsSpecFlat = 0.5f;
-  inst->featureExtractionParams.limitPeakWeightsSpecDiff = 0.5f;
+  // Limit on relevance of second peak.
+  self->featureExtractionParams.limitPeakWeightsSpecFlat = 0.5f;
+  self->featureExtractionParams.limitPeakWeightsSpecDiff = 0.5f;
 
-  // fluctuation limit of lrt feature
-  inst->featureExtractionParams.thresFluctLrt = 0.05f;
+  // Fluctuation limit of LRT feature.
+  self->featureExtractionParams.thresFluctLrt = 0.05f;
 
-  // limit on the max and min values for the feature thresholds
-  inst->featureExtractionParams.maxLrt = 1.f;
-  inst->featureExtractionParams.minLrt = 0.2f;
+  // Limit on the max and min values for the feature thresholds.
+  self->featureExtractionParams.maxLrt = 1.f;
+  self->featureExtractionParams.minLrt = 0.2f;
 
-  inst->featureExtractionParams.maxSpecFlat = 0.95f;
-  inst->featureExtractionParams.minSpecFlat = 0.1f;
+  self->featureExtractionParams.maxSpecFlat = 0.95f;
+  self->featureExtractionParams.minSpecFlat = 0.1f;
 
-  inst->featureExtractionParams.maxSpecDiff = 1.f;
-  inst->featureExtractionParams.minSpecDiff = 0.16f;
+  self->featureExtractionParams.maxSpecDiff = 1.f;
+  self->featureExtractionParams.minSpecDiff = 0.16f;
 
-  // criteria of weight of histogram peak  to accept/reject feature
-  inst->featureExtractionParams.thresWeightSpecFlat =
-      (int)(0.3 * (inst->modelUpdatePars[1]));  // for spectral flatness
-  inst->featureExtractionParams.thresWeightSpecDiff =
-      (int)(0.3 * (inst->modelUpdatePars[1]));  // for spectral difference
+  // Criteria of weight of histogram peak to accept/reject feature.
+  self->featureExtractionParams.thresWeightSpecFlat =
+      (int)(0.3 * (self->modelUpdatePars[1]));  // For spectral flatness.
+  self->featureExtractionParams.thresWeightSpecDiff =
+      (int)(0.3 * (self->modelUpdatePars[1]));  // For spectral difference.
 }
 
-// Initialize state
-int WebRtcNs_InitCore(NSinst_t* inst, uint32_t fs) {
+// Initialize state.
+int WebRtcNs_InitCore(NSinst_t* self, uint32_t fs) {
   int i;
-  // We only support 10ms frames
-
-  // check for valid pointer
-  if (inst == NULL) {
+  // Check for valid pointer.
+  if (self == NULL) {
     return -1;
   }
 
-  // Initialization of struct
+  // Initialization of struct.
   if (fs == 8000 || fs == 16000 || fs == 32000) {
-    inst->fs = fs;
+    self->fs = fs;
   } else {
     return -1;
   }
-  inst->windShift = 0;
+  self->windShift = 0;
   if (fs == 8000) {
-    // We only support 10ms frames
-    inst->blockLen = 80;
-    inst->anaLen = 128;
-    inst->window = kBlocks80w128;
+    // We only support 10ms frames.
+    self->blockLen = 80;
+    self->anaLen = 128;
+    self->window = kBlocks80w128;
   } else if (fs == 16000) {
-    // We only support 10ms frames
-    inst->blockLen = 160;
-    inst->anaLen = 256;
-    inst->window = kBlocks160w256;
+    // We only support 10ms frames.
+    self->blockLen = 160;
+    self->anaLen = 256;
+    self->window = kBlocks160w256;
   } else if (fs == 32000) {
-    // We only support 10ms frames
-    inst->blockLen = 160;
-    inst->anaLen = 256;
-    inst->window = kBlocks160w256;
+    // We only support 10ms frames.
+    self->blockLen = 160;
+    self->anaLen = 256;
+    self->window = kBlocks160w256;
   }
-  inst->magnLen = inst->anaLen / 2 + 1;  // Number of frequency bins
+  self->magnLen = self->anaLen / 2 + 1;  // Number of frequency bins.
 
-  // Initialize fft work arrays.
-  inst->ip[0] = 0;  // Setting this triggers initialization.
-  memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
-  WebRtc_rdft(inst->anaLen, 1, inst->dataBuf, inst->ip, inst->wfft);
+  // Initialize FFT work arrays.
+  self->ip[0] = 0;  // Setting this triggers initialization.
+  memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+  WebRtc_rdft(self->anaLen, 1, self->dataBuf, self->ip, self->wfft);
 
-  memset(inst->analyzeBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
-  memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
-  memset(inst->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+  memset(self->analyzeBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+  memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+  memset(self->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
 
-  // for HB processing
-  memset(inst->dataBufHB, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+  // For HB processing.
+  memset(self->dataBufHB, 0, sizeof(float) * ANAL_BLOCKL_MAX);
 
-  // for quantile noise estimation
-  memset(inst->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // For quantile noise estimation.
+  memset(self->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL);
   for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
-    inst->lquantile[i] = 8.f;
-    inst->density[i] = 0.3f;
+    self->lquantile[i] = 8.f;
+    self->density[i] = 0.3f;
   }
 
   for (i = 0; i < SIMULT; i++) {
-    inst->counter[i] =
+    self->counter[i] =
         (int)floor((float)(END_STARTUP_LONG * (i + 1)) / (float)SIMULT);
   }
 
-  inst->updates = 0;
+  self->updates = 0;
 
-  // Wiener filter initialization
+  // Wiener filter initialization.
   for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
-    inst->smooth[i] = 1.f;
+    self->smooth[i] = 1.f;
   }
 
-  // Set the aggressiveness: default
-  inst->aggrMode = 0;
+  // Set the aggressiveness: default.
+  self->aggrMode = 0;
 
-  // initialize variables for new method
-  inst->priorSpeechProb = 0.5f;  // prior prob for speech/noise
-  // previous analyze mag spectrum
-  memset(inst->magnPrevAnalyze, 0, sizeof(float) * HALF_ANAL_BLOCKL);
-  // previous process mag spectrum
-  memset(inst->magnPrevProcess, 0, sizeof(float) * HALF_ANAL_BLOCKL);
-  // current noise-spectrum
-  memset(inst->noise, 0, sizeof(float) * HALF_ANAL_BLOCKL);
-  // previous noise-spectrum
-  memset(inst->noisePrev, 0, sizeof(float) * HALF_ANAL_BLOCKL);
-  // conservative noise spectrum estimate
-  memset(inst->magnAvgPause, 0, sizeof(float) * HALF_ANAL_BLOCKL);
-  // for estimation of HB in second pass
-  memset(inst->speechProb, 0, sizeof(float) * HALF_ANAL_BLOCKL);
-  // initial average mag spectrum
-  memset(inst->initMagnEst, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // Initialize variables for new method.
+  self->priorSpeechProb = 0.5f;  // Prior prob for speech/noise.
+  // Previous analyze mag spectrum.
+  memset(self->magnPrevAnalyze, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // Previous process mag spectrum.
+  memset(self->magnPrevProcess, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // Current noise-spectrum.
+  memset(self->noise, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // Previous noise-spectrum.
+  memset(self->noisePrev, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // Conservative noise spectrum estimate.
+  memset(self->magnAvgPause, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // For estimation of HB in second pass.
+  memset(self->speechProb, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+  // Initial average magnitude spectrum.
+  memset(self->initMagnEst, 0, sizeof(float) * HALF_ANAL_BLOCKL);
   for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
-    inst->logLrtTimeAvg[i] =
-        LRT_FEATURE_THR;                 // smooth LR ratio (same as threshold)
+    // Smooth LR (same as threshold).
+    self->logLrtTimeAvg[i] = LRT_FEATURE_THR;
   }
 
-  // feature quantities
-  inst->featureData[0] =
-      SF_FEATURE_THR;  // spectral flatness (start on threshold)
-  inst->featureData[1] = 0.f;  // spectral entropy: not used in this version
-  inst->featureData[2] = 0.f;  // spectral variance: not used in this version
-  inst->featureData[3] =
-      LRT_FEATURE_THR;  // average lrt factor (start on threshold)
-  inst->featureData[4] =
-      SF_FEATURE_THR;  // spectral template diff (start on threshold)
-  inst->featureData[5] = 0.f;  // normalization for spectral-diff
-  inst->featureData[6] =
-      0.f;  // window time-average of input magnitude spectrum
+  // Feature quantities.
+  // Spectral flatness (start on threshold).
+  self->featureData[0] = SF_FEATURE_THR;
+  self->featureData[1] = 0.f;  // Spectral entropy: not used in this version.
+  self->featureData[2] = 0.f;  // Spectral variance: not used in this version.
+  // Average LRT factor (start on threshold).
+  self->featureData[3] = LRT_FEATURE_THR;
+  // Spectral template diff (start on threshold).
+  self->featureData[4] = SF_FEATURE_THR;
+  self->featureData[5] = 0.f;  // Normalization for spectral difference.
+  // Window time-average of input magnitude spectrum.
+  self->featureData[6] = 0.f;
 
-  // histogram quantities: used to estimate/update thresholds for features
-  memset(inst->histLrt, 0, sizeof(int) * HIST_PAR_EST);
-  memset(inst->histSpecFlat, 0, sizeof(int) * HIST_PAR_EST);
-  memset(inst->histSpecDiff, 0, sizeof(int) * HIST_PAR_EST);
+  // Histogram quantities: used to estimate/update thresholds for features.
+  memset(self->histLrt, 0, sizeof(int) * HIST_PAR_EST);
+  memset(self->histSpecFlat, 0, sizeof(int) * HIST_PAR_EST);
+  memset(self->histSpecDiff, 0, sizeof(int) * HIST_PAR_EST);
 
 
-  inst->blockInd = -1;  // frame counter
-  inst->priorModelPars[0] =
-      LRT_FEATURE_THR;             // default threshold for lrt feature
-  inst->priorModelPars[1] = 0.5f;  // threshold for spectral flatness:
-  // determined on-line
-  inst->priorModelPars[2] = 1.f;  // sgn_map par for spectral measure:
-  // 1 for flatness measure
-  inst->priorModelPars[3] = 0.5f;  // threshold for template-difference feature:
-  // determined on-line
-  inst->priorModelPars[4] = 1.f;  // default weighting parameter for lrt feature
-  inst->priorModelPars[5] = 0.f;  // default weighting parameter for
-  // spectral flatness feature
-  inst->priorModelPars[6] = 0.f;  // default weighting parameter for
-  // spectral difference feature
+  self->blockInd = -1;  // Frame counter.
+  // Default threshold for LRT feature.
+  self->priorModelPars[0] = LRT_FEATURE_THR;
+  // Threshold for spectral flatness: determined on-line.
+  self->priorModelPars[1] = 0.5f;
+  // sgn_map par for spectral measure: 1 for flatness measure.
+  self->priorModelPars[2] = 1.f;
+  // Threshold for template-difference feature: determined on-line.
+  self->priorModelPars[3] = 0.5f;
+  // Default weighting parameter for LRT feature.
+  self->priorModelPars[4] = 1.f;
+  // Default weighting parameter for spectral flatness feature.
+  self->priorModelPars[5] = 0.f;
+  // Default weighting parameter for spectral difference feature.
+  self->priorModelPars[6] = 0.f;
 
-  inst->modelUpdatePars[0] = 2;  // update flag for parameters:
-  // 0 no update, 1=update once, 2=update every window
-  inst->modelUpdatePars[1] = 500;  // window for update
-  inst->modelUpdatePars[2] =
-      0;  // counter for update of conservative noise spectrum
-  // counter if the feature thresholds are updated during the sequence
-  inst->modelUpdatePars[3] = inst->modelUpdatePars[1];
+  // Update flag for parameters:
+  // 0 no update, 1 = update once, 2 = update every window.
+  self->modelUpdatePars[0] = 2;
+  self->modelUpdatePars[1] = 500;  // Window for update.
+  // Counter for update of conservative noise spectrum.
+  self->modelUpdatePars[2] = 0;
+  // Counter if the feature thresholds are updated during the sequence.
+  self->modelUpdatePars[3] = self->modelUpdatePars[1];
 
-  inst->signalEnergy = 0.0;
-  inst->sumMagn = 0.0;
-  inst->whiteNoiseLevel = 0.0;
-  inst->pinkNoiseNumerator = 0.0;
-  inst->pinkNoiseExp = 0.0;
+  self->signalEnergy = 0.0;
+  self->sumMagn = 0.0;
+  self->whiteNoiseLevel = 0.0;
+  self->pinkNoiseNumerator = 0.0;
+  self->pinkNoiseExp = 0.0;
 
-  WebRtcNs_set_feature_extraction_parameters(inst);
+  set_feature_extraction_parameters(self);
 
-  // default mode
-  WebRtcNs_set_policy_core(inst, 0);
+  // Default mode.
+  WebRtcNs_set_policy_core(self, 0);
 
-  inst->initFlag = 1;
+  self->initFlag = 1;
   return 0;
 }
 
-int WebRtcNs_set_policy_core(NSinst_t* inst, int mode) {
-  // allow for modes:0,1,2,3
-  if (mode < 0 || mode > 3) {
-    return (-1);
-  }
-
-  inst->aggrMode = mode;
-  if (mode == 0) {
-    inst->overdrive = 1.f;
-    inst->denoiseBound = 0.5f;
-    inst->gainmap = 0;
-  } else if (mode == 1) {
-    // inst->overdrive = 1.25f;
-    inst->overdrive = 1.f;
-    inst->denoiseBound = 0.25f;
-    inst->gainmap = 1;
-  } else if (mode == 2) {
-    // inst->overdrive = 1.25f;
-    inst->overdrive = 1.1f;
-    inst->denoiseBound = 0.125f;
-    inst->gainmap = 1;
-  } else if (mode == 3) {
-    // inst->overdrive = 1.3f;
-    inst->overdrive = 1.25f;
-    inst->denoiseBound = 0.09f;
-    inst->gainmap = 1;
-  }
-  return 0;
-}
-
-// Estimate noise
-void WebRtcNs_NoiseEstimation(NSinst_t* inst, float* magn, float* noise) {
+// Estimate noise.
+static void NoiseEstimation(NSinst_t* self, float* magn, float* noise) {
   int i, s, offset;
   float lmagn[HALF_ANAL_BLOCKL], delta;
 
-  if (inst->updates < END_STARTUP_LONG) {
-    inst->updates++;
+  if (self->updates < END_STARTUP_LONG) {
+    self->updates++;
   }
 
-  for (i = 0; i < inst->magnLen; i++) {
+  for (i = 0; i < self->magnLen; i++) {
     lmagn[i] = (float)log(magn[i]);
   }
 
-  // loop over simultaneous estimates
+  // Loop over simultaneous estimates.
   for (s = 0; s < SIMULT; s++) {
-    offset = s * inst->magnLen;
+    offset = s * self->magnLen;
 
     // newquantest(...)
-    for (i = 0; i < inst->magnLen; i++) {
-      // compute delta
-      if (inst->density[offset + i] > 1.0) {
-        delta = FACTOR * 1.f / inst->density[offset + i];
+    for (i = 0; i < self->magnLen; i++) {
+      // Compute delta.
+      if (self->density[offset + i] > 1.0) {
+        delta = FACTOR * 1.f / self->density[offset + i];
       } else {
         delta = FACTOR;
       }
 
-      // update log quantile estimate
-      if (lmagn[i] > inst->lquantile[offset + i]) {
-        inst->lquantile[offset + i] +=
-            QUANTILE * delta / (float)(inst->counter[s] + 1);
+      // Update log quantile estimate.
+      if (lmagn[i] > self->lquantile[offset + i]) {
+        self->lquantile[offset + i] +=
+            QUANTILE * delta / (float)(self->counter[s] + 1);
       } else {
-        inst->lquantile[offset + i] -=
-            (1.f - QUANTILE) * delta / (float)(inst->counter[s] + 1);
+        self->lquantile[offset + i] -=
+            (1.f - QUANTILE) * delta / (float)(self->counter[s] + 1);
       }
 
-      // update density estimate
-      if (fabs(lmagn[i] - inst->lquantile[offset + i]) < WIDTH) {
-        inst->density[offset + i] =
-            ((float)inst->counter[s] * inst->density[offset + i] +
+      // Update density estimate.
+      if (fabs(lmagn[i] - self->lquantile[offset + i]) < WIDTH) {
+        self->density[offset + i] =
+            ((float)self->counter[s] * self->density[offset + i] +
              1.f / (2.f * WIDTH)) /
-            (float)(inst->counter[s] + 1);
+            (float)(self->counter[s] + 1);
       }
-    }  // end loop over magnitude spectrum
+    }  // End loop over magnitude spectrum.
 
-    if (inst->counter[s] >= END_STARTUP_LONG) {
-      inst->counter[s] = 0;
-      if (inst->updates >= END_STARTUP_LONG) {
-        for (i = 0; i < inst->magnLen; i++) {
-          inst->quantile[i] = (float)exp(inst->lquantile[offset + i]);
+    if (self->counter[s] >= END_STARTUP_LONG) {
+      self->counter[s] = 0;
+      if (self->updates >= END_STARTUP_LONG) {
+        for (i = 0; i < self->magnLen; i++) {
+          self->quantile[i] = (float)exp(self->lquantile[offset + i]);
         }
       }
     }
 
-    inst->counter[s]++;
-  }  // end loop over simultaneous estimates
+    self->counter[s]++;
+  }  // End loop over simultaneous estimates.
 
-  // Sequentially update the noise during startup
-  if (inst->updates < END_STARTUP_LONG) {
+  // Sequentially update the noise during startup.
+  if (self->updates < END_STARTUP_LONG) {
     // Use the last "s" to get noise during startup that differ from zero.
-    for (i = 0; i < inst->magnLen; i++) {
-      inst->quantile[i] = (float)exp(inst->lquantile[offset + i]);
+    for (i = 0; i < self->magnLen; i++) {
+      self->quantile[i] = (float)exp(self->lquantile[offset + i]);
     }
   }
 
-  for (i = 0; i < inst->magnLen; i++) {
-    noise[i] = inst->quantile[i];
+  for (i = 0; i < self->magnLen; i++) {
+    noise[i] = self->quantile[i];
   }
 }
 
-// Extract thresholds for feature parameters
-// histograms are computed over some window_size (given by
-// inst->modelUpdatePars[1])
-// thresholds and weights are extracted every window
-// flag 0 means update histogram only, flag 1 means compute the
-// thresholds/weights
-// threshold and weights are returned in: inst->priorModelPars
-void WebRtcNs_FeatureParameterExtraction(NSinst_t* inst, int flag) {
+// Extract thresholds for feature parameters.
+// Histograms are computed over some window size (given by
+// self->modelUpdatePars[1]).
+// Thresholds and weights are extracted every window.
+// |flag| = 0 updates histogram only, |flag| = 1 computes the threshold/weights.
+// Threshold and weights are returned in: self->priorModelPars.
+static void FeatureParameterExtraction(NSinst_t* self, int flag) {
   int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt;
   int maxPeak1, maxPeak2;
   int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff,
@@ -333,81 +302,81 @@
   float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff;
   float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl;
 
-  // 3 features: lrt, flatness, difference
-  // lrt_feature = inst->featureData[3];
-  // flat_feature = inst->featureData[0];
-  // diff_feature = inst->featureData[4];
+  // 3 features: LRT, flatness, difference.
+  // lrt_feature = self->featureData[3];
+  // flat_feature = self->featureData[0];
+  // diff_feature = self->featureData[4];
 
-  // update histograms
+  // Update histograms.
   if (flag == 0) {
     // LRT
-    if ((inst->featureData[3] <
-         HIST_PAR_EST * inst->featureExtractionParams.binSizeLrt) &&
-        (inst->featureData[3] >= 0.0)) {
-      i = (int)(inst->featureData[3] /
-                inst->featureExtractionParams.binSizeLrt);
-      inst->histLrt[i]++;
+    if ((self->featureData[3] <
+         HIST_PAR_EST * self->featureExtractionParams.binSizeLrt) &&
+        (self->featureData[3] >= 0.0)) {
+      i = (int)(self->featureData[3] /
+                self->featureExtractionParams.binSizeLrt);
+      self->histLrt[i]++;
     }
-    // Spectral flatness
-    if ((inst->featureData[0] <
-         HIST_PAR_EST * inst->featureExtractionParams.binSizeSpecFlat) &&
-        (inst->featureData[0] >= 0.0)) {
-      i = (int)(inst->featureData[0] /
-                inst->featureExtractionParams.binSizeSpecFlat);
-      inst->histSpecFlat[i]++;
+    // Spectral flatness.
+    if ((self->featureData[0] <
+         HIST_PAR_EST * self->featureExtractionParams.binSizeSpecFlat) &&
+        (self->featureData[0] >= 0.0)) {
+      i = (int)(self->featureData[0] /
+                self->featureExtractionParams.binSizeSpecFlat);
+      self->histSpecFlat[i]++;
     }
-    // Spectral difference
-    if ((inst->featureData[4] <
-         HIST_PAR_EST * inst->featureExtractionParams.binSizeSpecDiff) &&
-        (inst->featureData[4] >= 0.0)) {
-      i = (int)(inst->featureData[4] /
-                inst->featureExtractionParams.binSizeSpecDiff);
-      inst->histSpecDiff[i]++;
+    // Spectral difference.
+    if ((self->featureData[4] <
+         HIST_PAR_EST * self->featureExtractionParams.binSizeSpecDiff) &&
+        (self->featureData[4] >= 0.0)) {
+      i = (int)(self->featureData[4] /
+                self->featureExtractionParams.binSizeSpecDiff);
+      self->histSpecDiff[i]++;
     }
   }
 
-  // extract parameters for speech/noise probability
+  // Extract parameters for speech/noise probability.
   if (flag == 1) {
-    // lrt feature: compute the average over
-    // inst->featureExtractionParams.rangeAvgHistLrt
+    // LRT feature: compute the average over
+    // self->featureExtractionParams.rangeAvgHistLrt.
     avgHistLrt = 0.0;
     avgHistLrtCompl = 0.0;
     avgSquareHistLrt = 0.0;
     numHistLrt = 0;
     for (i = 0; i < HIST_PAR_EST; i++) {
-      binMid = ((float)i + 0.5f) * inst->featureExtractionParams.binSizeLrt;
-      if (binMid <= inst->featureExtractionParams.rangeAvgHistLrt) {
-        avgHistLrt += inst->histLrt[i] * binMid;
-        numHistLrt += inst->histLrt[i];
+      binMid = ((float)i + 0.5f) * self->featureExtractionParams.binSizeLrt;
+      if (binMid <= self->featureExtractionParams.rangeAvgHistLrt) {
+        avgHistLrt += self->histLrt[i] * binMid;
+        numHistLrt += self->histLrt[i];
       }
-      avgSquareHistLrt += inst->histLrt[i] * binMid * binMid;
-      avgHistLrtCompl += inst->histLrt[i] * binMid;
+      avgSquareHistLrt += self->histLrt[i] * binMid * binMid;
+      avgHistLrtCompl += self->histLrt[i] * binMid;
     }
     if (numHistLrt > 0) {
       avgHistLrt = avgHistLrt / ((float)numHistLrt);
     }
-    avgHistLrtCompl = avgHistLrtCompl / ((float)inst->modelUpdatePars[1]);
-    avgSquareHistLrt = avgSquareHistLrt / ((float)inst->modelUpdatePars[1]);
+    avgHistLrtCompl = avgHistLrtCompl / ((float)self->modelUpdatePars[1]);
+    avgSquareHistLrt = avgSquareHistLrt / ((float)self->modelUpdatePars[1]);
     fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl;
-    // get threshold for lrt feature:
-    if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) {
-      // very low fluct, so likely noise
-      inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt;
+    // Get threshold for LRT feature.
+    if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
+      // Very low fluctuation, so likely noise.
+      self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
     } else {
-      inst->priorModelPars[0] =
-          inst->featureExtractionParams.factor1ModelPars * avgHistLrt;
-      // check if value is within min/max range
-      if (inst->priorModelPars[0] < inst->featureExtractionParams.minLrt) {
-        inst->priorModelPars[0] = inst->featureExtractionParams.minLrt;
+      self->priorModelPars[0] =
+          self->featureExtractionParams.factor1ModelPars * avgHistLrt;
+      // Check if value is within min/max range.
+      if (self->priorModelPars[0] < self->featureExtractionParams.minLrt) {
+        self->priorModelPars[0] = self->featureExtractionParams.minLrt;
       }
-      if (inst->priorModelPars[0] > inst->featureExtractionParams.maxLrt) {
-        inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt;
+      if (self->priorModelPars[0] > self->featureExtractionParams.maxLrt) {
+        self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
       }
     }
-    // done with lrt feature
+    // Done with LRT feature.
 
-    // for spectral flatness and spectral difference: compute the main peaks of
-    // histogram
+    // For spectral flatness and spectral difference: compute the main peaks of
+    // histogram.
     maxPeak1 = 0;
     maxPeak2 = 0;
     posPeak1SpecFlat = 0.0;
@@ -415,233 +384,266 @@
     weightPeak1SpecFlat = 0;
     weightPeak2SpecFlat = 0;
 
-    // peaks for flatness
+    // Peaks for flatness.
     for (i = 0; i < HIST_PAR_EST; i++) {
       binMid =
-          (i + 0.5f) * inst->featureExtractionParams.binSizeSpecFlat;
-      if (inst->histSpecFlat[i] > maxPeak1) {
-        // Found new "first" peak
+          (i + 0.5f) * self->featureExtractionParams.binSizeSpecFlat;
+      if (self->histSpecFlat[i] > maxPeak1) {
+        // Found new "first" peak.
         maxPeak2 = maxPeak1;
         weightPeak2SpecFlat = weightPeak1SpecFlat;
         posPeak2SpecFlat = posPeak1SpecFlat;
 
-        maxPeak1 = inst->histSpecFlat[i];
-        weightPeak1SpecFlat = inst->histSpecFlat[i];
+        maxPeak1 = self->histSpecFlat[i];
+        weightPeak1SpecFlat = self->histSpecFlat[i];
         posPeak1SpecFlat = binMid;
-      } else if (inst->histSpecFlat[i] > maxPeak2) {
-        // Found new "second" peak
-        maxPeak2 = inst->histSpecFlat[i];
-        weightPeak2SpecFlat = inst->histSpecFlat[i];
+      } else if (self->histSpecFlat[i] > maxPeak2) {
+        // Found new "second" peak.
+        maxPeak2 = self->histSpecFlat[i];
+        weightPeak2SpecFlat = self->histSpecFlat[i];
         posPeak2SpecFlat = binMid;
       }
     }
 
-    // compute two peaks for spectral difference
+    // Compute two peaks for spectral difference.
     maxPeak1 = 0;
     maxPeak2 = 0;
     posPeak1SpecDiff = 0.0;
     posPeak2SpecDiff = 0.0;
     weightPeak1SpecDiff = 0;
     weightPeak2SpecDiff = 0;
-    // peaks for spectral difference
+    // Peaks for spectral difference.
     for (i = 0; i < HIST_PAR_EST; i++) {
       binMid =
-          ((float)i + 0.5f) * inst->featureExtractionParams.binSizeSpecDiff;
-      if (inst->histSpecDiff[i] > maxPeak1) {
-        // Found new "first" peak
+          ((float)i + 0.5f) * self->featureExtractionParams.binSizeSpecDiff;
+      if (self->histSpecDiff[i] > maxPeak1) {
+        // Found new "first" peak.
         maxPeak2 = maxPeak1;
         weightPeak2SpecDiff = weightPeak1SpecDiff;
         posPeak2SpecDiff = posPeak1SpecDiff;
 
-        maxPeak1 = inst->histSpecDiff[i];
-        weightPeak1SpecDiff = inst->histSpecDiff[i];
+        maxPeak1 = self->histSpecDiff[i];
+        weightPeak1SpecDiff = self->histSpecDiff[i];
         posPeak1SpecDiff = binMid;
-      } else if (inst->histSpecDiff[i] > maxPeak2) {
-        // Found new "second" peak
-        maxPeak2 = inst->histSpecDiff[i];
-        weightPeak2SpecDiff = inst->histSpecDiff[i];
+      } else if (self->histSpecDiff[i] > maxPeak2) {
+        // Found new "second" peak.
+        maxPeak2 = self->histSpecDiff[i];
+        weightPeak2SpecDiff = self->histSpecDiff[i];
         posPeak2SpecDiff = binMid;
       }
     }
 
-    // for spectrum flatness feature
+    // For spectrum flatness feature.
     useFeatureSpecFlat = 1;
-    // merge the two peaks if they are close
+    // Merge the two peaks if they are close.
     if ((fabs(posPeak2SpecFlat - posPeak1SpecFlat) <
-         inst->featureExtractionParams.limitPeakSpacingSpecFlat) &&
+         self->featureExtractionParams.limitPeakSpacingSpecFlat) &&
         (weightPeak2SpecFlat >
-         inst->featureExtractionParams.limitPeakWeightsSpecFlat *
+         self->featureExtractionParams.limitPeakWeightsSpecFlat *
              weightPeak1SpecFlat)) {
       weightPeak1SpecFlat += weightPeak2SpecFlat;
       posPeak1SpecFlat = 0.5f * (posPeak1SpecFlat + posPeak2SpecFlat);
     }
-    // reject if weight of peaks is not large enough, or peak value too small
+    // Reject if weight of peaks is not large enough, or peak value too small.
     if (weightPeak1SpecFlat <
-            inst->featureExtractionParams.thresWeightSpecFlat ||
-        posPeak1SpecFlat < inst->featureExtractionParams.thresPosSpecFlat) {
+            self->featureExtractionParams.thresWeightSpecFlat ||
+        posPeak1SpecFlat < self->featureExtractionParams.thresPosSpecFlat) {
       useFeatureSpecFlat = 0;
     }
-    // if selected, get the threshold
+    // If selected, get the threshold.
     if (useFeatureSpecFlat == 1) {
-      // compute the threshold
-      inst->priorModelPars[1] =
-          inst->featureExtractionParams.factor2ModelPars * posPeak1SpecFlat;
-      // check if value is within min/max range
-      if (inst->priorModelPars[1] < inst->featureExtractionParams.minSpecFlat) {
-        inst->priorModelPars[1] = inst->featureExtractionParams.minSpecFlat;
+      // Compute the threshold.
+      self->priorModelPars[1] =
+          self->featureExtractionParams.factor2ModelPars * posPeak1SpecFlat;
+      // Check if value is within min/max range.
+      if (self->priorModelPars[1] < self->featureExtractionParams.minSpecFlat) {
+        self->priorModelPars[1] = self->featureExtractionParams.minSpecFlat;
       }
-      if (inst->priorModelPars[1] > inst->featureExtractionParams.maxSpecFlat) {
-        inst->priorModelPars[1] = inst->featureExtractionParams.maxSpecFlat;
+      if (self->priorModelPars[1] > self->featureExtractionParams.maxSpecFlat) {
+        self->priorModelPars[1] = self->featureExtractionParams.maxSpecFlat;
       }
     }
-    // done with flatness feature
+    // Done with flatness feature.
 
-    // for template feature
+    // For template feature.
     useFeatureSpecDiff = 1;
-    // merge the two peaks if they are close
+    // Merge the two peaks if they are close.
     if ((fabs(posPeak2SpecDiff - posPeak1SpecDiff) <
-         inst->featureExtractionParams.limitPeakSpacingSpecDiff) &&
+         self->featureExtractionParams.limitPeakSpacingSpecDiff) &&
         (weightPeak2SpecDiff >
-         inst->featureExtractionParams.limitPeakWeightsSpecDiff *
+         self->featureExtractionParams.limitPeakWeightsSpecDiff *
              weightPeak1SpecDiff)) {
       weightPeak1SpecDiff += weightPeak2SpecDiff;
       posPeak1SpecDiff = 0.5f * (posPeak1SpecDiff + posPeak2SpecDiff);
     }
-    // get the threshold value
-    inst->priorModelPars[3] =
-        inst->featureExtractionParams.factor1ModelPars * posPeak1SpecDiff;
-    // reject if weight of peaks is not large enough
+    // Get the threshold value.
+    self->priorModelPars[3] =
+        self->featureExtractionParams.factor1ModelPars * posPeak1SpecDiff;
+    // Reject if weight of peaks is not large enough.
     if (weightPeak1SpecDiff <
-        inst->featureExtractionParams.thresWeightSpecDiff) {
+        self->featureExtractionParams.thresWeightSpecDiff) {
       useFeatureSpecDiff = 0;
     }
-    // check if value is within min/max range
-    if (inst->priorModelPars[3] < inst->featureExtractionParams.minSpecDiff) {
-      inst->priorModelPars[3] = inst->featureExtractionParams.minSpecDiff;
+    // Check if value is within min/max range.
+    if (self->priorModelPars[3] < self->featureExtractionParams.minSpecDiff) {
+      self->priorModelPars[3] = self->featureExtractionParams.minSpecDiff;
     }
-    if (inst->priorModelPars[3] > inst->featureExtractionParams.maxSpecDiff) {
-      inst->priorModelPars[3] = inst->featureExtractionParams.maxSpecDiff;
+    if (self->priorModelPars[3] > self->featureExtractionParams.maxSpecDiff) {
+      self->priorModelPars[3] = self->featureExtractionParams.maxSpecDiff;
     }
-    // done with spectral difference feature
+    // Done with spectral difference feature.
 
-    // don't use template feature if fluctuation of lrt feature is very low:
-    //  most likely just noise state
-    if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) {
+    // Don't use template feature if fluctuation of LRT feature is very low:
+    // most likely just noise state.
+    if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
       useFeatureSpecDiff = 0;
     }
 
-    // select the weights between the features
-    // inst->priorModelPars[4] is weight for lrt: always selected
-    // inst->priorModelPars[5] is weight for spectral flatness
-    // inst->priorModelPars[6] is weight for spectral difference
+    // Select the weights between the features.
+    // self->priorModelPars[4] is weight for LRT: always selected.
+    // self->priorModelPars[5] is weight for spectral flatness.
+    // self->priorModelPars[6] is weight for spectral difference.
     featureSum = (float)(1 + useFeatureSpecFlat + useFeatureSpecDiff);
-    inst->priorModelPars[4] = 1.f / featureSum;
-    inst->priorModelPars[5] = ((float)useFeatureSpecFlat) / featureSum;
-    inst->priorModelPars[6] = ((float)useFeatureSpecDiff) / featureSum;
+    self->priorModelPars[4] = 1.f / featureSum;
+    self->priorModelPars[5] = ((float)useFeatureSpecFlat) / featureSum;
+    self->priorModelPars[6] = ((float)useFeatureSpecDiff) / featureSum;
 
-    // set hists to zero for next update
-    if (inst->modelUpdatePars[0] >= 1) {
+    // Set hists to zero for next update.
+    if (self->modelUpdatePars[0] >= 1) {
       for (i = 0; i < HIST_PAR_EST; i++) {
-        inst->histLrt[i] = 0;
-        inst->histSpecFlat[i] = 0;
-        inst->histSpecDiff[i] = 0;
+        self->histLrt[i] = 0;
+        self->histSpecFlat[i] = 0;
+        self->histSpecDiff[i] = 0;
       }
     }
-  }  // end of flag == 1
+  }  // End of flag == 1.
 }
 
-// Compute spectral flatness on input spectrum
-// magnIn is the magnitude spectrum
-// spectral flatness is returned in inst->featureData[0]
-void WebRtcNs_ComputeSpectralFlatness(NSinst_t* inst, float* magnIn) {
+// Compute spectral flatness on input spectrum.
+// |magnIn| is the magnitude spectrum.
+// Spectral flatness is returned in self->featureData[0].
+static void ComputeSpectralFlatness(NSinst_t* self, const float* magnIn) {
   int i;
-  int shiftLP = 1;  // option to remove first bin(s) from spectral measures
+  int shiftLP = 1;  // Option to remove first bin(s) from spectral measures.
   float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp;
 
-  // comute spectral measures
-  // for flatness
+  // Compute spectral measures.
+  // For flatness.
   avgSpectralFlatnessNum = 0.0;
-  avgSpectralFlatnessDen = inst->sumMagn;
+  avgSpectralFlatnessDen = self->sumMagn;
   for (i = 0; i < shiftLP; i++) {
     avgSpectralFlatnessDen -= magnIn[i];
   }
-  // compute log of ratio of the geometric to arithmetic mean: check for log(0)
-  // case
-  for (i = shiftLP; i < inst->magnLen; i++) {
+  // Compute log of ratio of the geometric to arithmetic mean: check for log(0)
+  // case.
+  for (i = shiftLP; i < self->magnLen; i++) {
     if (magnIn[i] > 0.0) {
       avgSpectralFlatnessNum += (float)log(magnIn[i]);
     } else {
-      inst->featureData[0] -= SPECT_FL_TAVG * inst->featureData[0];
+      self->featureData[0] -= SPECT_FL_TAVG * self->featureData[0];
       return;
     }
   }
-  // normalize
-  avgSpectralFlatnessDen = avgSpectralFlatnessDen / inst->magnLen;
-  avgSpectralFlatnessNum = avgSpectralFlatnessNum / inst->magnLen;
+  // Normalize.
+  avgSpectralFlatnessDen = avgSpectralFlatnessDen / self->magnLen;
+  avgSpectralFlatnessNum = avgSpectralFlatnessNum / self->magnLen;
 
-  // ratio and inverse log: check for case of log(0)
+  // Ratio and inverse log: check for case of log(0).
   spectralTmp = (float)exp(avgSpectralFlatnessNum) / avgSpectralFlatnessDen;
 
-  // time-avg update of spectral flatness feature
-  inst->featureData[0] += SPECT_FL_TAVG * (spectralTmp - inst->featureData[0]);
-  // done with flatness feature
+  // Time-avg update of spectral flatness feature.
+  self->featureData[0] += SPECT_FL_TAVG * (spectralTmp - self->featureData[0]);
+  // Done with flatness feature.
+}
+
+// Compute prior and post SNR based on quantile noise estimation.
+// Compute DD estimate of prior SNR.
+// Inputs:
+//   * |magn| is the signal magnitude spectrum estimate.
+//   * |noise| is the magnitude noise spectrum estimate.
+// Outputs:
+//   * |snrLocPrior| is the computed prior SNR.
+//   * |snrLocPost| is the computed post SNR.
+static void ComputeSnr(const NSinst_t* self,
+                       const float* magn,
+                       const float* noise,
+                       float* snrLocPrior,
+                       float* snrLocPost) {
+  int i;
+
+  for (i = 0; i < self->magnLen; i++) {
+    // Previous post SNR.
+    // Previous estimate: based on previous frame with gain filter.
+    float previousEstimateStsa = self->magnPrevAnalyze[i] /
+        (self->noisePrev[i] + 0.0001f) * self->smooth[i];
+    // Post SNR.
+    snrLocPost[i] = 0.f;
+    if (magn[i] > noise[i]) {
+      snrLocPost[i] = magn[i] / (noise[i] + 0.0001f) - 1.f;
+    }
+    // DD estimate is sum of two terms: current estimate and previous estimate.
+    // Directed decision update of snrPrior.
+    snrLocPrior[i] =
+        DD_PR_SNR * previousEstimateStsa + (1.f - DD_PR_SNR) * snrLocPost[i];
+  }  // End of loop over frequencies.
 }
 
 // Compute the difference measure between input spectrum and a template/learned
-// noise spectrum
-// magnIn is the input spectrum
-// the reference/template spectrum is inst->magnAvgPause[i]
-// returns (normalized) spectral difference in inst->featureData[4]
-void WebRtcNs_ComputeSpectralDifference(NSinst_t* inst, float* magnIn) {
+// noise spectrum.
+// |magnIn| is the input spectrum.
+// The reference/template spectrum is self->magnAvgPause[i].
+// Returns (normalized) spectral difference in self->featureData[4].
+static void ComputeSpectralDifference(NSinst_t* self,
+                                      const float* magnIn) {
   // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 /
   // var(magnAvgPause)
   int i;
   float avgPause, avgMagn, covMagnPause, varPause, varMagn, avgDiffNormMagn;
 
   avgPause = 0.0;
-  avgMagn = inst->sumMagn;
-  // compute average quantities
-  for (i = 0; i < inst->magnLen; i++) {
-    // conservative smooth noise spectrum from pause frames
-    avgPause += inst->magnAvgPause[i];
+  avgMagn = self->sumMagn;
+  // Compute average quantities.
+  for (i = 0; i < self->magnLen; i++) {
+    // Conservative smooth noise spectrum from pause frames.
+    avgPause += self->magnAvgPause[i];
   }
-  avgPause = avgPause / ((float)inst->magnLen);
-  avgMagn = avgMagn / ((float)inst->magnLen);
+  avgPause = avgPause / ((float)self->magnLen);
+  avgMagn = avgMagn / ((float)self->magnLen);
 
   covMagnPause = 0.0;
   varPause = 0.0;
   varMagn = 0.0;
-  // compute variance and covariance quantities
-  for (i = 0; i < inst->magnLen; i++) {
-    covMagnPause += (magnIn[i] - avgMagn) * (inst->magnAvgPause[i] - avgPause);
+  // Compute variance and covariance quantities.
+  for (i = 0; i < self->magnLen; i++) {
+    covMagnPause += (magnIn[i] - avgMagn) * (self->magnAvgPause[i] - avgPause);
     varPause +=
-        (inst->magnAvgPause[i] - avgPause) * (inst->magnAvgPause[i] - avgPause);
+        (self->magnAvgPause[i] - avgPause) * (self->magnAvgPause[i] - avgPause);
     varMagn += (magnIn[i] - avgMagn) * (magnIn[i] - avgMagn);
   }
-  covMagnPause = covMagnPause / ((float)inst->magnLen);
-  varPause = varPause / ((float)inst->magnLen);
-  varMagn = varMagn / ((float)inst->magnLen);
-  // update of average magnitude spectrum
-  inst->featureData[6] += inst->signalEnergy;
+  covMagnPause = covMagnPause / ((float)self->magnLen);
+  varPause = varPause / ((float)self->magnLen);
+  varMagn = varMagn / ((float)self->magnLen);
+  // Update of average magnitude spectrum.
+  self->featureData[6] += self->signalEnergy;
 
   avgDiffNormMagn =
       varMagn - (covMagnPause * covMagnPause) / (varPause + 0.0001f);
-  // normalize and compute time-avg update of difference feature
-  avgDiffNormMagn = (float)(avgDiffNormMagn / (inst->featureData[5] + 0.0001f));
-  inst->featureData[4] +=
-      SPECT_DIFF_TAVG * (avgDiffNormMagn - inst->featureData[4]);
+  // Normalize and compute time-avg update of difference feature.
+  avgDiffNormMagn = (float)(avgDiffNormMagn / (self->featureData[5] + 0.0001f));
+  self->featureData[4] +=
+      SPECT_DIFF_TAVG * (avgDiffNormMagn - self->featureData[4]);
 }
 
-// Compute speech/noise probability
-// speech/noise probability is returned in: probSpeechFinal
-// magn is the input magnitude spectrum
-// noise is the noise spectrum
-// snrLocPrior is the prior snr for each freq.
-// snr loc_post is the post snr for each freq.
-void WebRtcNs_SpeechNoiseProb(NSinst_t* inst,
-                              float* probSpeechFinal,
-                              float* snrLocPrior,
-                              float* snrLocPost) {
+// Compute speech/noise probability.
+// Speech/noise probability is returned in |probSpeechFinal|.
+// |magn| is the input magnitude spectrum.
+// |noise| is the noise spectrum.
+// |snrLocPrior| is the prior SNR for each frequency.
+// |snrLocPost| is the post SNR for each frequency.
+static void SpeechNoiseProb(NSinst_t* self,
+                            float* probSpeechFinal,
+                            const float* snrLocPrior,
+                            const float* snrLocPost) {
   int i, sgnMap;
   float invLrt, gainPrior, indPrior;
   float logLrtTimeAvgKsum, besselTmp;
@@ -652,119 +654,406 @@
   float widthPrior, widthPrior0, widthPrior1, widthPrior2;
 
   widthPrior0 = WIDTH_PR_MAP;
-  widthPrior1 = 2.f * WIDTH_PR_MAP;  // width for pause region:
-  // lower range, so increase width in tanh map
-  widthPrior2 = 2.f * WIDTH_PR_MAP;  // for spectral-difference measure
+  // Width for pause region: lower range, so increase width in tanh map.
+  widthPrior1 = 2.f * WIDTH_PR_MAP;
+  widthPrior2 = 2.f * WIDTH_PR_MAP;  // For spectral-difference measure.
 
-  // threshold parameters for features
-  threshPrior0 = inst->priorModelPars[0];
-  threshPrior1 = inst->priorModelPars[1];
-  threshPrior2 = inst->priorModelPars[3];
+  // Threshold parameters for features.
+  threshPrior0 = self->priorModelPars[0];
+  threshPrior1 = self->priorModelPars[1];
+  threshPrior2 = self->priorModelPars[3];
 
-  // sign for flatness feature
-  sgnMap = (int)(inst->priorModelPars[2]);
+  // Sign for flatness feature.
+  sgnMap = (int)(self->priorModelPars[2]);
 
-  // weight parameters for features
-  weightIndPrior0 = inst->priorModelPars[4];
-  weightIndPrior1 = inst->priorModelPars[5];
-  weightIndPrior2 = inst->priorModelPars[6];
+  // Weight parameters for features.
+  weightIndPrior0 = self->priorModelPars[4];
+  weightIndPrior1 = self->priorModelPars[5];
+  weightIndPrior2 = self->priorModelPars[6];
 
-  // compute feature based on average LR factor
-  // this is the average over all frequencies of the smooth log lrt
+  // Compute feature based on average LR factor.
+  // This is the average over all frequencies of the smooth log LRT.
   logLrtTimeAvgKsum = 0.0;
-  for (i = 0; i < inst->magnLen; i++) {
+  for (i = 0; i < self->magnLen; i++) {
     tmpFloat1 = 1.f + 2.f * snrLocPrior[i];
     tmpFloat2 = 2.f * snrLocPrior[i] / (tmpFloat1 + 0.0001f);
     besselTmp = (snrLocPost[i] + 1.f) * tmpFloat2;
-    inst->logLrtTimeAvg[i] +=
-        LRT_TAVG * (besselTmp - (float)log(tmpFloat1) - inst->logLrtTimeAvg[i]);
-    logLrtTimeAvgKsum += inst->logLrtTimeAvg[i];
+    self->logLrtTimeAvg[i] +=
+        LRT_TAVG * (besselTmp - (float)log(tmpFloat1) - self->logLrtTimeAvg[i]);
+    logLrtTimeAvgKsum += self->logLrtTimeAvg[i];
   }
-  logLrtTimeAvgKsum = (float)logLrtTimeAvgKsum / (inst->magnLen);
-  inst->featureData[3] = logLrtTimeAvgKsum;
-  // done with computation of LR factor
+  logLrtTimeAvgKsum = (float)logLrtTimeAvgKsum / (self->magnLen);
+  self->featureData[3] = logLrtTimeAvgKsum;
+  // Done with computation of LR factor.
 
-  //
-  // compute the indicator functions
-  //
-
-  // average lrt feature
+  // Compute the indicator functions.
+  // Average LRT feature.
   widthPrior = widthPrior0;
-  // use larger width in tanh map for pause regions
+  // Use larger width in tanh map for pause regions.
   if (logLrtTimeAvgKsum < threshPrior0) {
     widthPrior = widthPrior1;
   }
-  // compute indicator function: sigmoid map
+  // Compute indicator function: sigmoid map.
   indicator0 =
       0.5f *
       ((float)tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.f);
 
-  // spectral flatness feature
-  tmpFloat1 = inst->featureData[0];
+  // Spectral flatness feature.
+  tmpFloat1 = self->featureData[0];
   widthPrior = widthPrior0;
-  // use larger width in tanh map for pause regions
+  // Use larger width in tanh map for pause regions.
   if (sgnMap == 1 && (tmpFloat1 > threshPrior1)) {
     widthPrior = widthPrior1;
   }
   if (sgnMap == -1 && (tmpFloat1 < threshPrior1)) {
     widthPrior = widthPrior1;
   }
-  // compute indicator function: sigmoid map
+  // Compute indicator function: sigmoid map.
   indicator1 =
       0.5f *
       ((float)tanh((float)sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) +
        1.f);
 
-  // for template spectrum-difference
-  tmpFloat1 = inst->featureData[4];
+  // For template spectrum-difference.
+  tmpFloat1 = self->featureData[4];
   widthPrior = widthPrior0;
-  // use larger width in tanh map for pause regions
+  // Use larger width in tanh map for pause regions.
   if (tmpFloat1 < threshPrior2) {
     widthPrior = widthPrior2;
   }
-  // compute indicator function: sigmoid map
+  // Compute indicator function: sigmoid map.
   indicator2 =
       0.5f * ((float)tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.f);
 
-  // combine the indicator function with the feature weights
+  // Combine the indicator function with the feature weights.
   indPrior = weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 +
              weightIndPrior2 * indicator2;
-  // done with computing indicator function
+  // Done with computing indicator function.
 
-  // compute the prior probability
-  inst->priorSpeechProb += PRIOR_UPDATE * (indPrior - inst->priorSpeechProb);
-  // make sure probabilities are within range: keep floor to 0.01
-  if (inst->priorSpeechProb > 1.f) {
-    inst->priorSpeechProb = 1.f;
+  // Compute the prior probability.
+  self->priorSpeechProb += PRIOR_UPDATE * (indPrior - self->priorSpeechProb);
+  // Make sure probabilities are within range: keep floor to 0.01.
+  if (self->priorSpeechProb > 1.f) {
+    self->priorSpeechProb = 1.f;
   }
-  if (inst->priorSpeechProb < 0.01f) {
-    inst->priorSpeechProb = 0.01f;
+  if (self->priorSpeechProb < 0.01f) {
+    self->priorSpeechProb = 0.01f;
   }
 
-  // final speech probability: combine prior model with LR factor:
-  gainPrior = (1.f - inst->priorSpeechProb) / (inst->priorSpeechProb + 0.0001f);
-  for (i = 0; i < inst->magnLen; i++) {
-    invLrt = (float)exp(-inst->logLrtTimeAvg[i]);
+  // Final speech probability: combine prior model with LR factor:.
+  gainPrior = (1.f - self->priorSpeechProb) / (self->priorSpeechProb + 0.0001f);
+  for (i = 0; i < self->magnLen; i++) {
+    invLrt = (float)exp(-self->logLrtTimeAvg[i]);
     invLrt = (float)gainPrior * invLrt;
     probSpeechFinal[i] = 1.f / (1.f + invLrt);
   }
 }
 
-int WebRtcNs_AnalyzeCore(NSinst_t* inst, float* speechFrame) {
+// Update the noise features.
+// Inputs:
+//   * |magn| is the signal magnitude spectrum estimate.
+//   * |updateParsFlag| is an update flag for parameters.
+static void FeatureUpdate(NSinst_t* self,
+                          const float* magn,
+                          int updateParsFlag) {
+  // Compute spectral flatness on input spectrum.
+  ComputeSpectralFlatness(self, magn);
+  // Compute difference of input spectrum with learned/estimated noise spectrum.
+  ComputeSpectralDifference(self, magn);
+  // Compute histograms for parameter decisions (thresholds and weights for
+  // features).
+  // Parameters are extracted once every window time.
+  // (=self->modelUpdatePars[1])
+  if (updateParsFlag >= 1) {
+    // Counter update.
+    self->modelUpdatePars[3]--;
+    // Update histogram.
+    if (self->modelUpdatePars[3] > 0) {
+      FeatureParameterExtraction(self, 0);
+    }
+    // Compute model parameters.
+    if (self->modelUpdatePars[3] == 0) {
+      FeatureParameterExtraction(self, 1);
+      self->modelUpdatePars[3] = self->modelUpdatePars[1];
+      // If wish to update only once, set flag to zero.
+      if (updateParsFlag == 1) {
+        self->modelUpdatePars[0] = 0;
+      } else {
+        // Update every window:
+        // Get normalization for spectral difference for next window estimate.
+        self->featureData[6] =
+            self->featureData[6] / ((float)self->modelUpdatePars[1]);
+        self->featureData[5] =
+            0.5f * (self->featureData[6] + self->featureData[5]);
+        self->featureData[6] = 0.f;
+      }
+    }
+  }
+}
+
+// Update the noise estimate.
+// Inputs:
+//   * |magn| is the signal magnitude spectrum estimate.
+//   * |snrLocPrior| is the prior SNR.
+//   * |snrLocPost| is the post SNR.
+// Output:
+//   * |noise| is the updated noise magnitude spectrum estimate.
+static void UpdateNoiseEstimate(NSinst_t* self,
+                                const float* magn,
+                                const float* snrLocPrior,
+                                const float* snrLocPost,
+                                float* noise) {
+  int i;
+  float probSpeech, probNonSpeech;
+  // Time-avg parameter for noise update.
+  float gammaNoiseTmp = NOISE_UPDATE;
+  float gammaNoiseOld;
+  float noiseUpdateTmp;
+
+  for (i = 0; i < self->magnLen; i++) {
+    probSpeech = self->speechProb[i];
+    probNonSpeech = 1.f - probSpeech;
+    // Temporary noise update:
+    // Use it for speech frames if update value is less than previous.
+    noiseUpdateTmp = gammaNoiseTmp * self->noisePrev[i] +
+                     (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
+                                              probSpeech * self->noisePrev[i]);
+    // Time-constant based on speech/noise state.
+    gammaNoiseOld = gammaNoiseTmp;
+    gammaNoiseTmp = NOISE_UPDATE;
+    // Increase gamma (i.e., less noise update) for frame likely to be speech.
+    if (probSpeech > PROB_RANGE) {
+      gammaNoiseTmp = SPEECH_UPDATE;
+    }
+    // Conservative noise update.
+    if (probSpeech < PROB_RANGE) {
+      self->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - self->magnAvgPause[i]);
+    }
+    // Noise update.
+    if (gammaNoiseTmp == gammaNoiseOld) {
+      noise[i] = noiseUpdateTmp;
+    } else {
+      noise[i] = gammaNoiseTmp * self->noisePrev[i] +
+                 (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
+                                          probSpeech * self->noisePrev[i]);
+      // Allow for noise update downwards:
+      // If noise update decreases the noise, it is safe, so allow it to
+      // happen.
+      if (noiseUpdateTmp < noise[i]) {
+        noise[i] = noiseUpdateTmp;
+      }
+    }
+  }  // End of freq loop.
+}
+
+// Updates |buffer| with a new |frame|.
+// Inputs:
+//   * |frame| is a new speech frame or NULL for setting to zero.
+//   * |frame_length| is the length of the new frame.
+//   * |buffer_length| is the length of the buffer.
+// Output:
+//   * |buffer| is the updated buffer.
+static void UpdateBuffer(const float* frame,
+                         int frame_length,
+                         int buffer_length,
+                         float* buffer) {
+  assert(buffer_length < 2 * frame_length);
+
+  memcpy(buffer,
+         buffer + frame_length,
+         sizeof(*buffer) * (buffer_length - frame_length));
+  if (frame) {
+    memcpy(buffer + buffer_length - frame_length,
+           frame,
+           sizeof(*buffer) * frame_length);
+  } else {
+    memset(buffer + buffer_length - frame_length,
+           0,
+           sizeof(*buffer) * frame_length);
+  }
+}
+
+// Transforms the signal from time to frequency domain.
+// Inputs:
+//   * |time_data| is the signal in the time domain.
+//   * |time_data_length| is the length of the analysis buffer.
+//   * |magnitude_length| is the length of the spectrum magnitude, which equals
+//     the length of both |real| and |imag| (time_data_length / 2 + 1).
+// Outputs:
+//   * |time_data| is the signal in the frequency domain.
+//   * |real| is the real part of the frequency domain.
+//   * |imag| is the imaginary part of the frequency domain.
+//   * |magn| is the calculated signal magnitude in the frequency domain.
+static void FFT(NSinst_t* self,
+                float* time_data,
+                int time_data_length,
+                int magnitude_length,
+                float* real,
+                float* imag,
+                float* magn) {
+  int i;
+
+  assert(magnitude_length == time_data_length / 2 + 1);
+
+  WebRtc_rdft(time_data_length, 1, time_data, self->ip, self->wfft);
+
+  imag[0] = 0;
+  real[0] = time_data[0];
+  magn[0] = fabs(real[0]) + 1.f;
+  imag[magnitude_length - 1] = 0;
+  real[magnitude_length - 1] = time_data[1];
+  magn[magnitude_length - 1] = fabs(real[magnitude_length - 1]) + 1.f;
+  for (i = 1; i < magnitude_length - 1; ++i) {
+    real[i] = time_data[2 * i];
+    imag[i] = time_data[2 * i + 1];
+    // Magnitude spectrum.
+    magn[i] = sqrtf(real[i] * real[i] + imag[i] * imag[i]) + 1.f;
+  }
+}
+
+// Transforms the signal from frequency to time domain.
+// Inputs:
+//   * |real| is the real part of the frequency domain.
+//   * |imag| is the imaginary part of the frequency domain.
+//   * |magnitude_length| is the length of the spectrum magnitude, which equals
+//     the length of both |real| and |imag|.
+//   * |time_data_length| is the length of the analysis buffer
+//     (2 * (magnitude_length - 1)).
+// Output:
+//   * |time_data| is the signal in the time domain.
+static void IFFT(NSinst_t* self,
+                 const float* real,
+                 const float* imag,
+                 int magnitude_length,
+                 int time_data_length,
+                 float* time_data) {
+  int i;
+
+  assert(time_data_length == 2 * (magnitude_length - 1));
+
+  time_data[0] = real[0];
+  time_data[1] = real[magnitude_length - 1];
+  for (i = 1; i < magnitude_length - 1; ++i) {
+    time_data[2 * i] = real[i];
+    time_data[2 * i + 1] = imag[i];
+  }
+  WebRtc_rdft(time_data_length, -1, time_data, self->ip, self->wfft);
+
+  for (i = 0; i < time_data_length; ++i) {
+    time_data[i] *= 2.f / time_data_length;  // FFT scaling.
+  }
+}
+
+// Calculates the energy of a buffer.
+// Inputs:
+//   * |buffer| is the buffer over which the energy is calculated.
+//   * |length| is the length of the buffer.
+// Returns the calculated energy.
+static float Energy(const float* buffer, int length) {
+  int i;
+  float energy = 0.f;
+
+  for (i = 0; i < length; ++i) {
+    energy += buffer[i] * buffer[i];
+  }
+
+  return energy;
+}
+
+// Windows a buffer.
+// Inputs:
+//   * |window| is the window by which to multiply.
+//   * |data| is the data without windowing.
+//   * |length| is the length of the window and data.
+// Output:
+//   * |data_windowed| is the windowed data.
+static void Windowing(const float* window,
+                      const float* data,
+                      int length,
+                      float* data_windowed) {
+  int i;
+
+  for (i = 0; i < length; ++i) {
+    data_windowed[i] = window[i] * data[i];
+  }
+}
+
+// Estimate prior SNR decision-directed and compute DD based Wiener Filter.
+// Input:
+//   * |magn| is the signal magnitude spectrum estimate.
+// Output:
+//   * |theFilter| is the frequency response of the computed Wiener filter.
+static void ComputeDdBasedWienerFilter(const NSinst_t* self,
+                                       const float* magn,
+                                       float* theFilter) {
+  int i;
+  float snrPrior, previousEstimateStsa, currentEstimateStsa;
+
+  for (i = 0; i < self->magnLen; i++) {
+    // Previous estimate: based on previous frame with gain filter.
+    previousEstimateStsa = self->magnPrevProcess[i] /
+                           (self->noisePrev[i] + 0.0001f) * self->smooth[i];
+    // Post and prior SNR.
+    currentEstimateStsa = 0.f;
+    if (magn[i] > self->noise[i]) {
+      currentEstimateStsa = magn[i] / (self->noise[i] + 0.0001f) - 1.f;
+    }
+    // DD estimate is sum of two terms: current estimate and previous estimate.
+    // Directed decision update of |snrPrior|.
+    snrPrior = DD_PR_SNR * previousEstimateStsa +
+               (1.f - DD_PR_SNR) * currentEstimateStsa;
+    // Gain filter.
+    theFilter[i] = snrPrior / (self->overdrive + snrPrior);
+  }  // End of loop over frequencies.
+}
+
+// Changes the aggressiveness of the noise suppression method.
+// |mode| = 0 is mild (6dB), |mode| = 1 is medium (10dB) and |mode| = 2 is
+// aggressive (15dB).
+// Returns 0 on success and -1 otherwise.
+int WebRtcNs_set_policy_core(NSinst_t* self, int mode) {
+  // Allow for modes: 0, 1, 2, 3.
+  if (mode < 0 || mode > 3) {
+    return (-1);
+  }
+
+  self->aggrMode = mode;
+  if (mode == 0) {
+    self->overdrive = 1.f;
+    self->denoiseBound = 0.5f;
+    self->gainmap = 0;
+  } else if (mode == 1) {
+    // self->overdrive = 1.25f;
+    self->overdrive = 1.f;
+    self->denoiseBound = 0.25f;
+    self->gainmap = 1;
+  } else if (mode == 2) {
+    // self->overdrive = 1.25f;
+    self->overdrive = 1.1f;
+    self->denoiseBound = 0.125f;
+    self->gainmap = 1;
+  } else if (mode == 3) {
+    // self->overdrive = 1.3f;
+    self->overdrive = 1.25f;
+    self->denoiseBound = 0.09f;
+    self->gainmap = 1;
+  }
+  return 0;
+}
+
+int WebRtcNs_AnalyzeCore(NSinst_t* self, float* speechFrame) {
   int i;
   const int kStartBand = 5;  // Skip first frequency bins during estimation.
   int updateParsFlag;
   float energy;
-  float signalEnergy, sumMagn;
-  float tmpFloat1, tmpFloat2, tmpFloat3, probSpeech, probNonSpeech;
-  float gammaNoiseTmp, gammaNoiseOld;
-  float noiseUpdateTmp, fTmp;
+  float signalEnergy = 0.f;
+  float sumMagn = 0.f;
+  float tmpFloat1, tmpFloat2, tmpFloat3;
   float winData[ANAL_BLOCKL_MAX];
   float magn[HALF_ANAL_BLOCKL], noise[HALF_ANAL_BLOCKL];
   float snrLocPost[HALF_ANAL_BLOCKL], snrLocPrior[HALF_ANAL_BLOCKL];
-  float previousEstimateStsa[HALF_ANAL_BLOCKL];
   float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
-  // Variables during startup
+  // Variables during startup.
   float sum_log_i = 0.0;
   float sum_log_i_square = 0.0;
   float sum_log_magn = 0.0;
@@ -772,30 +1061,19 @@
   float parametric_exp = 0.0;
   float parametric_num = 0.0;
 
-  // Check that initiation has been done
-  if (inst->initFlag != 1) {
+  // Check that initiation has been done.
+  if (self->initFlag != 1) {
     return (-1);
   }
-  //
-  updateParsFlag = inst->modelUpdatePars[0];
-  //
+  updateParsFlag = self->modelUpdatePars[0];
 
-  // update analysis buffer for L band
-  memcpy(inst->analyzeBuf,
-         inst->analyzeBuf + inst->blockLen,
-         sizeof(float) * (inst->anaLen - inst->blockLen));
-  memcpy(inst->analyzeBuf + inst->anaLen - inst->blockLen,
-         speechFrame,
-         sizeof(float) * inst->blockLen);
+  // Update analysis buffer for L band.
+  UpdateBuffer(speechFrame, self->blockLen, self->anaLen, self->analyzeBuf);
 
-  // windowing
-  energy = 0.0;
-  for (i = 0; i < inst->anaLen; i++) {
-    winData[i] = inst->window[i] * inst->analyzeBuf[i];
-    energy += winData[i] * winData[i];
-  }
+  Windowing(self->window, self->analyzeBuf, self->anaLen, winData);
+  energy = Energy(winData, self->anaLen);
   if (energy == 0.0) {
-    // we want to avoid updating statistics in this case:
+    // We want to avoid updating statistics in this case:
     // Updating feature statistics when we have zeros only will cause
     // thresholds to move towards zero signal situations. This in turn has the
     // effect that once the signal is "turned on" (non-zero values) everything
@@ -806,38 +1084,14 @@
     return 0;
   }
 
-  //
-  inst->blockInd++;  // Update the block index only when we process a block.
-  // FFT
-  WebRtc_rdft(inst->anaLen, 1, winData, inst->ip, inst->wfft);
+  self->blockInd++;  // Update the block index only when we process a block.
 
-  imag[0] = 0;
-  real[0] = winData[0];
-  magn[0] = fabs(real[0]) + 1.f;
-  imag[inst->magnLen - 1] = 0;
-  real[inst->magnLen - 1] = winData[1];
-  magn[inst->magnLen - 1] = fabs(real[inst->magnLen - 1]) + 1.f;
-  signalEnergy = (float)(real[0] * real[0]) +
-                 (float)(real[inst->magnLen - 1] * real[inst->magnLen - 1]);
-  sumMagn = magn[0] + magn[inst->magnLen - 1];
-  if (inst->blockInd < END_STARTUP_SHORT) {
-    tmpFloat2 = log((float)(inst->magnLen - 1));
-    sum_log_i = tmpFloat2;
-    sum_log_i_square = tmpFloat2 * tmpFloat2;
-    tmpFloat1 = log(magn[inst->magnLen - 1]);
-    sum_log_magn = tmpFloat1;
-    sum_log_i_log_magn = tmpFloat2 * tmpFloat1;
-  }
-  for (i = 1; i < inst->magnLen - 1; i++) {
-    real[i] = winData[2 * i];
-    imag[i] = winData[2 * i + 1];
-    // magnitude spectrum
-    fTmp = real[i] * real[i];
-    fTmp += imag[i] * imag[i];
-    signalEnergy += fTmp;
-    magn[i] = ((float)sqrt(fTmp)) + 1.f;
+  FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
+
+  for (i = 0; i < self->magnLen; i++) {
+    signalEnergy += real[i] * real[i] + imag[i] * imag[i];
     sumMagn += magn[i];
-    if (inst->blockInd < END_STARTUP_SHORT) {
+    if (self->blockInd < END_STARTUP_SHORT) {
       if (i >= kStartBand) {
         tmpFloat2 = log((float)i);
         sum_log_i += tmpFloat2;
@@ -848,199 +1102,106 @@
       }
     }
   }
-  signalEnergy = signalEnergy / ((float)inst->magnLen);
-  inst->signalEnergy = signalEnergy;
-  inst->sumMagn = sumMagn;
+  signalEnergy = signalEnergy / ((float)self->magnLen);
+  self->signalEnergy = signalEnergy;
+  self->sumMagn = sumMagn;
 
-  // compute spectral flatness on input spectrum
-  WebRtcNs_ComputeSpectralFlatness(inst, magn);
-  // quantile noise estimate
-  WebRtcNs_NoiseEstimation(inst, magn, noise);
-  // compute simplified noise model during startup
-  if (inst->blockInd < END_STARTUP_SHORT) {
-    // Estimate White noise
-    inst->whiteNoiseLevel += sumMagn / ((float)inst->magnLen) * inst->overdrive;
-    // Estimate Pink noise parameters
-    tmpFloat1 = sum_log_i_square * ((float)(inst->magnLen - kStartBand));
+  // Quantile noise estimate.
+  NoiseEstimation(self, magn, noise);
+  // Compute simplified noise model during startup.
+  if (self->blockInd < END_STARTUP_SHORT) {
+    // Estimate White noise.
+    self->whiteNoiseLevel += sumMagn / ((float)self->magnLen) * self->overdrive;
+    // Estimate Pink noise parameters.
+    tmpFloat1 = sum_log_i_square * ((float)(self->magnLen - kStartBand));
     tmpFloat1 -= (sum_log_i * sum_log_i);
     tmpFloat2 =
         (sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn);
     tmpFloat3 = tmpFloat2 / tmpFloat1;
-    // Constrain the estimated spectrum to be positive
+    // Constrain the estimated spectrum to be positive.
     if (tmpFloat3 < 0.f) {
       tmpFloat3 = 0.f;
     }
-    inst->pinkNoiseNumerator += tmpFloat3;
+    self->pinkNoiseNumerator += tmpFloat3;
     tmpFloat2 = (sum_log_i * sum_log_magn);
-    tmpFloat2 -= ((float)(inst->magnLen - kStartBand)) * sum_log_i_log_magn;
+    tmpFloat2 -= ((float)(self->magnLen - kStartBand)) * sum_log_i_log_magn;
     tmpFloat3 = tmpFloat2 / tmpFloat1;
-    // Constrain the pink noise power to be in the interval [0, 1];
+    // Constrain the pink noise power to be in the interval [0, 1].
     if (tmpFloat3 < 0.f) {
       tmpFloat3 = 0.f;
     }
     if (tmpFloat3 > 1.f) {
       tmpFloat3 = 1.f;
     }
-    inst->pinkNoiseExp += tmpFloat3;
+    self->pinkNoiseExp += tmpFloat3;
 
     // Calculate frequency independent parts of parametric noise estimate.
-    if (inst->pinkNoiseExp > 0.f) {
-      // Use pink noise estimate
+    if (self->pinkNoiseExp > 0.f) {
+      // Use pink noise estimate.
       parametric_num =
-          exp(inst->pinkNoiseNumerator / (float)(inst->blockInd + 1));
-      parametric_num *= (float)(inst->blockInd + 1);
-      parametric_exp = inst->pinkNoiseExp / (float)(inst->blockInd + 1);
+          exp(self->pinkNoiseNumerator / (float)(self->blockInd + 1));
+      parametric_num *= (float)(self->blockInd + 1);
+      parametric_exp = self->pinkNoiseExp / (float)(self->blockInd + 1);
     }
-    for (i = 0; i < inst->magnLen; i++) {
+    for (i = 0; i < self->magnLen; i++) {
       // Estimate the background noise using the white and pink noise
-      // parameters
-      if (inst->pinkNoiseExp == 0.f) {
-        // Use white noise estimate
-        inst->parametricNoise[i] = inst->whiteNoiseLevel;
+      // parameters.
+      if (self->pinkNoiseExp == 0.f) {
+        // Use white noise estimate.
+        self->parametricNoise[i] = self->whiteNoiseLevel;
       } else {
-        // Use pink noise estimate
+        // Use pink noise estimate.
         float use_band = (float)(i < kStartBand ? kStartBand : i);
-        inst->parametricNoise[i] =
+        self->parametricNoise[i] =
             parametric_num / pow(use_band, parametric_exp);
       }
-      // Weight quantile noise with modeled noise
-      noise[i] *= (inst->blockInd);
+      // Weight quantile noise with modeled noise.
+      noise[i] *= (self->blockInd);
       tmpFloat2 =
-          inst->parametricNoise[i] * (END_STARTUP_SHORT - inst->blockInd);
-      noise[i] += (tmpFloat2 / (float)(inst->blockInd + 1));
+          self->parametricNoise[i] * (END_STARTUP_SHORT - self->blockInd);
+      noise[i] += (tmpFloat2 / (float)(self->blockInd + 1));
       noise[i] /= END_STARTUP_SHORT;
     }
   }
-  // compute average signal during END_STARTUP_LONG time:
-  // used to normalize spectral difference measure
-  if (inst->blockInd < END_STARTUP_LONG) {
-    inst->featureData[5] *= inst->blockInd;
-    inst->featureData[5] += signalEnergy;
-    inst->featureData[5] /= (inst->blockInd + 1);
+  // Compute average signal during END_STARTUP_LONG time:
+  // used to normalize spectral difference measure.
+  if (self->blockInd < END_STARTUP_LONG) {
+    self->featureData[5] *= self->blockInd;
+    self->featureData[5] += signalEnergy;
+    self->featureData[5] /= (self->blockInd + 1);
   }
 
-  // start processing at frames == converged+1
-  // STEP 1: compute  prior and post snr based on quantile noise est
-  // compute DD estimate of prior SNR: needed for new method
-  for (i = 0; i < inst->magnLen; i++) {
-    // post snr
-    snrLocPost[i] = 0.f;
-    if (magn[i] > noise[i]) {
-      snrLocPost[i] = magn[i] / (noise[i] + 0.0001f) - 1.f;
-    }
-    // previous post snr
-    // previous estimate: based on previous frame with gain filter
-    previousEstimateStsa[i] = inst->magnPrevAnalyze[i] /
-                              (inst->noisePrev[i] + 0.0001f) * inst->smooth[i];
-    // DD estimate is sum of two terms: current estimate and previous estimate
-    // directed decision update of snrPrior
-    snrLocPrior[i] =
-        DD_PR_SNR * previousEstimateStsa[i] + (1.f - DD_PR_SNR) * snrLocPost[i];
-    // post and prior snr needed for step 2
-  }  // end of loop over freqs
-     // done with step 1: dd computation of prior and post snr
+  // Post and prior SNR needed for SpeechNoiseProb.
+  ComputeSnr(self, magn, noise, snrLocPrior, snrLocPost);
 
-  // STEP 2: compute speech/noise likelihood
-  // compute difference of input spectrum with learned/estimated noise
-  // spectrum
-  WebRtcNs_ComputeSpectralDifference(inst, magn);
-  // compute histograms for parameter decisions (thresholds and weights for
-  // features)
-  // parameters are extracted once every window time
-  // (=inst->modelUpdatePars[1])
-  if (updateParsFlag >= 1) {
-    // counter update
-    inst->modelUpdatePars[3]--;
-    // update histogram
-    if (inst->modelUpdatePars[3] > 0) {
-      WebRtcNs_FeatureParameterExtraction(inst, 0);
-    }
-    // compute model parameters
-    if (inst->modelUpdatePars[3] == 0) {
-      WebRtcNs_FeatureParameterExtraction(inst, 1);
-      inst->modelUpdatePars[3] = inst->modelUpdatePars[1];
-      // if wish to update only once, set flag to zero
-      if (updateParsFlag == 1) {
-        inst->modelUpdatePars[0] = 0;
-      } else {
-        // update every window:
-        // get normalization for spectral difference for next window estimate
-        inst->featureData[6] =
-            inst->featureData[6] / ((float)inst->modelUpdatePars[1]);
-        inst->featureData[5] =
-            0.5f * (inst->featureData[6] + inst->featureData[5]);
-        inst->featureData[6] = 0.f;
-      }
-    }
-  }
-  // compute speech/noise probability
-  WebRtcNs_SpeechNoiseProb(inst, inst->speechProb, snrLocPrior, snrLocPost);
-  // time-avg parameter for noise update
-  gammaNoiseTmp = NOISE_UPDATE;
-  for (i = 0; i < inst->magnLen; i++) {
-    probSpeech = inst->speechProb[i];
-    probNonSpeech = 1.f - probSpeech;
-    // temporary noise update:
-    // use it for speech frames if update value is less than previous
-    noiseUpdateTmp = gammaNoiseTmp * inst->noisePrev[i] +
-                     (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
-                                              probSpeech * inst->noisePrev[i]);
-    //
-    // time-constant based on speech/noise state
-    gammaNoiseOld = gammaNoiseTmp;
-    gammaNoiseTmp = NOISE_UPDATE;
-    // increase gamma (i.e., less noise update) for frame likely to be speech
-    if (probSpeech > PROB_RANGE) {
-      gammaNoiseTmp = SPEECH_UPDATE;
-    }
-    // conservative noise update
-    if (probSpeech < PROB_RANGE) {
-      inst->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - inst->magnAvgPause[i]);
-    }
-    // noise update
-    if (gammaNoiseTmp == gammaNoiseOld) {
-      noise[i] = noiseUpdateTmp;
-    } else {
-      noise[i] = gammaNoiseTmp * inst->noisePrev[i] +
-                 (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
-                                          probSpeech * inst->noisePrev[i]);
-      // allow for noise update downwards:
-      // if noise update decreases the noise, it is safe, so allow it to
-      // happen
-      if (noiseUpdateTmp < noise[i]) {
-        noise[i] = noiseUpdateTmp;
-      }
-    }
-  }  // end of freq loop
-  // done with step 2: noise update
+  FeatureUpdate(self, magn, updateParsFlag);
+  SpeechNoiseProb(self, self->speechProb, snrLocPrior, snrLocPost);
+  UpdateNoiseEstimate(self, magn, snrLocPrior, snrLocPost, noise);
 
-  // keep track of noise spectrum for next frame
-  memcpy(inst->noise, noise, sizeof(*noise) * inst->magnLen);
-  memcpy(inst->magnPrevAnalyze, magn, sizeof(*magn) * inst->magnLen);
+  // Keep track of noise spectrum for next frame.
+  memcpy(self->noise, noise, sizeof(*noise) * self->magnLen);
+  memcpy(self->magnPrevAnalyze, magn, sizeof(*magn) * self->magnLen);
 
   return 0;
 }
 
-int WebRtcNs_ProcessCore(NSinst_t* inst,
+int WebRtcNs_ProcessCore(NSinst_t* self,
                          float* speechFrame,
                          float* speechFrameHB,
                          float* outFrame,
                          float* outFrameHB) {
-  // main routine for noise reduction
+  // Main routine for noise reduction.
   int flagHB = 0;
   int i;
 
   float energy1, energy2, gain, factor, factor1, factor2;
-  float snrPrior, previousEstimateStsa, currentEstimateStsa;
-  float tmpFloat1, tmpFloat2;
-  float fTmp;
   float fout[BLOCKL_MAX];
   float winData[ANAL_BLOCKL_MAX];
   float magn[HALF_ANAL_BLOCKL];
   float theFilter[HALF_ANAL_BLOCKL], theFilterTmp[HALF_ANAL_BLOCKL];
   float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
 
-  // SWB variables
+  // SWB variables.
   int deltaBweHB = 1;
   int deltaGainHB = 1;
   float decayBweHB = 1.0;
@@ -1049,178 +1210,111 @@
   float avgProbSpeechHB, avgProbSpeechHBTmp, avgFilterGainHB, gainModHB;
   float sumMagnAnalyze, sumMagnProcess;
 
-  // Check that initiation has been done
-  if (inst->initFlag != 1) {
+  // Check that initiation has been done.
+  if (self->initFlag != 1) {
     return (-1);
   }
-  // Check for valid pointers based on sampling rate
-  if (inst->fs == 32000) {
+  // Check for valid pointers based on sampling rate.
+  if (self->fs == 32000) {
     if (speechFrameHB == NULL) {
       return -1;
     }
     flagHB = 1;
-    // range for averaging low band quantities for H band gain
-    deltaBweHB = (int)inst->magnLen / 4;
+    // Range for averaging low band quantities for H band gain.
+    deltaBweHB = (int)self->magnLen / 4;
     deltaGainHB = deltaBweHB;
   }
 
-  // update analysis buffer for L band
-  memcpy(inst->dataBuf,
-         inst->dataBuf + inst->blockLen,
-         sizeof(float) * (inst->anaLen - inst->blockLen));
-  memcpy(inst->dataBuf + inst->anaLen - inst->blockLen,
-         speechFrame,
-         sizeof(float) * inst->blockLen);
+  // Update analysis buffer for L band.
+  UpdateBuffer(speechFrame, self->blockLen, self->anaLen, self->dataBuf);
 
   if (flagHB == 1) {
-    // update analysis buffer for H band
-    memcpy(inst->dataBufHB,
-           inst->dataBufHB + inst->blockLen,
-           sizeof(float) * (inst->anaLen - inst->blockLen));
-    memcpy(inst->dataBufHB + inst->anaLen - inst->blockLen,
-           speechFrameHB,
-           sizeof(float) * inst->blockLen);
+    // Update analysis buffer for H band.
+    UpdateBuffer(speechFrameHB, self->blockLen, self->anaLen, self->dataBufHB);
   }
 
-  // windowing
-  energy1 = 0.0;
-  for (i = 0; i < inst->anaLen; i++) {
-    winData[i] = inst->window[i] * inst->dataBuf[i];
-    energy1 += winData[i] * winData[i];
-  }
+  Windowing(self->window, self->dataBuf, self->anaLen, winData);
+  energy1 = Energy(winData, self->anaLen);
   if (energy1 == 0.0) {
-    // synthesize the special case of zero input
-    // read out fully processed segment
-    for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) {
-      fout[i - inst->windShift] = inst->syntBuf[i];
+    // Synthesize the special case of zero input.
+    // Read out fully processed segment.
+    for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
+      fout[i - self->windShift] = self->syntBuf[i];
     }
-    // update synthesis buffer
-    memcpy(inst->syntBuf,
-           inst->syntBuf + inst->blockLen,
-           sizeof(float) * (inst->anaLen - inst->blockLen));
-    memset(inst->syntBuf + inst->anaLen - inst->blockLen,
-           0,
-           sizeof(float) * inst->blockLen);
+    // Update synthesis buffer.
+    UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
 
-    for (i = 0; i < inst->blockLen; ++i)
+    for (i = 0; i < self->blockLen; ++i)
       outFrame[i] =
           WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fout[i], WEBRTC_SPL_WORD16_MIN);
 
-    // for time-domain gain of HB
+    // For time-domain gain of HB.
     if (flagHB == 1)
-      for (i = 0; i < inst->blockLen; ++i)
+      for (i = 0; i < self->blockLen; ++i)
         outFrameHB[i] = WEBRTC_SPL_SAT(
-            WEBRTC_SPL_WORD16_MAX, inst->dataBufHB[i], WEBRTC_SPL_WORD16_MIN);
+            WEBRTC_SPL_WORD16_MAX, self->dataBufHB[i], WEBRTC_SPL_WORD16_MIN);
 
     return 0;
   }
-  // FFT
-  WebRtc_rdft(inst->anaLen, 1, winData, inst->ip, inst->wfft);
 
-  imag[0] = 0;
-  real[0] = winData[0];
-  magn[0] = fabs(real[0]) + 1.f;
-  imag[inst->magnLen - 1] = 0;
-  real[inst->magnLen - 1] = winData[1];
-  magn[inst->magnLen - 1] = fabs(real[inst->magnLen - 1]) + 1.f;
-  if (inst->blockInd < END_STARTUP_SHORT) {
-    inst->initMagnEst[0] += magn[0];
-    inst->initMagnEst[inst->magnLen - 1] += magn[inst->magnLen - 1];
-  }
-  for (i = 1; i < inst->magnLen - 1; i++) {
-    real[i] = winData[2 * i];
-    imag[i] = winData[2 * i + 1];
-    // magnitude spectrum
-    fTmp = real[i] * real[i];
-    fTmp += imag[i] * imag[i];
-    magn[i] = ((float)sqrt(fTmp)) + 1.f;
-    if (inst->blockInd < END_STARTUP_SHORT) {
-      inst->initMagnEst[i] += magn[i];
+  FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
+
+  if (self->blockInd < END_STARTUP_SHORT) {
+    for (i = 0; i < self->magnLen; i++) {
+      self->initMagnEst[i] += magn[i];
     }
   }
 
-  // Compute dd update of prior snr and post snr based on new noise estimate
-  for (i = 0; i < inst->magnLen; i++) {
-    // previous estimate: based on previous frame with gain filter
-    previousEstimateStsa = inst->magnPrevProcess[i] /
-                           (inst->noisePrev[i] + 0.0001f) * inst->smooth[i];
-    // post and prior snr
-    currentEstimateStsa = 0.f;
-    if (magn[i] > inst->noise[i]) {
-      currentEstimateStsa = magn[i] / (inst->noise[i] + 0.0001f) - 1.f;
-    }
-    // DD estimate is sume of two terms: current estimate and previous
-    // estimate
-    // directed decision update of snrPrior
-    snrPrior = DD_PR_SNR * previousEstimateStsa +
-               (1.f - DD_PR_SNR) * currentEstimateStsa;
-    // gain filter
-    tmpFloat1 = inst->overdrive + snrPrior;
-    tmpFloat2 = (float)snrPrior / tmpFloat1;
-    theFilter[i] = (float)tmpFloat2;
-  }  // end of loop over freqs
+  ComputeDdBasedWienerFilter(self, magn, theFilter);
 
-  for (i = 0; i < inst->magnLen; i++) {
-    // flooring bottom
-    if (theFilter[i] < inst->denoiseBound) {
-      theFilter[i] = inst->denoiseBound;
+  for (i = 0; i < self->magnLen; i++) {
+    // Flooring bottom.
+    if (theFilter[i] < self->denoiseBound) {
+      theFilter[i] = self->denoiseBound;
     }
-    // flooring top
+    // Flooring top.
     if (theFilter[i] > 1.f) {
       theFilter[i] = 1.f;
     }
-    if (inst->blockInd < END_STARTUP_SHORT) {
+    if (self->blockInd < END_STARTUP_SHORT) {
       theFilterTmp[i] =
-          (inst->initMagnEst[i] - inst->overdrive * inst->parametricNoise[i]);
-      theFilterTmp[i] /= (inst->initMagnEst[i] + 0.0001f);
-      // flooring bottom
-      if (theFilterTmp[i] < inst->denoiseBound) {
-        theFilterTmp[i] = inst->denoiseBound;
+          (self->initMagnEst[i] - self->overdrive * self->parametricNoise[i]);
+      theFilterTmp[i] /= (self->initMagnEst[i] + 0.0001f);
+      // Flooring bottom.
+      if (theFilterTmp[i] < self->denoiseBound) {
+        theFilterTmp[i] = self->denoiseBound;
       }
-      // flooring top
+      // Flooring top.
       if (theFilterTmp[i] > 1.f) {
         theFilterTmp[i] = 1.f;
       }
-      // Weight the two suppression filters
-      theFilter[i] *= (inst->blockInd);
-      theFilterTmp[i] *= (END_STARTUP_SHORT - inst->blockInd);
+      // Weight the two suppression filters.
+      theFilter[i] *= (self->blockInd);
+      theFilterTmp[i] *= (END_STARTUP_SHORT - self->blockInd);
       theFilter[i] += theFilterTmp[i];
       theFilter[i] /= (END_STARTUP_SHORT);
     }
-    // smoothing
-    inst->smooth[i] = theFilter[i];
-    real[i] *= inst->smooth[i];
-    imag[i] *= inst->smooth[i];
-  }
-  // keep track of magn spectrum for next frame
-  memcpy(inst->magnPrevProcess, magn, sizeof(*magn) * inst->magnLen);
-  memcpy(inst->noisePrev, inst->noise, sizeof(inst->noise[0]) * inst->magnLen);
-  // back to time domain
-  winData[0] = real[0];
-  winData[1] = real[inst->magnLen - 1];
-  for (i = 1; i < inst->magnLen - 1; i++) {
-    winData[2 * i] = real[i];
-    winData[2 * i + 1] = imag[i];
-  }
-  WebRtc_rdft(inst->anaLen, -1, winData, inst->ip, inst->wfft);
 
-  for (i = 0; i < inst->anaLen; i++) {
-    real[i] = 2.f * winData[i] / inst->anaLen;  // fft scaling
+    self->smooth[i] = theFilter[i];
+    real[i] *= self->smooth[i];
+    imag[i] *= self->smooth[i];
   }
+  // Keep track of |magn| spectrum for next frame.
+  memcpy(self->magnPrevProcess, magn, sizeof(*magn) * self->magnLen);
+  memcpy(self->noisePrev, self->noise, sizeof(self->noise[0]) * self->magnLen);
+  // Back to time domain.
+  IFFT(self, real, imag, self->magnLen, self->anaLen, winData);
 
-  // scale factor: only do it after END_STARTUP_LONG time
+  // Scale factor: only do it after END_STARTUP_LONG time.
   factor = 1.f;
-  if (inst->gainmap == 1 && inst->blockInd > END_STARTUP_LONG) {
+  if (self->gainmap == 1 && self->blockInd > END_STARTUP_LONG) {
     factor1 = 1.f;
     factor2 = 1.f;
 
-    energy2 = 0.0;
-    for (i = 0; i < inst->anaLen; i++) {
-      energy2 += (float)real[i] * (float)real[i];
-    }
+    energy2 = Energy(winData, self->anaLen);
     gain = (float)sqrt(energy2 / (energy1 + 1.f));
 
-    // scaling for new version
+    // Scaling for new version.
     if (gain > B_LIM) {
       factor1 = 1.f + 1.3f * (gain - B_LIM);
       if (gain * factor1 > 1.f) {
@@ -1228,46 +1322,43 @@
       }
     }
     if (gain < B_LIM) {
-      // don't reduce scale too much for pause regions:
-      // attenuation here should be controlled by flooring
-      if (gain <= inst->denoiseBound) {
-        gain = inst->denoiseBound;
+      // Don't reduce scale too much for pause regions:
+      // attenuation here should be controlled by flooring.
+      if (gain <= self->denoiseBound) {
+        gain = self->denoiseBound;
       }
       factor2 = 1.f - 0.3f * (B_LIM - gain);
     }
-    // combine both scales with speech/noise prob:
-    // note prior (priorSpeechProb) is not frequency dependent
-    factor = inst->priorSpeechProb * factor1 +
-             (1.f - inst->priorSpeechProb) * factor2;
-  }  // out of inst->gainmap==1
+    // Combine both scales with speech/noise prob:
+    // note prior (priorSpeechProb) is not frequency dependent.
+    factor = self->priorSpeechProb * factor1 +
+             (1.f - self->priorSpeechProb) * factor2;
+  }  // Out of self->gainmap == 1.
 
-  // synthesis
-  for (i = 0; i < inst->anaLen; i++) {
-    inst->syntBuf[i] += factor * inst->window[i] * (float)real[i];
-  }
-  // read out fully processed segment
-  for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) {
-    fout[i - inst->windShift] = inst->syntBuf[i];
-  }
-  // update synthesis buffer
-  memcpy(inst->syntBuf,
-         inst->syntBuf + inst->blockLen,
-         sizeof(float) * (inst->anaLen - inst->blockLen));
-  memset(inst->syntBuf + inst->anaLen - inst->blockLen,
-         0,
-         sizeof(float) * inst->blockLen);
+  Windowing(self->window, winData, self->anaLen, winData);
 
-  for (i = 0; i < inst->blockLen; ++i)
+  // Synthesis.
+  for (i = 0; i < self->anaLen; i++) {
+    self->syntBuf[i] += factor * winData[i];
+  }
+  // Read out fully processed segment.
+  for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
+    fout[i - self->windShift] = self->syntBuf[i];
+  }
+  // Update synthesis buffer.
+  UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
+
+  for (i = 0; i < self->blockLen; ++i)
     outFrame[i] =
         WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fout[i], WEBRTC_SPL_WORD16_MIN);
 
-  // for time-domain gain of HB
+  // For time-domain gain of HB.
   if (flagHB == 1) {
-    // average speech prob from low band
-    // avg over second half (i.e., 4->8kHz) of freq. spectrum
+    // Average speech prob from low band.
+    // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
     avgProbSpeechHB = 0.0;
-    for (i = inst->magnLen - deltaBweHB - 1; i < inst->magnLen - 1; i++) {
-      avgProbSpeechHB += inst->speechProb[i];
+    for (i = self->magnLen - deltaBweHB - 1; i < self->magnLen - 1; i++) {
+      avgProbSpeechHB += self->speechProb[i];
     }
     avgProbSpeechHB = avgProbSpeechHB / ((float)deltaBweHB);
     // If the speech was suppressed by a component between Analyze and
@@ -1275,44 +1366,43 @@
     // for high band suppression purposes.
     sumMagnAnalyze = 0;
     sumMagnProcess = 0;
-    for (i = 0; i < inst->magnLen; ++i) {
-      sumMagnAnalyze += inst->magnPrevAnalyze[i];
-      sumMagnProcess += inst->magnPrevProcess[i];
+    for (i = 0; i < self->magnLen; ++i) {
+      sumMagnAnalyze += self->magnPrevAnalyze[i];
+      sumMagnProcess += self->magnPrevProcess[i];
     }
     avgProbSpeechHB *= sumMagnProcess / sumMagnAnalyze;
-    // average filter gain from low band
-    // average over second half (i.e., 4->8kHz) of freq. spectrum
+    // Average filter gain from low band.
+    // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
     avgFilterGainHB = 0.0;
-    for (i = inst->magnLen - deltaGainHB - 1; i < inst->magnLen - 1; i++) {
-      avgFilterGainHB += inst->smooth[i];
+    for (i = self->magnLen - deltaGainHB - 1; i < self->magnLen - 1; i++) {
+      avgFilterGainHB += self->smooth[i];
     }
     avgFilterGainHB = avgFilterGainHB / ((float)(deltaGainHB));
     avgProbSpeechHBTmp = 2.f * avgProbSpeechHB - 1.f;
-    // gain based on speech prob:
+    // Gain based on speech probability.
     gainModHB = 0.5f * (1.f + (float)tanh(gainMapParHB * avgProbSpeechHBTmp));
-    // combine gain with low band gain
+    // Combine gain with low band gain.
     gainTimeDomainHB = 0.5f * gainModHB + 0.5f * avgFilterGainHB;
     if (avgProbSpeechHB >= 0.5f) {
       gainTimeDomainHB = 0.25f * gainModHB + 0.75f * avgFilterGainHB;
     }
     gainTimeDomainHB = gainTimeDomainHB * decayBweHB;
-    // make sure gain is within flooring range
-    // flooring bottom
-    if (gainTimeDomainHB < inst->denoiseBound) {
-      gainTimeDomainHB = inst->denoiseBound;
+    // Make sure gain is within flooring range.
+    // Flooring bottom.
+    if (gainTimeDomainHB < self->denoiseBound) {
+      gainTimeDomainHB = self->denoiseBound;
     }
-    // flooring top
+    // Flooring top.
     if (gainTimeDomainHB > 1.f) {
       gainTimeDomainHB = 1.f;
     }
-    // apply gain
-    for (i = 0; i < inst->blockLen; i++) {
-      float o = gainTimeDomainHB * inst->dataBufHB[i];
+    // Apply gain.
+    for (i = 0; i < self->blockLen; i++) {
+      float o = gainTimeDomainHB * self->dataBufHB[i];
       outFrameHB[i] =
           WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, o, WEBRTC_SPL_WORD16_MIN);
     }
-  }  // end of H band gain computation
-  //
+  }  // End of H band gain computation.
 
   return 0;
 }
diff --git a/modules/audio_processing/ns/ns_core.h b/modules/audio_processing/ns/ns_core.h
index a4718fb..d20c60b 100644
--- a/modules/audio_processing/ns/ns_core.h
+++ b/modules/audio_processing/ns/ns_core.h
@@ -14,36 +14,36 @@
 #include "webrtc/modules/audio_processing/ns/defines.h"
 
 typedef struct NSParaExtract_t_ {
-  // bin size of histogram
+  // Bin size of histogram.
   float binSizeLrt;
   float binSizeSpecFlat;
   float binSizeSpecDiff;
-  // range of histogram over which lrt threshold is computed
+  // Range of histogram over which LRT threshold is computed.
   float rangeAvgHistLrt;
-  // scale parameters: multiply dominant peaks of the histograms by scale factor
-  // to obtain thresholds for prior model
-  float factor1ModelPars;  // for lrt and spectral difference
-  float factor2ModelPars;  // for spectral_flatness: used when noise is flatter
-                           // than speech
-  // peak limit for spectral flatness (varies between 0 and 1)
+  // Scale parameters: multiply dominant peaks of the histograms by scale factor
+  // to obtain thresholds for prior model.
+  float factor1ModelPars;  // For LRT and spectral difference.
+  float factor2ModelPars;  // For spectral_flatness: used when noise is flatter
+                           // than speech.
+  // Peak limit for spectral flatness (varies between 0 and 1).
   float thresPosSpecFlat;
-  // limit on spacing of two highest peaks in histogram: spacing determined by
-  // bin size
+  // Limit on spacing of two highest peaks in histogram: spacing determined by
+  // bin size.
   float limitPeakSpacingSpecFlat;
   float limitPeakSpacingSpecDiff;
-  // limit on relevance of second peak:
+  // Limit on relevance of second peak.
   float limitPeakWeightsSpecFlat;
   float limitPeakWeightsSpecDiff;
-  // limit on fluctuation of lrt feature
+  // Limit on fluctuation of LRT feature.
   float thresFluctLrt;
-  // limit on the max and min values for the feature thresholds
+  // Limit on the max and min values for the feature thresholds.
   float maxLrt;
   float minLrt;
   float maxSpecFlat;
   float minSpecFlat;
   float maxSpecDiff;
   float minSpecDiff;
-  // criteria of weight of histogram peak  to accept/reject feature
+  // Criteria of weight of histogram peak to accept/reject feature.
   int thresWeightSpecFlat;
   int thresWeightSpecDiff;
 
@@ -62,51 +62,53 @@
   float syntBuf[ANAL_BLOCKL_MAX];
 
   int initFlag;
-  // parameters for quantile noise estimation
+  // Parameters for quantile noise estimation.
   float density[SIMULT * HALF_ANAL_BLOCKL];
   float lquantile[SIMULT * HALF_ANAL_BLOCKL];
   float quantile[HALF_ANAL_BLOCKL];
   int counter[SIMULT];
   int updates;
-  // parameters for Wiener filter
+  // Parameters for Wiener filter.
   float smooth[HALF_ANAL_BLOCKL];
   float overdrive;
   float denoiseBound;
   int gainmap;
-  // fft work arrays.
+  // FFT work arrays.
   int ip[IP_LENGTH];
   float wfft[W_LENGTH];
 
-  // parameters for new method: some not needed, will reduce/cleanup later
-  int32_t blockInd;  // frame index counter
-  int modelUpdatePars[4];  // parameters for updating or estimating
-  // thresholds/weights for prior model
-  float priorModelPars[7];  // parameters for prior model
-  float noise[HALF_ANAL_BLOCKL];      // noise spectrum from current frame
-  float noisePrev[HALF_ANAL_BLOCKL];  // noise spectrum from previous frame
-  // magnitude spectrum of previous analyze frame
+  // Parameters for new method: some not needed, will reduce/cleanup later.
+  int32_t blockInd;  // Frame index counter.
+  int modelUpdatePars[4];  // Parameters for updating or estimating.
+  // Thresholds/weights for prior model.
+  float priorModelPars[7];  // Parameters for prior model.
+  float noise[HALF_ANAL_BLOCKL];  // Noise spectrum from current frame.
+  float noisePrev[HALF_ANAL_BLOCKL];  // Noise spectrum from previous frame.
+  // Magnitude spectrum of previous analyze frame.
   float magnPrevAnalyze[HALF_ANAL_BLOCKL];
-  // magnitude spectrum of previous process frame
+  // Magnitude spectrum of previous process frame.
   float magnPrevProcess[HALF_ANAL_BLOCKL];
-  float logLrtTimeAvg[HALF_ANAL_BLOCKL];  // log lrt factor with time-smoothing
-  float priorSpeechProb;  // prior speech/noise probability
-  float featureData[7];  // data for features
-  float magnAvgPause[HALF_ANAL_BLOCKL];  // conservative noise spectrum estimate
-  float signalEnergy;  // energy of magn
-  float sumMagn;  // sum of magn
-  float whiteNoiseLevel;  // initial noise estimate
-  float initMagnEst[HALF_ANAL_BLOCKL];  // initial magnitude spectrum estimate
-  float pinkNoiseNumerator;  // pink noise parameter: numerator
-  float pinkNoiseExp;  // pink noise parameter: power of freq
+  float logLrtTimeAvg[HALF_ANAL_BLOCKL];  // Log LRT factor with time-smoothing.
+  float priorSpeechProb;  // Prior speech/noise probability.
+  float featureData[7];
+  // Conservative noise spectrum estimate.
+  float magnAvgPause[HALF_ANAL_BLOCKL];
+  float signalEnergy;  // Energy of |magn|.
+  float sumMagn;
+  float whiteNoiseLevel;  // Initial noise estimate.
+  float initMagnEst[HALF_ANAL_BLOCKL];  // Initial magnitude spectrum estimate.
+  float pinkNoiseNumerator;  // Pink noise parameter: numerator.
+  float pinkNoiseExp;  // Pink noise parameter: power of frequencies.
   float parametricNoise[HALF_ANAL_BLOCKL];
-  NSParaExtract_t featureExtractionParams;  // parameters for feature extraction
-  // histograms for parameter estimation
+  // Parameters for feature extraction.
+  NSParaExtract_t featureExtractionParams;
+  // Histograms for parameter estimation.
   int histLrt[HIST_PAR_EST];
   int histSpecFlat[HIST_PAR_EST];
   int histSpecDiff[HIST_PAR_EST];
-  // quantities for high band estimate
-  float speechProb[HALF_ANAL_BLOCKL];  // final speech/noise prob: prior + LRT
-  float dataBufHB[ANAL_BLOCKL_MAX];  // buffering data for HB
+  // Quantities for high band estimate.
+  float speechProb[HALF_ANAL_BLOCKL];  // Final speech/noise prob: prior + LRT.
+  float dataBufHB[ANAL_BLOCKL_MAX];  // Buffering data for HB.
 
 } NSinst_t;
 
@@ -120,16 +122,16 @@
  * This function initializes a noise suppression instance
  *
  * Input:
- *      - inst          : Instance that should be initialized
+ *      - self          : Instance that should be initialized
  *      - fs            : Sampling frequency
  *
  * Output:
- *      - inst          : Initialized instance
+ *      - self          : Initialized instance
  *
  * Return value         :  0 - Ok
  *                        -1 - Error
  */
-int WebRtcNs_InitCore(NSinst_t* inst, uint32_t fs);
+int WebRtcNs_InitCore(NSinst_t* self, uint32_t fs);
 
 /****************************************************************************
  * WebRtcNs_set_policy_core(...)
@@ -137,16 +139,16 @@
  * This changes the aggressiveness of the noise suppression method.
  *
  * Input:
- *      - inst          : Instance that should be initialized
+ *      - self          : Instance that should be initialized
  *      - mode          : 0: Mild (6dB), 1: Medium (10dB), 2: Aggressive (15dB)
  *
  * Output:
- *      - NS_inst      : Initialized instance
+ *      - self          : Initialized instance
  *
  * Return value         :  0 - Ok
  *                        -1 - Error
  */
-int WebRtcNs_set_policy_core(NSinst_t* inst, int mode);
+int WebRtcNs_set_policy_core(NSinst_t* self, int mode);
 
 /****************************************************************************
  * WebRtcNs_AnalyzeCore
@@ -154,16 +156,16 @@
  * Estimate the background noise.
  *
  * Input:
- *      - inst          : Instance that should be initialized
+ *      - self          : Instance that should be initialized
  *      - speechFrame   : Input speech frame for lower band
  *
  * Output:
- *      - inst          : Updated instance
+ *      - self          : Updated instance
  *
  * Return value         :  0 - OK
  *                        -1 - Error
  */
-int WebRtcNs_AnalyzeCore(NSinst_t* inst, float* speechFrame);
+int WebRtcNs_AnalyzeCore(NSinst_t* self, float* speechFrame);
 
 /****************************************************************************
  * WebRtcNs_ProcessCore
@@ -171,19 +173,19 @@
  * Do noise suppression.
  *
  * Input:
- *      - inst          : Instance that should be initialized
+ *      - self          : Instance that should be initialized
  *      - inFrameLow    : Input speech frame for lower band
  *      - inFrameHigh   : Input speech frame for higher band
  *
  * Output:
- *      - inst          : Updated instance
+ *      - self          : Updated instance
  *      - outFrameLow   : Output speech frame for lower band
  *      - outFrameHigh  : Output speech frame for higher band
  *
  * Return value         :  0 - OK
  *                        -1 - Error
  */
-int WebRtcNs_ProcessCore(NSinst_t* inst,
+int WebRtcNs_ProcessCore(NSinst_t* self,
                          float* inFrameLow,
                          float* inFrameHigh,
                          float* outFrameLow,
diff --git a/modules/audio_processing/ns/nsx_core_neon.c b/modules/audio_processing/ns/nsx_core_neon.c
index f249141..93099db 100644
--- a/modules/audio_processing/ns/nsx_core_neon.c
+++ b/modules/audio_processing/ns/nsx_core_neon.c
@@ -490,110 +490,91 @@
 void WebRtcNsx_SynthesisUpdateNeon(NsxInst_t* inst,
                                    int16_t* out_frame,
                                    int16_t gain_factor) {
-  int16_t* ptr_real = &inst->real[0];
-  int16_t* ptr_syn = &inst->synthesisBuffer[0];
-  const int16_t* ptr_window = &inst->window[0];
+  assert(inst->anaLen % 16 == 0);
+  assert(inst->blockLen10ms % 16 == 0);
 
-  // synthesis
-  __asm__ __volatile__("vdup.16 d24, %0" : : "r"(gain_factor) : "d24");
-  // Loop unrolled once. All pointers are incremented in the assembly code.
-  for (; ptr_syn < &inst->synthesisBuffer[inst->anaLen];) {
-    __asm__ __volatile__(
-      // Load variables.
-      "vld1.16 d22, [%[ptr_real]]!\n\t"
-      "vld1.16 d23, [%[ptr_window]]!\n\t"
-      "vld1.16 d25, [%[ptr_syn]]\n\t"
-      // tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-      //           inst->window[i], inst->real[i], 14); // Q0, window in Q14
-      "vmull.s16 q11, d22, d23\n\t"
-      "vrshrn.i32 d22, q11, #14\n\t"
-      // tmp32 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13);
-      "vmull.s16 q11, d24, d22\n\t"
-      // tmp16b = WebRtcSpl_SatW32ToW16(tmp32); // Q0
-      "vqrshrn.s32 d22, q11, #13\n\t"
-      // inst->synthesisBuffer[i] = WebRtcSpl_AddSatW16(
-      //     inst->synthesisBuffer[i], tmp16b); // Q0
-      "vqadd.s16 d25, d22\n\t"
-      "vst1.16 d25, [%[ptr_syn]]!\n\t"
+  int16_t* preal_start = inst->real;
+  const int16_t* pwindow = inst->window;
+  int16_t* preal_end = preal_start + inst->anaLen;
+  int16_t* psynthesis_buffer = inst->synthesisBuffer;
 
-      // Load variables.
-      "vld1.16 d26, [%[ptr_real]]!\n\t"
-      "vld1.16 d27, [%[ptr_window]]!\n\t"
-      "vld1.16 d28, [%[ptr_syn]]\n\t"
-      // tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-      //           inst->window[i], inst->real[i], 14); // Q0, window in Q14
-      "vmull.s16 q13, d26, d27\n\t"
-      "vrshrn.i32 d26, q13, #14\n\t"
-      // tmp32 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13);
-      "vmull.s16 q13, d24, d26\n\t"
-      // tmp16b = WebRtcSpl_SatW32ToW16(tmp32); // Q0
-      "vqrshrn.s32 d26, q13, #13\n\t"
-      // inst->synthesisBuffer[i] = WebRtcSpl_AddSatW16(
-      //     inst->synthesisBuffer[i], tmp16b); // Q0
-      "vqadd.s16 d28, d26\n\t"
-      "vst1.16 d28, [%[ptr_syn]]!\n\t"
+  while (preal_start < preal_end) {
+    // Loop unroll.
+    int16x8_t window_0 = vld1q_s16(pwindow);
+    int16x8_t real_0 = vld1q_s16(preal_start);
+    int16x8_t synthesis_buffer_0 = vld1q_s16(psynthesis_buffer);
 
-      // Specify constraints.
-      :[ptr_real]"+r"(ptr_real),
-       [ptr_window]"+r"(ptr_window),
-       [ptr_syn]"+r"(ptr_syn)
-      :
-      :"d22", "d23", "d24", "d25", "d26", "d27", "d28", "q11", "q12", "q13"
-    );
+    int16x8_t window_1 = vld1q_s16(pwindow + 8);
+    int16x8_t real_1 = vld1q_s16(preal_start + 8);
+    int16x8_t synthesis_buffer_1 = vld1q_s16(psynthesis_buffer + 8);
+
+    int32x4_t tmp32a_0_low = vmull_s16(vget_low_s16(real_0),
+                                       vget_low_s16(window_0));
+    int32x4_t tmp32a_0_high = vmull_s16(vget_high_s16(real_0),
+                                        vget_high_s16(window_0));
+
+    int32x4_t tmp32a_1_low = vmull_s16(vget_low_s16(real_1),
+                                       vget_low_s16(window_1));
+    int32x4_t tmp32a_1_high = vmull_s16(vget_high_s16(real_1),
+                                        vget_high_s16(window_1));
+
+    int16x4_t tmp16a_0_low = vqrshrn_n_s32(tmp32a_0_low, 14);
+    int16x4_t tmp16a_0_high = vqrshrn_n_s32(tmp32a_0_high, 14);
+
+    int16x4_t tmp16a_1_low = vqrshrn_n_s32(tmp32a_1_low, 14);
+    int16x4_t tmp16a_1_high = vqrshrn_n_s32(tmp32a_1_high, 14);
+
+    int32x4_t tmp32b_0_low = vmull_n_s16(tmp16a_0_low, gain_factor);
+    int32x4_t tmp32b_0_high = vmull_n_s16(tmp16a_0_high, gain_factor);
+
+    int32x4_t tmp32b_1_low = vmull_n_s16(tmp16a_1_low, gain_factor);
+    int32x4_t tmp32b_1_high = vmull_n_s16(tmp16a_1_high, gain_factor);
+
+    int16x4_t tmp16b_0_low = vqrshrn_n_s32(tmp32b_0_low, 13);
+    int16x4_t tmp16b_0_high = vqrshrn_n_s32(tmp32b_0_high, 13);
+
+    int16x4_t tmp16b_1_low = vqrshrn_n_s32(tmp32b_1_low, 13);
+    int16x4_t tmp16b_1_high = vqrshrn_n_s32(tmp32b_1_high, 13);
+
+    synthesis_buffer_0 = vqaddq_s16(vcombine_s16(tmp16b_0_low, tmp16b_0_high),
+                                    synthesis_buffer_0);
+    synthesis_buffer_1 = vqaddq_s16(vcombine_s16(tmp16b_1_low, tmp16b_1_high),
+                                    synthesis_buffer_1);
+    vst1q_s16(psynthesis_buffer, synthesis_buffer_0);
+    vst1q_s16(psynthesis_buffer + 8, synthesis_buffer_1);
+
+    pwindow += 16;
+    preal_start += 16;
+    psynthesis_buffer += 16;
   }
 
-  int16_t* ptr_out = &out_frame[0];
-  ptr_syn = &inst->synthesisBuffer[0];
-  // read out fully processed segment
-  for (; ptr_syn < &inst->synthesisBuffer[inst->blockLen10ms];) {
-    // Loop unrolled once. Both pointers are incremented in the assembly code.
-    __asm__ __volatile__(
-      // out_frame[i] = inst->synthesisBuffer[i]; // Q0
-      "vld1.16 {d22, d23}, [%[ptr_syn]]!\n\t"
-      "vld1.16 {d24, d25}, [%[ptr_syn]]!\n\t"
-      "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t"
-      "vst1.16 {d24, d25}, [%[ptr_out]]!\n\t"
-      :[ptr_syn]"+r"(ptr_syn),
-       [ptr_out]"+r"(ptr_out)
-      :
-      :"d22", "d23", "d24", "d25"
-    );
+  // Read out fully processed segment.
+  int16_t * p_start = inst->synthesisBuffer;
+  int16_t * p_end = inst->synthesisBuffer + inst->blockLen10ms;
+  int16_t * p_frame = out_frame;
+  while (p_start < p_end) {
+    int16x8_t frame_0 = vld1q_s16(p_start);
+    vst1q_s16(p_frame, frame_0);
+    p_start += 8;
+    p_frame += 8;
   }
 
   // Update synthesis buffer.
-  // C code:
-  // WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer,
-  //                      inst->synthesisBuffer + inst->blockLen10ms,
-  //                      inst->anaLen - inst->blockLen10ms);
-  ptr_out = &inst->synthesisBuffer[0],
-  ptr_syn = &inst->synthesisBuffer[inst->blockLen10ms];
-  for (; ptr_syn < &inst->synthesisBuffer[inst->anaLen];) {
-    // Loop unrolled once. Both pointers are incremented in the assembly code.
-    __asm__ __volatile__(
-      "vld1.16 {d22, d23}, [%[ptr_syn]]!\n\t"
-      "vld1.16 {d24, d25}, [%[ptr_syn]]!\n\t"
-      "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t"
-      "vst1.16 {d24, d25}, [%[ptr_out]]!\n\t"
-      :[ptr_syn]"+r"(ptr_syn),
-       [ptr_out]"+r"(ptr_out)
-      :
-      :"d22", "d23", "d24", "d25"
-    );
+  int16_t* p_start_src = inst->synthesisBuffer + inst->blockLen10ms;
+  int16_t* p_end_src = inst->synthesisBuffer + inst->anaLen;
+  int16_t* p_start_dst = inst->synthesisBuffer;
+  while (p_start_src < p_end_src) {
+    int16x8_t frame = vld1q_s16(p_start_src);
+    vst1q_s16(p_start_dst, frame);
+    p_start_src += 8;
+    p_start_dst += 8;
   }
 
-  // C code:
-  // WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer
-  //    + inst->anaLen - inst->blockLen10ms, inst->blockLen10ms);
-  __asm__ __volatile__("vdup.16 q10, %0" : : "r"(0) : "q10");
-  for (; ptr_out < &inst->synthesisBuffer[inst->anaLen];) {
-    // Loop unrolled once. Pointer is incremented in the assembly code.
-    __asm__ __volatile__(
-      "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t"
-      "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t"
-      :[ptr_out]"+r"(ptr_out)
-      :
-      :"d20", "d21"
-    );
+  p_start = inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms;
+  p_end = p_start + inst->blockLen10ms;
+  int16x8_t zero = vdupq_n_s16(0);
+  for (;p_start < p_end; p_start += 8) {
+    vst1q_s16(p_start, zero);
   }
 }
 
@@ -601,75 +582,64 @@
 void WebRtcNsx_AnalysisUpdateNeon(NsxInst_t* inst,
                                   int16_t* out,
                                   int16_t* new_speech) {
-
-  int16_t* ptr_ana = &inst->analysisBuffer[inst->blockLen10ms];
-  int16_t* ptr_out = &inst->analysisBuffer[0];
+  assert(inst->blockLen10ms % 16 == 0);
+  assert(inst->anaLen % 16 == 0);
 
   // For lower band update analysis buffer.
   // WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer,
   //                      inst->analysisBuffer + inst->blockLen10ms,
   //                      inst->anaLen - inst->blockLen10ms);
-  for (; ptr_out < &inst->analysisBuffer[inst->anaLen - inst->blockLen10ms];) {
-    // Loop unrolled once, so both pointers are incremented by 8 twice.
-    __asm__ __volatile__(
-      "vld1.16 {d20, d21}, [%[ptr_ana]]!\n\t"
-      "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t"
-      "vld1.16 {d22, d23}, [%[ptr_ana]]!\n\t"
-      "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t"
-      :[ptr_ana]"+r"(ptr_ana),
-       [ptr_out]"+r"(ptr_out)
-      :
-      :"d20", "d21", "d22", "d23"
-    );
+  int16_t* p_start_src = inst->analysisBuffer + inst->blockLen10ms;
+  int16_t* p_end_src = inst->analysisBuffer + inst->anaLen;
+  int16_t* p_start_dst = inst->analysisBuffer;
+  while (p_start_src < p_end_src) {
+    int16x8_t frame = vld1q_s16(p_start_src);
+    vst1q_s16(p_start_dst, frame);
+
+    p_start_src += 8;
+    p_start_dst += 8;
   }
 
   // WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer
   //    + inst->anaLen - inst->blockLen10ms, new_speech, inst->blockLen10ms);
-  for (ptr_ana = new_speech; ptr_out < &inst->analysisBuffer[inst->anaLen];) {
-    // Loop unrolled once, so both pointers are incremented by 8 twice.
-    __asm__ __volatile__(
-      "vld1.16 {d20, d21}, [%[ptr_ana]]!\n\t"
-      "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t"
-      "vld1.16 {d22, d23}, [%[ptr_ana]]!\n\t"
-      "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t"
-      :[ptr_ana]"+r"(ptr_ana),
-       [ptr_out]"+r"(ptr_out)
-      :
-      :"d20", "d21", "d22", "d23"
-    );
+  p_start_src = new_speech;
+  p_end_src = new_speech + inst->blockLen10ms;
+  p_start_dst = inst->analysisBuffer + inst->anaLen - inst->blockLen10ms;
+  while (p_start_src < p_end_src) {
+    int16x8_t frame = vld1q_s16(p_start_src);
+    vst1q_s16(p_start_dst, frame);
+
+    p_start_src += 8;
+    p_start_dst += 8;
   }
 
-  // Window data before FFT
-  const int16_t* ptr_window = &inst->window[0];
-  ptr_out = &out[0];
-  ptr_ana = &inst->analysisBuffer[0];
-  for (; ptr_out < &out[inst->anaLen];) {
+  // Window data before FFT.
+  int16_t* p_start_window = (int16_t*) inst->window;
+  int16_t* p_start_buffer = inst->analysisBuffer;
+  int16_t* p_start_out = out;
+  const int16_t* p_end_out = out + inst->anaLen;
 
-    // Loop unrolled once, so all pointers are incremented by 4 twice.
-    __asm__ __volatile__(
-      "vld1.16 d20, [%[ptr_ana]]!\n\t"
-      "vld1.16 d21, [%[ptr_window]]!\n\t"
-      // out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-      //           inst->window[i], inst->analysisBuffer[i], 14); // Q0
-      "vmull.s16 q10, d20, d21\n\t"
-      "vrshrn.i32 d20, q10, #14\n\t"
-      "vst1.16 d20, [%[ptr_out]]!\n\t"
+  // Load the first element to reduce pipeline bubble.
+  int16x8_t window = vld1q_s16(p_start_window);
+  int16x8_t buffer = vld1q_s16(p_start_buffer);
+  p_start_window += 8;
+  p_start_buffer += 8;
 
-      "vld1.16 d22, [%[ptr_ana]]!\n\t"
-      "vld1.16 d23, [%[ptr_window]]!\n\t"
-      // out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-      //           inst->window[i], inst->analysisBuffer[i], 14); // Q0
-      "vmull.s16 q11, d22, d23\n\t"
-      "vrshrn.i32 d22, q11, #14\n\t"
-      "vst1.16 d22, [%[ptr_out]]!\n\t"
+  while (p_start_out < p_end_out) {
+    // Unroll loop.
+    int32x4_t tmp32_low = vmull_s16(vget_low_s16(window), vget_low_s16(buffer));
+    int32x4_t tmp32_high = vmull_s16(vget_high_s16(window),
+                                     vget_high_s16(buffer));
+    window = vld1q_s16(p_start_window);
+    buffer = vld1q_s16(p_start_buffer);
 
-      // Specify constraints.
-      :[ptr_ana]"+r"(ptr_ana),
-       [ptr_window]"+r"(ptr_window),
-       [ptr_out]"+r"(ptr_out)
-      :
-      :"d20", "d21", "d22", "d23", "q10", "q11"
-    );
+    int16x4_t result_low = vrshrn_n_s32(tmp32_low, 14);
+    int16x4_t result_high = vrshrn_n_s32(tmp32_high, 14);
+    vst1q_s16(p_start_out, vcombine_s16(result_low, result_high));
+
+    p_start_buffer += 8;
+    p_start_window += 8;
+    p_start_out += 8;
   }
 }
 
diff --git a/modules/audio_processing/test/audio_processing_unittest.cc b/modules/audio_processing/test/audio_processing_unittest.cc
index a0fb303..401391a 100644
--- a/modules/audio_processing/test/audio_processing_unittest.cc
+++ b/modules/audio_processing/test/audio_processing_unittest.cc
@@ -66,9 +66,9 @@
                cb->samples_per_channel(),
                cb->num_channels(),
                cb_int.channels());
-  ScaleToFloat(cb_int.data(),
-               cb->samples_per_channel() * cb->num_channels(),
-               cb->data());
+  S16ToFloat(cb_int.data(),
+           cb->samples_per_channel() * cb->num_channels(),
+           cb->data());
 }
 
 void ConvertToFloat(const AudioFrame& frame, ChannelBuffer<float>* cb) {
@@ -96,14 +96,13 @@
 
 void MixStereoToMono(const float* stereo, float* mono,
                      int samples_per_channel) {
-  for (int i = 0; i < samples_per_channel; ++i) {
+  for (int i = 0; i < samples_per_channel; ++i)
     mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
-  }
 }
 
 void MixStereoToMono(const int16_t* stereo, int16_t* mono,
                      int samples_per_channel) {
-  for (int i = 0; i < samples_per_channel; i++)
+  for (int i = 0; i < samples_per_channel; ++i)
     mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
 }
 
@@ -135,7 +134,7 @@
 
 void ScaleFrame(AudioFrame* frame, float scale) {
   for (int i = 0; i < frame->samples_per_channel_ * frame->num_channels_; ++i) {
-    frame->data_[i] = RoundToInt16(frame->data_[i] * scale);
+    frame->data_[i] = FloatS16ToS16(frame->data_[i] * scale);
   }
 }
 
@@ -1650,7 +1649,7 @@
 #endif  // WEBRTC_AUDIOPROC_DEBUG_DUMP
 }
 
-TEST_F(ApmTest, FloatAndIntInterfacesGiveIdenticalResults) {
+TEST_F(ApmTest, FloatAndIntInterfacesGiveSimilarResults) {
   audioproc::OutputData ref_data;
   OpenFileAndReadMessage(ref_filename_, &ref_data);
 
@@ -1679,7 +1678,8 @@
     Init(fapm.get());
 
     ChannelBuffer<int16_t> output_cb(samples_per_channel, num_input_channels);
-    scoped_ptr<int16_t[]> output_int16(new int16_t[output_length]);
+    ChannelBuffer<int16_t> output_int16(samples_per_channel,
+                                        num_input_channels);
 
     int analog_level = 127;
     while (ReadFrame(far_file_, revframe_, revfloat_cb_.get()) &&
@@ -1701,7 +1701,9 @@
       EXPECT_NOERR(fapm->gain_control()->set_stream_analog_level(analog_level));
 
       EXPECT_NOERR(apm_->ProcessStream(frame_));
-      // TODO(ajm): Update to support different output rates.
+      Deinterleave(frame_->data_, samples_per_channel, num_output_channels,
+                   output_int16.channels());
+
       EXPECT_NOERR(fapm->ProcessStream(
           float_cb_->channels(),
           samples_per_channel,
@@ -1711,24 +1713,34 @@
           LayoutFromChannels(num_output_channels),
           float_cb_->channels()));
 
-      // Convert to interleaved int16.
-      ScaleAndRoundToInt16(float_cb_->data(), output_length, output_cb.data());
-      Interleave(output_cb.channels(),
-                 samples_per_channel,
-                 num_output_channels,
-                 output_int16.get());
-      // Verify float and int16 paths produce identical output.
-      EXPECT_EQ(0, memcmp(frame_->data_, output_int16.get(), output_length));
+      FloatToS16(float_cb_->data(), output_length, output_cb.data());
+      for (int j = 0; j < num_output_channels; ++j) {
+        float variance = 0;
+        float snr = ComputeSNR(output_int16.channel(j), output_cb.channel(j),
+                               samples_per_channel, &variance);
+  #if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
+        // There are a few chunks in the fixed-point profile that give low SNR.
+        // Listening confirmed the difference is acceptable.
+        const float kVarianceThreshold = 150;
+        const float kSNRThreshold = 10;
+  #else
+        const float kVarianceThreshold = 20;
+        const float kSNRThreshold = 20;
+  #endif
+        // Skip frames with low energy.
+        if (sqrt(variance) > kVarianceThreshold) {
+          EXPECT_LT(kSNRThreshold, snr);
+        }
+      }
 
       analog_level = fapm->gain_control()->stream_analog_level();
       EXPECT_EQ(apm_->gain_control()->stream_analog_level(),
                 fapm->gain_control()->stream_analog_level());
       EXPECT_EQ(apm_->echo_cancellation()->stream_has_echo(),
                 fapm->echo_cancellation()->stream_has_echo());
-      EXPECT_EQ(apm_->voice_detection()->stream_has_voice(),
-                fapm->voice_detection()->stream_has_voice());
-      EXPECT_EQ(apm_->noise_suppression()->speech_probability(),
-                fapm->noise_suppression()->speech_probability());
+      EXPECT_NEAR(apm_->noise_suppression()->speech_probability(),
+                  fapm->noise_suppression()->speech_probability(),
+                  0.0005);
 
       // Reset in case of downmixing.
       frame_->num_channels_ = test->num_input_channels();
@@ -2002,7 +2014,7 @@
     return false;  // This is expected.
   }
 
-  ScaleToFloat(int_data, frame_size, float_data);
+  S16ToFloat(int_data, frame_size, float_data);
   if (cb->num_channels() == 1) {
     MixStereoToMono(float_data, cb->data(), cb->samples_per_channel());
   } else {
@@ -2109,7 +2121,9 @@
                             int num_output_channels,
                             int num_reverse_channels,
                             std::string output_file_prefix) {
-    scoped_ptr<AudioProcessing> ap(AudioProcessing::Create());
+    Config config;
+    config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
+    scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config));
     EnableAllAPComponents(ap.get());
     ap->Initialize(input_rate,
                    output_rate,
diff --git a/modules/audio_processing/test/process_test.cc b/modules/audio_processing/test/process_test.cc
index b6d51e4..76a916d 100644
--- a/modules/audio_processing/test/process_test.cc
+++ b/modules/audio_processing/test/process_test.cc
@@ -489,7 +489,7 @@
   FILE* aecm_echo_path_in_file = NULL;
   FILE* aecm_echo_path_out_file = NULL;
 
-  scoped_ptr<WavFile> output_wav_file;
+  scoped_ptr<WavWriter> output_wav_file;
   scoped_ptr<RawFile> output_raw_file;
 
   if (pb_filename) {
@@ -637,9 +637,9 @@
         if (!raw_output) {
           // The WAV file needs to be reset every time, because it cant change
           // it's sample rate or number of channels.
-          output_wav_file.reset(new WavFile(out_filename + ".wav",
-                                            output_sample_rate,
-                                            msg.num_output_channels()));
+          output_wav_file.reset(new WavWriter(out_filename + ".wav",
+                                              output_sample_rate,
+                                              msg.num_output_channels()));
         }
 
       } else if (event_msg.type() == Event::REVERSE_STREAM) {
@@ -876,9 +876,9 @@
         if (!raw_output) {
           // The WAV file needs to be reset every time, because it can't change
           // it's sample rate or number of channels.
-          output_wav_file.reset(new WavFile(out_filename + ".wav",
-                                            sample_rate_hz,
-                                            num_capture_output_channels));
+          output_wav_file.reset(new WavWriter(out_filename + ".wav",
+                                              sample_rate_hz,
+                                              num_capture_output_channels));
         }
 
         if (verbose) {
@@ -1029,9 +1029,9 @@
           output_raw_file.reset(new RawFile(out_filename + ".pcm"));
         }
         if (!raw_output && !output_wav_file) {
-          output_wav_file.reset(new WavFile(out_filename + ".wav",
-                                            sample_rate_hz,
-                                            num_capture_output_channels));
+          output_wav_file.reset(new WavWriter(out_filename + ".wav",
+                                              sample_rate_hz,
+                                              num_capture_output_channels));
         }
         WriteIntData(near_frame.data_,
                      size,
diff --git a/modules/audio_processing/test/test_utils.h b/modules/audio_processing/test/test_utils.h
index 61edd8f..d0d08cb 100644
--- a/modules/audio_processing/test/test_utils.h
+++ b/modules/audio_processing/test/test_utils.h
@@ -8,11 +8,12 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <math.h>
 #include <limits>
 
 #include "webrtc/audio_processing/debug.pb.h"
 #include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/wav_writer.h"
+#include "webrtc/common_audio/wav_file.h"
 #include "webrtc/modules/audio_processing/common.h"
 #include "webrtc/modules/audio_processing/include/audio_processing.h"
 #include "webrtc/modules/interface/module_common_types.h"
@@ -49,7 +50,7 @@
 
 static inline void WriteIntData(const int16_t* data,
                                 size_t length,
-                                WavFile* wav_file,
+                                WavWriter* wav_file,
                                 RawFile* raw_file) {
   if (wav_file) {
     wav_file->WriteSamples(data, length);
@@ -62,7 +63,7 @@
 static inline void WriteFloatData(const float* const* data,
                                   size_t samples_per_channel,
                                   int num_channels,
-                                  WavFile* wav_file,
+                                  WavWriter* wav_file,
                                   RawFile* raw_file) {
   size_t length = num_channels * samples_per_channel;
   scoped_ptr<float[]> buffer(new float[length]);
@@ -153,4 +154,26 @@
   return msg->ParseFromArray(bytes.get(), size);
 }
 
+template <typename T>
+float ComputeSNR(const T* ref, const T* test, int length, float* variance) {
+  float mse = 0;
+  float mean = 0;
+  *variance = 0;
+  for (int i = 0; i < length; ++i) {
+    T error = ref[i] - test[i];
+    mse += error * error;
+    *variance += ref[i] * ref[i];
+    mean += ref[i];
+  }
+  mse /= length;
+  *variance /= length;
+  mean /= length;
+  *variance -= mean * mean;
+
+  float snr = 100;  // We assign 100 dB to the zero-error case.
+  if (mse > 0)
+    snr = 10 * log10(*variance / mse);
+  return snr;
+}
+
 }  // namespace webrtc
diff --git a/modules/audio_processing/test/unpack.cc b/modules/audio_processing/test/unpack.cc
index 249b668..ee4e263 100644
--- a/modules/audio_processing/test/unpack.cc
+++ b/modules/audio_processing/test/unpack.cc
@@ -73,9 +73,9 @@
   int num_reverse_channels = 0;
   int num_input_channels = 0;
   int num_output_channels = 0;
-  scoped_ptr<WavFile> reverse_wav_file;
-  scoped_ptr<WavFile> input_wav_file;
-  scoped_ptr<WavFile> output_wav_file;
+  scoped_ptr<WavWriter> reverse_wav_file;
+  scoped_ptr<WavWriter> input_wav_file;
+  scoped_ptr<WavWriter> output_wav_file;
   scoped_ptr<RawFile> reverse_raw_file;
   scoped_ptr<RawFile> input_raw_file;
   scoped_ptr<RawFile> output_raw_file;
@@ -235,15 +235,15 @@
       if (!FLAGS_raw) {
         // The WAV files need to be reset every time, because they cant change
         // their sample rate or number of channels.
-        reverse_wav_file.reset(new WavFile(FLAGS_reverse_file + ".wav",
-                                           reverse_sample_rate,
-                                           num_reverse_channels));
-        input_wav_file.reset(new WavFile(FLAGS_input_file + ".wav",
-                                         input_sample_rate,
-                                         num_input_channels));
-        output_wav_file.reset(new WavFile(FLAGS_output_file + ".wav",
-                                          output_sample_rate,
-                                          num_output_channels));
+        reverse_wav_file.reset(new WavWriter(FLAGS_reverse_file + ".wav",
+                                             reverse_sample_rate,
+                                             num_reverse_channels));
+        input_wav_file.reset(new WavWriter(FLAGS_input_file + ".wav",
+                                           input_sample_rate,
+                                           num_input_channels));
+        output_wav_file.reset(new WavWriter(FLAGS_output_file + ".wav",
+                                            output_sample_rate,
+                                            num_output_channels));
       }
     }
   }
diff --git a/modules/audio_processing_neon.target.darwin-arm.mk b/modules/audio_processing_neon.target.darwin-arm.mk
index fee1901..f3550b5 100644
--- a/modules/audio_processing_neon.target.darwin-arm.mk
+++ b/modules/audio_processing_neon.target.darwin-arm.mk
@@ -94,11 +94,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,6 +116,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -216,11 +219,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -236,6 +241,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing_neon.target.linux-arm.mk b/modules/audio_processing_neon.target.linux-arm.mk
index fee1901..f3550b5 100644
--- a/modules/audio_processing_neon.target.linux-arm.mk
+++ b/modules/audio_processing_neon.target.linux-arm.mk
@@ -94,11 +94,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,6 +116,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -216,11 +219,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -236,6 +241,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing_sse2.target.darwin-x86.mk b/modules/audio_processing_sse2.target.darwin-x86.mk
index b0d022c..2abc781 100644
--- a/modules/audio_processing_sse2.target.darwin-x86.mk
+++ b/modules/audio_processing_sse2.target.darwin-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing_sse2.target.darwin-x86_64.mk b/modules/audio_processing_sse2.target.darwin-x86_64.mk
index e24f149..3de3358 100644
--- a/modules/audio_processing_sse2.target.darwin-x86_64.mk
+++ b/modules/audio_processing_sse2.target.darwin-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing_sse2.target.linux-x86.mk b/modules/audio_processing_sse2.target.linux-x86.mk
index b0d022c..2abc781 100644
--- a/modules/audio_processing_sse2.target.linux-x86.mk
+++ b/modules/audio_processing_sse2.target.linux-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audio_processing_sse2.target.linux-x86_64.mk b/modules/audio_processing_sse2.target.linux-x86_64.mk
index e24f149..3de3358 100644
--- a/modules/audio_processing_sse2.target.linux-x86_64.mk
+++ b/modules/audio_processing_sse2.target.linux-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.darwin-arm.mk b/modules/audioproc_debug_proto.target.darwin-arm.mk
index 067c074..9ffb17b 100644
--- a/modules/audioproc_debug_proto.target.darwin-arm.mk
+++ b/modules/audioproc_debug_proto.target.darwin-arm.mk
@@ -111,11 +111,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -134,6 +136,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -233,11 +236,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -256,6 +261,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.darwin-arm64.mk b/modules/audioproc_debug_proto.target.darwin-arm64.mk
index 72050f3..80cc5b2 100644
--- a/modules/audioproc_debug_proto.target.darwin-arm64.mk
+++ b/modules/audioproc_debug_proto.target.darwin-arm64.mk
@@ -100,11 +100,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -113,6 +115,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -120,6 +123,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -207,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -220,6 +226,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -227,6 +234,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.darwin-mips.mk b/modules/audioproc_debug_proto.target.darwin-mips.mk
index b159859..9a48401 100644
--- a/modules/audioproc_debug_proto.target.darwin-mips.mk
+++ b/modules/audioproc_debug_proto.target.darwin-mips.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -127,6 +129,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -242,6 +247,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.darwin-mips64.mk b/modules/audioproc_debug_proto.target.darwin-mips64.mk
new file mode 100644
index 0000000..04bc712
--- /dev/null
+++ b/modules/audioproc_debug_proto.target.darwin-mips64.mk
@@ -0,0 +1,301 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audioproc_debug_proto_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(gyp_shared_intermediate_dir)/protoc
+
+
+### Generated for rule "third_party_webrtc_modules_modules_gyp_audioproc_debug_proto_target_genproto":
+# "{'inputs': ['../../../tools/protoc_wrapper/protoc_wrapper.py', '$(gyp_shared_intermediate_dir)/protoc'], 'process_outputs_as_sources': '1', 'extension': 'proto', 'outputs': ['$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/%(INPUT_ROOT)s_pb2.py', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/%(INPUT_ROOT)s.pb.cc', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/%(INPUT_ROOT)s.pb.h'], 'rule_name': 'genproto', 'rule_sources': ['audio_processing/debug.proto'], 'action': ['python', '../../../tools/protoc_wrapper/protoc_wrapper.py', '--include', '', '--protobuf', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/%(INPUT_ROOT)s.pb.h', '--proto-in-dir', 'audio_processing', '--proto-in-file', '%(INPUT_ROOT)s$(suffix $<)', '--use-system-protobuf=0', '--', '$(gyp_shared_intermediate_dir)/protoc', '--cpp_out', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing', '--python_out', '$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing'], 'message': 'Generating C++ and Python code from $(RULE_SOURCES)'}":
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_var_prefix := $(GYP_VAR_PREFIX)
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: $(LOCAL_PATH)/third_party/webrtc/modules/audio_processing/debug.proto $(LOCAL_PATH)/tools/protoc_wrapper/protoc_wrapper.py $(gyp_shared_intermediate_dir)/protoc $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing $(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing; cd $(gyp_local_path)/third_party/webrtc/modules; python ../../../tools/protoc_wrapper/protoc_wrapper.py --include "" --protobuf "$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h" --proto-in-dir audio_processing --proto-in-file "debug$(suffix $<)" "--use-system-protobuf=0" -- "$(gyp_shared_intermediate_dir)/protoc" --cpp_out "$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing" --python_out "$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing"
+
+$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.cc: $(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py ;
+$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h: $(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py ;
+
+
+GYP_GENERATED_OUTPUTS := \
+	$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.cc \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+$(gyp_intermediate_dir)/debug.pb.cc: $(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.cc
+	mkdir -p $(@D); cp $< $@
+LOCAL_GENERATED_SOURCES := \
+	$(gyp_intermediate_dir)/debug.pb.cc \
+	$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS := \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing
+
+LOCAL_SRC_FILES :=
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audioproc_debug_proto_gyp
+
+# Alias gyp target name.
+.PHONY: audioproc_debug_proto
+audioproc_debug_proto: third_party_webrtc_modules_audioproc_debug_proto_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audioproc_debug_proto.target.darwin-x86.mk b/modules/audioproc_debug_proto.target.darwin-x86.mk
index 059d6cf..67c7761 100644
--- a/modules/audioproc_debug_proto.target.darwin-x86.mk
+++ b/modules/audioproc_debug_proto.target.darwin-x86.mk
@@ -106,11 +106,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -126,6 +128,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -219,11 +222,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -239,6 +244,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.darwin-x86_64.mk b/modules/audioproc_debug_proto.target.darwin-x86_64.mk
index 5729e02..ac69b6a 100644
--- a/modules/audioproc_debug_proto.target.darwin-x86_64.mk
+++ b/modules/audioproc_debug_proto.target.darwin-x86_64.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -217,11 +220,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.linux-arm.mk b/modules/audioproc_debug_proto.target.linux-arm.mk
index 067c074..9ffb17b 100644
--- a/modules/audioproc_debug_proto.target.linux-arm.mk
+++ b/modules/audioproc_debug_proto.target.linux-arm.mk
@@ -111,11 +111,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -134,6 +136,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -233,11 +236,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -256,6 +261,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.linux-arm64.mk b/modules/audioproc_debug_proto.target.linux-arm64.mk
index 72050f3..80cc5b2 100644
--- a/modules/audioproc_debug_proto.target.linux-arm64.mk
+++ b/modules/audioproc_debug_proto.target.linux-arm64.mk
@@ -100,11 +100,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -113,6 +115,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -120,6 +123,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -207,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -220,6 +226,7 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
@@ -227,6 +234,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.linux-mips.mk b/modules/audioproc_debug_proto.target.linux-mips.mk
index b159859..9a48401 100644
--- a/modules/audioproc_debug_proto.target.linux-mips.mk
+++ b/modules/audioproc_debug_proto.target.linux-mips.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -127,6 +129,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -242,6 +247,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.linux-mips64.mk b/modules/audioproc_debug_proto.target.linux-mips64.mk
new file mode 100644
index 0000000..04bc712
--- /dev/null
+++ b/modules/audioproc_debug_proto.target.linux-mips64.mk
@@ -0,0 +1,301 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_audioproc_debug_proto_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(gyp_shared_intermediate_dir)/protoc
+
+
+### Generated for rule "third_party_webrtc_modules_modules_gyp_audioproc_debug_proto_target_genproto":
+# "{'inputs': ['../../../tools/protoc_wrapper/protoc_wrapper.py', '$(gyp_shared_intermediate_dir)/protoc'], 'process_outputs_as_sources': '1', 'extension': 'proto', 'outputs': ['$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/%(INPUT_ROOT)s_pb2.py', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/%(INPUT_ROOT)s.pb.cc', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/%(INPUT_ROOT)s.pb.h'], 'rule_name': 'genproto', 'rule_sources': ['audio_processing/debug.proto'], 'action': ['python', '../../../tools/protoc_wrapper/protoc_wrapper.py', '--include', '', '--protobuf', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/%(INPUT_ROOT)s.pb.h', '--proto-in-dir', 'audio_processing', '--proto-in-file', '%(INPUT_ROOT)s$(suffix $<)', '--use-system-protobuf=0', '--', '$(gyp_shared_intermediate_dir)/protoc', '--cpp_out', '$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing', '--python_out', '$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing'], 'message': 'Generating C++ and Python code from $(RULE_SOURCES)'}":
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_var_prefix := $(GYP_VAR_PREFIX)
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py: $(LOCAL_PATH)/third_party/webrtc/modules/audio_processing/debug.proto $(LOCAL_PATH)/tools/protoc_wrapper/protoc_wrapper.py $(gyp_shared_intermediate_dir)/protoc $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing $(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing; cd $(gyp_local_path)/third_party/webrtc/modules; python ../../../tools/protoc_wrapper/protoc_wrapper.py --include "" --protobuf "$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h" --proto-in-dir audio_processing --proto-in-file "debug$(suffix $<)" "--use-system-protobuf=0" -- "$(gyp_shared_intermediate_dir)/protoc" --cpp_out "$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing" --python_out "$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing"
+
+$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.cc: $(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py ;
+$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h: $(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py ;
+
+
+GYP_GENERATED_OUTPUTS := \
+	$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.cc \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+$(gyp_intermediate_dir)/debug.pb.cc: $(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.cc
+	mkdir -p $(@D); cp $< $@
+LOCAL_GENERATED_SOURCES := \
+	$(gyp_intermediate_dir)/debug.pb.cc \
+	$(gyp_shared_intermediate_dir)/pyproto/webrtc/audio_processing/debug_pb2.py \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing/debug.pb.h
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS := \
+	$(gyp_shared_intermediate_dir)/protoc_out/webrtc/audio_processing
+
+LOCAL_SRC_FILES :=
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DPROTOBUF_USE_DLLS' \
+	'-DGOOGLE_PROTOBUF_NO_RTTI' \
+	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(gyp_shared_intermediate_dir)/protoc_out \
+	$(LOCAL_PATH)/third_party/protobuf \
+	$(LOCAL_PATH)/third_party/protobuf/src
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_audioproc_debug_proto_gyp
+
+# Alias gyp target name.
+.PHONY: audioproc_debug_proto
+audioproc_debug_proto: third_party_webrtc_modules_audioproc_debug_proto_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/audioproc_debug_proto.target.linux-x86.mk b/modules/audioproc_debug_proto.target.linux-x86.mk
index 059d6cf..67c7761 100644
--- a/modules/audioproc_debug_proto.target.linux-x86.mk
+++ b/modules/audioproc_debug_proto.target.linux-x86.mk
@@ -106,11 +106,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -126,6 +128,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -219,11 +222,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -239,6 +244,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/audioproc_debug_proto.target.linux-x86_64.mk b/modules/audioproc_debug_proto.target.linux-x86_64.mk
index 5729e02..ac69b6a 100644
--- a/modules/audioproc_debug_proto.target.linux-x86_64.mk
+++ b/modules/audioproc_debug_proto.target.linux-x86_64.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -217,11 +220,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DPROTOBUF_USE_DLLS' \
 	'-DGOOGLE_PROTOBUF_NO_RTTI' \
 	'-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.darwin-arm.mk b/modules/bitrate_controller.target.darwin-arm.mk
index 0b66d54..4d956c7 100644
--- a/modules/bitrate_controller.target.darwin-arm.mk
+++ b/modules/bitrate_controller.target.darwin-arm.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -225,6 +230,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.darwin-arm64.mk b/modules/bitrate_controller.target.darwin-arm64.mk
index a9ae88a..07c34c0 100644
--- a/modules/bitrate_controller.target.darwin-arm64.mk
+++ b/modules/bitrate_controller.target.darwin-arm64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -90,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -192,10 +198,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.darwin-mips.mk b/modules/bitrate_controller.target.darwin-mips.mk
index ed387bc..964e171 100644
--- a/modules/bitrate_controller.target.darwin-mips.mk
+++ b/modules/bitrate_controller.target.darwin-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.darwin-mips64.mk b/modules/bitrate_controller.target.darwin-mips64.mk
new file mode 100644
index 0000000..f3802c9
--- /dev/null
+++ b/modules/bitrate_controller.target.darwin-mips64.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_bitrate_controller_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc \
+	third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_bitrate_controller_gyp
+
+# Alias gyp target name.
+.PHONY: bitrate_controller
+bitrate_controller: third_party_webrtc_modules_bitrate_controller_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/bitrate_controller.target.darwin-x86.mk b/modules/bitrate_controller.target.darwin-x86.mk
index def87d2..36529ec 100644
--- a/modules/bitrate_controller.target.darwin-x86.mk
+++ b/modules/bitrate_controller.target.darwin-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.darwin-x86_64.mk b/modules/bitrate_controller.target.darwin-x86_64.mk
index c5e90e9..d7922a5 100644
--- a/modules/bitrate_controller.target.darwin-x86_64.mk
+++ b/modules/bitrate_controller.target.darwin-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.linux-arm.mk b/modules/bitrate_controller.target.linux-arm.mk
index 0b66d54..4d956c7 100644
--- a/modules/bitrate_controller.target.linux-arm.mk
+++ b/modules/bitrate_controller.target.linux-arm.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -205,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -225,6 +230,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.linux-arm64.mk b/modules/bitrate_controller.target.linux-arm64.mk
index a9ae88a..07c34c0 100644
--- a/modules/bitrate_controller.target.linux-arm64.mk
+++ b/modules/bitrate_controller.target.linux-arm64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -90,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -192,10 +198,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.linux-mips.mk b/modules/bitrate_controller.target.linux-mips.mk
index ed387bc..964e171 100644
--- a/modules/bitrate_controller.target.linux-mips.mk
+++ b/modules/bitrate_controller.target.linux-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.linux-mips64.mk b/modules/bitrate_controller.target.linux-mips64.mk
new file mode 100644
index 0000000..f3802c9
--- /dev/null
+++ b/modules/bitrate_controller.target.linux-mips64.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_bitrate_controller_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc \
+	third_party/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_bitrate_controller_gyp
+
+# Alias gyp target name.
+.PHONY: bitrate_controller
+bitrate_controller: third_party_webrtc_modules_bitrate_controller_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/bitrate_controller.target.linux-x86.mk b/modules/bitrate_controller.target.linux-x86.mk
index def87d2..36529ec 100644
--- a/modules/bitrate_controller.target.linux-x86.mk
+++ b/modules/bitrate_controller.target.linux-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller.target.linux-x86_64.mk b/modules/bitrate_controller.target.linux-x86_64.mk
index c5e90e9..d7922a5 100644
--- a/modules/bitrate_controller.target.linux-x86_64.mk
+++ b/modules/bitrate_controller.target.linux-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/bitrate_controller/bitrate_controller_unittest.cc b/modules/bitrate_controller/bitrate_controller_unittest.cc
index 8523d50..fddab9d 100644
--- a/modules/bitrate_controller/bitrate_controller_unittest.cc
+++ b/modules/bitrate_controller/bitrate_controller_unittest.cc
@@ -83,6 +83,27 @@
   controller_->RemoveBitrateObserver(&bitrate_observer);
 }
 
+TEST_F(BitrateControllerTest, InitialRemb) {
+  TestBitrateObserver bitrate_observer;
+  controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 1500000);
+  const uint32_t kRemb = 1000000u;
+  const uint32_t kSecondRemb = kRemb + 500000u;
+
+  // Initial REMB applies immediately.
+  bandwidth_observer_->OnReceivedEstimatedBitrate(kRemb);
+  webrtc::ReportBlockList report_blocks;
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 1));
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1);
+  report_blocks.clear();
+  EXPECT_EQ(kRemb, bitrate_observer.last_bitrate_);
+
+  // Second REMB doesn't apply immediately.
+  bandwidth_observer_->OnReceivedEstimatedBitrate(kRemb + 500000);
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 21));
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001);
+  EXPECT_LT(bitrate_observer.last_bitrate_, kSecondRemb);
+}
+
 TEST_F(BitrateControllerTest, UpdatingBitrateObserver) {
   TestBitrateObserver bitrate_observer;
   controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 1500000);
@@ -105,51 +126,65 @@
   TestBitrateObserver bitrate_observer;
   controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 300000);
 
-  // Receive a high remb, test bitrate inc.
-  bandwidth_observer_->OnReceivedEstimatedBitrate(400000);
+  // First REMB applies immediately.
+  int64_t time_ms = 1001;
+  webrtc::ReportBlockList report_blocks;
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 1));
+  bandwidth_observer_->OnReceivedEstimatedBitrate(200000);
   EXPECT_EQ(200000u, bitrate_observer.last_bitrate_);
   EXPECT_EQ(0, bitrate_observer.last_fraction_loss_);
   EXPECT_EQ(0u, bitrate_observer.last_rtt_);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
+  report_blocks.clear();
+  time_ms += 2000;
+
+  // Receive a high remb, test bitrate inc.
+  bandwidth_observer_->OnReceivedEstimatedBitrate(400000);
 
   // Test bitrate increase 8% per second.
-  webrtc::ReportBlockList report_blocks;
-  report_blocks.push_back(CreateReportBlock(1, 2, 0, 1));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1);
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 21));
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(217000u, bitrate_observer.last_bitrate_);
   EXPECT_EQ(0, bitrate_observer.last_fraction_loss_);
   EXPECT_EQ(50u, bitrate_observer.last_rtt_);
-
-  report_blocks.clear();
-  report_blocks.push_back(CreateReportBlock(1, 2, 0, 21));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1001);
-  EXPECT_EQ(235360u, bitrate_observer.last_bitrate_);
-  EXPECT_EQ(0, bitrate_observer.last_fraction_loss_);
-  EXPECT_EQ(50u, bitrate_observer.last_rtt_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 41));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001);
-  EXPECT_EQ(255189u, bitrate_observer.last_bitrate_);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
+  EXPECT_EQ(235360u, bitrate_observer.last_bitrate_);
+  EXPECT_EQ(0, bitrate_observer.last_fraction_loss_);
+  EXPECT_EQ(50u, bitrate_observer.last_rtt_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 61));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 3001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
+  EXPECT_EQ(255189u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
+
+  report_blocks.clear();
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 81));
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(276604u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 801));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 4001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(299732u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
 
   // Reach max cap.
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 101));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 5001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(300000u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 141));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 7001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(300000u, bitrate_observer.last_bitrate_);
 
   // Test that a low REMB trigger immediately.
@@ -167,78 +202,86 @@
   TestBitrateObserver bitrate_observer;
   controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 300000);
 
+  // REMBs during the first 2 seconds apply immediately.
+  int64_t time_ms = 1;
+  webrtc::ReportBlockList report_blocks;
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 1));
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
+  report_blocks.clear();
+  time_ms += 500;
+
   RtcpBandwidthObserver* second_bandwidth_observer =
       controller_->CreateRtcpBandwidthObserver();
 
-  // Receive a high remb, test bitrate inc.
-  bandwidth_observer_->OnReceivedEstimatedBitrate(400000);
-  EXPECT_EQ(200000u, bitrate_observer.last_bitrate_);
-  EXPECT_EQ(0, bitrate_observer.last_fraction_loss_);
-  EXPECT_EQ(0u, bitrate_observer.last_rtt_);
-
   // Test start bitrate.
-  webrtc::ReportBlockList report_blocks;
-  report_blocks.push_back(CreateReportBlock(1, 2, 0, 1));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1);
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 21));
   second_bandwidth_observer->OnReceivedRtcpReceiverReport(
       report_blocks, 100, 1);
   EXPECT_EQ(217000u, bitrate_observer.last_bitrate_);
   EXPECT_EQ(0, bitrate_observer.last_fraction_loss_);
   EXPECT_EQ(100u, bitrate_observer.last_rtt_);
+  time_ms += 500;
 
   // Test bitrate increase 8% per second.
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 21));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 501);
-  second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 100,
-                                                          1001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
+  time_ms += 500;
+  second_bandwidth_observer->OnReceivedRtcpReceiverReport(
+      report_blocks, 100, time_ms);
   EXPECT_EQ(235360u, bitrate_observer.last_bitrate_);
   EXPECT_EQ(0, bitrate_observer.last_fraction_loss_);
   EXPECT_EQ(100u, bitrate_observer.last_rtt_);
+  time_ms += 500;
 
   // Extra report should not change estimate.
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 31));
-  second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 100,
-                                                          1501);
+  second_bandwidth_observer->OnReceivedRtcpReceiverReport(
+      report_blocks, 100, time_ms);
   EXPECT_EQ(235360u, bitrate_observer.last_bitrate_);
+  time_ms += 500;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 41));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(255189u, bitrate_observer.last_bitrate_);
 
   // Second report should not change estimate.
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 41));
-  second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 100,
-                                                          2001);
+  second_bandwidth_observer->OnReceivedRtcpReceiverReport(
+      report_blocks, 100, time_ms);
   EXPECT_EQ(255189u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
 
   // Reports from only one bandwidth observer is ok.
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 61));
-  second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 50,
-                                                          3001);
+  second_bandwidth_observer->OnReceivedRtcpReceiverReport(
+      report_blocks, 50, time_ms);
   EXPECT_EQ(276604u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 81));
-  second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 50,
-                                                          4001);
+  second_bandwidth_observer->OnReceivedRtcpReceiverReport(
+      report_blocks, 50, time_ms);
   EXPECT_EQ(299732u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
 
   // Reach max cap.
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 121));
   second_bandwidth_observer->OnReceivedRtcpReceiverReport(
-      report_blocks, 50, 5001);
+      report_blocks, 50, time_ms);
   EXPECT_EQ(300000u, bitrate_observer.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 141));
   second_bandwidth_observer->OnReceivedRtcpReceiverReport(
-      report_blocks, 50, 6001);
+      report_blocks, 50, time_ms);
   EXPECT_EQ(300000u, bitrate_observer.last_bitrate_);
 
   // Test that a low REMB trigger immediately.
@@ -264,11 +307,18 @@
   controller_->SetBitrateObserver(&bitrate_observer, kStartBitrate, kMinBitrate,
                                   kMaxBitrate);
 
+  // REMBs during the first 2 seconds apply immediately.
+  int64_t time_ms = 1001;
+  webrtc::ReportBlockList report_blocks;
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, sequence_number[0]));
+  bandwidth_observer_->OnReceivedEstimatedBitrate(kStartBitrate);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
+  report_blocks.clear();
+  time_ms += 2000;
+
   // Receive a high REMB, test bitrate increase.
   bandwidth_observer_->OnReceivedEstimatedBitrate(400000);
 
-  webrtc::ReportBlockList report_blocks;
-  int64_t time_ms = 1001;
   uint32_t last_bitrate = 0;
   // Ramp up to max bitrate.
   for (int i = 0; i < 6; ++i) {
@@ -333,20 +383,29 @@
   controller_->SetBitrateObserver(&bitrate_observer_2, 200000, 200000, 300000);
   controller_->SetBitrateObserver(&bitrate_observer_1, 200000, 100000, 300000);
 
-  // Receive a high remb, test bitrate inc.
-  // Test too low start bitrate, hence lower than sum of min.
-  bandwidth_observer_->OnReceivedEstimatedBitrate(400000);
+  // REMBs during the first 2 seconds apply immediately.
+  int64_t time_ms = 1001;
+  webrtc::ReportBlockList report_blocks;
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 1));
+  bandwidth_observer_->OnReceivedEstimatedBitrate(200000);
   EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_);
   EXPECT_EQ(0u, bitrate_observer_1.last_rtt_);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
+  report_blocks.clear();
+  time_ms += 2000;
+
+  // Receive a high remb, test bitrate inc.
+  // Test too low start bitrate, hence lower than sum of min.
+  bandwidth_observer_->OnReceivedEstimatedBitrate(400000);
 
   // Test bitrate increase 8% per second, distributed equally.
-  webrtc::ReportBlockList report_blocks;
-  report_blocks.push_back(CreateReportBlock(1, 2, 0, 1));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1001);
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, 21));
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(112500u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_);
   EXPECT_EQ(50u, bitrate_observer_1.last_rtt_);
+  time_ms += 1000;
 
   EXPECT_EQ(212500u, bitrate_observer_2.last_bitrate_);
   EXPECT_EQ(0, bitrate_observer_2.last_fraction_loss_);
@@ -354,59 +413,67 @@
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 41));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(126000u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(226000u, bitrate_observer_2.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 61));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 3001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(140580u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(240580u, bitrate_observer_2.last_bitrate_);
+  time_ms += 1000;
 
   // Check that the bitrate sum honor our REMB.
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 101));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 5001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(150000u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(250000u, bitrate_observer_2.last_bitrate_);
+  time_ms += 1000;
 
   // Remove REMB cap, higher than sum of max.
   bandwidth_observer_->OnReceivedEstimatedBitrate(700000);
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 121));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 6001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(166500u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(266500u, bitrate_observer_2.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 141));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 7001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(184320u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(284320u, bitrate_observer_2.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 161));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 8001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(207130u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_);  // Max cap.
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 181));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 9001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(248700u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 201));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 10001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(293596u, bitrate_observer_1.last_bitrate_);
   EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_);
+  time_ms += 1000;
 
   report_blocks.clear();
   report_blocks.push_back(CreateReportBlock(1, 2, 0, 221));
-  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 11001);
+  bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(300000u, bitrate_observer_1.last_bitrate_);  // Max cap.
   EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_);
 
diff --git a/modules/bitrate_controller/send_side_bandwidth_estimation.cc b/modules/bitrate_controller/send_side_bandwidth_estimation.cc
index 5da23f0..47a79ad 100644
--- a/modules/bitrate_controller/send_side_bandwidth_estimation.cc
+++ b/modules/bitrate_controller/send_side_bandwidth_estimation.cc
@@ -13,6 +13,7 @@
 #include <cmath>
 
 #include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/metrics.h"
 
 namespace webrtc {
 namespace {
@@ -20,6 +21,7 @@
 enum { kBweDecreaseIntervalMs = 300 };
 enum { kLimitNumPackets = 20 };
 enum { kAvgPacketSizeBytes = 1000 };
+enum { kStartPhaseMs = 2000 };
 
 // Calculate the rate that TCP-Friendly Rate Control (TFRC) would apply.
 // The formula in RFC 3448, Section 3.1, is used.
@@ -56,7 +58,11 @@
       last_fraction_loss_(0),
       last_round_trip_time_ms_(0),
       bwe_incoming_(0),
-      time_last_decrease_ms_(0) {}
+      time_last_decrease_ms_(0),
+      first_report_time_ms_(-1),
+      initially_lost_packets_(0),
+      uma_updated_(false) {
+}
 
 SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {}
 
@@ -88,7 +94,7 @@
 
 void SendSideBandwidthEstimation::UpdateReceiverEstimate(uint32_t bandwidth) {
   bwe_incoming_ = bandwidth;
-  CapBitrateToThresholds();
+  bitrate_ = CapBitrateToThresholds(bitrate_);
 }
 
 void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
@@ -121,11 +127,35 @@
   }
   time_last_receiver_block_ms_ = now_ms;
   UpdateEstimate(now_ms);
+
+  if (first_report_time_ms_ == -1) {
+    first_report_time_ms_ = now_ms;
+  } else if (IsInStartPhase(now_ms)) {
+    initially_lost_packets_ += (fraction_loss * number_of_packets) >> 8;
+  } else if (!uma_updated_) {
+    uma_updated_ = true;
+    RTC_HISTOGRAM_COUNTS(
+        "WebRTC.BWE.InitiallyLostPackets", initially_lost_packets_, 0, 100, 50);
+    RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialRtt", rtt, 0, 2000, 50);
+    RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialBandwidthEstimate",
+                         (bitrate_ + 500) / 1000,
+                         0,
+                         2000,
+                         50);
+  }
 }
 
 void SendSideBandwidthEstimation::UpdateEstimate(uint32_t now_ms) {
+  // We trust the REMB during the first 2 seconds if we haven't had any
+  // packet loss reported, to allow startup bitrate probing.
+  if (last_fraction_loss_ == 0 && IsInStartPhase(now_ms) &&
+      bwe_incoming_ > bitrate_) {
+    bitrate_ = CapBitrateToThresholds(bwe_incoming_);
+    min_bitrate_history_.clear();
+    min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_));
+    return;
+  }
   UpdateMinHistory(now_ms);
-
   // Only start updating bitrate when receiving receiver blocks.
   if (time_last_receiver_block_ms_ != 0) {
     if (last_fraction_loss_ <= 5) {
@@ -172,7 +202,12 @@
       }
     }
   }
-  CapBitrateToThresholds();
+  bitrate_ = CapBitrateToThresholds(bitrate_);
+}
+
+bool SendSideBandwidthEstimation::IsInStartPhase(int64_t now_ms) const {
+  return first_report_time_ms_ == -1 ||
+         now_ms - first_report_time_ms_ < kStartPhaseMs;
 }
 
 void SendSideBandwidthEstimation::UpdateMinHistory(uint32_t now_ms) {
@@ -195,19 +230,20 @@
   min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_));
 }
 
-void SendSideBandwidthEstimation::CapBitrateToThresholds() {
-  if (bwe_incoming_ > 0 && bitrate_ > bwe_incoming_) {
-    bitrate_ = bwe_incoming_;
+uint32_t SendSideBandwidthEstimation::CapBitrateToThresholds(uint32_t bitrate) {
+  if (bwe_incoming_ > 0 && bitrate > bwe_incoming_) {
+    bitrate = bwe_incoming_;
   }
-  if (bitrate_ > max_bitrate_configured_) {
-    bitrate_ = max_bitrate_configured_;
+  if (bitrate > max_bitrate_configured_) {
+    bitrate = max_bitrate_configured_;
   }
-  if (bitrate_ < min_bitrate_configured_) {
-    LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate_ / 1000
+  if (bitrate < min_bitrate_configured_) {
+    LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate / 1000
                     << " kbps is below configured min bitrate "
                     << min_bitrate_configured_ / 1000 << " kbps.";
-    bitrate_ = min_bitrate_configured_;
+    bitrate = min_bitrate_configured_;
   }
+  return bitrate;
 }
 
 }  // namespace webrtc
diff --git a/modules/bitrate_controller/send_side_bandwidth_estimation.h b/modules/bitrate_controller/send_side_bandwidth_estimation.h
index eb675d1..0fe3ae6 100644
--- a/modules/bitrate_controller/send_side_bandwidth_estimation.h
+++ b/modules/bitrate_controller/send_side_bandwidth_estimation.h
@@ -43,7 +43,11 @@
   void SetMinBitrate(uint32_t min_bitrate);
 
  private:
-  void CapBitrateToThresholds();
+  bool IsInStartPhase(int64_t now_ms) const;
+
+  // Returns the input bitrate capped to the thresholds defined by the max,
+  // min and incoming bandwidth.
+  uint32_t CapBitrateToThresholds(uint32_t bitrate);
 
   // Updates history of min bitrates.
   // After this method returns min_bitrate_history_.front().second contains the
@@ -66,6 +70,9 @@
 
   uint32_t bwe_incoming_;
   uint32_t time_last_decrease_ms_;
+  int64_t first_report_time_ms_;
+  int initially_lost_packets_;
+  bool uma_updated_;
 };
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_BITRATE_CONTROLLER_SEND_SIDE_BANDWIDTH_ESTIMATION_H_
diff --git a/modules/iLBC.target.darwin-arm.mk b/modules/iLBC.target.darwin-arm.mk
index f2df23a..93ecd49 100644
--- a/modules/iLBC.target.darwin-arm.mk
+++ b/modules/iLBC.target.darwin-arm.mk
@@ -154,11 +154,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -174,6 +176,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -275,11 +278,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -295,6 +300,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.darwin-arm64.mk b/modules/iLBC.target.darwin-arm64.mk
index 411bd41..821d452 100644
--- a/modules/iLBC.target.darwin-arm64.mk
+++ b/modules/iLBC.target.darwin-arm64.mk
@@ -143,11 +143,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -156,10 +158,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -249,11 +253,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -262,10 +268,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.darwin-mips.mk b/modules/iLBC.target.darwin-mips.mk
index 8d36a77..779d109 100644
--- a/modules/iLBC.target.darwin-mips.mk
+++ b/modules/iLBC.target.darwin-mips.mk
@@ -148,11 +148,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -167,6 +169,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -262,11 +265,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -281,6 +286,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.darwin-mips64.mk b/modules/iLBC.target.darwin-mips64.mk
new file mode 100644
index 0000000..0e6f536
--- /dev/null
+++ b/modules/iLBC.target.darwin-mips64.mk
@@ -0,0 +1,342 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_iLBC_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/abs_quant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/abs_quant_loop.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/augmented_cb_corr.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/bw_expand.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_mem_energy.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_search.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_search_core.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_update_best_index.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/chebyshev.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/comp_corr.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/constants.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/create_augmented_vec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/do_plc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/energy_inverse.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/enh_upsample.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/enhancer.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/enhancer_interface.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/filtered_cb_vecs.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/frame_classify.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/gain_dequant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/gain_quant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/get_lsp_poly.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/get_sync_seq.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/hp_input.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/hp_output.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/ilbc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/index_conv_dec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/index_conv_enc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/init_decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/init_encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/interpolate.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/interpolate_samples.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lpc_encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_check.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_dec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_enc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_to_lsp.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_to_poly.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsp_to_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/my_corr.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/nearest_neighbor.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/pack_bits.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/poly_to_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/poly_to_lsp.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/refiner.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_interpolate_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_lpc_analysis.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_lsf_dequant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_lsf_quant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/smooth.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/smooth_out_data.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/sort_sq.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/split_vq.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/state_construct.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/state_search.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/swap_bytes.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/unpack_bits.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/vq3.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/vq4.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/window32_w32.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/xcorr_coef.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_iLBC_gyp
+
+# Alias gyp target name.
+.PHONY: iLBC
+iLBC: third_party_webrtc_modules_iLBC_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/iLBC.target.darwin-x86.mk b/modules/iLBC.target.darwin-x86.mk
index 9bbce45..fe2b073 100644
--- a/modules/iLBC.target.darwin-x86.mk
+++ b/modules/iLBC.target.darwin-x86.mk
@@ -149,11 +149,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -166,6 +168,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -261,11 +264,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -278,6 +283,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.darwin-x86_64.mk b/modules/iLBC.target.darwin-x86_64.mk
index 0fe1602..1d3aa7f 100644
--- a/modules/iLBC.target.darwin-x86_64.mk
+++ b/modules/iLBC.target.darwin-x86_64.mk
@@ -148,11 +148,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -165,6 +167,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -259,11 +262,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -276,6 +281,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.linux-arm.mk b/modules/iLBC.target.linux-arm.mk
index f2df23a..93ecd49 100644
--- a/modules/iLBC.target.linux-arm.mk
+++ b/modules/iLBC.target.linux-arm.mk
@@ -154,11 +154,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -174,6 +176,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -275,11 +278,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -295,6 +300,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.linux-arm64.mk b/modules/iLBC.target.linux-arm64.mk
index 411bd41..821d452 100644
--- a/modules/iLBC.target.linux-arm64.mk
+++ b/modules/iLBC.target.linux-arm64.mk
@@ -143,11 +143,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -156,10 +158,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -249,11 +253,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -262,10 +268,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.linux-mips.mk b/modules/iLBC.target.linux-mips.mk
index 8d36a77..779d109 100644
--- a/modules/iLBC.target.linux-mips.mk
+++ b/modules/iLBC.target.linux-mips.mk
@@ -148,11 +148,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -167,6 +169,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -262,11 +265,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -281,6 +286,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.linux-mips64.mk b/modules/iLBC.target.linux-mips64.mk
new file mode 100644
index 0000000..0e6f536
--- /dev/null
+++ b/modules/iLBC.target.linux-mips64.mk
@@ -0,0 +1,342 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_iLBC_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/abs_quant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/abs_quant_loop.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/augmented_cb_corr.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/bw_expand.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_mem_energy.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_search.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_search_core.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/cb_update_best_index.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/chebyshev.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/comp_corr.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/constants.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/create_augmented_vec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/do_plc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/energy_inverse.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/enh_upsample.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/enhancer.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/enhancer_interface.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/filtered_cb_vecs.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/frame_classify.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/gain_dequant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/gain_quant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/get_lsp_poly.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/get_sync_seq.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/hp_input.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/hp_output.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/ilbc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/index_conv_dec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/index_conv_enc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/init_decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/init_encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/interpolate.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/interpolate_samples.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lpc_encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_check.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_dec.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_enc.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_to_lsp.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsf_to_poly.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/lsp_to_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/my_corr.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/nearest_neighbor.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/pack_bits.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/poly_to_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/poly_to_lsp.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/refiner.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_interpolate_lsf.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_lpc_analysis.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_lsf_dequant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/simple_lsf_quant.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/smooth.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/smooth_out_data.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/sort_sq.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/split_vq.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/state_construct.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/state_search.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/swap_bytes.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/unpack_bits.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/vq3.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/vq4.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/window32_w32.c \
+	third_party/webrtc/modules/audio_coding/codecs/ilbc/xcorr_coef.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_iLBC_gyp
+
+# Alias gyp target name.
+.PHONY: iLBC
+iLBC: third_party_webrtc_modules_iLBC_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/iLBC.target.linux-x86.mk b/modules/iLBC.target.linux-x86.mk
index 9bbce45..fe2b073 100644
--- a/modules/iLBC.target.linux-x86.mk
+++ b/modules/iLBC.target.linux-x86.mk
@@ -149,11 +149,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -166,6 +168,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -261,11 +264,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -278,6 +283,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iLBC.target.linux-x86_64.mk b/modules/iLBC.target.linux-x86_64.mk
index 0fe1602..1d3aa7f 100644
--- a/modules/iLBC.target.linux-x86_64.mk
+++ b/modules/iLBC.target.linux-x86_64.mk
@@ -148,11 +148,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -165,6 +167,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -259,11 +262,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -276,6 +281,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.darwin-arm.mk b/modules/iSAC.target.darwin-arm.mk
index da974a0..be3fbf3 100644
--- a/modules/iSAC.target.darwin-arm.mk
+++ b/modules/iSAC.target.darwin-arm.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -234,11 +237,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -254,6 +259,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.darwin-arm64.mk b/modules/iSAC.target.darwin-arm64.mk
index 95e4e84..05f4e86 100644
--- a/modules/iSAC.target.darwin-arm64.mk
+++ b/modules/iSAC.target.darwin-arm64.mk
@@ -102,11 +102,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -115,10 +117,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +212,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,10 +227,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.darwin-mips.mk b/modules/iSAC.target.darwin-mips.mk
index a853b62..9c49163 100644
--- a/modules/iSAC.target.darwin-mips.mk
+++ b/modules/iSAC.target.darwin-mips.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -126,6 +128,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -221,11 +224,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -240,6 +245,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.darwin-mips64.mk b/modules/iSAC.target.darwin-mips64.mk
new file mode 100644
index 0000000..f25e998
--- /dev/null
+++ b/modules/iSAC.target.darwin-mips64.mk
@@ -0,0 +1,301 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_iSAC_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/fft.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_iSAC_gyp
+
+# Alias gyp target name.
+.PHONY: iSAC
+iSAC: third_party_webrtc_modules_iSAC_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/iSAC.target.darwin-x86.mk b/modules/iSAC.target.darwin-x86.mk
index e7061b0..9a4fc48 100644
--- a/modules/iSAC.target.darwin-x86.mk
+++ b/modules/iSAC.target.darwin-x86.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.darwin-x86_64.mk b/modules/iSAC.target.darwin-x86_64.mk
index e93fea6..b939b4a 100644
--- a/modules/iSAC.target.darwin-x86_64.mk
+++ b/modules/iSAC.target.darwin-x86_64.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -218,11 +221,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -235,6 +240,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.linux-arm.mk b/modules/iSAC.target.linux-arm.mk
index da974a0..be3fbf3 100644
--- a/modules/iSAC.target.linux-arm.mk
+++ b/modules/iSAC.target.linux-arm.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -234,11 +237,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -254,6 +259,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.linux-arm64.mk b/modules/iSAC.target.linux-arm64.mk
index 95e4e84..05f4e86 100644
--- a/modules/iSAC.target.linux-arm64.mk
+++ b/modules/iSAC.target.linux-arm64.mk
@@ -102,11 +102,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -115,10 +117,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +212,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,10 +227,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.linux-mips.mk b/modules/iSAC.target.linux-mips.mk
index a853b62..9c49163 100644
--- a/modules/iSAC.target.linux-mips.mk
+++ b/modules/iSAC.target.linux-mips.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -126,6 +128,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -221,11 +224,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -240,6 +245,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.linux-mips64.mk b/modules/iSAC.target.linux-mips64.mk
new file mode 100644
index 0000000..f25e998
--- /dev/null
+++ b/modules/iSAC.target.linux-mips64.mk
@@ -0,0 +1,301 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_iSAC_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/fft.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_iSAC_gyp
+
+# Alias gyp target name.
+.PHONY: iSAC
+iSAC: third_party_webrtc_modules_iSAC_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/iSAC.target.linux-x86.mk b/modules/iSAC.target.linux-x86.mk
index e7061b0..9a4fc48 100644
--- a/modules/iSAC.target.linux-x86.mk
+++ b/modules/iSAC.target.linux-x86.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSAC.target.linux-x86_64.mk b/modules/iSAC.target.linux-x86_64.mk
index e93fea6..b939b4a 100644
--- a/modules/iSAC.target.linux-x86_64.mk
+++ b/modules/iSAC.target.linux-x86_64.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -218,11 +221,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -235,6 +240,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.darwin-arm.mk b/modules/iSACFix.target.darwin-arm.mk
index cc5dd24..e9d8ccc 100644
--- a/modules/iSACFix.target.darwin-arm.mk
+++ b/modules/iSACFix.target.darwin-arm.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -235,11 +238,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.darwin-arm64.mk b/modules/iSACFix.target.darwin-arm64.mk
index d3ccea5..c690ae6 100644
--- a/modules/iSACFix.target.darwin-arm64.mk
+++ b/modules/iSACFix.target.darwin-arm64.mk
@@ -102,11 +102,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -115,10 +117,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -209,11 +213,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -222,10 +228,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.darwin-mips.mk b/modules/iSACFix.target.darwin-mips.mk
index 200ea4f..639671d 100644
--- a/modules/iSACFix.target.darwin-mips.mk
+++ b/modules/iSACFix.target.darwin-mips.mk
@@ -110,11 +110,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -129,6 +131,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -225,11 +228,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -244,6 +249,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.darwin-mips64.mk b/modules/iSACFix.target.darwin-mips64.mk
new file mode 100644
index 0000000..61251da
--- /dev/null
+++ b/modules/iSACFix.target.darwin-mips64.mk
@@ -0,0 +1,303 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_iSACFix_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/arith_routines.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/decode_bwe.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/decode_plc.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/fft.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/filterbanks.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/filters.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/initialize.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lattice.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lattice_c.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lpc_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/transform.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/transform_tables.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_iSACFix_gyp
+
+# Alias gyp target name.
+.PHONY: iSACFix
+iSACFix: third_party_webrtc_modules_iSACFix_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/iSACFix.target.darwin-x86.mk b/modules/iSACFix.target.darwin-x86.mk
index 090a022..c90c54f 100644
--- a/modules/iSACFix.target.darwin-x86.mk
+++ b/modules/iSACFix.target.darwin-x86.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -221,11 +224,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -238,6 +243,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.darwin-x86_64.mk b/modules/iSACFix.target.darwin-x86_64.mk
index e82859c..76d2293 100644
--- a/modules/iSACFix.target.darwin-x86_64.mk
+++ b/modules/iSACFix.target.darwin-x86_64.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -219,11 +222,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -236,6 +241,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.linux-arm.mk b/modules/iSACFix.target.linux-arm.mk
index cc5dd24..e9d8ccc 100644
--- a/modules/iSACFix.target.linux-arm.mk
+++ b/modules/iSACFix.target.linux-arm.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -235,11 +238,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.linux-arm64.mk b/modules/iSACFix.target.linux-arm64.mk
index d3ccea5..c690ae6 100644
--- a/modules/iSACFix.target.linux-arm64.mk
+++ b/modules/iSACFix.target.linux-arm64.mk
@@ -102,11 +102,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -115,10 +117,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -209,11 +213,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -222,10 +228,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.linux-mips.mk b/modules/iSACFix.target.linux-mips.mk
index 200ea4f..639671d 100644
--- a/modules/iSACFix.target.linux-mips.mk
+++ b/modules/iSACFix.target.linux-mips.mk
@@ -110,11 +110,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -129,6 +131,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -225,11 +228,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -244,6 +249,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.linux-mips64.mk b/modules/iSACFix.target.linux-mips64.mk
new file mode 100644
index 0000000..61251da
--- /dev/null
+++ b/modules/iSACFix.target.linux-mips64.mk
@@ -0,0 +1,303 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_iSACFix_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/arith_routines.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/decode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/decode_bwe.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/decode_plc.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/encode.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/fft.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/filterbanks.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/filters.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/initialize.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/isacfix.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lattice.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lattice_c.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/lpc_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/transform.c \
+	third_party/webrtc/modules/audio_coding/codecs/isac/fix/source/transform_tables.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_iSACFix_gyp
+
+# Alias gyp target name.
+.PHONY: iSACFix
+iSACFix: third_party_webrtc_modules_iSACFix_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/iSACFix.target.linux-x86.mk b/modules/iSACFix.target.linux-x86.mk
index 090a022..c90c54f 100644
--- a/modules/iSACFix.target.linux-x86.mk
+++ b/modules/iSACFix.target.linux-x86.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -221,11 +224,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -238,6 +243,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/iSACFix.target.linux-x86_64.mk b/modules/iSACFix.target.linux-x86_64.mk
index e82859c..76d2293 100644
--- a/modules/iSACFix.target.linux-x86_64.mk
+++ b/modules/iSACFix.target.linux-x86_64.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -219,11 +222,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -236,6 +241,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/isac_neon.target.darwin-arm.mk b/modules/isac_neon.target.darwin-arm.mk
index c496a91..3260869 100644
--- a/modules/isac_neon.target.darwin-arm.mk
+++ b/modules/isac_neon.target.darwin-arm.mk
@@ -93,11 +93,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -113,6 +115,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -215,11 +218,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -235,6 +240,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/isac_neon.target.linux-arm.mk b/modules/isac_neon.target.linux-arm.mk
index c496a91..3260869 100644
--- a/modules/isac_neon.target.linux-arm.mk
+++ b/modules/isac_neon.target.linux-arm.mk
@@ -93,11 +93,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -113,6 +115,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -215,11 +218,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -235,6 +240,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.darwin-arm.mk b/modules/media_file.target.darwin-arm.mk
index 6a78abc..d1c8ad6 100644
--- a/modules/media_file.target.darwin-arm.mk
+++ b/modules/media_file.target.darwin-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.darwin-arm64.mk b/modules/media_file.target.darwin-arm64.mk
index 9ebbee8..7b61e3a 100644
--- a/modules/media_file.target.darwin-arm64.mk
+++ b/modules/media_file.target.darwin-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.darwin-mips.mk b/modules/media_file.target.darwin-mips.mk
index 342bf04..96f821a 100644
--- a/modules/media_file.target.darwin-mips.mk
+++ b/modules/media_file.target.darwin-mips.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.darwin-mips64.mk b/modules/media_file.target.darwin-mips64.mk
new file mode 100644
index 0000000..0f13b29
--- /dev/null
+++ b/modules/media_file.target.darwin-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_media_file_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/media_file/source/avi_file.cc \
+	third_party/webrtc/modules/media_file/source/media_file_impl.cc \
+	third_party/webrtc/modules/media_file/source/media_file_utility.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_media_file_gyp
+
+# Alias gyp target name.
+.PHONY: media_file
+media_file: third_party_webrtc_modules_media_file_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/media_file.target.darwin-x86.mk b/modules/media_file.target.darwin-x86.mk
index 1967f13..b0a9f51 100644
--- a/modules/media_file.target.darwin-x86.mk
+++ b/modules/media_file.target.darwin-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.darwin-x86_64.mk b/modules/media_file.target.darwin-x86_64.mk
index a486b79..5486ac6 100644
--- a/modules/media_file.target.darwin-x86_64.mk
+++ b/modules/media_file.target.darwin-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.linux-arm.mk b/modules/media_file.target.linux-arm.mk
index 6a78abc..d1c8ad6 100644
--- a/modules/media_file.target.linux-arm.mk
+++ b/modules/media_file.target.linux-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.linux-arm64.mk b/modules/media_file.target.linux-arm64.mk
index 9ebbee8..7b61e3a 100644
--- a/modules/media_file.target.linux-arm64.mk
+++ b/modules/media_file.target.linux-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.linux-mips.mk b/modules/media_file.target.linux-mips.mk
index 342bf04..96f821a 100644
--- a/modules/media_file.target.linux-mips.mk
+++ b/modules/media_file.target.linux-mips.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.linux-mips64.mk b/modules/media_file.target.linux-mips64.mk
new file mode 100644
index 0000000..0f13b29
--- /dev/null
+++ b/modules/media_file.target.linux-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_media_file_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/media_file/source/avi_file.cc \
+	third_party/webrtc/modules/media_file/source/media_file_impl.cc \
+	third_party/webrtc/modules/media_file/source/media_file_utility.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_media_file_gyp
+
+# Alias gyp target name.
+.PHONY: media_file
+media_file: third_party_webrtc_modules_media_file_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/media_file.target.linux-x86.mk b/modules/media_file.target.linux-x86.mk
index 1967f13..b0a9f51 100644
--- a/modules/media_file.target.linux-x86.mk
+++ b/modules/media_file.target.linux-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/media_file.target.linux-x86_64.mk b/modules/media_file.target.linux-x86_64.mk
index a486b79..5486ac6 100644
--- a/modules/media_file.target.linux-x86_64.mk
+++ b/modules/media_file.target.linux-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/modules.gyp b/modules/modules.gyp
index 9650e66..3caf41f 100644
--- a/modules/modules.gyp
+++ b/modules/modules.gyp
@@ -95,11 +95,13 @@
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
             '<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
+            '<(webrtc_root)/modules/modules.gyp:video_capture_module_impl',
             '<(webrtc_root)/modules/video_coding/codecs/vp8/vp8.gyp:webrtc_vp8',
+            '<(webrtc_root)/modules/video_coding/codecs/vp9/vp9.gyp:webrtc_vp9',
             '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-            '<(webrtc_root)/test/test.gyp:test_support_main',
             '<(webrtc_root)/test/test.gyp:frame_generator',
-            '<(webrtc_root)/test/test.gyp:rtcp_packet_parser',
+            '<(webrtc_root)/test/test.gyp:rtp_test_utils',
+            '<(webrtc_root)/test/test.gyp:test_support_main',
           ],
           'sources': [
             'audio_coding/main/acm2/acm_opus_unittest.cc',
@@ -179,6 +181,7 @@
             'desktop_capture/win/cursor_unittest_resources.rc',
             'media_file/source/media_file_unittest.cc',
             'module_common_types_unittest.cc',
+            'pacing/bitrate_prober_unittest.cc',
             'pacing/paced_sender_unittest.cc',
             'remote_bitrate_estimator/bwe_simulations.cc',
             'remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h',
@@ -211,6 +214,7 @@
             'rtp_rtcp/source/rtcp_packet_unittest.cc',
             'rtp_rtcp/source/rtcp_receiver_unittest.cc',
             'rtp_rtcp/source/rtcp_sender_unittest.cc',
+            'rtp_rtcp/source/rtcp_utility_unittest.cc',
             'rtp_rtcp/source/rtp_fec_unittest.cc',
             'rtp_rtcp/source/rtp_format_h264_unittest.cc',
             'rtp_rtcp/source/rtp_format_vp8_unittest.cc',
@@ -323,6 +327,7 @@
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(webrtc_root)/common_video/common_video.gyp:common_video',
             '<(webrtc_root)/modules/video_coding/codecs/vp8/vp8.gyp:webrtc_vp8',
+            '<(webrtc_root)/modules/video_coding/codecs/vp9/vp9.gyp:webrtc_vp9',
             '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
             '<(webrtc_root)/test/metrics.gyp:metrics',
             '<(webrtc_root)/test/test.gyp:test_support',
@@ -394,7 +399,6 @@
               ],
               'includes': [
                 '../build/isolate.gypi',
-                'modules_tests.isolate',
               ],
               'sources': [
                 'modules_tests.isolate',
@@ -408,7 +412,6 @@
               ],
               'includes': [
                 '../build/isolate.gypi',
-                'modules_unittests.isolate',
               ],
               'sources': [
                 'modules_unittests.isolate',
diff --git a/modules/modules_tests.isolate b/modules/modules_tests.isolate
index e5055f0..c29c65b 100644
--- a/modules/modules_tests.isolate
+++ b/modules/modules_tests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,7 +21,7 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/modules_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/DEPS',
           '<(DEPTH)/resources/audio_coding/testfile32kHz.pcm',
           '<(DEPTH)/resources/audio_coding/teststereo32kHz.pcm',
@@ -30,9 +30,6 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/modules_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/modules/modules_unittests.isolate b/modules/modules_unittests.isolate
index 09ace1c..967ff32 100644
--- a/modules/modules_unittests.isolate
+++ b/modules/modules_unittests.isolate
@@ -9,16 +9,10 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
-        'isolate_dependency_tracked': [
-          '<(DEPTH)/resources/short_mixed_mono_48.dat',
-          '<(DEPTH)/resources/short_mixed_mono_48.pcm',
-          '<(DEPTH)/resources/short_mixed_stereo_48.dat',
-          '<(DEPTH)/resources/short_mixed_stereo_48.pcm',
-        ],
       },
     }],
     ['OS=="linux" or OS=="mac" or OS=="win"', {
@@ -27,7 +21,7 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/modules_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/DEPS',
           '<(DEPTH)/data/audio_processing/output_data_float.pb',
           '<(DEPTH)/data/voice_engine/audio_tiny48.wav',
@@ -105,9 +99,6 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/modules_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/modules/neteq.target.darwin-arm.mk b/modules/neteq.target.darwin-arm.mk
index 4ff035c..7400e1e 100644
--- a/modules/neteq.target.darwin-arm.mk
+++ b/modules/neteq.target.darwin-arm.mk
@@ -119,11 +119,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -140,6 +142,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -251,11 +254,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -272,6 +277,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.darwin-arm64.mk b/modules/neteq.target.darwin-arm64.mk
index 62eb70e..d2f26cd 100644
--- a/modules/neteq.target.darwin-arm64.mk
+++ b/modules/neteq.target.darwin-arm64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -121,11 +123,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -225,11 +229,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -238,11 +244,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.darwin-mips.mk b/modules/neteq.target.darwin-mips.mk
index 61110cc..6028d0c 100644
--- a/modules/neteq.target.darwin-mips.mk
+++ b/modules/neteq.target.darwin-mips.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -238,11 +241,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -258,6 +263,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.darwin-mips64.mk b/modules/neteq.target.darwin-mips64.mk
new file mode 100644
index 0000000..44be3d6
--- /dev/null
+++ b/modules/neteq.target.darwin-mips64.mk
@@ -0,0 +1,329 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_neteq_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/neteq/accelerate.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_classifier.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_decoder.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_multi_vector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_vector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/background_noise.cc \
+	third_party/webrtc/modules/audio_coding/neteq/buffer_level_filter.cc \
+	third_party/webrtc/modules/audio_coding/neteq/comfort_noise.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decision_logic.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decision_logic_fax.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decision_logic_normal.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decoder_database.cc \
+	third_party/webrtc/modules/audio_coding/neteq/delay_manager.cc \
+	third_party/webrtc/modules/audio_coding/neteq/delay_peak_detector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/dsp_helper.cc \
+	third_party/webrtc/modules/audio_coding/neteq/dtmf_buffer.cc \
+	third_party/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc \
+	third_party/webrtc/modules/audio_coding/neteq/expand.cc \
+	third_party/webrtc/modules/audio_coding/neteq/merge.cc \
+	third_party/webrtc/modules/audio_coding/neteq/neteq_impl.cc \
+	third_party/webrtc/modules/audio_coding/neteq/neteq.cc \
+	third_party/webrtc/modules/audio_coding/neteq/statistics_calculator.cc \
+	third_party/webrtc/modules/audio_coding/neteq/normal.cc \
+	third_party/webrtc/modules/audio_coding/neteq/packet_buffer.cc \
+	third_party/webrtc/modules/audio_coding/neteq/payload_splitter.cc \
+	third_party/webrtc/modules/audio_coding/neteq/post_decode_vad.cc \
+	third_party/webrtc/modules/audio_coding/neteq/preemptive_expand.cc \
+	third_party/webrtc/modules/audio_coding/neteq/random_vector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/rtcp.cc \
+	third_party/webrtc/modules/audio_coding/neteq/sync_buffer.cc \
+	third_party/webrtc/modules/audio_coding/neteq/timestamp_scaler.cc \
+	third_party/webrtc/modules/audio_coding/neteq/time_stretch.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/opus/src/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/opus/src/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_neteq_gyp
+
+# Alias gyp target name.
+.PHONY: neteq
+neteq: third_party_webrtc_modules_neteq_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/neteq.target.darwin-x86.mk b/modules/neteq.target.darwin-x86.mk
index d0da44f..22eef0b 100644
--- a/modules/neteq.target.darwin-x86.mk
+++ b/modules/neteq.target.darwin-x86.mk
@@ -114,11 +114,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -237,11 +240,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.darwin-x86_64.mk b/modules/neteq.target.darwin-x86_64.mk
index 631a8bd..7c412bb 100644
--- a/modules/neteq.target.darwin-x86_64.mk
+++ b/modules/neteq.target.darwin-x86_64.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -131,6 +133,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -235,11 +238,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -253,6 +258,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.linux-arm.mk b/modules/neteq.target.linux-arm.mk
index 4ff035c..7400e1e 100644
--- a/modules/neteq.target.linux-arm.mk
+++ b/modules/neteq.target.linux-arm.mk
@@ -119,11 +119,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -140,6 +142,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -251,11 +254,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -272,6 +277,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.linux-arm64.mk b/modules/neteq.target.linux-arm64.mk
index 62eb70e..d2f26cd 100644
--- a/modules/neteq.target.linux-arm64.mk
+++ b/modules/neteq.target.linux-arm64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -121,11 +123,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -225,11 +229,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -238,11 +244,13 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.linux-mips.mk b/modules/neteq.target.linux-mips.mk
index 61110cc..6028d0c 100644
--- a/modules/neteq.target.linux-mips.mk
+++ b/modules/neteq.target.linux-mips.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -238,11 +241,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -258,6 +263,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.linux-mips64.mk b/modules/neteq.target.linux-mips64.mk
new file mode 100644
index 0000000..44be3d6
--- /dev/null
+++ b/modules/neteq.target.linux-mips64.mk
@@ -0,0 +1,329 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_neteq_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/neteq/accelerate.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_classifier.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_decoder.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_multi_vector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/audio_vector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/background_noise.cc \
+	third_party/webrtc/modules/audio_coding/neteq/buffer_level_filter.cc \
+	third_party/webrtc/modules/audio_coding/neteq/comfort_noise.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decision_logic.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decision_logic_fax.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decision_logic_normal.cc \
+	third_party/webrtc/modules/audio_coding/neteq/decoder_database.cc \
+	third_party/webrtc/modules/audio_coding/neteq/delay_manager.cc \
+	third_party/webrtc/modules/audio_coding/neteq/delay_peak_detector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/dsp_helper.cc \
+	third_party/webrtc/modules/audio_coding/neteq/dtmf_buffer.cc \
+	third_party/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc \
+	third_party/webrtc/modules/audio_coding/neteq/expand.cc \
+	third_party/webrtc/modules/audio_coding/neteq/merge.cc \
+	third_party/webrtc/modules/audio_coding/neteq/neteq_impl.cc \
+	third_party/webrtc/modules/audio_coding/neteq/neteq.cc \
+	third_party/webrtc/modules/audio_coding/neteq/statistics_calculator.cc \
+	third_party/webrtc/modules/audio_coding/neteq/normal.cc \
+	third_party/webrtc/modules/audio_coding/neteq/packet_buffer.cc \
+	third_party/webrtc/modules/audio_coding/neteq/payload_splitter.cc \
+	third_party/webrtc/modules/audio_coding/neteq/post_decode_vad.cc \
+	third_party/webrtc/modules/audio_coding/neteq/preemptive_expand.cc \
+	third_party/webrtc/modules/audio_coding/neteq/random_vector.cc \
+	third_party/webrtc/modules/audio_coding/neteq/rtcp.cc \
+	third_party/webrtc/modules/audio_coding/neteq/sync_buffer.cc \
+	third_party/webrtc/modules/audio_coding/neteq/timestamp_scaler.cc \
+	third_party/webrtc/modules/audio_coding/neteq/time_stretch.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/opus/src/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/opus/src/celt \
+	$(LOCAL_PATH)/third_party/opus/src/src \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g711/include \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/g722/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/pcm16b/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/ilbc/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/isac/fix/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/codecs/cng/include \
+	$(LOCAL_PATH)/third_party/opus/src/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_neteq_gyp
+
+# Alias gyp target name.
+.PHONY: neteq
+neteq: third_party_webrtc_modules_neteq_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/neteq.target.linux-x86.mk b/modules/neteq.target.linux-x86.mk
index d0da44f..22eef0b 100644
--- a/modules/neteq.target.linux-x86.mk
+++ b/modules/neteq.target.linux-x86.mk
@@ -114,11 +114,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -237,11 +240,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -255,6 +260,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/neteq.target.linux-x86_64.mk b/modules/neteq.target.linux-x86_64.mk
index 631a8bd..7c412bb 100644
--- a/modules/neteq.target.linux-x86_64.mk
+++ b/modules/neteq.target.linux-x86_64.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -131,6 +133,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -235,11 +238,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -253,6 +258,7 @@
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_CODEC_OPUS' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.darwin-arm.mk b/modules/paced_sender.target.darwin-arm.mk
index 4c6cb67..4e335d7 100644
--- a/modules/paced_sender.target.darwin-arm.mk
+++ b/modules/paced_sender.target.darwin-arm.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -87,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +230,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.darwin-arm64.mk b/modules/paced_sender.target.darwin-arm64.mk
index ea0eb7b..4759947 100644
--- a/modules/paced_sender.target.darwin-arm64.mk
+++ b/modules/paced_sender.target.darwin-arm64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -76,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +198,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.darwin-mips.mk b/modules/paced_sender.target.darwin-mips.mk
index 9a3c2d8..6dab91a 100644
--- a/modules/paced_sender.target.darwin-mips.mk
+++ b/modules/paced_sender.target.darwin-mips.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -81,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.darwin-mips64.mk b/modules/paced_sender.target.darwin-mips64.mk
new file mode 100644
index 0000000..62477c3
--- /dev/null
+++ b/modules/paced_sender.target.darwin-mips64.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_paced_sender_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
+	third_party/webrtc/modules/pacing/paced_sender.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_paced_sender_gyp
+
+# Alias gyp target name.
+.PHONY: paced_sender
+paced_sender: third_party_webrtc_modules_paced_sender_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/paced_sender.target.darwin-x86.mk b/modules/paced_sender.target.darwin-x86.mk
index 2a90a58..7e392bb 100644
--- a/modules/paced_sender.target.darwin-x86.mk
+++ b/modules/paced_sender.target.darwin-x86.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -82,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.darwin-x86_64.mk b/modules/paced_sender.target.darwin-x86_64.mk
index b7269cb..6a9b563 100644
--- a/modules/paced_sender.target.darwin-x86_64.mk
+++ b/modules/paced_sender.target.darwin-x86_64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -81,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.linux-arm.mk b/modules/paced_sender.target.linux-arm.mk
index 4c6cb67..4e335d7 100644
--- a/modules/paced_sender.target.linux-arm.mk
+++ b/modules/paced_sender.target.linux-arm.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -87,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +208,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +230,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.linux-arm64.mk b/modules/paced_sender.target.linux-arm64.mk
index ea0eb7b..4759947 100644
--- a/modules/paced_sender.target.linux-arm64.mk
+++ b/modules/paced_sender.target.linux-arm64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -76,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +198,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.linux-mips.mk b/modules/paced_sender.target.linux-mips.mk
index 9a3c2d8..6dab91a 100644
--- a/modules/paced_sender.target.linux-mips.mk
+++ b/modules/paced_sender.target.linux-mips.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -81,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.linux-mips64.mk b/modules/paced_sender.target.linux-mips64.mk
new file mode 100644
index 0000000..62477c3
--- /dev/null
+++ b/modules/paced_sender.target.linux-mips64.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_paced_sender_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
+	third_party/webrtc/modules/pacing/paced_sender.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_paced_sender_gyp
+
+# Alias gyp target name.
+.PHONY: paced_sender
+paced_sender: third_party_webrtc_modules_paced_sender_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/paced_sender.target.linux-x86.mk b/modules/paced_sender.target.linux-x86.mk
index 2a90a58..7e392bb 100644
--- a/modules/paced_sender.target.linux-x86.mk
+++ b/modules/paced_sender.target.linux-x86.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -82,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/paced_sender.target.linux-x86_64.mk b/modules/paced_sender.target.linux-x86_64.mk
index b7269cb..6a9b563 100644
--- a/modules/paced_sender.target.linux-x86_64.mk
+++ b/modules/paced_sender.target.linux-x86_64.mk
@@ -24,6 +24,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/pacing/bitrate_prober.cc \
 	third_party/webrtc/modules/pacing/paced_sender.cc
 
 
@@ -81,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/pacing/BUILD.gn b/modules/pacing/BUILD.gn
index 58a73ae..aa44b0d 100644
--- a/modules/pacing/BUILD.gn
+++ b/modules/pacing/BUILD.gn
@@ -9,6 +9,8 @@
 source_set("pacing") {
   sources = [
     "include/paced_sender.h",
+    "bitrate_prober.cc",
+    "bitrate_prober.h",
     "paced_sender.cc",
   ]
 
diff --git a/modules/pacing/bitrate_prober.cc b/modules/pacing/bitrate_prober.cc
new file mode 100644
index 0000000..04e71c5
--- /dev/null
+++ b/modules/pacing/bitrate_prober.cc
@@ -0,0 +1,120 @@
+/*
+ *  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.
+ */
+
+#include "webrtc/modules/pacing/bitrate_prober.h"
+
+#include <assert.h>
+#include <limits>
+#include <sstream>
+
+#include "webrtc/system_wrappers/interface/logging.h"
+
+namespace webrtc {
+
+namespace {
+int ComputeDeltaFromBitrate(size_t packet_size, int bitrate_bps) {
+  assert(bitrate_bps > 0);
+  // Compute the time delta needed to send packet_size bytes at bitrate_bps
+  // bps. Result is in milliseconds.
+  return static_cast<int>(1000ll * static_cast<int64_t>(packet_size) * 8ll /
+      bitrate_bps);
+}
+}  // namespace
+
+BitrateProber::BitrateProber()
+    : probing_state_(kDisabled),
+      packet_size_last_send_(0),
+      time_last_send_ms_(-1) {
+}
+
+void BitrateProber::SetEnabled(bool enable) {
+  if (enable) {
+    if (probing_state_ == kDisabled) {
+      probing_state_ = kAllowedToProbe;
+      LOG(LS_INFO) << "Initial bandwidth probing enabled";
+    }
+  } else {
+    probing_state_ = kDisabled;
+    LOG(LS_INFO) << "Initial bandwidth probing disabled";
+  }
+}
+
+bool BitrateProber::IsProbing() const {
+  return probing_state_ == kProbing;
+}
+
+void BitrateProber::MaybeInitializeProbe(int bitrate_bps) {
+  if (probing_state_ != kAllowedToProbe)
+    return;
+  probe_bitrates_.clear();
+  // Max number of packets used for probing.
+  const int kMaxProbeLength = 15;
+  const int kMaxNumProbes = 3;
+  const int kPacketsPerProbe = kMaxProbeLength / kMaxNumProbes;
+  const float kProbeBitrateMultipliers[kMaxNumProbes] = {2.5, 4, 6};
+  int bitrates_bps[kMaxNumProbes];
+  std::stringstream bitrate_log;
+  bitrate_log << "Start probing for bandwidth, bitrates:";
+  for (int i = 0; i < kMaxNumProbes; ++i) {
+    bitrates_bps[i] = kProbeBitrateMultipliers[i] * bitrate_bps;
+    bitrate_log << " " << bitrates_bps[i];
+    for (int j = 0; j < kPacketsPerProbe; ++j)
+      probe_bitrates_.push_back(bitrates_bps[i]);
+  }
+  bitrate_log << ", num packets: " << probe_bitrates_.size();
+  LOG(LS_INFO) << bitrate_log.str().c_str();
+  probing_state_ = kProbing;
+}
+
+int BitrateProber::TimeUntilNextProbe(int64_t now_ms) {
+  if (probing_state_ != kDisabled && probe_bitrates_.empty()) {
+    probing_state_ = kWait;
+  }
+  if (probe_bitrates_.empty()) {
+    // No probe started, or waiting for next probe.
+    return std::numeric_limits<int>::max();
+  }
+  int64_t elapsed_time_ms = now_ms - time_last_send_ms_;
+  // We will send the first probe packet immediately if no packet has been
+  // sent before.
+  int time_until_probe_ms = 0;
+  if (packet_size_last_send_ > 0 && probing_state_ == kProbing) {
+    int next_delta_ms = ComputeDeltaFromBitrate(packet_size_last_send_,
+                                                probe_bitrates_.front());
+    time_until_probe_ms = next_delta_ms - elapsed_time_ms;
+    // There is no point in trying to probe with less than 1 ms between packets
+    // as it essentially means trying to probe at infinite bandwidth.
+    const int kMinProbeDeltaMs = 1;
+    // If we have waited more than 3 ms for a new packet to probe with we will
+    // consider this probing session over.
+    const int kMaxProbeDelayMs = 3;
+    if (next_delta_ms < kMinProbeDeltaMs ||
+        time_until_probe_ms < -kMaxProbeDelayMs) {
+      // We currently disable probing after the first probe, as we only want
+      // to probe at the beginning of a connection. We should set this to
+      // kWait if we later want to probe periodically.
+      probing_state_ = kWait;
+      LOG(LS_INFO) << "Next delta too small, stop probing.";
+      time_until_probe_ms = 0;
+    }
+  }
+  return time_until_probe_ms;
+}
+
+void BitrateProber::PacketSent(int64_t now_ms, size_t packet_size) {
+  assert(packet_size > 0);
+  packet_size_last_send_ = packet_size;
+  time_last_send_ms_ = now_ms;
+  if (probing_state_ != kProbing)
+    return;
+  if (!probe_bitrates_.empty())
+    probe_bitrates_.pop_front();
+}
+}  // namespace webrtc
diff --git a/modules/pacing/bitrate_prober.h b/modules/pacing/bitrate_prober.h
new file mode 100644
index 0000000..04a8580
--- /dev/null
+++ b/modules/pacing/bitrate_prober.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_PACING_BITRATE_PROBER_H_
+#define WEBRTC_MODULES_PACING_BITRATE_PROBER_H_
+
+#include <cstddef>
+#include <list>
+
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+// Note that this class isn't thread-safe by itself and therefore relies
+// on being protected by the caller.
+class BitrateProber {
+ public:
+  BitrateProber();
+
+  void SetEnabled(bool enable);
+
+  // Returns true if the prober is in a probing session, i.e., it currently
+  // wants packets to be sent out according to the time returned by
+  // TimeUntilNextProbe().
+  bool IsProbing() const;
+
+  // Initializes a new probing session if the prober is allowed to probe.
+  void MaybeInitializeProbe(int bitrate_bps);
+
+  // Returns the number of milliseconds until the next packet should be sent to
+  // get accurate probing.
+  int TimeUntilNextProbe(int64_t now_ms);
+
+  // Called to report to the prober that a packet has been sent, which helps the
+  // prober know when to move to the next packet in a probe.
+  void PacketSent(int64_t now_ms, size_t packet_size);
+
+ private:
+  enum ProbingState { kDisabled, kAllowedToProbe, kProbing, kWait };
+
+  ProbingState probing_state_;
+  // Probe bitrate per packet. These are used to compute the delta relative to
+  // the previous probe packet based on the size and time when that packet was
+  // sent.
+  std::list<int> probe_bitrates_;
+  size_t packet_size_last_send_;
+  int64_t time_last_send_ms_;
+};
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_PACING_BITRATE_PROBER_H_
diff --git a/modules/pacing/bitrate_prober_unittest.cc b/modules/pacing/bitrate_prober_unittest.cc
new file mode 100644
index 0000000..15b1cc5
--- /dev/null
+++ b/modules/pacing/bitrate_prober_unittest.cc
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/pacing/bitrate_prober.h"
+
+namespace webrtc {
+
+TEST(BitrateProberTest, VerifyStatesAndTimeBetweenProbes) {
+  BitrateProber prober;
+  EXPECT_FALSE(prober.IsProbing());
+  int64_t now_ms = 0;
+  EXPECT_EQ(std::numeric_limits<int>::max(), prober.TimeUntilNextProbe(now_ms));
+
+  prober.SetEnabled(true);
+  EXPECT_FALSE(prober.IsProbing());
+
+  prober.MaybeInitializeProbe(300000);
+  EXPECT_TRUE(prober.IsProbing());
+
+  EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
+  prober.PacketSent(now_ms, 1000);
+
+  for (int i = 0; i < 4; ++i) {
+    EXPECT_EQ(10, prober.TimeUntilNextProbe(now_ms));
+    now_ms += 5;
+    EXPECT_EQ(5, prober.TimeUntilNextProbe(now_ms));
+    now_ms += 5;
+    EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
+    prober.PacketSent(now_ms, 1000);
+  }
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_EQ(6, prober.TimeUntilNextProbe(now_ms));
+    now_ms += 6;
+    EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
+    prober.PacketSent(now_ms, 1000);
+  }
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_EQ(4, prober.TimeUntilNextProbe(now_ms));
+    now_ms += 4;
+    EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
+    prober.PacketSent(now_ms, 1000);
+  }
+
+  EXPECT_EQ(std::numeric_limits<int>::max(), prober.TimeUntilNextProbe(now_ms));
+  EXPECT_FALSE(prober.IsProbing());
+}
+}  // namespace webrtc
diff --git a/modules/pacing/include/mock/mock_paced_sender.h b/modules/pacing/include/mock/mock_paced_sender.h
index 6600a92..0c9e354 100644
--- a/modules/pacing/include/mock/mock_paced_sender.h
+++ b/modules/pacing/include/mock/mock_paced_sender.h
@@ -22,7 +22,7 @@
 
 class MockPacedSender : public PacedSender {
  public:
-  MockPacedSender() : PacedSender(Clock::GetRealTimeClock(), NULL, 0, 0) {}
+  MockPacedSender() : PacedSender(Clock::GetRealTimeClock(), NULL, 0, 0, 0) {}
   MOCK_METHOD6(SendPacket, bool(Priority priority,
                                 uint32_t ssrc,
                                 uint16_t sequence_number,
diff --git a/modules/pacing/include/paced_sender.h b/modules/pacing/include/paced_sender.h
index 14a3a3d..d7efb8e 100644
--- a/modules/pacing/include/paced_sender.h
+++ b/modules/pacing/include/paced_sender.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_MODULES_PACED_SENDER_H_
-#define WEBRTC_MODULES_PACED_SENDER_H_
+#ifndef WEBRTC_MODULES_PACING_INCLUDE_PACED_SENDER_H_
+#define WEBRTC_MODULES_PACING_INCLUDE_PACED_SENDER_H_
 
 #include <list>
 #include <set>
@@ -20,13 +20,14 @@
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
+class BitrateProber;
 class Clock;
 class CriticalSectionWrapper;
 
 namespace paced_sender {
 class IntervalBudget;
 struct Packet;
-class PacketList;
+class PacketQueue;
 }  // namespace paced_sender
 
 class PacedSender : public Module {
@@ -67,7 +68,10 @@
   // overshoots from the encoder.
   static const float kDefaultPaceMultiplier;
 
-  PacedSender(Clock* clock, Callback* callback, int max_bitrate_kbps,
+  PacedSender(Clock* clock,
+              Callback* callback,
+              int bitrate_kbps,
+              int max_bitrate_kbps,
               int min_bitrate_kbps);
 
   virtual ~PacedSender();
@@ -83,9 +87,14 @@
   // Resume sending packets.
   void Resume();
 
-  // Set target bitrates for the pacer. Padding packets will be utilized to
-  // reach |min_bitrate| unless enough media packets are available.
-  void UpdateBitrate(int max_bitrate_kbps, int min_bitrate_kbps);
+  // Set target bitrates for the pacer.
+  // We will pace out bursts of packets at a bitrate of |max_bitrate_kbps|.
+  // |bitrate_kbps| is our estimate of what we are allowed to send on average.
+  // Padding packets will be utilized to reach |min_bitrate| unless enough media
+  // packets are available.
+  void UpdateBitrate(int bitrate_kbps,
+                     int max_bitrate_kbps,
+                     int min_bitrate_kbps);
 
   // Returns true if we send the packet now, else it will add the packet
   // information to the queue and call TimeToSendPacket when it's time to send.
@@ -96,13 +105,15 @@
                           int bytes,
                           bool retransmission);
 
-  // Sets the max length of the pacer queue in milliseconds.
-  // A negative queue size is interpreted as infinite.
-  virtual void set_max_queue_length_ms(int max_queue_length_ms);
-
   // Returns the time since the oldest queued packet was enqueued.
   virtual int QueueInMs() const;
 
+  virtual size_t QueueSizePackets() const;
+
+  // Returns the number of milliseconds it will take to send the current
+  // packets in the queue, given the current size and bitrate, ignoring prio.
+  virtual int ExpectedQueueTimeMs() const;
+
   // Returns the number of milliseconds until the module want a worker thread
   // to call Process.
   virtual int32_t TimeUntilNextProcess() OVERRIDE;
@@ -110,25 +121,17 @@
   // Process any pending packets in the queue(s).
   virtual int32_t Process() OVERRIDE;
 
+ protected:
+  virtual bool ProbingExperimentIsEnabled() const;
+
  private:
-  // Return true if next packet in line should be transmitted.
-  // Return packet list that contains the next packet.
-  bool ShouldSendNextPacket(paced_sender::PacketList** packet_list)
-      EXCLUSIVE_LOCKS_REQUIRED(critsect_);
-
-  // Local helper function to GetNextPacket.
-  paced_sender::Packet GetNextPacketFromList(paced_sender::PacketList* packets)
-      EXCLUSIVE_LOCKS_REQUIRED(critsect_);
-
-  bool SendPacketFromList(paced_sender::PacketList* packet_list)
-      EXCLUSIVE_LOCKS_REQUIRED(critsect_);
-
   // Updates the number of bytes that can be sent for the next time interval.
   void UpdateBytesPerInterval(uint32_t delta_time_in_ms)
       EXCLUSIVE_LOCKS_REQUIRED(critsect_);
 
-  // Updates the buffers with the number of bytes that we sent.
-  void UpdateMediaBytesSent(int num_bytes) EXCLUSIVE_LOCKS_REQUIRED(critsect_);
+  bool SendPacket(const paced_sender::Packet& packet)
+      EXCLUSIVE_LOCKS_REQUIRED(critsect_);
+  void SendPadding(int padding_needed) EXCLUSIVE_LOCKS_REQUIRED(critsect_);
 
   Clock* const clock_;
   Callback* const callback_;
@@ -136,7 +139,6 @@
   scoped_ptr<CriticalSectionWrapper> critsect_;
   bool enabled_ GUARDED_BY(critsect_);
   bool paused_ GUARDED_BY(critsect_);
-  int max_queue_length_ms_ GUARDED_BY(critsect_);
   // This is the media budget, keeping track of how many bits of media
   // we can pace out during the current interval.
   scoped_ptr<paced_sender::IntervalBudget> media_budget_ GUARDED_BY(critsect_);
@@ -146,17 +148,13 @@
   scoped_ptr<paced_sender::IntervalBudget> padding_budget_
       GUARDED_BY(critsect_);
 
-  int64_t time_last_update_us_ GUARDED_BY(critsect_);
-  int64_t time_last_send_us_ GUARDED_BY(critsect_);
-  int64_t capture_time_ms_last_queued_ GUARDED_BY(critsect_);
-  int64_t capture_time_ms_last_sent_ GUARDED_BY(critsect_);
+  scoped_ptr<BitrateProber> prober_ GUARDED_BY(critsect_);
+  int bitrate_bps_ GUARDED_BY(critsect_);
 
-  scoped_ptr<paced_sender::PacketList> high_priority_packets_
-      GUARDED_BY(critsect_);
-  scoped_ptr<paced_sender::PacketList> normal_priority_packets_
-      GUARDED_BY(critsect_);
-  scoped_ptr<paced_sender::PacketList> low_priority_packets_
-      GUARDED_BY(critsect_);
+  int64_t time_last_update_us_ GUARDED_BY(critsect_);
+
+  scoped_ptr<paced_sender::PacketQueue> packets_ GUARDED_BY(critsect_);
+  uint64_t packet_counter_ GUARDED_BY(critsect_);
 };
 }  // namespace webrtc
-#endif  // WEBRTC_MODULES_PACED_SENDER_H_
+#endif  // WEBRTC_MODULES_PACING_INCLUDE_PACED_SENDER_H_
diff --git a/modules/pacing/paced_sender.cc b/modules/pacing/paced_sender.cc
index 6204a9a..a071ffc 100644
--- a/modules/pacing/paced_sender.cc
+++ b/modules/pacing/paced_sender.cc
@@ -13,11 +13,15 @@
 #include <assert.h>
 
 #include <map>
+#include <queue>
 #include <set>
 
 #include "webrtc/modules/interface/module_common_types.h"
+#include "webrtc/modules/pacing/bitrate_prober.h"
 #include "webrtc/system_wrappers/interface/clock.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/interface/field_trial.h"
+#include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/system_wrappers/interface/trace_event.h"
 
 namespace {
@@ -28,69 +32,140 @@
 // time.
 const int kMaxIntervalTimeMs = 30;
 
-// Max time that the first packet in the queue can sit in the queue if no
-// packets are sent, regardless of buffer state. In practice only in effect at
-// low bitrates (less than 320 kbits/s).
-const int kMaxQueueTimeWithoutSendingUs = 30000;
-
 }  // namespace
 
 namespace webrtc {
 namespace paced_sender {
 struct Packet {
-  Packet(uint32_t ssrc,
+  Packet(PacedSender::Priority priority,
+         uint32_t ssrc,
          uint16_t seq_number,
          int64_t capture_time_ms,
          int64_t enqueue_time_ms,
          int length_in_bytes,
-         bool retransmission)
-      : ssrc(ssrc),
+         bool retransmission,
+         uint64_t enqueue_order)
+      : priority(priority),
+        ssrc(ssrc),
         sequence_number(seq_number),
         capture_time_ms(capture_time_ms),
         enqueue_time_ms(enqueue_time_ms),
         bytes(length_in_bytes),
-        retransmission(retransmission) {}
+        retransmission(retransmission),
+        enqueue_order(enqueue_order) {}
+
+  PacedSender::Priority priority;
   uint32_t ssrc;
   uint16_t sequence_number;
   int64_t capture_time_ms;
   int64_t enqueue_time_ms;
   int bytes;
   bool retransmission;
+  uint64_t enqueue_order;
+  std::list<Packet>::iterator this_it;
 };
 
-// STL list style class which prevents duplicates in the list.
-class PacketList {
+// Used by priority queue to sort packets.
+struct Comparator {
+  bool operator()(const Packet* first, const Packet* second) {
+    // Highest prio = 0.
+    if (first->priority != second->priority)
+      return first->priority > second->priority;
+
+    // Retransmissions go first.
+    if (second->retransmission && !first->retransmission)
+      return true;
+
+    // Older frames have higher prio.
+    if (first->capture_time_ms != second->capture_time_ms)
+      return first->capture_time_ms > second->capture_time_ms;
+
+    return first->enqueue_order > second->enqueue_order;
+  }
+};
+
+// Class encapsulating a priority queue with some extensions.
+class PacketQueue {
  public:
-  PacketList() {};
+  PacketQueue() : bytes_(0) {}
+  virtual ~PacketQueue() {}
 
-  bool empty() const {
-    return packet_list_.empty();
+  void Push(const Packet& packet) {
+    if (!AddToDupeSet(packet))
+      return;
+
+    // Store packet in list, use pointers in priority queue for cheaper moves.
+    // Packets have a handle to its own iterator in the list, for easy removal
+    // when popping from queue.
+    packet_list_.push_front(packet);
+    std::list<Packet>::iterator it = packet_list_.begin();
+    it->this_it = it;          // Handle for direct removal from list.
+    prio_queue_.push(&(*it));  // Pointer into list.
+    bytes_ += packet.bytes;
   }
 
-  Packet front() const {
-    return packet_list_.front();
+  const Packet& BeginPop() {
+    const Packet& packet = *prio_queue_.top();
+    prio_queue_.pop();
+    return packet;
   }
 
-  void pop_front() {
-    Packet& packet = packet_list_.front();
-    uint16_t sequence_number = packet.sequence_number;
-    uint32_t ssrc = packet.ssrc;
-    packet_list_.pop_front();
-    sequence_number_set_[ssrc].erase(sequence_number);
+  void CancelPop(const Packet& packet) { prio_queue_.push(&(*packet.this_it)); }
+
+  void FinalizePop(const Packet& packet) {
+    RemoveFromDupeSet(packet);
+    bytes_ -= packet.bytes;
+    packet_list_.erase(packet.this_it);
   }
 
-  void push_back(const Packet& packet) {
-    if (sequence_number_set_[packet.ssrc].find(packet.sequence_number) ==
-        sequence_number_set_[packet.ssrc].end()) {
-      // Don't insert duplicates.
-      packet_list_.push_back(packet);
-      sequence_number_set_[packet.ssrc].insert(packet.sequence_number);
-    }
+  bool Empty() const { return prio_queue_.empty(); }
+
+  size_t SizeInPackets() const { return prio_queue_.size(); }
+
+  uint32_t SizeInBytes() const { return bytes_; }
+
+  int64_t OldestEnqueueTime() const {
+    std::list<Packet>::const_reverse_iterator it = packet_list_.rbegin();
+    if (it == packet_list_.rend())
+      return 0;
+    return it->enqueue_time_ms;
   }
 
  private:
+  // Try to add a packet to the set of ssrc/seqno identifiers currently in the
+  // queue. Return true if inserted, false if this is a duplicate.
+  bool AddToDupeSet(const Packet& packet) {
+    SsrcSeqNoMap::iterator it = dupe_map_.find(packet.ssrc);
+    if (it == dupe_map_.end()) {
+      // First for this ssrc, just insert.
+      dupe_map_[packet.ssrc].insert(packet.sequence_number);
+      return true;
+    }
+
+    // Insert returns a pair, where second is a bool set to true if new element.
+    return it->second.insert(packet.sequence_number).second;
+  }
+
+  void RemoveFromDupeSet(const Packet& packet) {
+    SsrcSeqNoMap::iterator it = dupe_map_.find(packet.ssrc);
+    assert(it != dupe_map_.end());
+    it->second.erase(packet.sequence_number);
+    if (it->second.empty()) {
+      dupe_map_.erase(it);
+    }
+  }
+
+  // List of packets, in the order the were enqueued. Since dequeueing may
+  // occur out of order, use list instead of vector.
   std::list<Packet> packet_list_;
-  std::map<uint32_t, std::set<uint16_t> > sequence_number_set_;
+  // Priority queue of the packets, sorted according to Comparator.
+  // Use pointers into list, to avoid moving whole struct within heap.
+  std::priority_queue<Packet*, std::vector<Packet*>, Comparator> prio_queue_;
+  // Total number of bytes in the queue.
+  uint64_t bytes_;
+  // Map<ssrc, set<seq_no> >, for checking duplicates.
+  typedef std::map<uint32_t, std::set<uint16_t> > SsrcSeqNoMap;
+  SsrcSeqNoMap dupe_map_;
 };
 
 class IntervalBudget {
@@ -121,6 +196,8 @@
 
   int bytes_remaining() const { return bytes_remaining_; }
 
+  int target_rate_kbps() const { return target_rate_kbps_; }
+
  private:
   int target_rate_kbps_;
   int bytes_remaining_;
@@ -131,6 +208,7 @@
 
 PacedSender::PacedSender(Clock* clock,
                          Callback* callback,
+                         int bitrate_kbps,
                          int max_bitrate_kbps,
                          int min_bitrate_kbps)
     : clock_(clock),
@@ -138,15 +216,13 @@
       critsect_(CriticalSectionWrapper::CreateCriticalSection()),
       enabled_(true),
       paused_(false),
-      max_queue_length_ms_(kDefaultMaxQueueLengthMs),
       media_budget_(new paced_sender::IntervalBudget(max_bitrate_kbps)),
       padding_budget_(new paced_sender::IntervalBudget(min_bitrate_kbps)),
+      prober_(new BitrateProber()),
+      bitrate_bps_(1000 * bitrate_kbps),
       time_last_update_us_(clock->TimeInMicroseconds()),
-      capture_time_ms_last_queued_(0),
-      capture_time_ms_last_sent_(0),
-      high_priority_packets_(new paced_sender::PacketList),
-      normal_priority_packets_(new paced_sender::PacketList),
-      low_priority_packets_(new paced_sender::PacketList) {
+      packets_(new paced_sender::PacketQueue()),
+      packet_counter_(0) {
   UpdateBytesPerInterval(kMinPacketLimitMs);
 }
 
@@ -172,11 +248,13 @@
   return enabled_;
 }
 
-void PacedSender::UpdateBitrate(int max_bitrate_kbps,
+void PacedSender::UpdateBitrate(int bitrate_kbps,
+                                int max_bitrate_kbps,
                                 int min_bitrate_kbps) {
   CriticalSectionScoped cs(critsect_.get());
   media_budget_->set_target_rate_kbps(max_bitrate_kbps);
   padding_budget_->set_target_rate_kbps(min_bitrate_kbps);
+  bitrate_bps_ = 1000 * bitrate_kbps;
 }
 
 bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
@@ -187,69 +265,51 @@
   if (!enabled_) {
     return true;  // We can send now.
   }
+  // Enable probing if the probing experiment is enabled.
+  if (!prober_->IsProbing() && ProbingExperimentIsEnabled()) {
+    prober_->SetEnabled(true);
+  }
+  prober_->MaybeInitializeProbe(bitrate_bps_);
+
   if (capture_time_ms < 0) {
     capture_time_ms = clock_->TimeInMilliseconds();
   }
-  if (priority != kHighPriority &&
-      capture_time_ms > capture_time_ms_last_queued_) {
-    capture_time_ms_last_queued_ = capture_time_ms;
-    TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", capture_time_ms,
-                             "capture_time_ms", capture_time_ms);
-  }
-  paced_sender::PacketList* packet_list = NULL;
-  switch (priority) {
-    case kHighPriority:
-      packet_list = high_priority_packets_.get();
-      break;
-    case kNormalPriority:
-      packet_list = normal_priority_packets_.get();
-      break;
-    case kLowPriority:
-      packet_list = low_priority_packets_.get();
-      break;
-  }
-  packet_list->push_back(paced_sender::Packet(ssrc,
-                                              sequence_number,
-                                              capture_time_ms,
-                                              clock_->TimeInMilliseconds(),
-                                              bytes,
-                                              retransmission));
+
+  packets_->Push(paced_sender::Packet(
+      priority, ssrc, sequence_number, capture_time_ms,
+      clock_->TimeInMilliseconds(), bytes, retransmission, packet_counter_++));
   return false;
 }
 
-void PacedSender::set_max_queue_length_ms(int max_queue_length_ms) {
+int PacedSender::ExpectedQueueTimeMs() const {
   CriticalSectionScoped cs(critsect_.get());
-  max_queue_length_ms_ = max_queue_length_ms;
+  int target_rate = media_budget_->target_rate_kbps();
+  assert(target_rate > 0);
+  return packets_->SizeInBytes() * 8 / target_rate;
+}
+
+size_t PacedSender::QueueSizePackets() const {
+  CriticalSectionScoped cs(critsect_.get());
+  return packets_->SizeInPackets();
 }
 
 int PacedSender::QueueInMs() const {
   CriticalSectionScoped cs(critsect_.get());
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  int64_t oldest_packet_enqueue_time = now_ms;
-  if (!high_priority_packets_->empty()) {
-    oldest_packet_enqueue_time =
-        std::min(oldest_packet_enqueue_time,
-                 high_priority_packets_->front().enqueue_time_ms);
-  }
-  if (!normal_priority_packets_->empty()) {
-    oldest_packet_enqueue_time =
-        std::min(oldest_packet_enqueue_time,
-                 normal_priority_packets_->front().enqueue_time_ms);
-  }
-  if (!low_priority_packets_->empty()) {
-    oldest_packet_enqueue_time =
-        std::min(oldest_packet_enqueue_time,
-                 low_priority_packets_->front().enqueue_time_ms);
-  }
-  return now_ms - oldest_packet_enqueue_time;
+
+  int64_t oldest_packet = packets_->OldestEnqueueTime();
+  if (oldest_packet == 0)
+    return 0;
+
+  return clock_->TimeInMilliseconds() - oldest_packet;
 }
 
 int32_t PacedSender::TimeUntilNextProcess() {
   CriticalSectionScoped cs(critsect_.get());
-  int64_t elapsed_time_ms = (clock_->TimeInMicroseconds() -
-      time_last_update_us_ + 500) / 1000;
-  if (elapsed_time_ms <= 0) {
-    return kMinPacketLimitMs;
+  int64_t elapsed_time_us = clock_->TimeInMicroseconds() - time_last_update_us_;
+  int elapsed_time_ms = static_cast<int>((elapsed_time_us + 500) / 1000);
+  if (prober_->IsProbing()) {
+    int next_probe = prober_->TimeUntilNextProbe(clock_->TimeInMilliseconds());
+    return next_probe;
   }
   if (elapsed_time_ms >= kMinPacketLimitMs) {
     return 0;
@@ -270,54 +330,61 @@
       uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
       UpdateBytesPerInterval(delta_time_ms);
     }
-    paced_sender::PacketList* packet_list;
-    while (ShouldSendNextPacket(&packet_list)) {
-      if (!SendPacketFromList(packet_list))
+
+    while (!packets_->Empty()) {
+      if (media_budget_->bytes_remaining() <= 0 && !prober_->IsProbing())
         return 0;
+
+      // Since we need to release the lock in order to send, we first pop the
+      // element from the priority queue but keep it in storage, so that we can
+      // reinsert it if send fails.
+      const paced_sender::Packet& packet = packets_->BeginPop();
+      if (SendPacket(packet)) {
+        // Send succeeded, remove it from the queue.
+        packets_->FinalizePop(packet);
+        if (prober_->IsProbing())
+          return 0;
+      } else {
+        // Send failed, put it back into the queue.
+        packets_->CancelPop(packet);
+        return 0;
+      }
     }
-    if (high_priority_packets_->empty() &&
-        normal_priority_packets_->empty() &&
-        low_priority_packets_->empty() &&
-        padding_budget_->bytes_remaining() > 0) {
-      int padding_needed = padding_budget_->bytes_remaining();
-      critsect_->Leave();
-      int bytes_sent = callback_->TimeToSendPadding(padding_needed);
-      critsect_->Enter();
-      media_budget_->UseBudget(bytes_sent);
-      padding_budget_->UseBudget(bytes_sent);
+
+    int padding_needed = padding_budget_->bytes_remaining();
+    if (padding_needed > 0) {
+      SendPadding(padding_needed);
     }
   }
   return 0;
 }
 
-bool PacedSender::SendPacketFromList(paced_sender::PacketList* packet_list)
-    EXCLUSIVE_LOCKS_REQUIRED(critsect_.get()) {
-  paced_sender::Packet packet = GetNextPacketFromList(packet_list);
+bool PacedSender::SendPacket(const paced_sender::Packet& packet) {
   critsect_->Leave();
-
   const bool success = callback_->TimeToSendPacket(packet.ssrc,
                                                    packet.sequence_number,
                                                    packet.capture_time_ms,
                                                    packet.retransmission);
   critsect_->Enter();
-  // If packet cannot be sent then keep it in packet list and exit early.
-  // There's no need to send more packets.
-  if (!success) {
-    return false;
+
+  if (success) {
+    // Update media bytes sent.
+    prober_->PacketSent(clock_->TimeInMilliseconds(), packet.bytes);
+    media_budget_->UseBudget(packet.bytes);
+    padding_budget_->UseBudget(packet.bytes);
   }
-  packet_list->pop_front();
-  const bool last_packet =
-      packet_list->empty() ||
-      packet_list->front().capture_time_ms > packet.capture_time_ms;
-  if (packet_list != high_priority_packets_.get()) {
-    if (packet.capture_time_ms > capture_time_ms_last_sent_) {
-      capture_time_ms_last_sent_ = packet.capture_time_ms;
-    } else if (packet.capture_time_ms == capture_time_ms_last_sent_ &&
-               last_packet) {
-      TRACE_EVENT_ASYNC_END0("webrtc_rtp", "PacedSend", packet.capture_time_ms);
-    }
-  }
-  return true;
+
+  return success;
+}
+
+void PacedSender::SendPadding(int padding_needed) {
+  critsect_->Leave();
+  int bytes_sent = callback_->TimeToSendPadding(padding_needed);
+  critsect_->Enter();
+
+  // Update padding bytes sent.
+  media_budget_->UseBudget(bytes_sent);
+  padding_budget_->UseBudget(bytes_sent);
 }
 
 void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
@@ -325,67 +392,8 @@
   padding_budget_->IncreaseBudget(delta_time_ms);
 }
 
-bool PacedSender::ShouldSendNextPacket(paced_sender::PacketList** packet_list) {
-  *packet_list = NULL;
-  if (media_budget_->bytes_remaining() <= 0) {
-    // All bytes consumed for this interval.
-    // Check if we have not sent in a too long time.
-    if (clock_->TimeInMicroseconds() - time_last_send_us_ >
-        kMaxQueueTimeWithoutSendingUs) {
-      if (!high_priority_packets_->empty()) {
-        *packet_list = high_priority_packets_.get();
-        return true;
-      }
-      if (!normal_priority_packets_->empty()) {
-        *packet_list = normal_priority_packets_.get();
-        return true;
-      }
-    }
-    // Send any old packets to avoid queuing for too long.
-    if (max_queue_length_ms_ >= 0 && QueueInMs() > max_queue_length_ms_) {
-      int64_t high_priority_capture_time = -1;
-      if (!high_priority_packets_->empty()) {
-        high_priority_capture_time =
-            high_priority_packets_->front().capture_time_ms;
-        *packet_list = high_priority_packets_.get();
-      }
-      if (!normal_priority_packets_->empty() &&
-          (high_priority_capture_time == -1 ||
-           high_priority_capture_time >
-               normal_priority_packets_->front().capture_time_ms)) {
-        *packet_list = normal_priority_packets_.get();
-      }
-      if (*packet_list)
-        return true;
-    }
-    return false;
-  }
-  if (!high_priority_packets_->empty()) {
-    *packet_list = high_priority_packets_.get();
-    return true;
-  }
-  if (!normal_priority_packets_->empty()) {
-    *packet_list = normal_priority_packets_.get();
-    return true;
-  }
-  if (!low_priority_packets_->empty()) {
-    *packet_list = low_priority_packets_.get();
-    return true;
-  }
-  return false;
+bool PacedSender::ProbingExperimentIsEnabled() const {
+  return webrtc::field_trial::FindFullName("WebRTC-BitrateProbing") ==
+         "Enabled";
 }
-
-paced_sender::Packet PacedSender::GetNextPacketFromList(
-    paced_sender::PacketList* packets) {
-  paced_sender::Packet packet = packets->front();
-  UpdateMediaBytesSent(packet.bytes);
-  return packet;
-}
-
-void PacedSender::UpdateMediaBytesSent(int num_bytes) {
-  time_last_send_us_ = clock_->TimeInMicroseconds();
-  media_budget_->UseBudget(num_bytes);
-  padding_budget_->UseBudget(num_bytes);
-}
-
 }  // namespace webrtc
diff --git a/modules/pacing/paced_sender_unittest.cc b/modules/pacing/paced_sender_unittest.cc
index 14dcdbc..34787d1 100644
--- a/modules/pacing/paced_sender_unittest.cc
+++ b/modules/pacing/paced_sender_unittest.cc
@@ -8,9 +8,10 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <list>
+
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-
 #include "webrtc/modules/pacing/include/paced_sender.h"
 #include "webrtc/system_wrappers/interface/clock.h"
 
@@ -26,8 +27,10 @@
 class MockPacedSenderCallback : public PacedSender::Callback {
  public:
   MOCK_METHOD4(TimeToSendPacket,
-      bool(uint32_t ssrc, uint16_t sequence_number, int64_t capture_time_ms,
-           bool retransmission));
+               bool(uint32_t ssrc,
+                    uint16_t sequence_number,
+                    int64_t capture_time_ms,
+                    bool retransmission));
   MOCK_METHOD1(TimeToSendPadding,
       int(int bytes));
 };
@@ -36,8 +39,10 @@
  public:
   PacedSenderPadding() : padding_sent_(0) {}
 
-  bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number,
-                        int64_t capture_time_ms, bool retransmission) {
+  bool TimeToSendPacket(uint32_t ssrc,
+                        uint16_t sequence_number,
+                        int64_t capture_time_ms,
+                        bool retransmission) {
     return true;
   }
 
@@ -54,24 +59,67 @@
   int padding_sent_;
 };
 
+class PacedSenderProbing : public PacedSender::Callback {
+ public:
+  PacedSenderProbing(const std::list<int>& expected_deltas, Clock* clock)
+      : prev_packet_time_ms_(-1),
+        expected_deltas_(expected_deltas),
+        packets_sent_(0),
+        clock_(clock) {}
+
+  bool TimeToSendPacket(uint32_t ssrc,
+                        uint16_t sequence_number,
+                        int64_t capture_time_ms,
+                        bool retransmission) {
+    ++packets_sent_;
+    EXPECT_FALSE(expected_deltas_.empty());
+    if (expected_deltas_.empty())
+      return false;
+    int64_t now_ms = clock_->TimeInMilliseconds();
+    if (prev_packet_time_ms_ >= 0) {
+      EXPECT_EQ(expected_deltas_.front(), now_ms - prev_packet_time_ms_);
+      expected_deltas_.pop_front();
+    }
+    prev_packet_time_ms_ = now_ms;
+    return true;
+  }
+
+  int TimeToSendPadding(int bytes) {
+    EXPECT_TRUE(false);
+    return bytes;
+  }
+
+  int packets_sent() const { return packets_sent_; }
+
+ private:
+  int64_t prev_packet_time_ms_;
+  std::list<int> expected_deltas_;
+  int packets_sent_;
+  Clock* clock_;
+};
+
 class PacedSenderTest : public ::testing::Test {
  protected:
   PacedSenderTest() : clock_(123456) {
     srand(0);
     // Need to initialize PacedSender after we initialize clock.
-    send_bucket_.reset(
-        new PacedSender(
-            &clock_, &callback_, kPaceMultiplier * kTargetBitrate, 0));
+    send_bucket_.reset(new PacedSender(&clock_,
+                                       &callback_,
+                                       kTargetBitrate,
+                                       kPaceMultiplier * kTargetBitrate,
+                                       0));
   }
 
   void SendAndExpectPacket(PacedSender::Priority priority,
-                           uint32_t ssrc, uint16_t sequence_number,
-                           int64_t capture_time_ms, int size,
+                           uint32_t ssrc,
+                           uint16_t sequence_number,
+                           int64_t capture_time_ms,
+                           int size,
                            bool retransmission) {
     EXPECT_FALSE(send_bucket_->SendPacket(priority, ssrc,
         sequence_number, capture_time_ms, size, retransmission));
-    EXPECT_CALL(callback_, TimeToSendPacket(
-        ssrc, sequence_number, capture_time_ms, false))
+    EXPECT_CALL(callback_,
+                TimeToSendPacket(ssrc, sequence_number, capture_time_ms, false))
         .Times(1)
         .WillRepeatedly(Return(true));
   }
@@ -85,12 +133,24 @@
   uint32_t ssrc = 12345;
   uint16_t sequence_number = 1234;
   // Due to the multiplicative factor we can send 3 packets not 2 packets.
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
   int64_t queued_packet_timestamp = clock_.TimeInMilliseconds();
   EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc,
       sequence_number, queued_packet_timestamp, 250, false));
@@ -101,16 +161,25 @@
   EXPECT_EQ(1, send_bucket_->TimeUntilNextProcess());
   clock_.AdvanceTimeMilliseconds(1);
   EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess());
-  EXPECT_CALL(callback_, TimeToSendPacket(
-      ssrc, sequence_number++, queued_packet_timestamp, false))
+  EXPECT_CALL(
+      callback_,
+      TimeToSendPacket(ssrc, sequence_number++, queued_packet_timestamp, false))
       .Times(1)
       .WillRepeatedly(Return(true));
   send_bucket_->Process();
   sequence_number++;
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
   EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc,
       sequence_number++, clock_.TimeInMilliseconds(), 250, false));
   send_bucket_->Process();
@@ -122,8 +191,12 @@
 
   // Due to the multiplicative factor we can send 3 packets not 2 packets.
   for (int i = 0; i < 3; ++i) {
-    SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                        clock_.TimeInMilliseconds(), 250, false);
+    SendAndExpectPacket(PacedSender::kNormalPriority,
+                        ssrc,
+                        sequence_number++,
+                        clock_.TimeInMilliseconds(),
+                        250,
+                        false);
   }
   for (int j = 0; j < 30; ++j) {
     EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc,
@@ -134,8 +207,7 @@
   for (int k = 0; k < 10; ++k) {
     EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess());
     clock_.AdvanceTimeMilliseconds(5);
-    EXPECT_CALL(callback_,
-        TimeToSendPacket(ssrc, _, _, false))
+    EXPECT_CALL(callback_, TimeToSendPacket(ssrc, _, _, false))
         .Times(3)
         .WillRepeatedly(Return(true));
     EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess());
@@ -145,12 +217,24 @@
   clock_.AdvanceTimeMilliseconds(5);
   EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess());
   EXPECT_EQ(0, send_bucket_->Process());
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
   EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc,
       sequence_number, clock_.TimeInMilliseconds(), 250, false));
   send_bucket_->Process();
@@ -163,8 +247,12 @@
 
   // Due to the multiplicative factor we can send 3 packets not 2 packets.
   for (int i = 0; i < 3; ++i) {
-    SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                        clock_.TimeInMilliseconds(), 250, false);
+    SendAndExpectPacket(PacedSender::kNormalPriority,
+                        ssrc,
+                        sequence_number++,
+                        clock_.TimeInMilliseconds(),
+                        250,
+                        false);
   }
   queued_sequence_number = sequence_number;
 
@@ -182,9 +270,8 @@
     clock_.AdvanceTimeMilliseconds(5);
 
     for (int i = 0; i < 3; ++i) {
-      EXPECT_CALL(callback_, TimeToSendPacket(ssrc, queued_sequence_number++,
-                                              _,
-                                              false))
+      EXPECT_CALL(callback_,
+                  TimeToSendPacket(ssrc, queued_sequence_number++, _, false))
           .Times(1)
           .WillRepeatedly(Return(true));
    }
@@ -195,12 +282,24 @@
   clock_.AdvanceTimeMilliseconds(5);
   EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess());
   EXPECT_EQ(0, send_bucket_->Process());
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
   EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc,
       sequence_number++, clock_.TimeInMilliseconds(), 250, false));
   send_bucket_->Process();
@@ -233,14 +332,27 @@
   uint32_t ssrc = 12345;
   uint16_t sequence_number = 1234;
 
-  send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
+  send_bucket_->UpdateBitrate(
+      kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate);
   // Due to the multiplicative factor we can send 3 packets not 2 packets.
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      clock_.TimeInMilliseconds(), 250, false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      clock_.TimeInMilliseconds(),
+                      250,
+                      false);
   // No padding is expected since we have sent too much already.
   EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0);
   EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess());
@@ -259,7 +371,8 @@
 
 TEST_F(PacedSenderTest, NoPaddingWhenDisabled) {
   send_bucket_->SetStatus(false);
-  send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
+  send_bucket_->UpdateBitrate(
+      kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate);
   // No padding is expected since the pacer is disabled.
   EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0);
   EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess());
@@ -279,11 +392,16 @@
   int64_t capture_time_ms = 56789;
   const int kTimeStep = 5;
   const int64_t kBitrateWindow = 100;
-  send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
+  send_bucket_->UpdateBitrate(
+      kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate);
   int64_t start_time = clock_.TimeInMilliseconds();
   while (clock_.TimeInMilliseconds() - start_time < kBitrateWindow) {
-    SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                        capture_time_ms, 250, false);
+    SendAndExpectPacket(PacedSender::kNormalPriority,
+                        ssrc,
+                        sequence_number++,
+                        capture_time_ms,
+                        250,
+                        false);
     clock_.AdvanceTimeMilliseconds(kTimeStep);
     EXPECT_CALL(callback_, TimeToSendPadding(250)).Times(1).
         WillOnce(Return(250));
@@ -298,9 +416,10 @@
   const int kTimeStep = 5;
   const int64_t kBitrateWindow = 10000;
   PacedSenderPadding callback;
-  send_bucket_.reset(
-      new PacedSender(&clock_, &callback, kPaceMultiplier * kTargetBitrate, 0));
-  send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
+  send_bucket_.reset(new PacedSender(
+      &clock_, &callback, kTargetBitrate, kPaceMultiplier * kTargetBitrate, 0));
+  send_bucket_->UpdateBitrate(
+      kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate);
   int64_t start_time = clock_.TimeInMilliseconds();
   int media_bytes = 0;
   while (clock_.TimeInMilliseconds() - start_time < kBitrateWindow) {
@@ -324,12 +443,24 @@
   int64_t capture_time_ms_low_priority = 1234567;
 
   // Due to the multiplicative factor we can send 3 packets not 2 packets.
-  SendAndExpectPacket(PacedSender::kLowPriority, ssrc, sequence_number++,
-                      capture_time_ms, 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      capture_time_ms, 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      capture_time_ms, 250, false);
+  SendAndExpectPacket(PacedSender::kLowPriority,
+                      ssrc,
+                      sequence_number++,
+                      capture_time_ms,
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      capture_time_ms,
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      capture_time_ms,
+                      250,
+                      false);
   send_bucket_->Process();
 
   // Expect normal and low priority to be queued and high to pass through.
@@ -354,8 +485,9 @@
   EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess());
   EXPECT_EQ(0, send_bucket_->Process());
 
-  EXPECT_CALL(callback_, TimeToSendPacket(
-      ssrc_low_priority, _, capture_time_ms_low_priority, false))
+  EXPECT_CALL(callback_,
+              TimeToSendPacket(
+                  ssrc_low_priority, _, capture_time_ms_low_priority, false))
       .Times(1)
       .WillRepeatedly(Return(true));
 
@@ -374,12 +506,24 @@
   EXPECT_EQ(0, send_bucket_->QueueInMs());
 
   // Due to the multiplicative factor we can send 3 packets not 2 packets.
-  SendAndExpectPacket(PacedSender::kLowPriority, ssrc, sequence_number++,
-                      capture_time_ms, 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      capture_time_ms, 250, false);
-  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
-                      capture_time_ms, 250, false);
+  SendAndExpectPacket(PacedSender::kLowPriority,
+                      ssrc,
+                      sequence_number++,
+                      capture_time_ms,
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      capture_time_ms,
+                      250,
+                      false);
+  SendAndExpectPacket(PacedSender::kNormalPriority,
+                      ssrc,
+                      sequence_number++,
+                      capture_time_ms,
+                      250,
+                      false);
   send_bucket_->Process();
 
   send_bucket_->Pause();
@@ -423,8 +567,7 @@
   EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess());
   EXPECT_EQ(0, send_bucket_->Process());
 
-  EXPECT_CALL(
-      callback_, TimeToSendPacket(_, _, second_capture_time_ms, false))
+  EXPECT_CALL(callback_, TimeToSendPacket(_, _, second_capture_time_ms, false))
       .Times(1)
       .WillRepeatedly(Return(true));
   EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess());
@@ -457,8 +600,8 @@
   EXPECT_EQ(clock_.TimeInMilliseconds() - capture_time_ms,
             send_bucket_->QueueInMs());
   // Fails to send first packet so only one call.
-  EXPECT_CALL(callback_, TimeToSendPacket(
-      ssrc, sequence_number, capture_time_ms, false))
+  EXPECT_CALL(callback_,
+              TimeToSendPacket(ssrc, sequence_number, capture_time_ms, false))
       .Times(1)
       .WillOnce(Return(false));
   clock_.AdvanceTimeMilliseconds(10000);
@@ -469,12 +612,13 @@
             send_bucket_->QueueInMs());
 
   // Fails to send second packet.
-  EXPECT_CALL(callback_, TimeToSendPacket(
-      ssrc, sequence_number, capture_time_ms, false))
+  EXPECT_CALL(callback_,
+              TimeToSendPacket(ssrc, sequence_number, capture_time_ms, false))
       .Times(1)
       .WillOnce(Return(true));
-  EXPECT_CALL(callback_, TimeToSendPacket(
-      ssrc, sequence_number + 1, capture_time_ms + 1, false))
+  EXPECT_CALL(
+      callback_,
+      TimeToSendPacket(ssrc, sequence_number + 1, capture_time_ms + 1, false))
       .Times(1)
       .WillOnce(Return(false));
   clock_.AdvanceTimeMilliseconds(10000);
@@ -485,8 +629,9 @@
             send_bucket_->QueueInMs());
 
   // Send second packet and queue becomes empty.
-  EXPECT_CALL(callback_, TimeToSendPacket(
-      ssrc, sequence_number + 1, capture_time_ms + 1, false))
+  EXPECT_CALL(
+      callback_,
+      TimeToSendPacket(ssrc, sequence_number + 1, capture_time_ms + 1, false))
       .Times(1)
       .WillOnce(Return(true));
   clock_.AdvanceTimeMilliseconds(10000);
@@ -494,34 +639,40 @@
   EXPECT_EQ(0, send_bucket_->QueueInMs());
 }
 
-TEST_F(PacedSenderTest, MaxQueueLength) {
+TEST_F(PacedSenderTest, ExpectedQueueTimeMs) {
   uint32_t ssrc = 12346;
   uint16_t sequence_number = 1234;
-  EXPECT_EQ(0, send_bucket_->QueueInMs());
+  const int32_t kNumPackets = 60;
+  const int32_t kPacketSize = 1200;
+  const int32_t kMaxBitrate = kPaceMultiplier * 30;
+  EXPECT_EQ(0, send_bucket_->ExpectedQueueTimeMs());
 
-  send_bucket_->UpdateBitrate(kPaceMultiplier * 30, 0);
-  for (int i = 0; i < 30; ++i) {
-    SendAndExpectPacket(PacedSender::kNormalPriority,
-                        ssrc,
-                        sequence_number++,
-                        clock_.TimeInMilliseconds(),
-                        1200,
-                        false);
+  send_bucket_->UpdateBitrate(30, kMaxBitrate, 0);
+  for (int i = 0; i < kNumPackets; ++i) {
+    SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
+                        clock_.TimeInMilliseconds(), kPacketSize, false);
   }
 
-  clock_.AdvanceTimeMilliseconds(2001);
-  SendAndExpectPacket(PacedSender::kNormalPriority,
-                      ssrc,
-                      sequence_number++,
-                      clock_.TimeInMilliseconds(),
-                      1200,
-                      false);
-  EXPECT_EQ(2001, send_bucket_->QueueInMs());
-  send_bucket_->Process();
-  EXPECT_EQ(0, send_bucket_->QueueInMs());
-  clock_.AdvanceTimeMilliseconds(31);
+  // Queue in ms = 1000 * (bytes in queue) / (kbit per second * 1000 / 8)
+  int32_t queue_in_ms = kNumPackets * kPacketSize * 8 / kMaxBitrate;
+  EXPECT_EQ(queue_in_ms, send_bucket_->ExpectedQueueTimeMs());
 
-  send_bucket_->Process();
+  int64_t time_start = clock_.TimeInMilliseconds();
+  while (send_bucket_->QueueSizePackets() > 0) {
+    int time_until_process = send_bucket_->TimeUntilNextProcess();
+    if (time_until_process <= 0) {
+      send_bucket_->Process();
+    } else {
+      clock_.AdvanceTimeMilliseconds(time_until_process);
+    }
+  }
+  int64_t duration = clock_.TimeInMilliseconds() - time_start;
+
+  EXPECT_EQ(0, send_bucket_->ExpectedQueueTimeMs());
+
+  // Allow for aliasing, duration should be in [expected(n - 1), expected(n)].
+  EXPECT_LE(duration, queue_in_ms);
+  EXPECT_GE(duration, queue_in_ms - (kPacketSize * 8 / kMaxBitrate));
 }
 
 TEST_F(PacedSenderTest, QueueTimeGrowsOverTime) {
@@ -529,7 +680,7 @@
   uint16_t sequence_number = 1234;
   EXPECT_EQ(0, send_bucket_->QueueInMs());
 
-  send_bucket_->UpdateBitrate(kPaceMultiplier * 30, 0);
+  send_bucket_->UpdateBitrate(30, kPaceMultiplier * 30, 0);
   SendAndExpectPacket(PacedSender::kNormalPriority,
                       ssrc,
                       sequence_number,
@@ -542,5 +693,130 @@
   send_bucket_->Process();
   EXPECT_EQ(0, send_bucket_->QueueInMs());
 }
+
+class ProbingPacedSender : public PacedSender {
+ public:
+  ProbingPacedSender(Clock* clock,
+                     Callback* callback,
+                     int bitrate_kbps,
+                     int max_bitrate_kbps,
+                     int min_bitrate_kbps)
+      : PacedSender(clock,
+                    callback,
+                    bitrate_kbps,
+                    max_bitrate_kbps,
+                    min_bitrate_kbps) {}
+
+  virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; }
+};
+
+TEST_F(PacedSenderTest, ProbingWithInitialFrame) {
+  const int kNumPackets = 15;
+  const int kPacketSize = 1200;
+  const int kInitialBitrateKbps = 300;
+  uint32_t ssrc = 12346;
+  uint16_t sequence_number = 1234;
+  const int expected_deltas[kNumPackets - 1] = {
+      12, 12, 12, 12, 8, 8, 8, 8, 8, 5, 5, 5, 5, 5};
+  std::list<int> expected_deltas_list(expected_deltas,
+                                      expected_deltas + kNumPackets - 1);
+  PacedSenderProbing callback(expected_deltas_list, &clock_);
+  send_bucket_.reset(
+      new ProbingPacedSender(&clock_,
+                             &callback,
+                             kInitialBitrateKbps,
+                             kPaceMultiplier * kInitialBitrateKbps,
+                             0));
+  for (int i = 0; i < kNumPackets; ++i) {
+    EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority,
+                                          ssrc,
+                                          sequence_number++,
+                                          clock_.TimeInMilliseconds(),
+                                          kPacketSize,
+                                          false));
+  }
+  while (callback.packets_sent() < kNumPackets) {
+    int time_until_process = send_bucket_->TimeUntilNextProcess();
+    if (time_until_process <= 0) {
+      send_bucket_->Process();
+    } else {
+      clock_.AdvanceTimeMilliseconds(time_until_process);
+    }
+  }
+}
+
+TEST_F(PacedSenderTest, PriorityInversion) {
+  uint32_t ssrc = 12346;
+  uint16_t sequence_number = 1234;
+  const int32_t kPacketSize = 1200;
+
+  EXPECT_FALSE(send_bucket_->SendPacket(
+      PacedSender::kHighPriority, ssrc, sequence_number + 3,
+      clock_.TimeInMilliseconds() + 33, kPacketSize, true));
+
+  EXPECT_FALSE(send_bucket_->SendPacket(
+      PacedSender::kHighPriority, ssrc, sequence_number + 2,
+      clock_.TimeInMilliseconds() + 33, kPacketSize, true));
+
+  EXPECT_FALSE(send_bucket_->SendPacket(
+      PacedSender::kHighPriority, ssrc, sequence_number,
+      clock_.TimeInMilliseconds(), kPacketSize, true));
+
+  EXPECT_FALSE(send_bucket_->SendPacket(
+      PacedSender::kHighPriority, ssrc, sequence_number + 1,
+      clock_.TimeInMilliseconds(), kPacketSize, true));
+
+  // Packets from earlier frames should be sent first.
+  {
+    ::testing::InSequence sequence;
+    EXPECT_CALL(callback_, TimeToSendPacket(ssrc, sequence_number,
+                                            clock_.TimeInMilliseconds(), true))
+        .WillOnce(Return(true));
+    EXPECT_CALL(callback_, TimeToSendPacket(ssrc, sequence_number + 1,
+                                            clock_.TimeInMilliseconds(), true))
+        .WillOnce(Return(true));
+    EXPECT_CALL(callback_, TimeToSendPacket(ssrc, sequence_number + 3,
+                                            clock_.TimeInMilliseconds() + 33,
+                                            true)).WillOnce(Return(true));
+    EXPECT_CALL(callback_, TimeToSendPacket(ssrc, sequence_number + 2,
+                                            clock_.TimeInMilliseconds() + 33,
+                                            true)).WillOnce(Return(true));
+
+    while (send_bucket_->QueueSizePackets() > 0) {
+      int time_until_process = send_bucket_->TimeUntilNextProcess();
+      if (time_until_process <= 0) {
+        send_bucket_->Process();
+      } else {
+        clock_.AdvanceTimeMilliseconds(time_until_process);
+      }
+    }
+  }
+}
+
+TEST_F(PacedSenderTest, PaddingOveruse) {
+  uint32_t ssrc = 12346;
+  uint16_t sequence_number = 1234;
+  const int32_t kPacketSize = 1200;
+
+  // Min bitrate 0 => no padding, padding budget will stay at 0.
+  send_bucket_->UpdateBitrate(60, 90, 0);
+  SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
+                      clock_.TimeInMilliseconds(), kPacketSize, false);
+  send_bucket_->Process();
+
+  // Add 30kbit padding. When increasing budget, media budget will increase from
+  // negative (overuse) while padding budget will increase form 0.
+  clock_.AdvanceTimeMilliseconds(5);
+  send_bucket_->UpdateBitrate(60, 90, 30);
+
+  EXPECT_FALSE(send_bucket_->SendPacket(
+      PacedSender::kHighPriority, ssrc, sequence_number++,
+      clock_.TimeInMilliseconds(), kPacketSize, false));
+
+  // Don't send padding if queue is non-empty, even if padding budget > 0.
+  EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0);
+  send_bucket_->Process();
+}
+
 }  // namespace test
 }  // namespace webrtc
diff --git a/modules/pacing/pacing.gypi b/modules/pacing/pacing.gypi
index 07b4338..3668450 100644
--- a/modules/pacing/pacing.gypi
+++ b/modules/pacing/pacing.gypi
@@ -16,6 +16,8 @@
       ],
       'sources': [
         'include/paced_sender.h',
+        'bitrate_prober.cc',
+        'bitrate_prober.h',
         'paced_sender.cc',
       ],
     },
diff --git a/modules/remote_bitrate_estimator.target.darwin-arm.mk b/modules/remote_bitrate_estimator.target.darwin-arm.mk
index 97d1c16..280e6cb 100644
--- a/modules/remote_bitrate_estimator.target.darwin-arm.mk
+++ b/modules/remote_bitrate_estimator.target.darwin-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.darwin-arm64.mk b/modules/remote_bitrate_estimator.target.darwin-arm64.mk
index c91d9df..5799e0b 100644
--- a/modules/remote_bitrate_estimator.target.darwin-arm64.mk
+++ b/modules/remote_bitrate_estimator.target.darwin-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.darwin-mips.mk b/modules/remote_bitrate_estimator.target.darwin-mips.mk
index ece0f75..15b6a88 100644
--- a/modules/remote_bitrate_estimator.target.darwin-mips.mk
+++ b/modules/remote_bitrate_estimator.target.darwin-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.darwin-mips64.mk b/modules/remote_bitrate_estimator.target.darwin-mips64.mk
new file mode 100644
index 0000000..8428295
--- /dev/null
+++ b/modules/remote_bitrate_estimator.target.darwin-mips64.mk
@@ -0,0 +1,267 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_remote_bitrate_estimator_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/remote_bitrate_estimator/rate_statistics.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_remote_bitrate_estimator_gyp
+
+# Alias gyp target name.
+.PHONY: remote_bitrate_estimator
+remote_bitrate_estimator: third_party_webrtc_modules_remote_bitrate_estimator_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/remote_bitrate_estimator.target.darwin-x86.mk b/modules/remote_bitrate_estimator.target.darwin-x86.mk
index ab826c6..88819ca 100644
--- a/modules/remote_bitrate_estimator.target.darwin-x86.mk
+++ b/modules/remote_bitrate_estimator.target.darwin-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.darwin-x86_64.mk b/modules/remote_bitrate_estimator.target.darwin-x86_64.mk
index 4292514..5a0d24e 100644
--- a/modules/remote_bitrate_estimator.target.darwin-x86_64.mk
+++ b/modules/remote_bitrate_estimator.target.darwin-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.linux-arm.mk b/modules/remote_bitrate_estimator.target.linux-arm.mk
index 97d1c16..280e6cb 100644
--- a/modules/remote_bitrate_estimator.target.linux-arm.mk
+++ b/modules/remote_bitrate_estimator.target.linux-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.linux-arm64.mk b/modules/remote_bitrate_estimator.target.linux-arm64.mk
index c91d9df..5799e0b 100644
--- a/modules/remote_bitrate_estimator.target.linux-arm64.mk
+++ b/modules/remote_bitrate_estimator.target.linux-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.linux-mips.mk b/modules/remote_bitrate_estimator.target.linux-mips.mk
index ece0f75..15b6a88 100644
--- a/modules/remote_bitrate_estimator.target.linux-mips.mk
+++ b/modules/remote_bitrate_estimator.target.linux-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.linux-mips64.mk b/modules/remote_bitrate_estimator.target.linux-mips64.mk
new file mode 100644
index 0000000..8428295
--- /dev/null
+++ b/modules/remote_bitrate_estimator.target.linux-mips64.mk
@@ -0,0 +1,267 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_remote_bitrate_estimator_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/remote_bitrate_estimator/rate_statistics.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_remote_bitrate_estimator_gyp
+
+# Alias gyp target name.
+.PHONY: remote_bitrate_estimator
+remote_bitrate_estimator: third_party_webrtc_modules_remote_bitrate_estimator_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/remote_bitrate_estimator.target.linux-x86.mk b/modules/remote_bitrate_estimator.target.linux-x86.mk
index ab826c6..88819ca 100644
--- a/modules/remote_bitrate_estimator.target.linux-x86.mk
+++ b/modules/remote_bitrate_estimator.target.linux-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator.target.linux-x86_64.mk b/modules/remote_bitrate_estimator.target.linux-x86_64.mk
index 4292514..5a0d24e 100644
--- a/modules/remote_bitrate_estimator.target.linux-x86_64.mk
+++ b/modules/remote_bitrate_estimator.target.linux-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/bwe_simulations.cc b/modules/remote_bitrate_estimator/bwe_simulations.cc
index 142de87..f47984c 100644
--- a/modules/remote_bitrate_estimator/bwe_simulations.cc
+++ b/modules/remote_bitrate_estimator/bwe_simulations.cc
@@ -98,7 +98,7 @@
 
 TEST_P(BweSimulation, PacerChoke1000kbps500kbps1000kbps) {
   VerboseLogging(true);
-  AdaptiveVideoSender source(0, NULL, 30, 300, 0, 0);
+  PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 1000);
   PacedVideoSender sender(this, 300, &source);
   ChokeFilter filter(this);
   RateCounterFilter counter(this, "receiver_input");
@@ -111,9 +111,20 @@
   RunFor(60 * 1000);
 }
 
+TEST_P(BweSimulation, PacerChoke10000kbps) {
+  VerboseLogging(true);
+  PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 0);
+  PacedVideoSender sender(this, 300, &source);
+  ChokeFilter filter(this);
+  RateCounterFilter counter(this, "receiver_input");
+  filter.SetCapacity(10000);
+  filter.SetMaxDelay(500);
+  RunFor(60 * 1000);
+}
+
 TEST_P(BweSimulation, PacerChoke200kbps30kbps200kbps) {
   VerboseLogging(true);
-  AdaptiveVideoSender source(0, NULL, 30, 300, 0, 0);
+  PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 1000);
   PacedVideoSender sender(this, 300, &source);
   ChokeFilter filter(this);
   RateCounterFilter counter(this, "receiver_input");
@@ -151,6 +162,18 @@
   RunFor(300 * 1000);
 }
 
+TEST_P(BweSimulation, PacerGoogleWifiTrace3Mbps) {
+  VerboseLogging(true);
+  PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 1000);
+  PacedVideoSender sender(this, 300, &source);
+  RateCounterFilter counter1(this, "sender_output");
+  TraceBasedDeliveryFilter filter(this, "link_capacity");
+  filter.SetMaxDelay(500);
+  RateCounterFilter counter2(this, "receiver_input");
+  ASSERT_TRUE(filter.Init(test::ResourcePath("google-wifi-3mbps", "rx")));
+  RunFor(300 * 1000);
+}
+
 class MultiFlowBweSimulation : public BweSimulation {
  public:
   MultiFlowBweSimulation() : BweSimulation() {}
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm.mk b/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm.mk
index 10d2205..fea0372 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm.mk
@@ -85,11 +85,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -105,6 +107,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -197,11 +200,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -217,6 +222,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm64.mk b/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm64.mk
index b492201..12d98bb 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm64.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.darwin-arm64.mk
@@ -74,11 +74,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -87,10 +89,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -171,11 +175,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -184,10 +190,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.darwin-mips.mk b/modules/remote_bitrate_estimator/rbe_components.target.darwin-mips.mk
index a6c42f8..6360bf8 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.darwin-mips.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.darwin-mips.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -201,6 +206,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.darwin-mips64.mk b/modules/remote_bitrate_estimator/rbe_components.target.darwin-mips64.mk
new file mode 100644
index 0000000..28ee744
--- /dev/null
+++ b/modules/remote_bitrate_estimator/rbe_components.target.darwin-mips64.mk
@@ -0,0 +1,259 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_remote_bitrate_estimator_rbe_components_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/remote_bitrate_estimator/overuse_detector.cc \
+	third_party/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc \
+	third_party/webrtc/modules/remote_bitrate_estimator/remote_rate_control.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_remote_bitrate_estimator_rbe_components_gyp
+
+# Alias gyp target name.
+.PHONY: rbe_components
+rbe_components: third_party_webrtc_modules_remote_bitrate_estimator_rbe_components_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86.mk b/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86.mk
index 2a4bcc5..ff78cbe 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -183,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -200,6 +205,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86_64.mk b/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86_64.mk
index eafe4b2..3f840c9 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86_64.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.darwin-x86_64.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.linux-arm.mk b/modules/remote_bitrate_estimator/rbe_components.target.linux-arm.mk
index 10d2205..fea0372 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.linux-arm.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.linux-arm.mk
@@ -85,11 +85,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -105,6 +107,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -197,11 +200,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -217,6 +222,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.linux-arm64.mk b/modules/remote_bitrate_estimator/rbe_components.target.linux-arm64.mk
index b492201..12d98bb 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.linux-arm64.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.linux-arm64.mk
@@ -74,11 +74,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -87,10 +89,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -171,11 +175,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -184,10 +190,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.linux-mips.mk b/modules/remote_bitrate_estimator/rbe_components.target.linux-mips.mk
index a6c42f8..6360bf8 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.linux-mips.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.linux-mips.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -201,6 +206,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.linux-mips64.mk b/modules/remote_bitrate_estimator/rbe_components.target.linux-mips64.mk
new file mode 100644
index 0000000..28ee744
--- /dev/null
+++ b/modules/remote_bitrate_estimator/rbe_components.target.linux-mips64.mk
@@ -0,0 +1,259 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_remote_bitrate_estimator_rbe_components_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/remote_bitrate_estimator/overuse_detector.cc \
+	third_party/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc \
+	third_party/webrtc/modules/remote_bitrate_estimator/remote_rate_control.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_remote_bitrate_estimator_rbe_components_gyp
+
+# Alias gyp target name.
+.PHONY: rbe_components
+rbe_components: third_party_webrtc_modules_remote_bitrate_estimator_rbe_components_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.linux-x86.mk b/modules/remote_bitrate_estimator/rbe_components.target.linux-x86.mk
index 2a4bcc5..ff78cbe 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.linux-x86.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.linux-x86.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +99,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -183,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -200,6 +205,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/rbe_components.target.linux-x86_64.mk b/modules/remote_bitrate_estimator/rbe_components.target.linux-x86_64.mk
index eafe4b2..3f840c9 100644
--- a/modules/remote_bitrate_estimator/rbe_components.target.linux-x86_64.mk
+++ b/modules/remote_bitrate_estimator/rbe_components.target.linux-x86_64.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi b/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
index f290a34..f88a16a 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
@@ -45,7 +45,7 @@
       ],
       'dependencies': [
         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
         'bwe_tools_util',
         'rtp_rtcp',
       ],
@@ -68,7 +68,7 @@
       ],
       'dependencies': [
         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
         'bwe_tools_util',
         'rtp_rtcp',
       ],
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
index f67c7f3..08ba49d 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
@@ -40,45 +40,45 @@
 }
 
 TEST_F(RemoteBitrateEstimatorSingleTest, RateIncreaseRtpTimestamps) {
-  RateIncreaseRtpTimestampsTestHelper();
+  RateIncreaseRtpTimestampsTestHelper(1621);
 }
 
 // Verify that the time it takes for the estimator to reduce the bitrate when
 // the capacity is tightened stays the same.
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStream) {
-  CapacityDropTestHelper(1, false, 956214, 367);
+  CapacityDropTestHelper(1, false, 367);
 }
 
 // Verify that the time it takes for the estimator to reduce the bitrate when
 // the capacity is tightened stays the same. This test also verifies that we
 // handle wrap-arounds in this scenario.
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrap) {
-  CapacityDropTestHelper(1, true, 956214, 367);
+  CapacityDropTestHelper(1, true, 367);
 }
 
 // Verify that the time it takes for the estimator to reduce the bitrate when
 // the capacity is tightened stays the same. This test also verifies that we
 // handle wrap-arounds in this scenario. This is a multi-stream test.
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropTwoStreamsWrap) {
-  CapacityDropTestHelper(2, true, 927088, 267);
+  CapacityDropTestHelper(2, true, 267);
 }
 
 // Verify that the time it takes for the estimator to reduce the bitrate when
 // the capacity is tightened stays the same. This test also verifies that we
 // handle wrap-arounds in this scenario. This is a multi-stream test.
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) {
-  CapacityDropTestHelper(3, true, 920944, 333);
+  CapacityDropTestHelper(3, true, 333);
 }
 
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) {
-  CapacityDropTestHelper(13, true, 938944, 300);
+  CapacityDropTestHelper(13, true, 300);
 }
 
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {
-  CapacityDropTestHelper(19, true, 926718, 300);
+  CapacityDropTestHelper(19, true, 300);
 }
 
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirtyStreamsWrap) {
-  CapacityDropTestHelper(30, true, 927016, 300);
+  CapacityDropTestHelper(30, true, 300);
 }
 }  // namespace webrtc
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc
index 1b38a1e..4f9e16c 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc
@@ -14,7 +14,7 @@
 
 namespace webrtc {
 
-enum { kMtu = 1200 };
+enum { kMtu = 1200, kAcceptedBitrateErrorBps = 50000u };
 
 namespace testing {
 
@@ -225,6 +225,7 @@
   memset(&header, 0, sizeof(header));
   header.ssrc = ssrc;
   header.timestamp = rtp_timestamp;
+  header.extension.hasAbsoluteSendTime = true;
   header.extension.absoluteSendTime = absolute_send_time;
   bitrate_estimator_->IncomingPacket(arrival_time + kArrivalTimeClockOffsetMs,
       payload_size, header);
@@ -340,7 +341,7 @@
   EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
   ASSERT_EQ(1u, ssrcs.size());
   EXPECT_EQ(kDefaultSsrc, ssrcs.front());
-  EXPECT_EQ(expected_converge_bitrate, bitrate_bps);
+  EXPECT_NEAR(expected_converge_bitrate, bitrate_bps, kAcceptedBitrateErrorBps);
   EXPECT_TRUE(bitrate_observer_->updated());
   bitrate_observer_->Reset();
   EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps);
@@ -372,7 +373,9 @@
   }
   bitrate_estimator_->Process();
   EXPECT_TRUE(bitrate_observer_->updated());
-  EXPECT_EQ(expected_bitrate_bps, bitrate_observer_->latest_bitrate());
+  EXPECT_NEAR(expected_bitrate_bps,
+              bitrate_observer_->latest_bitrate(),
+              kAcceptedBitrateErrorBps);
   for (int i = 0; i < 10; ++i) {
     clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
     timestamp += 2 * 90 * kFrameIntervalMs;
@@ -387,15 +390,17 @@
   }
   bitrate_estimator_->Process();
   EXPECT_TRUE(bitrate_observer_->updated());
-  EXPECT_EQ(expected_bitrate_bps, bitrate_observer_->latest_bitrate());
+  EXPECT_NEAR(expected_bitrate_bps,
+              bitrate_observer_->latest_bitrate(),
+              kAcceptedBitrateErrorBps);
 }
 
 // Make sure we initially increase the bitrate as expected.
-void RemoteBitrateEstimatorTest::RateIncreaseRtpTimestampsTestHelper() {
+void RemoteBitrateEstimatorTest::RateIncreaseRtpTimestampsTestHelper(
+    int expected_iterations) {
   // This threshold corresponds approximately to increasing linearly with
   // bitrate(i) = 1.04 * bitrate(i-1) + 1000
   // until bitrate(i) > 500000, with bitrate(1) ~= 30000.
-  const int kExpectedIterations = 1621;
   unsigned int bitrate_bps = 30000;
   int iterations = 0;
   AddDefaultStream();
@@ -412,15 +417,14 @@
       bitrate_observer_->Reset();
     }
     ++iterations;
-    ASSERT_LE(iterations, kExpectedIterations);
+    ASSERT_LE(iterations, expected_iterations);
   }
-  ASSERT_EQ(kExpectedIterations, iterations);
+  ASSERT_EQ(expected_iterations, iterations);
 }
 
 void RemoteBitrateEstimatorTest::CapacityDropTestHelper(
     int number_of_streams,
     bool wrap_time_stamp,
-    unsigned int expected_converge_bitrate,
     unsigned int expected_bitrate_drop_delta) {
   const int kFramerate = 30;
   const int kStartBitrate = 900e3;
@@ -430,14 +434,11 @@
   const unsigned int kReducedCapacityBps = 500e3;
 
   int steady_state_time = 0;
-  int expected_overuse_start_time = 0;
   if (number_of_streams <= 1) {
     steady_state_time = 10;
-    expected_overuse_start_time = 10000;
     AddDefaultStream();
   } else {
     steady_state_time = 8 * number_of_streams;
-    expected_overuse_start_time = 8000;
     int bitrate_sum = 0;
     int kBitrateDenom = number_of_streams * (number_of_streams - 1);
     for (int i = 0; i < number_of_streams; i++) {
@@ -471,13 +472,12 @@
                                             kMinExpectedBitrate,
                                             kMaxExpectedBitrate,
                                             kInitialCapacityBps);
-  EXPECT_EQ(expected_converge_bitrate, bitrate_bps);
+  EXPECT_NEAR(kInitialCapacityBps, bitrate_bps, 100000u);
   bitrate_observer_->Reset();
 
   // Reduce the capacity and verify the decrease time.
   stream_generator_->set_capacity_bps(kReducedCapacityBps);
   int64_t overuse_start_time = clock_.TimeInMilliseconds();
-  EXPECT_EQ(expected_overuse_start_time, overuse_start_time);
   int64_t bitrate_drop_time = -1;
   for (int i = 0; i < 100 * number_of_streams; ++i) {
     GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h
index 1d748c5..2ef2f45 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h
@@ -191,10 +191,9 @@
 
   void InitialBehaviorTestHelper(unsigned int expected_converge_bitrate);
   void RateIncreaseReorderingTestHelper(unsigned int expected_bitrate);
-  void RateIncreaseRtpTimestampsTestHelper();
+  void RateIncreaseRtpTimestampsTestHelper(int expected_iterations);
   void CapacityDropTestHelper(int number_of_streams,
                               bool wrap_time_stamp,
-                              unsigned int expected_converge_bitrate,
                               unsigned int expected_bitrate_drop_delta);
 
   static const unsigned int kDefaultSsrc;
diff --git a/modules/remote_bitrate_estimator/test/bwe_test_framework.cc b/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
index 194db4d..f7a7197 100644
--- a/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
+++ b/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
@@ -155,6 +155,7 @@
 }
 
 void Packet::SetAbsSendTimeMs(int64_t abs_send_time_ms) {
+  header_.extension.hasAbsoluteSendTime = true;
   header_.extension.absoluteSendTime = ((static_cast<int64_t>(abs_send_time_ms *
     (1 << 18)) + 500) / 1000) & 0x00fffffful;
 }
@@ -543,8 +544,11 @@
 
 }
 
-VideoSender::VideoSender(int flow_id, PacketProcessorListener* listener,
-                         float fps, uint32_t kbps, uint32_t ssrc,
+VideoSender::VideoSender(int flow_id,
+                         PacketProcessorListener* listener,
+                         float fps,
+                         uint32_t kbps,
+                         uint32_t ssrc,
                          float first_frame_offset)
     : PacketSender(listener, FlowIds(1, flow_id)),
       kMaxPayloadSizeBytes(1200),
@@ -566,6 +570,15 @@
   return (bytes_per_second_ * 8) / 1000;
 }
 
+uint32_t VideoSender::NextFrameSize() {
+  return frame_size_bytes_;
+}
+
+uint32_t VideoSender::NextPacketSize(uint32_t frame_size,
+                                     uint32_t remaining_payload) {
+  return std::min(kMaxPayloadSizeBytes, remaining_payload);
+}
+
 void VideoSender::RunFor(int64_t time_ms, Packets* in_out) {
   assert(in_out);
   now_ms_ += time_ms;
@@ -580,10 +593,12 @@
     // one packet, we will see a number of equally sized packets followed by
     // one smaller at the tail.
     int64_t send_time_us = next_frame_ms_ * 1000.0;
-    uint32_t payload_size = frame_size_bytes_;
+    uint32_t frame_size = NextFrameSize();
+    uint32_t payload_size = frame_size;
+
     while (payload_size > 0) {
       ++prototype_header_.sequenceNumber;
-      uint32_t size = std::min(kMaxPayloadSizeBytes, payload_size);
+      uint32_t size = NextPacketSize(frame_size, payload_size);
       new_packets.push_back(Packet(flow_ids()[0], send_time_us, size,
                                    prototype_header_));
       new_packets.back().SetAbsSendTimeMs(next_frame_ms_);
@@ -601,13 +616,69 @@
                                          uint32_t kbps,
                                          uint32_t ssrc,
                                          float first_frame_offset)
-    : VideoSender(flow_id, listener, fps, kbps, ssrc, first_frame_offset) {}
+    : VideoSender(flow_id, listener, fps, kbps, ssrc, first_frame_offset) {
+}
 
 void AdaptiveVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) {
-  bytes_per_second_ = feedback.estimated_bps / 8;
+  bytes_per_second_ = std::min(feedback.estimated_bps / 8, 2500000u / 8);
   frame_size_bytes_ = (bytes_per_second_ * frame_period_ms_ + 500) / 1000;
 }
 
+PeriodicKeyFrameSender::PeriodicKeyFrameSender(
+    int flow_id,
+    PacketProcessorListener* listener,
+    float fps,
+    uint32_t kbps,
+    uint32_t ssrc,
+    float first_frame_offset,
+    int key_frame_interval)
+    : AdaptiveVideoSender(flow_id,
+                          listener,
+                          fps,
+                          kbps,
+                          ssrc,
+                          first_frame_offset),
+      key_frame_interval_(key_frame_interval),
+      frame_counter_(0),
+      compensation_bytes_(0),
+      compensation_per_frame_(0) {
+}
+
+uint32_t PeriodicKeyFrameSender::NextFrameSize() {
+  uint32_t payload_size = frame_size_bytes_;
+  if (frame_counter_ == 0) {
+    payload_size = kMaxPayloadSizeBytes * 12;
+    compensation_bytes_ = 4 * frame_size_bytes_;
+    compensation_per_frame_ = compensation_bytes_ / 30;
+  } else if (key_frame_interval_ > 0 &&
+             (frame_counter_ % key_frame_interval_ == 0)) {
+    payload_size *= 5;
+    compensation_bytes_ = payload_size - frame_size_bytes_;
+    compensation_per_frame_ = compensation_bytes_ / 30;
+  } else if (compensation_bytes_ > 0) {
+    if (compensation_per_frame_ > static_cast<int>(payload_size)) {
+      // Skip this frame.
+      compensation_bytes_ -= payload_size;
+      payload_size = 0;
+    } else {
+      payload_size -= compensation_per_frame_;
+      compensation_bytes_ -= compensation_per_frame_;
+    }
+  }
+  if (compensation_bytes_ < 0)
+    compensation_bytes_ = 0;
+  ++frame_counter_;
+  return payload_size;
+}
+
+uint32_t PeriodicKeyFrameSender::NextPacketSize(uint32_t frame_size,
+                                                uint32_t remaining_payload) {
+  uint32_t fragments =
+      (frame_size + (kMaxPayloadSizeBytes - 1)) / kMaxPayloadSizeBytes;
+  uint32_t avg_size = (frame_size + fragments - 1) / fragments;
+  return std::min(avg_size, remaining_payload);
+}
+
 PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener,
                                    uint32_t kbps,
                                    AdaptiveVideoSender* source)
@@ -617,22 +688,40 @@
     : PacketSender(listener, source->flow_ids()),
       clock_(0),
       start_of_run_ms_(0),
-      pacer_(&clock_, this, PacedSender::kDefaultPaceMultiplier * kbps, 0),
-      source_(source) {}
+      pacer_(&clock_, this, kbps, PacedSender::kDefaultPaceMultiplier* kbps, 0),
+      source_(source) {
+}
 
 void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
   start_of_run_ms_ = clock_.TimeInMilliseconds();
   Packets generated_packets;
   source_->RunFor(time_ms, &generated_packets);
-  Packets::iterator it = generated_packets.begin();
   // Run process periodically to allow the packets to be paced out.
-  const int kProcessIntervalMs = 10;
-  for (int64_t current_time = 0; current_time < time_ms;
-       current_time += kProcessIntervalMs) {
-    int64_t end_of_interval_us =
-        1000 * (clock_.TimeInMilliseconds() + kProcessIntervalMs);
-    while (it != generated_packets.end() &&
-           end_of_interval_us >= it->send_time_us()) {
+  int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms;
+  Packets::iterator it = generated_packets.begin();
+  while (clock_.TimeInMilliseconds() <= end_time_ms) {
+    int time_until_process_ms = pacer_.TimeUntilNextProcess();
+    if (time_until_process_ms < 0)
+      time_until_process_ms = 0;
+    int time_until_packet_ms = time_ms;
+    if (it != generated_packets.end())
+      time_until_packet_ms =
+          (it->send_time_us() + 500) / 1000 - clock_.TimeInMilliseconds();
+    assert(time_until_packet_ms >= 0);
+    int time_until_next_event_ms = time_until_packet_ms;
+    if (time_until_process_ms < time_until_packet_ms &&
+        pacer_.QueueSizePackets() > 0)
+      time_until_next_event_ms = time_until_process_ms;
+
+    if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms) {
+      clock_.AdvanceTimeMilliseconds(end_time_ms - clock_.TimeInMilliseconds());
+      break;
+    }
+    clock_.AdvanceTimeMilliseconds(time_until_next_event_ms);
+    if (time_until_process_ms < time_until_packet_ms) {
+      // Time to process.
+      pacer_.Process();
+    } else {
       // Time to send next packet to pacer.
       pacer_.SendPacket(PacedSender::kNormalPriority,
                         it->header().ssrc,
@@ -641,16 +730,14 @@
                         it->payload_size(),
                         false);
       pacer_queue_.push_back(*it);
-      const size_t kMaxPacerQueueSize = 1000;
+      const size_t kMaxPacerQueueSize = 10000;
       if (pacer_queue_.size() > kMaxPacerQueueSize) {
         pacer_queue_.pop_front();
       }
       ++it;
     }
-    clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
-    pacer_.Process();
   }
-  QueuePackets(in_out, (start_of_run_ms_ + time_ms) * 1000);
+  QueuePackets(in_out, end_time_ms * 1000);
 }
 
 void PacedVideoSender::QueuePackets(Packets* batch,
@@ -673,7 +760,9 @@
 void PacedVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) {
   source_->GiveFeedback(feedback);
   pacer_.UpdateBitrate(
-      PacedSender::kDefaultPaceMultiplier * feedback.estimated_bps / 1000, 0);
+      feedback.estimated_bps / 1000,
+      PacedSender::kDefaultPaceMultiplier * feedback.estimated_bps / 1000,
+      0);
 }
 
 bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc,
@@ -686,7 +775,7 @@
       int64_t pace_out_time_ms = clock_.TimeInMilliseconds();
       // Make sure a packet is never paced out earlier than when it was put into
       // the pacer.
-      assert(1000 * pace_out_time_ms >= it->send_time_us());
+      assert(pace_out_time_ms >= (it->send_time_us() + 500) / 1000);
       it->SetAbsSendTimeMs(pace_out_time_ms);
       it->set_send_time_us(1000 * pace_out_time_ms);
       queue_.push_back(*it);
diff --git a/modules/remote_bitrate_estimator/test/bwe_test_framework.h b/modules/remote_bitrate_estimator/test/bwe_test_framework.h
index 0ab3b5f..6098197 100644
--- a/modules/remote_bitrate_estimator/test/bwe_test_framework.h
+++ b/modules/remote_bitrate_estimator/test/bwe_test_framework.h
@@ -387,8 +387,12 @@
 
 class VideoSender : public PacketSender {
  public:
-  VideoSender(int flow_id, PacketProcessorListener* listener, float fps,
-              uint32_t kbps, uint32_t ssrc, float first_frame_offset);
+  VideoSender(int flow_id,
+              PacketProcessorListener* listener,
+              float fps,
+              uint32_t kbps,
+              uint32_t ssrc,
+              float first_frame_offset);
   virtual ~VideoSender() {}
 
   uint32_t max_payload_size_bytes() const { return kMaxPayloadSizeBytes; }
@@ -399,6 +403,10 @@
   virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
 
  protected:
+  virtual uint32_t NextFrameSize();
+  virtual uint32_t NextPacketSize(uint32_t frame_size,
+                                  uint32_t remaining_payload);
+
   const uint32_t kMaxPayloadSizeBytes;
   const uint32_t kTimestampBase;
   const double frame_period_ms_;
@@ -427,6 +435,30 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(AdaptiveVideoSender);
 };
 
+class PeriodicKeyFrameSender : public AdaptiveVideoSender {
+ public:
+  PeriodicKeyFrameSender(int flow_id,
+                         PacketProcessorListener* listener,
+                         float fps,
+                         uint32_t kbps,
+                         uint32_t ssrc,
+                         float first_frame_offset,
+                         int key_frame_interval);
+  virtual ~PeriodicKeyFrameSender() {}
+
+ protected:
+  virtual uint32_t NextFrameSize() OVERRIDE;
+  virtual uint32_t NextPacketSize(uint32_t frame_size,
+                                  uint32_t remaining_payload) OVERRIDE;
+
+ private:
+  int key_frame_interval_;
+  uint32_t frame_counter_;
+  int compensation_bytes_;
+  int compensation_per_frame_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(PeriodicKeyFrameSender);
+};
+
 class PacedVideoSender : public PacketSender, public PacedSender::Callback {
  public:
   PacedVideoSender(PacketProcessorListener* listener,
@@ -445,12 +477,28 @@
   virtual int TimeToSendPadding(int bytes) OVERRIDE;
 
  private:
+  class ProbingPacedSender : public PacedSender {
+   public:
+    ProbingPacedSender(Clock* clock,
+                       Callback* callback,
+                       int bitrate_kbps,
+                       int max_bitrate_kbps,
+                       int min_bitrate_kbps)
+        : PacedSender(clock,
+                      callback,
+                      bitrate_kbps,
+                      max_bitrate_kbps,
+                      min_bitrate_kbps) {}
+
+    virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; }
+  };
+
   void QueuePackets(Packets* batch, int64_t end_of_batch_time_us);
 
   static const int64_t kInitialTimeMs = 0;
   SimulatedClock clock_;
   int64_t start_of_run_ms_;
-  PacedSender pacer_;
+  ProbingPacedSender pacer_;
   Packets pacer_queue_;
   Packets queue_;
   AdaptiveVideoSender* source_;
diff --git a/modules/rtp_rtcp.target.darwin-arm.mk b/modules/rtp_rtcp.target.darwin-arm.mk
index 03d2054..0b6d5b2 100644
--- a/modules/rtp_rtcp.target.darwin-arm.mk
+++ b/modules/rtp_rtcp.target.darwin-arm.mk
@@ -119,11 +119,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -139,6 +141,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -236,11 +239,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -256,6 +261,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.darwin-arm64.mk b/modules/rtp_rtcp.target.darwin-arm64.mk
index c17344d..0369ec3 100644
--- a/modules/rtp_rtcp.target.darwin-arm64.mk
+++ b/modules/rtp_rtcp.target.darwin-arm64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -121,10 +123,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -210,11 +214,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,10 +229,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.darwin-mips.mk b/modules/rtp_rtcp.target.darwin-mips.mk
index 9cead13..addcbf4 100644
--- a/modules/rtp_rtcp.target.darwin-mips.mk
+++ b/modules/rtp_rtcp.target.darwin-mips.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -223,11 +226,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -242,6 +247,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.darwin-mips64.mk b/modules/rtp_rtcp.target.darwin-mips64.mk
new file mode 100644
index 0000000..8fd5536
--- /dev/null
+++ b/modules/rtp_rtcp.target.darwin-mips64.mk
@@ -0,0 +1,299 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_rtp_rtcp_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/rtp_rtcp/source/bitrate.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_header_parser.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_sender.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_utility.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/ssrc_database.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/tmmbr_help.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/dtmf_queue.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/producer_fec.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_rtp_rtcp_gyp
+
+# Alias gyp target name.
+.PHONY: rtp_rtcp
+rtp_rtcp: third_party_webrtc_modules_rtp_rtcp_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/rtp_rtcp.target.darwin-x86.mk b/modules/rtp_rtcp.target.darwin-x86.mk
index 640347f..afad3a5 100644
--- a/modules/rtp_rtcp.target.darwin-x86.mk
+++ b/modules/rtp_rtcp.target.darwin-x86.mk
@@ -114,11 +114,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -131,6 +133,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -222,11 +225,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -239,6 +244,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.darwin-x86_64.mk b/modules/rtp_rtcp.target.darwin-x86_64.mk
index 85a9b7a..fca9b24 100644
--- a/modules/rtp_rtcp.target.darwin-x86_64.mk
+++ b/modules/rtp_rtcp.target.darwin-x86_64.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -130,6 +132,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.linux-arm.mk b/modules/rtp_rtcp.target.linux-arm.mk
index 03d2054..0b6d5b2 100644
--- a/modules/rtp_rtcp.target.linux-arm.mk
+++ b/modules/rtp_rtcp.target.linux-arm.mk
@@ -119,11 +119,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -139,6 +141,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -236,11 +239,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -256,6 +261,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.linux-arm64.mk b/modules/rtp_rtcp.target.linux-arm64.mk
index c17344d..0369ec3 100644
--- a/modules/rtp_rtcp.target.linux-arm64.mk
+++ b/modules/rtp_rtcp.target.linux-arm64.mk
@@ -108,11 +108,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -121,10 +123,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -210,11 +214,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,10 +229,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.linux-mips.mk b/modules/rtp_rtcp.target.linux-mips.mk
index 9cead13..addcbf4 100644
--- a/modules/rtp_rtcp.target.linux-mips.mk
+++ b/modules/rtp_rtcp.target.linux-mips.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -223,11 +226,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -242,6 +247,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.linux-mips64.mk b/modules/rtp_rtcp.target.linux-mips64.mk
new file mode 100644
index 0000000..8fd5536
--- /dev/null
+++ b/modules/rtp_rtcp.target.linux-mips64.mk
@@ -0,0 +1,299 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_rtp_rtcp_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/rtp_rtcp/source/bitrate.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_header_parser.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_sender.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_utility.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/ssrc_database.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/tmmbr_help.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/dtmf_queue.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/producer_fec.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc \
+	third_party/webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_rtp_rtcp_gyp
+
+# Alias gyp target name.
+.PHONY: rtp_rtcp
+rtp_rtcp: third_party_webrtc_modules_rtp_rtcp_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/rtp_rtcp.target.linux-x86.mk b/modules/rtp_rtcp.target.linux-x86.mk
index 640347f..afad3a5 100644
--- a/modules/rtp_rtcp.target.linux-x86.mk
+++ b/modules/rtp_rtcp.target.linux-x86.mk
@@ -114,11 +114,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -131,6 +133,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -222,11 +225,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -239,6 +244,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp.target.linux-x86_64.mk b/modules/rtp_rtcp.target.linux-x86_64.mk
index 85a9b7a..fca9b24 100644
--- a/modules/rtp_rtcp.target.linux-x86_64.mk
+++ b/modules/rtp_rtcp.target.linux-x86_64.mk
@@ -113,11 +113,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -130,6 +132,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc
index a934314..1d1e291 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -833,6 +833,8 @@
 
     if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack) {
       ++packet_type_counter_.nack_packets;
+      packet_type_counter_.nack_requests = nack_stats_.requests();
+      packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
     }
 }
 
@@ -842,6 +844,7 @@
                              RTCPPacketInformation& rtcpPacketInformation)
 {
     rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID);
+    nack_stats_.ReportRequest(rtcpPacket.NACKItem.PacketID);
 
     uint16_t bitMask = rtcpPacket.NACKItem.BitMask;
     if(bitMask)
@@ -851,6 +854,7 @@
             if(bitMask & 0x01)
             {
                 rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID + i);
+                nack_stats_.ReportRequest(rtcpPacket.NACKItem.PacketID + i);
             }
             bitMask = bitMask >>1;
         }
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h
index 84eb24c..087722c 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -270,6 +270,8 @@
   RtcpStatisticsCallback* stats_callback_;
 
   RtcpPacketTypeCounter packet_type_counter_;
+
+  RTCPUtility::NackStats nack_stats_;
 };
 }  // namespace webrtc
 #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index b3a9d09..2a61573 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -592,13 +592,6 @@
   EXPECT_FALSE(rtcp_packet_info_.xr_dlrr_item);
 }
 
-TEST(RtcpUtilityTest, MidNtp) {
-  const uint32_t kNtpSec = 0x12345678;
-  const uint32_t kNtpFrac = 0x23456789;
-  const uint32_t kNtpMid = 0x56782345;
-  EXPECT_EQ(kNtpMid, RTCPUtility::MidNtp(kNtpSec, kNtpFrac));
-}
-
 TEST_F(RtcpReceiverTest, TestXrRrRttInitiallyFalse) {
   uint16_t rtt_ms;
   EXPECT_FALSE(rtcp_receiver_->GetAndResetXrRrRtt(&rtt_ms));
diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc
index 1edbee4..afe8019 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -1354,7 +1354,6 @@
     RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
     pos += 4;
 
-    NACKStringBuilder stringBuilder;
     // Build NACK bitmasks and write them to the RTCP message.
     // The nack list should be sorted and not contain duplicates if one
     // wants to build the smallest rtcp nack packet.
@@ -1363,13 +1362,11 @@
                                       (IP_PACKET_SIZE - pos) / 4);
     int i = 0;
     while (i < nackSize && numOfNackFields < maxNackFields) {
-      stringBuilder.PushNACK(nackList[i]);
       uint16_t nack = nackList[i++];
       uint16_t bitmask = 0;
       while (i < nackSize) {
         int shift = static_cast<uint16_t>(nackList[i] - nack) - 1;
         if (shift >= 0 && shift <= 15) {
-          stringBuilder.PushNACK(nackList[i]);
           bitmask |= (1 << shift);
           ++i;
         } else {
@@ -1384,11 +1381,21 @@
       pos += 2;
       numOfNackFields++;
     }
-    if (i != nackSize) {
-      LOG(LS_WARNING) << "Nack list to large for one packet.";
-    }
     rtcpbuffer[nackSizePos] = static_cast<uint8_t>(2 + numOfNackFields);
+
+    if (i != nackSize) {
+      LOG(LS_WARNING) << "Nack list too large for one packet.";
+    }
+
+    // Report stats.
+    NACKStringBuilder stringBuilder;
+    for (int idx = 0; idx < i; ++idx) {
+      stringBuilder.PushNACK(nackList[idx]);
+      nack_stats_.ReportRequest(nackList[idx]);
+    }
     *nackString = stringBuilder.GetResult();
+    packet_type_counter_.nack_requests = nack_stats_.requests();
+    packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
     return 0;
 }
 
diff --git a/modules/rtp_rtcp/source/rtcp_sender.h b/modules/rtp_rtcp/source/rtcp_sender.h
index c0b8ebd..06c373b 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/modules/rtp_rtcp/source/rtcp_sender.h
@@ -360,6 +360,8 @@
 
     RtcpPacketTypeCounter packet_type_counter_
         GUARDED_BY(_criticalSectionRTCPSender);
+
+    RTCPUtility::NackStats nack_stats_ GUARDED_BY(_criticalSectionRTCPSender);
 };
 }  // namespace webrtc
 
diff --git a/modules/rtp_rtcp/source/rtcp_utility.cc b/modules/rtp_rtcp/source/rtcp_utility.cc
index 9acab73..0423389 100644
--- a/modules/rtp_rtcp/source/rtcp_utility.cc
+++ b/modules/rtp_rtcp/source/rtcp_utility.cc
@@ -17,6 +17,23 @@
 namespace webrtc {
 
 namespace RTCPUtility {
+
+NackStats::NackStats()
+    : max_sequence_number_(0),
+      requests_(0),
+      unique_requests_(0) {}
+
+NackStats::~NackStats() {}
+
+void NackStats::ReportRequest(uint16_t sequence_number) {
+  if (requests_ == 0 ||
+      webrtc::IsNewerSequenceNumber(sequence_number, max_sequence_number_)) {
+    max_sequence_number_ =  sequence_number;
+    ++unique_requests_;
+  }
+  ++requests_;
+}
+
 uint32_t MidNtp(uint32_t ntp_sec, uint32_t ntp_frac) {
   return (ntp_sec << 16) + (ntp_frac >> 16);
 }  // end RTCPUtility
diff --git a/modules/rtp_rtcp/source/rtcp_utility.h b/modules/rtp_rtcp/source/rtcp_utility.h
index f0867a7..804e8b9 100644
--- a/modules/rtp_rtcp/source/rtcp_utility.h
+++ b/modules/rtp_rtcp/source/rtcp_utility.h
@@ -19,6 +19,29 @@
 
 namespace webrtc {
 namespace RTCPUtility {
+
+class NackStats {
+ public:
+  NackStats();
+  ~NackStats();
+
+  // Updates stats with requested sequence number.
+  // This function should be called for each NACK request to calculate the
+  // number of unique NACKed RTP packets.
+  void ReportRequest(uint16_t sequence_number);
+
+  // Gets the number of NACKed RTP packets.
+  uint32_t requests() const { return requests_; }
+
+  // Gets the number of unique NACKed RTP packets.
+  uint32_t unique_requests() const { return unique_requests_; }
+
+ private:
+  uint16_t max_sequence_number_;
+  uint32_t requests_;
+  uint32_t unique_requests_;
+};
+
     uint32_t MidNtp(uint32_t ntp_sec, uint32_t ntp_frac);
 
     // CNAME
diff --git a/modules/rtp_rtcp/source/rtcp_utility_unittest.cc b/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
new file mode 100644
index 0000000..275b007
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
@@ -0,0 +1,72 @@
+/*
+ *  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.
+ */
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+namespace webrtc {
+
+TEST(RtcpUtilityTest, MidNtp) {
+  const uint32_t kNtpSec = 0x12345678;
+  const uint32_t kNtpFrac = 0x23456789;
+  const uint32_t kNtpMid = 0x56782345;
+  EXPECT_EQ(kNtpMid, RTCPUtility::MidNtp(kNtpSec, kNtpFrac));
+}
+
+TEST(RtcpUtilityTest, NackRequests) {
+  RTCPUtility::NackStats stats;
+  EXPECT_EQ(0U, stats.unique_requests());
+  EXPECT_EQ(0U, stats.requests());
+  stats.ReportRequest(10);
+  EXPECT_EQ(1U, stats.unique_requests());
+  EXPECT_EQ(1U, stats.requests());
+
+  stats.ReportRequest(10);
+  EXPECT_EQ(1U, stats.unique_requests());
+  stats.ReportRequest(11);
+  EXPECT_EQ(2U, stats.unique_requests());
+
+  stats.ReportRequest(11);
+  EXPECT_EQ(2U, stats.unique_requests());
+  stats.ReportRequest(13);
+  EXPECT_EQ(3U, stats.unique_requests());
+
+  stats.ReportRequest(11);
+  EXPECT_EQ(3U, stats.unique_requests());
+  EXPECT_EQ(6U, stats.requests());
+}
+
+TEST(RtcpUtilityTest, NackRequestsWithWrap) {
+  RTCPUtility::NackStats stats;
+  stats.ReportRequest(65534);
+  EXPECT_EQ(1U, stats.unique_requests());
+
+  stats.ReportRequest(65534);
+  EXPECT_EQ(1U, stats.unique_requests());
+  stats.ReportRequest(65535);
+  EXPECT_EQ(2U, stats.unique_requests());
+
+  stats.ReportRequest(65535);
+  EXPECT_EQ(2U, stats.unique_requests());
+  stats.ReportRequest(0);
+  EXPECT_EQ(3U, stats.unique_requests());
+
+  stats.ReportRequest(65535);
+  EXPECT_EQ(3U, stats.unique_requests());
+  stats.ReportRequest(0);
+  EXPECT_EQ(3U, stats.unique_requests());
+  stats.ReportRequest(1);
+  EXPECT_EQ(4U, stats.unique_requests());
+  EXPECT_EQ(8U, stats.requests());
+}
+
+}  // namespace webrtc
+
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
index 4868b71..24ff227 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
@@ -18,8 +18,10 @@
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
 #include "webrtc/system_wrappers/interface/scoped_vector.h"
+#include "webrtc/test/rtcp_packet_parser.h"
 
 using ::testing::_;
+using ::testing::ElementsAre;
 using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::SaveArg;
@@ -76,6 +78,10 @@
     return len;
   }
   virtual int SendRTCPPacket(int /*ch*/, const void *data, int len) OVERRIDE {
+    test::RtcpPacketParser parser;
+    parser.Parse(static_cast<const uint8_t*>(data), len);
+    last_nack_list_ = parser.nack_item()->last_nack_list();
+
     if (clock_) {
       clock_->AdvanceTimeMilliseconds(delay_ms_);
     }
@@ -89,6 +95,7 @@
   uint32_t delay_ms_;
   int rtp_packets_sent_;
   RTPHeader last_rtp_header_;
+  std::vector<uint16_t> last_nack_list_;
 };
 
 class RtpRtcpModule {
@@ -129,6 +136,9 @@
   uint16_t LastRtpSequenceNumber() {
     return transport_.last_rtp_header_.sequenceNumber;
   }
+  std::vector<uint16_t> LastNackListSent() {
+    return transport_.last_nack_list_;
+  }
 };
 }  // namespace
 
@@ -344,6 +354,46 @@
   EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets);
 }
 
+TEST_F(RtpRtcpImplTest, UniqueNackRequests) {
+  receiver_.transport_.SimulateNetworkDelay(0, &clock_);
+  EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets);
+  EXPECT_EQ(0U, receiver_.RtcpSent().nack_requests);
+  EXPECT_EQ(0U, receiver_.RtcpSent().unique_nack_requests);
+  EXPECT_EQ(0, receiver_.RtcpSent().UniqueNackRequestsInPercent());
+
+  // Receive module sends NACK request.
+  const uint16_t kNackLength = 4;
+  uint16_t nack_list[kNackLength] = {10, 11, 13, 18};
+  EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets);
+  EXPECT_EQ(4U, receiver_.RtcpSent().nack_requests);
+  EXPECT_EQ(4U, receiver_.RtcpSent().unique_nack_requests);
+  EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(10, 11, 13, 18));
+
+  // Send module receives the request.
+  EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets);
+  EXPECT_EQ(4U, sender_.RtcpReceived().nack_requests);
+  EXPECT_EQ(4U, sender_.RtcpReceived().unique_nack_requests);
+  EXPECT_EQ(100, sender_.RtcpReceived().UniqueNackRequestsInPercent());
+
+  // Receive module sends new request with duplicated packets.
+  const int kStartupRttMs = 100;
+  clock_.AdvanceTimeMilliseconds(kStartupRttMs + 1);
+  const uint16_t kNackLength2 = 4;
+  uint16_t nack_list2[kNackLength2] = {11, 18, 20, 21};
+  EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list2, kNackLength2));
+  EXPECT_EQ(2U, receiver_.RtcpSent().nack_packets);
+  EXPECT_EQ(8U, receiver_.RtcpSent().nack_requests);
+  EXPECT_EQ(6U, receiver_.RtcpSent().unique_nack_requests);
+  EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(11, 18, 20, 21));
+
+  // Send module receives the request.
+  EXPECT_EQ(2U, sender_.RtcpReceived().nack_packets);
+  EXPECT_EQ(8U, sender_.RtcpReceived().nack_requests);
+  EXPECT_EQ(6U, sender_.RtcpReceived().unique_nack_requests);
+  EXPECT_EQ(75, sender_.RtcpReceived().UniqueNackRequestsInPercent());
+}
+
 class RtpSendingTestTransport : public Transport {
  public:
   void ResetCounters() { bytes_received_.clear(); }
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index f544db2..0438b9f 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -50,12 +50,17 @@
                      FrameCountObserver* frame_count_observer,
                      SendSideDelayObserver* send_side_delay_observer)
     : clock_(clock),
+      // TODO(holmer): Remove this conversion when we remove the use of
+      // TickTime.
+      clock_delta_ms_(clock_->TimeInMilliseconds() -
+                      TickTime::MillisecondTimestamp()),
       bitrate_sent_(clock, this),
       id_(id),
       audio_configured_(audio),
       audio_(NULL),
       video_(NULL),
       paced_sender_(paced_sender),
+      last_capture_time_ms_sent_(0),
       send_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
       transport_(transport),
       sending_media_(true),                      // Default to sending media.
@@ -622,15 +627,10 @@
     }
     // Convert from TickTime to Clock since capture_time_ms is based on
     // TickTime.
-    // TODO(holmer): Remove this conversion when we remove the use of TickTime.
-    int64_t clock_delta_ms = clock_->TimeInMilliseconds() -
-        TickTime::MillisecondTimestamp();
-    if (!paced_sender_->SendPacket(PacedSender::kHighPriority,
-                                   header.ssrc,
-                                   header.sequenceNumber,
-                                   capture_time_ms + clock_delta_ms,
-                                   length - header.headerLength,
-                                   true)) {
+    int64_t corrected_capture_tims_ms = capture_time_ms + clock_delta_ms_;
+    if (!paced_sender_->SendPacket(
+            PacedSender::kHighPriority, header.ssrc, header.sequenceNumber,
+            corrected_capture_tims_ms, length - header.headerLength, true)) {
       // We can't send the packet right now.
       // We will be called when it is time.
       return length;
@@ -819,6 +819,10 @@
   RtpUtility::RtpHeaderParser rtp_parser(buffer, length);
   RTPHeader rtp_header;
   rtp_parser.Parse(rtp_header);
+  if (!is_retransmit && rtp_header.markerBit) {
+    TRACE_EVENT_ASYNC_END0("webrtc_rtp", "PacedSend", capture_time_ms);
+  }
+
   TRACE_EVENT_INSTANT2("webrtc_rtp", "PrepareAndSendPacket",
                        "timestamp", rtp_header.timestamp,
                        "seqnum", rtp_header.sequenceNumber);
@@ -937,12 +941,18 @@
   }
 
   if (paced_sender_ && storage != kDontStore) {
-    int64_t clock_delta_ms = clock_->TimeInMilliseconds() -
-        TickTime::MillisecondTimestamp();
+    // Correct offset between implementations of millisecond time stamps in
+    // TickTime and Clock.
+    int64_t corrected_time_ms = capture_time_ms + clock_delta_ms_;
     if (!paced_sender_->SendPacket(priority, rtp_header.ssrc,
-                                   rtp_header.sequenceNumber,
-                                   capture_time_ms + clock_delta_ms,
+                                   rtp_header.sequenceNumber, corrected_time_ms,
                                    payload_length, false)) {
+      if (last_capture_time_ms_sent_ == 0 ||
+          corrected_time_ms > last_capture_time_ms_sent_) {
+        last_capture_time_ms_sent_ = corrected_time_ms;
+        TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", corrected_time_ms,
+                                 "capture_time_ms", corrected_time_ms);
+      }
       // We can't send the packet right now.
       // We will be called when it is time.
       return 0;
@@ -954,7 +964,6 @@
   uint32_t length = payload_length + rtp_header_length;
   if (!SendPacketToNetwork(buffer, length))
     return -1;
-  assert(payload_length - rtp_header.paddingLength > 0);
   {
     CriticalSectionScoped lock(send_critsect_);
     media_has_been_sent_ = true;
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index b2f2e0c..780baa1 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -336,6 +336,7 @@
   bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const;
 
   Clock* clock_;
+  int64_t clock_delta_ms_;
   Bitrate bitrate_sent_;
 
   int32_t id_;
@@ -344,6 +345,7 @@
   RTPSenderVideo *video_;
 
   PacedSender *paced_sender_;
+  int64_t last_capture_time_ms_sent_;
   CriticalSectionWrapper *send_critsect_;
 
   Transport *transport_;
diff --git a/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java b/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java
index 926b350..2ebf911 100644
--- a/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java
+++ b/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java
@@ -11,11 +11,13 @@
 package org.webrtc.videoengine;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.concurrent.Exchanger;
 
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
+import android.hardware.Camera.Parameters;
 import android.hardware.Camera.PreviewCallback;
 import android.hardware.Camera;
 import android.opengl.GLES11Ext;
@@ -58,6 +60,7 @@
   private double averageDurationMs;
   private long lastCaptureTimeMs;
   private int frameCount;
+  private int frameDropRatio;
 
   // Requests future capturers to send their frames to |localPreview| directly.
   public static void setLocalPreview(SurfaceHolder localPreview) {
@@ -169,8 +172,40 @@
       if (parameters.isVideoStabilizationSupported()) {
         parameters.setVideoStabilization(true);
       }
+      parameters.setPictureSize(width, height);
       parameters.setPreviewSize(width, height);
+
+      // Check if requested fps range is supported by camera,
+      // otherwise calculate frame drop ratio.
+      List<int[]> supportedFpsRanges = parameters.getSupportedPreviewFpsRange();
+      frameDropRatio = Integer.MAX_VALUE;
+      for (int i = 0; i < supportedFpsRanges.size(); i++) {
+        int[] range = supportedFpsRanges.get(i);
+        if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == min_mfps &&
+            range[Parameters.PREVIEW_FPS_MAX_INDEX] == max_mfps) {
+          frameDropRatio = 1;
+          break;
+        }
+        if (range[Parameters.PREVIEW_FPS_MIN_INDEX] % min_mfps == 0 &&
+            range[Parameters.PREVIEW_FPS_MAX_INDEX] % max_mfps == 0) {
+          int dropRatio = range[Parameters.PREVIEW_FPS_MAX_INDEX] / max_mfps;
+          frameDropRatio = Math.min(dropRatio, frameDropRatio);
+        }
+      }
+      if (frameDropRatio == Integer.MAX_VALUE) {
+        Log.e(TAG, "Can not find camera fps range");
+        error = new RuntimeException("Can not find camera fps range");
+        exchange(result, false);
+        return;
+      }
+      if (frameDropRatio > 1) {
+        Log.d(TAG, "Frame dropper is enabled. Ratio: " + frameDropRatio);
+      }
+      min_mfps *= frameDropRatio;
+      max_mfps *= frameDropRatio;
+      Log.d(TAG, "Camera preview mfps range: " + min_mfps + " - " + max_mfps);
       parameters.setPreviewFpsRange(min_mfps, max_mfps);
+
       int format = ImageFormat.NV21;
       parameters.setPreviewFormat(format);
       camera.setParameters(parameters);
@@ -180,7 +215,7 @@
       }
       camera.setPreviewCallbackWithBuffer(this);
       frameCount = 0;
-      averageDurationMs = 1000 / max_mfps;
+      averageDurationMs = 1000000.0f / (max_mfps / frameDropRatio);
       camera.startPreview();
       exchange(result, true);
       return;
@@ -296,8 +331,13 @@
       throw new RuntimeException("Unexpected camera in callback!");
     }
     frameCount++;
+    // Check if frame needs to be dropped.
+    if ((frameDropRatio > 1) && (frameCount % frameDropRatio) > 0) {
+      camera.addCallbackBuffer(data);
+      return;
+    }
     long captureTimeMs = SystemClock.elapsedRealtime();
-    if (frameCount > 1) {
+    if (frameCount > frameDropRatio) {
       double durationMs = captureTimeMs - lastCaptureTimeMs;
       averageDurationMs = 0.9 * averageDurationMs + 0.1 * durationMs;
       if ((frameCount % 30) == 0) {
diff --git a/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java b/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
index fe207ca..4b0089b 100644
--- a/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
+++ b/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
@@ -75,6 +75,36 @@
           sizes.put(size);
         }
 
+        boolean is30fpsRange = false;
+        boolean is15fpsRange = false;
+        // If there is constant 30 fps mode, but no 15 fps - add 15 fps
+        // mode to the list of supported ranges. Frame drop will be done
+        // in software.
+        for (int[] range : supportedFpsRanges) {
+          if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == 30000 &&
+              range[Parameters.PREVIEW_FPS_MAX_INDEX] == 30000) {
+            is30fpsRange = true;
+          }
+          if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == 15000 &&
+              range[Parameters.PREVIEW_FPS_MAX_INDEX] == 15000) {
+            is15fpsRange = true;
+          }
+        }
+        if (is30fpsRange && !is15fpsRange) {
+          Log.d(TAG, "Adding 15 fps support");
+          int[] newRange = new int [Parameters.PREVIEW_FPS_MAX_INDEX + 1];
+          newRange[Parameters.PREVIEW_FPS_MIN_INDEX] = 15000;
+          newRange[Parameters.PREVIEW_FPS_MAX_INDEX] = 15000;
+          for (int j = 0; j < supportedFpsRanges.size(); j++ ) {
+            int[] range = supportedFpsRanges.get(j);
+            if (range[Parameters.PREVIEW_FPS_MAX_INDEX] >
+                newRange[Parameters.PREVIEW_FPS_MAX_INDEX]) {
+              supportedFpsRanges.add(j, newRange);
+              break;
+            }
+          }
+        }
+
         JSONArray mfpsRanges = new JSONArray();
         for (int[] range : supportedFpsRanges) {
           JSONObject mfpsRange = new JSONObject();
diff --git a/modules/video_capture/video_capture.gypi b/modules/video_capture/video_capture.gypi
index 888d772..22b8e02 100644
--- a/modules/video_capture/video_capture.gypi
+++ b/modules/video_capture/video_capture.gypi
@@ -161,7 +161,7 @@
           'type': '<(gtest_target_type)',
           'dependencies': [
             'video_capture_module',
-	    'video_capture_module_internal_impl',
+            'video_capture_module_internal_impl',
             'webrtc_utility',
             '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
             '<(DEPTH)/testing/gtest.gyp:gtest',
@@ -192,13 +192,13 @@
               'dependencies': [
                 '<(DEPTH)/testing/android/native_test.gyp:native_test_native_code',
               ],
-	      # Need to disable error due to the line in
-	      # base/android/jni_android.h triggering it:
-	      # const BASE_EXPORT jobject GetApplicationContext()
-	      # error: type qualifiers ignored on function return type
-	      'cflags': [
-	        '-Wno-ignored-qualifiers',
-	      ],
+              # Need to disable error due to the line in
+              # base/android/jni_android.h triggering it:
+              # const BASE_EXPORT jobject GetApplicationContext()
+              # error: type qualifiers ignored on function return type
+              'cflags': [
+                '-Wno-ignored-qualifiers',
+              ],
             }],
             ['OS=="mac"', {
               'dependencies': [
@@ -243,7 +243,6 @@
               ],
               'includes': [
                 '../../build/isolate.gypi',
-                'video_capture_tests.isolate',
               ],
               'sources': [
                 'video_capture_tests.isolate',
diff --git a/modules/video_capture/video_capture_tests.isolate b/modules/video_capture/video_capture_tests.isolate
index 57dd667..be10437 100644
--- a/modules/video_capture/video_capture_tests.isolate
+++ b/modules/video_capture/video_capture_tests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,13 +21,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/video_capture_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/video_capture_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/modules/video_capture_module.target.darwin-arm.mk b/modules/video_capture_module.target.darwin-arm.mk
index d007c5d..8aac804 100644
--- a/modules/video_capture_module.target.darwin-arm.mk
+++ b/modules/video_capture_module.target.darwin-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.darwin-arm64.mk b/modules/video_capture_module.target.darwin-arm64.mk
index 5afb948..372bca5 100644
--- a/modules/video_capture_module.target.darwin-arm64.mk
+++ b/modules/video_capture_module.target.darwin-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.darwin-mips.mk b/modules/video_capture_module.target.darwin-mips.mk
index 960b8fa..afe1d56 100644
--- a/modules/video_capture_module.target.darwin-mips.mk
+++ b/modules/video_capture_module.target.darwin-mips.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.darwin-mips64.mk b/modules/video_capture_module.target.darwin-mips64.mk
new file mode 100644
index 0000000..5b80915
--- /dev/null
+++ b/modules/video_capture_module.target.darwin-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_capture_module_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_capture/device_info_impl.cc \
+	third_party/webrtc/modules/video_capture/video_capture_factory.cc \
+	third_party/webrtc/modules/video_capture/video_capture_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_capture_module_gyp
+
+# Alias gyp target name.
+.PHONY: video_capture_module
+video_capture_module: third_party_webrtc_modules_video_capture_module_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_capture_module.target.darwin-x86.mk b/modules/video_capture_module.target.darwin-x86.mk
index 3d67380..702cc35 100644
--- a/modules/video_capture_module.target.darwin-x86.mk
+++ b/modules/video_capture_module.target.darwin-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.darwin-x86_64.mk b/modules/video_capture_module.target.darwin-x86_64.mk
index 127814e..01a7bef 100644
--- a/modules/video_capture_module.target.darwin-x86_64.mk
+++ b/modules/video_capture_module.target.darwin-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.linux-arm.mk b/modules/video_capture_module.target.linux-arm.mk
index d007c5d..8aac804 100644
--- a/modules/video_capture_module.target.linux-arm.mk
+++ b/modules/video_capture_module.target.linux-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.linux-arm64.mk b/modules/video_capture_module.target.linux-arm64.mk
index 5afb948..372bca5 100644
--- a/modules/video_capture_module.target.linux-arm64.mk
+++ b/modules/video_capture_module.target.linux-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.linux-mips.mk b/modules/video_capture_module.target.linux-mips.mk
index 960b8fa..afe1d56 100644
--- a/modules/video_capture_module.target.linux-mips.mk
+++ b/modules/video_capture_module.target.linux-mips.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.linux-mips64.mk b/modules/video_capture_module.target.linux-mips64.mk
new file mode 100644
index 0000000..5b80915
--- /dev/null
+++ b/modules/video_capture_module.target.linux-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_capture_module_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_capture/device_info_impl.cc \
+	third_party/webrtc/modules/video_capture/video_capture_factory.cc \
+	third_party/webrtc/modules/video_capture/video_capture_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_capture_module_gyp
+
+# Alias gyp target name.
+.PHONY: video_capture_module
+video_capture_module: third_party_webrtc_modules_video_capture_module_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_capture_module.target.linux-x86.mk b/modules/video_capture_module.target.linux-x86.mk
index 3d67380..702cc35 100644
--- a/modules/video_capture_module.target.linux-x86.mk
+++ b/modules/video_capture_module.target.linux-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module.target.linux-x86_64.mk b/modules/video_capture_module.target.linux-x86_64.mk
index 127814e..01a7bef 100644
--- a/modules/video_capture_module.target.linux-x86_64.mk
+++ b/modules/video_capture_module.target.linux-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.darwin-arm.mk b/modules/video_capture_module_impl.target.darwin-arm.mk
index 1df21a9..7e0df19 100644
--- a/modules/video_capture_module_impl.target.darwin-arm.mk
+++ b/modules/video_capture_module_impl.target.darwin-arm.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.darwin-arm64.mk b/modules/video_capture_module_impl.target.darwin-arm64.mk
index 758069c..b67e56a 100644
--- a/modules/video_capture_module_impl.target.darwin-arm64.mk
+++ b/modules/video_capture_module_impl.target.darwin-arm64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -90,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.darwin-mips.mk b/modules/video_capture_module_impl.target.darwin-mips.mk
index 5611034..265e3bc 100644
--- a/modules/video_capture_module_impl.target.darwin-mips.mk
+++ b/modules/video_capture_module_impl.target.darwin-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.darwin-mips64.mk b/modules/video_capture_module_impl.target.darwin-mips64.mk
new file mode 100644
index 0000000..0155245
--- /dev/null
+++ b/modules/video_capture_module_impl.target.darwin-mips64.mk
@@ -0,0 +1,266 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_capture_module_impl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_capture/external/device_info_external.cc \
+	third_party/webrtc/modules/video_capture/external/video_capture_external.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_capture_module_impl_gyp
+
+# Alias gyp target name.
+.PHONY: video_capture_module_impl
+video_capture_module_impl: third_party_webrtc_modules_video_capture_module_impl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_capture_module_impl.target.darwin-x86.mk b/modules/video_capture_module_impl.target.darwin-x86.mk
index 35ddb50..52a6a51 100644
--- a/modules/video_capture_module_impl.target.darwin-x86.mk
+++ b/modules/video_capture_module_impl.target.darwin-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.darwin-x86_64.mk b/modules/video_capture_module_impl.target.darwin-x86_64.mk
index 671273c..7e4d529 100644
--- a/modules/video_capture_module_impl.target.darwin-x86_64.mk
+++ b/modules/video_capture_module_impl.target.darwin-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.linux-arm.mk b/modules/video_capture_module_impl.target.linux-arm.mk
index 1df21a9..7e0df19 100644
--- a/modules/video_capture_module_impl.target.linux-arm.mk
+++ b/modules/video_capture_module_impl.target.linux-arm.mk
@@ -88,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.linux-arm64.mk b/modules/video_capture_module_impl.target.linux-arm64.mk
index 758069c..b67e56a 100644
--- a/modules/video_capture_module_impl.target.linux-arm64.mk
+++ b/modules/video_capture_module_impl.target.linux-arm64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -90,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.linux-mips.mk b/modules/video_capture_module_impl.target.linux-mips.mk
index 5611034..265e3bc 100644
--- a/modules/video_capture_module_impl.target.linux-mips.mk
+++ b/modules/video_capture_module_impl.target.linux-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.linux-mips64.mk b/modules/video_capture_module_impl.target.linux-mips64.mk
new file mode 100644
index 0000000..0155245
--- /dev/null
+++ b/modules/video_capture_module_impl.target.linux-mips64.mk
@@ -0,0 +1,266 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_capture_module_impl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_capture/external/device_info_external.cc \
+	third_party/webrtc/modules/video_capture/external/video_capture_external.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_capture_module_impl_gyp
+
+# Alias gyp target name.
+.PHONY: video_capture_module_impl
+video_capture_module_impl: third_party_webrtc_modules_video_capture_module_impl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_capture_module_impl.target.linux-x86.mk b/modules/video_capture_module_impl.target.linux-x86.mk
index 35ddb50..52a6a51 100644
--- a/modules/video_capture_module_impl.target.linux-x86.mk
+++ b/modules/video_capture_module_impl.target.linux-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_capture_module_impl.target.linux-x86_64.mk b/modules/video_capture_module_impl.target.linux-x86_64.mk
index 671273c..7e4d529 100644
--- a/modules/video_capture_module_impl.target.linux-x86_64.mk
+++ b/modules/video_capture_module_impl.target.linux-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index 07e7afc..706e9d9 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -77,6 +77,7 @@
     ":video_coding_utility",
     ":webrtc_i420",
     ":webrtc_vp8",
+    ":webrtc_vp9",
     "../../common_video",
     "../../system_wrappers",
   ]
@@ -159,3 +160,35 @@
     ]
   }
 }
+
+source_set("webrtc_vp9") {
+  sources = [
+    "codecs/vp9/include/vp9.h",
+    "codecs/vp9/vp9_impl.cc",
+    "codecs/vp9/vp9_impl.h",
+  ]
+
+  configs += [ "../..:common_config" ]
+  public_configs = [ "../..:common_inherited_config" ]
+
+  if (is_clang) {
+    # Suppress warnings from Chrome's Clang plugins.
+    # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
+    configs -= [ "//build/config/clang:find_bad_constructs" ]
+  }
+
+  # TODO(kjellander): Remove once libvpx has changed it's libvpx_config to be
+  # in direct_dependent_configs.
+  configs += [ "//third_party/libvpx:libvpx_config" ]
+
+  deps = [
+    ":video_coding_utility",
+    "../../common_video",
+    "../../system_wrappers",
+  ]
+  if (rtc_build_libvpx) {
+    deps += [
+      "//third_party/libvpx",
+    ]
+  }
+}
diff --git a/modules/video_coding/codecs/interface/video_codec_interface.h b/modules/video_coding/codecs/interface/video_codec_interface.h
index 82bcd26..da72feb 100644
--- a/modules/video_coding/codecs/interface/video_codec_interface.h
+++ b/modules/video_coding/codecs/interface/video_codec_interface.h
@@ -18,6 +18,7 @@
 #include "webrtc/modules/interface/module_common_types.h"
 #include "webrtc/modules/video_coding/codecs/interface/video_error_codes.h"
 #include "webrtc/typedefs.h"
+#include "webrtc/video_decoder.h"
 #include "webrtc/video_encoder.h"
 
 namespace webrtc
@@ -41,6 +42,19 @@
   int8_t keyIdx;  // Negative value to skip keyIdx.
 };
 
+struct CodecSpecificInfoVP9 {
+  bool hasReceivedSLI;
+  uint8_t pictureIdSLI;
+  bool hasReceivedRPSI;
+  uint64_t pictureIdRPSI;
+  int16_t pictureId;  // Negative value to skip pictureId.
+  bool nonReference;
+  uint8_t temporalIdx;
+  bool layerSync;
+  int tl0PicIdx;  // Negative value to skip tl0PicIdx.
+  int8_t keyIdx;  // Negative value to skip keyIdx.
+};
+
 struct CodecSpecificInfoGeneric {
   uint8_t simulcast_idx;
 };
@@ -50,6 +64,7 @@
 union CodecSpecificInfoUnion {
   CodecSpecificInfoGeneric generic;
   CodecSpecificInfoVP8 VP8;
+  CodecSpecificInfoVP9 VP9;
   CodecSpecificInfoH264 H264;
 };
 
@@ -62,96 +77,6 @@
     CodecSpecificInfoUnion codecSpecific;
 };
 
-class DecodedImageCallback
-{
-public:
-    virtual ~DecodedImageCallback() {};
-
-    // Callback function which is called when an image has been decoded.
-    //
-    // Input:
-    //          - decodedImage         : The decoded image.
-    //
-    // Return value                    : 0 if OK, < 0 otherwise.
-    virtual int32_t Decoded(I420VideoFrame& decodedImage) = 0;
-
-    virtual int32_t ReceivedDecodedReferenceFrame(const uint64_t pictureId) {return -1;}
-
-    virtual int32_t ReceivedDecodedFrame(const uint64_t pictureId) {return -1;}
-};
-
-class VideoDecoder
-{
-public:
-    virtual ~VideoDecoder() {};
-
-    // Initialize the decoder with the information from the VideoCodec.
-    //
-    // Input:
-    //          - inst              : Codec settings
-    //          - numberOfCores     : Number of cores available for the decoder
-    //
-    // Return value                 : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
-    virtual int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores) = 0;
-
-    // Decode encoded image (as a part of a video stream). The decoded image
-    // will be returned to the user through the decode complete callback.
-    //
-    // Input:
-    //          - inputImage        : Encoded image to be decoded
-    //          - missingFrames     : True if one or more frames have been lost
-    //                                since the previous decode call.
-    //          - fragmentation     : Specifies where the encoded frame can be
-    //                                split into separate fragments. The meaning
-    //                                of fragment is codec specific, but often
-    //                                means that each fragment is decodable by
-    //                                itself.
-    //          - codecSpecificInfo : Pointer to codec specific data
-    //          - renderTimeMs      : System time to render in milliseconds. Only
-    //                                used by decoders with internal rendering.
-    //
-    // Return value                 : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
-    virtual int32_t
-    Decode(const EncodedImage& inputImage,
-           bool missingFrames,
-           const RTPFragmentationHeader* fragmentation,
-           const CodecSpecificInfo* codecSpecificInfo = NULL,
-           int64_t renderTimeMs = -1) = 0;
-
-    // Register an decode complete callback object.
-    //
-    // Input:
-    //          - callback         : Callback object which handles decoded images.
-    //
-    // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
-    virtual int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback) = 0;
-
-    // Free decoder memory.
-    //
-    // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
-    virtual int32_t Release() = 0;
-
-    // Reset decoder state and prepare for a new call.
-    //
-    // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
-    virtual int32_t Reset() = 0;
-
-    // Codec configuration data sent out-of-band, i.e. in SIP call setup
-    //
-    // Input/Output:
-    //          - buffer           : Buffer pointer to the configuration data
-    //          - size             : The size of the configuration data in
-    //                               bytes
-    //
-    // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
-    virtual int32_t SetCodecConfigParameters(const uint8_t* /*buffer*/, int32_t /*size*/) { return WEBRTC_VIDEO_CODEC_ERROR; }
-
-    // Create a copy of the codec and its internal state.
-    //
-    // Return value                : A copy of the instance if OK, NULL otherwise.
-    virtual VideoDecoder* Copy() { return NULL; }
-};
-
 }  // namespace webrtc
 
 #endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_INTERFACE_VIDEO_CODEC_INTERFACE_H
diff --git a/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc b/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc
index bd4a563..73f774d 100644
--- a/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc
+++ b/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc
@@ -16,6 +16,7 @@
 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h"
 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h"
 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
+#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
 #include "webrtc/test/testsupport/fileutils.h"
@@ -37,6 +38,7 @@
 
 // Codec and network settings.
 struct CodecConfigPars {
+  VideoCodecType codec_type;
   float packet_loss;
   int num_temporal_layers;
   int key_frame_interval;
@@ -136,6 +138,7 @@
   float start_bitrate_;
 
   // Codec and network settings.
+  VideoCodecType codec_type_;
   float packet_loss_;
   int num_temporal_layers_;
   int key_frame_interval_;
@@ -149,8 +152,15 @@
   virtual ~VideoProcessorIntegrationTest() {}
 
   void SetUpCodecConfig() {
-    encoder_ = VP8Encoder::Create();
-    decoder_ = VP8Decoder::Create();
+    if (codec_type_ == kVideoCodecVP8) {
+      encoder_ = VP8Encoder::Create();
+      decoder_ = VP8Decoder::Create();
+      VideoCodingModule::Codec(kVideoCodecVP8, &codec_settings_);
+    } else if (codec_type_ == kVideoCodecVP9) {
+      encoder_ = VP9Encoder::Create();
+      decoder_ = VP9Decoder::Create();
+      VideoCodingModule::Codec(kVideoCodecVP9, &codec_settings_);
+    }
 
     // CIF is currently used for all tests below.
     // Setup the TestConfig struct for processing of a clip in CIF resolution.
@@ -169,26 +179,42 @@
     config_.keyframe_interval = key_frame_interval_;
     config_.networking_config.packet_loss_probability = packet_loss_;
 
-    // Get a codec configuration struct and configure it.
-    VideoCodingModule::Codec(kVideoCodecVP8, &codec_settings_);
+    // Configure codec settings.
     config_.codec_settings = &codec_settings_;
     config_.codec_settings->startBitrate = start_bitrate_;
     config_.codec_settings->width = kCIFWidth;
     config_.codec_settings->height = kCIFHeight;
-    // These features may be set depending on the test.
-    config_.codec_settings->codecSpecific.VP8.errorConcealmentOn =
-        error_concealment_on_;
-    config_.codec_settings->codecSpecific.VP8.denoisingOn =
-        denoising_on_;
-    config_.codec_settings->codecSpecific.VP8.numberOfTemporalLayers =
-        num_temporal_layers_;
-    config_.codec_settings->codecSpecific.VP8.frameDroppingOn =
-        frame_dropper_on_;
-    config_.codec_settings->codecSpecific.VP8.automaticResizeOn =
-        spatial_resize_on_;
-    config_.codec_settings->codecSpecific.VP8.keyFrameInterval =
-        kBaseKeyFrameInterval;
 
+    // These features may be set depending on the test.
+    switch (config_.codec_settings->codecType) {
+     case kVideoCodecVP8:
+       config_.codec_settings->codecSpecific.VP8.errorConcealmentOn =
+           error_concealment_on_;
+       config_.codec_settings->codecSpecific.VP8.denoisingOn =
+           denoising_on_;
+       config_.codec_settings->codecSpecific.VP8.numberOfTemporalLayers =
+           num_temporal_layers_;
+       config_.codec_settings->codecSpecific.VP8.frameDroppingOn =
+           frame_dropper_on_;
+       config_.codec_settings->codecSpecific.VP8.automaticResizeOn =
+           spatial_resize_on_;
+       config_.codec_settings->codecSpecific.VP8.keyFrameInterval =
+           kBaseKeyFrameInterval;
+       break;
+     case kVideoCodecVP9:
+       config_.codec_settings->codecSpecific.VP9.denoisingOn =
+           denoising_on_;
+       config_.codec_settings->codecSpecific.VP9.numberOfTemporalLayers =
+           num_temporal_layers_;
+       config_.codec_settings->codecSpecific.VP9.frameDroppingOn =
+           frame_dropper_on_;
+       config_.codec_settings->codecSpecific.VP9.keyFrameInterval =
+           kBaseKeyFrameInterval;
+       break;
+     default:
+       assert(false);
+       break;
+     }
     frame_reader_ =
         new webrtc::test::FrameReaderImpl(config_.input_filename,
                                           config_.frame_length_in_bytes);
@@ -405,6 +431,7 @@
                               CodecConfigPars process,
                               RateControlMetrics* rc_metrics) {
     // Codec/config settings.
+    codec_type_ = process.codec_type;
     start_bitrate_ = rate_profile.target_bit_rate[0];
     packet_loss_ = process.packet_loss;
     key_frame_interval_ = process.key_frame_interval;
@@ -514,6 +541,7 @@
 }
 
 void SetCodecParameters(CodecConfigPars* process_settings,
+                        VideoCodecType codec_type,
                         float packet_loss,
                         int key_frame_interval,
                         int num_temporal_layers,
@@ -521,6 +549,7 @@
                         bool denoising_on,
                         bool frame_dropper_on,
                         bool spatial_resize_on) {
+  process_settings->codec_type = codec_type;
   process_settings->packet_loss = packet_loss;
   process_settings->key_frame_interval =  key_frame_interval;
   process_settings->num_temporal_layers = num_temporal_layers,
@@ -560,7 +589,126 @@
   rc_metrics[update_index].num_spatial_resizes = num_spatial_resizes;
 }
 
-// Run with no packet loss and fixed bitrate. Quality should be very high.
+// VP9: Run with no packet loss and fixed bitrate. Quality should be very high.
+// One key frame (first frame only) in sequence. Setting |key_frame_interval|
+// to -1 below means no periodic key frames in test.
+TEST_F(VideoProcessorIntegrationTest, Process0PercentPacketLossVP9) {
+  // Bitrate and frame rate profile.
+  RateProfile rate_profile;
+  SetRateProfilePars(&rate_profile, 0, 500, 30, 0);
+  rate_profile.frame_index_rate_update[1] = kNbrFramesShort + 1;
+  rate_profile.num_frames = kNbrFramesShort;
+  // Codec/network settings.
+  CodecConfigPars process_settings;
+  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
+                     false, true, false);
+  // Metrics for expected quality.
+  QualityMetrics quality_metrics;
+  SetQualityMetrics(&quality_metrics, 37.5, 36.0, 0.94, 0.93);
+  // Metrics for rate control.
+  RateControlMetrics rc_metrics[1];
+  SetRateControlMetrics(rc_metrics, 0, 0, 40, 20, 10, 15, 0);
+  ProcessFramesAndVerify(quality_metrics,
+                         rate_profile,
+                         process_settings,
+                         rc_metrics);
+}
+
+// VP9: Run with 5% packet loss and fixed bitrate. Quality should be a bit
+// lower. One key frame (first frame only) in sequence.
+TEST_F(VideoProcessorIntegrationTest, Process5PercentPacketLossVP9) {
+  // Bitrate and frame rate profile.
+  RateProfile rate_profile;
+  SetRateProfilePars(&rate_profile, 0, 500, 30, 0);
+  rate_profile.frame_index_rate_update[1] = kNbrFramesShort + 1;
+  rate_profile.num_frames = kNbrFramesShort;
+  // Codec/network settings.
+  CodecConfigPars process_settings;
+  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.05f, -1, 1, false,
+                     false, true, false);
+  // Metrics for expected quality.
+  QualityMetrics quality_metrics;
+  SetQualityMetrics(&quality_metrics, 17.0, 15.0, 0.45, 0.38);
+  // Metrics for rate control.
+  RateControlMetrics rc_metrics[1];
+  SetRateControlMetrics(rc_metrics, 0, 0, 40, 20, 10, 15, 0);
+  ProcessFramesAndVerify(quality_metrics,
+                         rate_profile,
+                         process_settings,
+                         rc_metrics);
+}
+
+
+// VP9: Run with no packet loss, with varying bitrate (3 rate updates):
+// low to high to medium. Check that quality and encoder response to the new
+// target rate/per-frame bandwidth (for each rate update) is within limits.
+// One key frame (first frame only) in sequence.
+TEST_F(VideoProcessorIntegrationTest, ProcessNoLossChangeBitRateVP9) {
+  // Bitrate and frame rate profile.
+  RateProfile rate_profile;
+  SetRateProfilePars(&rate_profile, 0, 200, 30, 0);
+  SetRateProfilePars(&rate_profile, 1, 800, 30, 100);
+  SetRateProfilePars(&rate_profile, 2, 500, 30, 200);
+  rate_profile.frame_index_rate_update[3] = kNbrFramesLong + 1;
+  rate_profile.num_frames = kNbrFramesLong;
+  // Codec/network settings.
+  CodecConfigPars process_settings;
+  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
+                     false, true, false);
+  // Metrics for expected quality.
+  QualityMetrics quality_metrics;
+  SetQualityMetrics(&quality_metrics, 36.0, 32.0, 0.90, 0.85);
+  // Metrics for rate control.
+  RateControlMetrics rc_metrics[3];
+  SetRateControlMetrics(rc_metrics, 0, 0, 30, 20, 20, 20, 0);
+  SetRateControlMetrics(rc_metrics, 1, 2, 0, 20, 20, 60, 0);
+  SetRateControlMetrics(rc_metrics, 2, 0, 0, 20, 20, 30, 0);
+  ProcessFramesAndVerify(quality_metrics,
+                         rate_profile,
+                         process_settings,
+                         rc_metrics);
+}
+
+// VP9: Run with no packet loss, with an update (decrease) in frame rate.
+// Lower frame rate means higher per-frame-bandwidth, so easier to encode.
+// At the low bitrate in this test, this means better rate control after the
+// update(s) to lower frame rate. So expect less frame drops, and max values
+// for the rate control metrics can be lower. One key frame (first frame only).
+// Note: quality after update should be higher but we currently compute quality
+// metrics averaged over whole sequence run.
+TEST_F(VideoProcessorIntegrationTest,
+       ProcessNoLossChangeFrameRateFrameDropVP9) {
+  config_.networking_config.packet_loss_probability = 0;
+  // Bitrate and frame rate profile.
+  RateProfile rate_profile;
+  SetRateProfilePars(&rate_profile, 0, 50, 24, 0);
+  SetRateProfilePars(&rate_profile, 1, 50, 15, 100);
+  SetRateProfilePars(&rate_profile, 2, 50, 10, 200);
+  rate_profile.frame_index_rate_update[3] = kNbrFramesLong + 1;
+  rate_profile.num_frames = kNbrFramesLong;
+  // Codec/network settings.
+  CodecConfigPars process_settings;
+  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
+                     false, true, false);
+  // Metrics for expected quality.
+  QualityMetrics quality_metrics;
+  SetQualityMetrics(&quality_metrics, 30.0, 18.0, 0.80, 0.40);
+  // Metrics for rate control.
+  RateControlMetrics rc_metrics[3];
+  SetRateControlMetrics(rc_metrics, 0, 35, 55, 70, 15, 40, 0);
+  SetRateControlMetrics(rc_metrics, 1, 15, 0, 50, 10, 30, 0);
+  SetRateControlMetrics(rc_metrics, 2, 5, 0, 38, 10, 30, 0);
+  ProcessFramesAndVerify(quality_metrics,
+                         rate_profile,
+                         process_settings,
+                         rc_metrics);
+}
+
+
+// TODO(marpan): Add temporal layer test for VP9, once changes are in
+// vp9 wrapper for this.
+
+// VP8: Run with no packet loss and fixed bitrate. Quality should be very high.
 // One key frame (first frame only) in sequence. Setting |key_frame_interval|
 // to -1 below means no periodic key frames in test.
 TEST_F(VideoProcessorIntegrationTest, ProcessZeroPacketLoss) {
@@ -571,7 +719,8 @@
   rate_profile.num_frames = kNbrFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, 0.0f, -1, 1, false, true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 1, false,
+                     true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 34.95, 33.0, 0.90, 0.89);
@@ -584,8 +733,8 @@
                          rc_metrics);
 }
 
-// Run with 5% packet loss and fixed bitrate. Quality should be a bit lower.
-// One key frame (first frame only) in sequence.
+// VP8: Run with 5% packet loss and fixed bitrate. Quality should be a bit
+// lower. One key frame (first frame only) in sequence.
 TEST_F(VideoProcessorIntegrationTest, Process5PercentPacketLoss) {
   // Bitrate and frame rate profile.
   RateProfile rate_profile;
@@ -594,7 +743,8 @@
   rate_profile.num_frames = kNbrFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, 0.05f, -1, 1, false, true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.05f, -1, 1, false,
+                     true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 20.0, 16.0, 0.60, 0.40);
@@ -607,7 +757,7 @@
                          rc_metrics);
 }
 
-// Run with 10% packet loss and fixed bitrate. Quality should be even lower.
+// VP8: Run with 10% packet loss and fixed bitrate. Quality should be lower.
 // One key frame (first frame only) in sequence.
 TEST_F(VideoProcessorIntegrationTest, Process10PercentPacketLoss) {
   // Bitrate and frame rate profile.
@@ -617,7 +767,8 @@
   rate_profile.num_frames = kNbrFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, 0.1f, -1, 1, false, true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.1f, -1, 1, false,
+                     true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 19.0, 16.0, 0.50, 0.35);
@@ -639,12 +790,12 @@
 // disabled on Android. Some quality parameter in the above test has been
 // adjusted to also pass for |cpu_speed| <= 12.
 
-// Run with no packet loss, with varying bitrate (3 rate updates):
+// VP8: Run with no packet loss, with varying bitrate (3 rate updates):
 // low to high to medium. Check that quality and encoder response to the new
 // target rate/per-frame bandwidth (for each rate update) is within limits.
 // One key frame (first frame only) in sequence.
 TEST_F(VideoProcessorIntegrationTest,
-       DISABLED_ON_ANDROID(ProcessNoLossChangeBitRate)) {
+       DISABLED_ON_ANDROID(ProcessNoLossChangeBitRateVP8)) {
   // Bitrate and frame rate profile.
   RateProfile rate_profile;
   SetRateProfilePars(&rate_profile, 0, 200, 30, 0);
@@ -654,7 +805,8 @@
   rate_profile.num_frames = kNbrFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, 0.0f, -1, 1, false, true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 1, false,
+                     true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 34.0, 32.0, 0.85, 0.80);
@@ -669,15 +821,15 @@
                          rc_metrics);
 }
 
-// Run with no packet loss, with an update (decrease) in frame rate.
+// VP8: Run with no packet loss, with an update (decrease) in frame rate.
 // Lower frame rate means higher per-frame-bandwidth, so easier to encode.
 // At the bitrate in this test, this means better rate control after the
 // update(s) to lower frame rate. So expect less frame drops, and max values
 // for the rate control metrics can be lower. One key frame (first frame only).
 // Note: quality after update should be higher but we currently compute quality
-// metrics avergaed over whole sequence run.
+// metrics averaged over whole sequence run.
 TEST_F(VideoProcessorIntegrationTest,
-       DISABLED_ON_ANDROID(ProcessNoLossChangeFrameRateFrameDrop)) {
+       DISABLED_ON_ANDROID(ProcessNoLossChangeFrameRateFrameDropVP8)) {
   config_.networking_config.packet_loss_probability = 0;
   // Bitrate and frame rate profile.
   RateProfile rate_profile;
@@ -688,7 +840,8 @@
   rate_profile.num_frames = kNbrFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, 0.0f, -1, 1, false, true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 1, false,
+                     true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 31.0, 22.0, 0.80, 0.65);
@@ -706,7 +859,7 @@
 // Run with no packet loss, at low bitrate. During this time we should've
 // resized once.
 TEST_F(VideoProcessorIntegrationTest,
-       DISABLED_ON_ANDROID(ProcessNoLossSpatialResizeFrameDrop)) {
+       DISABLED_ON_ANDROID(ProcessNoLossSpatialResizeFrameDropVP8)) {
   config_.networking_config.packet_loss_probability = 0;
   // Bitrate and frame rate profile.
   RateProfile rate_profile;
@@ -715,8 +868,8 @@
   rate_profile.num_frames = kNbrFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(
-      &process_settings, 0.0f, kNbrFramesLong, 1, false, true, true, true);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, kNbrFramesLong,
+                     1, false, true, true, true);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 25.0, 15.0, 0.70, 0.40);
@@ -729,13 +882,13 @@
                          rc_metrics);
 }
 
-// Run with no packet loss, with 3 temporal layers, with a rate update in the
-// middle of the sequence. The max values for the frame size mismatch and
+// VP8: Run with no packet loss, with 3 temporal layers, with a rate update in
+// the middle of the sequence. The max values for the frame size mismatch and
 // encoding rate mismatch are applied to each layer.
 // No dropped frames in this test, and internal spatial resizer is off.
 // One key frame (first frame only) in sequence, so no spatial resizing.
 TEST_F(VideoProcessorIntegrationTest,
-       DISABLED_ON_ANDROID(ProcessNoLossTemporalLayers)) {
+       DISABLED_ON_ANDROID(ProcessNoLossTemporalLayersVP8)) {
   config_.networking_config.packet_loss_probability = 0;
   // Bitrate and frame rate profile.
   RateProfile rate_profile;
@@ -745,7 +898,8 @@
   rate_profile.num_frames = kNbrFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, 0.0f, -1, 3, false, true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 3, false,
+                     true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 32.5, 30.0, 0.85, 0.80);
diff --git a/modules/video_coding/codecs/tools/video_codecs_tools.gypi b/modules/video_coding/codecs/tools/video_codecs_tools.gypi
index 8f15b28..3e77a5b 100644
--- a/modules/video_coding/codecs/tools/video_codecs_tools.gypi
+++ b/modules/video_coding/codecs/tools/video_codecs_tools.gypi
@@ -17,7 +17,7 @@
             'video_codecs_test_framework',
             'webrtc_video_coding',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
-            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
             '<(webrtc_root)/test/metrics.gyp:metrics',
             '<(webrtc_vp8_dir)/vp8.gyp:webrtc_vp8',
           ],
diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
index 3cc8bc3..5e0bfc8 100644
--- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
@@ -192,7 +192,13 @@
   VideoCodec codec_inst_;
 };
 
+// Disabled on MemorySanitizer as it's breaking on generic libvpx.
+// https://code.google.com/p/webrtc/issues/detail?id=3904
+#if defined(MEMORY_SANITIZER)
+TEST_F(TestVp8Impl, DISABLED_BaseUnitTest) {
+#else
 TEST_F(TestVp8Impl, DISABLED_ON_ANDROID(BaseUnitTest)) {
+#endif
   // TODO(mikhal): Remove dependency. Move all test code here.
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release());
   UnitTest unittest;
diff --git a/modules/video_coding/codecs/vp8/vp8_impl.h b/modules/video_coding/codecs/vp8/vp8_impl.h
index 08ce3c9..fec53d5 100644
--- a/modules/video_coding/codecs/vp8/vp8_impl.h
+++ b/modules/video_coding/codecs/vp8/vp8_impl.h
@@ -35,73 +35,20 @@
 
   virtual ~VP8EncoderImpl();
 
-  // Free encoder memory.
-  //
-  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
   virtual int Release();
 
-  // Initialize the encoder with the information from the codecSettings
-  //
-  // Input:
-  //          - codec_settings    : Codec settings
-  //          - number_of_cores   : Number of cores available for the encoder
-  //          - max_payload_size  : The maximum size each payload is allowed
-  //                                to have. Usually MTU - overhead.
-  //
-  // Return value                 : Set bit rate if OK
-  //                                <0 - Errors:
-  //                                  WEBRTC_VIDEO_CODEC_ERR_PARAMETER
-  //                                  WEBRTC_VIDEO_CODEC_ERR_SIZE
-  //                                  WEBRTC_VIDEO_CODEC_LEVEL_EXCEEDED
-  //                                  WEBRTC_VIDEO_CODEC_MEMORY
-  //                                  WEBRTC_VIDEO_CODEC_ERROR
   virtual int InitEncode(const VideoCodec* codec_settings,
                          int number_of_cores,
                          uint32_t max_payload_size);
 
-  // Encode an I420 image (as a part of a video stream). The encoded image
-  // will be returned to the user through the encode complete callback.
-  //
-  // Input:
-  //          - input_image       : Image to be encoded
-  //          - frame_types       : Frame type to be generated by the encoder.
-  //
-  // Return value                 : WEBRTC_VIDEO_CODEC_OK if OK
-  //                                <0 - Errors:
-  //                                  WEBRTC_VIDEO_CODEC_ERR_PARAMETER
-  //                                  WEBRTC_VIDEO_CODEC_MEMORY
-  //                                  WEBRTC_VIDEO_CODEC_ERROR
-  //                                  WEBRTC_VIDEO_CODEC_TIMEOUT
-
   virtual int Encode(const I420VideoFrame& input_image,
                      const CodecSpecificInfo* codec_specific_info,
                      const std::vector<VideoFrameType>* frame_types);
 
-  // Register an encode complete callback object.
-  //
-  // Input:
-  //          - callback         : Callback object which handles encoded images.
-  //
-  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
   virtual int RegisterEncodeCompleteCallback(EncodedImageCallback* callback);
 
-  // Inform the encoder of the new packet loss rate and the round-trip time of
-  // the network.
-  //
-  //          - packet_loss : Fraction lost
-  //                          (loss rate in percent = 100 * packetLoss / 255)
-  //          - rtt         : Round-trip time in milliseconds
-  // Return value           : WEBRTC_VIDEO_CODEC_OK if OK
-  //                          <0 - Errors: WEBRTC_VIDEO_CODEC_ERROR
-  //
   virtual int SetChannelParameters(uint32_t packet_loss, int rtt);
 
-  // Inform the encoder about the new target bit rate.
-  //
-  //          - new_bitrate_kbit : New target bit rate
-  //          - frame_rate       : The target frame rate
-  //
-  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
   virtual int SetRates(uint32_t new_bitrate_kbit, uint32_t frame_rate);
 
  private:
@@ -150,61 +97,20 @@
 
   virtual ~VP8DecoderImpl();
 
-  // Initialize the decoder.
-  //
-  // Return value         :  WEBRTC_VIDEO_CODEC_OK.
-  //                        <0 - Errors:
-  //                                  WEBRTC_VIDEO_CODEC_ERROR
   virtual int InitDecode(const VideoCodec* inst, int number_of_cores);
 
-  // Decode encoded image (as a part of a video stream). The decoded image
-  // will be returned to the user through the decode complete callback.
-  //
-  // Input:
-  //          - input_image         : Encoded image to be decoded
-  //          - missing_frames      : True if one or more frames have been lost
-  //                                  since the previous decode call.
-  //          - fragmentation       : Specifies the start and length of each VP8
-  //                                  partition.
-  //          - codec_specific_info : pointer to specific codec data
-  //          - render_time_ms      : Render time in Ms
-  //
-  // Return value                 : WEBRTC_VIDEO_CODEC_OK if OK
-  //                                <0 - Errors:
-  //                                      WEBRTC_VIDEO_CODEC_ERROR
-  //                                      WEBRTC_VIDEO_CODEC_ERR_PARAMETER
   virtual int Decode(const EncodedImage& input_image,
                      bool missing_frames,
                      const RTPFragmentationHeader* fragmentation,
                      const CodecSpecificInfo* codec_specific_info,
                      int64_t /*render_time_ms*/);
 
-  // Register a decode complete callback object.
-  //
-  // Input:
-  //          - callback         : Callback object which handles decoded images.
-  //
-  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
   virtual int RegisterDecodeCompleteCallback(DecodedImageCallback* callback);
 
-  // Free decoder memory.
-  //
-  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK
-  //                               <0 - Errors:
-  //                                      WEBRTC_VIDEO_CODEC_ERROR
   virtual int Release();
 
-  // Reset decoder state and prepare for a new call.
-  //
-  // Return value         : WEBRTC_VIDEO_CODEC_OK.
-  //                        <0 - Errors:
-  //                                  WEBRTC_VIDEO_CODEC_UNINITIALIZED
-  //                                  WEBRTC_VIDEO_CODEC_ERROR
   virtual int Reset();
 
-  // Create a copy of the codec and its internal state.
-  //
-  // Return value                : A copy of the instance if OK, NULL otherwise.
   virtual VideoDecoder* Copy();
 
  private:
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm.mk
index 79bb0c7..04f686d 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm64.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm64.mk
index 268ec13..9e6c52e 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm64.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -177,11 +181,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -190,10 +196,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-mips.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-mips.mk
index 1b8eab8..9af54f9 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-mips.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-mips.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-mips64.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-mips64.mk
new file mode 100644
index 0000000..8ca243d
--- /dev/null
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-mips64.mk
@@ -0,0 +1,269 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp8_webrtc_vp8_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp8/reference_picture_selection.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/vp8_factory.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/realtime_temporal_layers.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp8_webrtc_vp8_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp8
+webrtc_vp8: third_party_webrtc_modules_video_coding_codecs_vp8_webrtc_vp8_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86.mk
index 1b4923a..6d28f75 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86_64.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86_64.mk
index c0fe3e0..e85d60c 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86_64.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.darwin-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm.mk
index 79bb0c7..04f686d 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm64.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm64.mk
index 268ec13..9e6c52e 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm64.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -177,11 +181,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -190,10 +196,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-mips.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-mips.mk
index 1b8eab8..9af54f9 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-mips.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-mips.mk
@@ -80,11 +80,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-mips64.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-mips64.mk
new file mode 100644
index 0000000..8ca243d
--- /dev/null
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-mips64.mk
@@ -0,0 +1,269 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp8_webrtc_vp8_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp8/reference_picture_selection.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/vp8_factory.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.cc \
+	third_party/webrtc/modules/video_coding/codecs/vp8/realtime_temporal_layers.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp8_webrtc_vp8_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp8
+webrtc_vp8: third_party_webrtc_modules_video_coding_codecs_vp8_webrtc_vp8_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86.mk
index 1b4923a..6d28f75 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86_64.mk b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86_64.mk
index c0fe3e0..e85d60c 100644
--- a/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86_64.mk
+++ b/modules/video_coding/codecs/vp8/webrtc_vp8.target.linux-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/codecs/vp9/include/vp9.h b/modules/video_coding/codecs/vp9/include/vp9.h
new file mode 100644
index 0000000..cd77f72
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/include/vp9.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_VP9_INCLUDE_VP9_H_
+#define WEBRTC_MODULES_VIDEO_CODING_CODECS_VP9_INCLUDE_VP9_H_
+
+#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
+
+namespace webrtc {
+
+class VP9Encoder : public VideoEncoder {
+ public:
+  static VP9Encoder* Create();
+
+  virtual ~VP9Encoder() {}
+};
+
+
+class VP9Decoder : public VideoDecoder {
+ public:
+  static VP9Decoder* Create();
+
+  virtual ~VP9Decoder() {}
+};
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_VIDEO_CODING_CODECS_VP9_INCLUDE_VP9_H_
diff --git a/modules/video_coding/codecs/vp9/vp9.gyp b/modules/video_coding/codecs/vp9/vp9.gyp
new file mode 100644
index 0000000..2bd46fe
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/vp9.gyp
@@ -0,0 +1,36 @@
+# 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.
+
+{
+  'includes': [
+    '../../../../build/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'webrtc_vp9',
+      'type': 'static_library',
+      'dependencies': [
+        '<(webrtc_root)/common_video/common_video.gyp:common_video',
+        '<(webrtc_root)/modules/video_coding/utility/video_coding_utility.gyp:video_coding_utility',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
+      ],
+      'conditions': [
+        ['build_libvpx==1', {
+          'dependencies': [
+            '<(DEPTH)/third_party/libvpx/libvpx.gyp:libvpx',
+          ],
+        }],
+      ],
+      'sources': [
+        'include/vp9.h',
+        'vp9_impl.cc',
+        'vp9_impl.h',
+      ],
+    },
+  ],
+}
diff --git a/modules/video_coding/codecs/vp9/vp9_impl.cc b/modules/video_coding/codecs/vp9/vp9_impl.cc
new file mode 100644
index 0000000..33f11a3
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/vp9_impl.cc
@@ -0,0 +1,487 @@
+/*
+ *  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.
+ *
+ */
+
+#include "webrtc/modules/video_coding/codecs/vp9/vp9_impl.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <vector>
+
+#include "vpx/vpx_encoder.h"
+#include "vpx/vpx_decoder.h"
+#include "vpx/vp8cx.h"
+#include "vpx/vp8dx.h"
+
+#include "webrtc/common.h"
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/modules/interface/module_common_types.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
+#include "webrtc/system_wrappers/interface/trace_event.h"
+
+namespace webrtc {
+
+VP9Encoder* VP9Encoder::Create() {
+  return new VP9EncoderImpl();
+}
+
+VP9EncoderImpl::VP9EncoderImpl()
+    : encoded_image_(),
+      encoded_complete_callback_(NULL),
+      inited_(false),
+      timestamp_(0),
+      picture_id_(0),
+      cpu_speed_(3),
+      rc_max_intra_target_(0),
+      encoder_(NULL),
+      config_(NULL),
+      raw_(NULL) {
+  memset(&codec_, 0, sizeof(codec_));
+  uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp());
+  srand(seed);
+}
+
+VP9EncoderImpl::~VP9EncoderImpl() {
+  Release();
+}
+
+int VP9EncoderImpl::Release() {
+  if (encoded_image_._buffer != NULL) {
+    delete [] encoded_image_._buffer;
+    encoded_image_._buffer = NULL;
+  }
+  if (encoder_ != NULL) {
+    if (vpx_codec_destroy(encoder_)) {
+      return WEBRTC_VIDEO_CODEC_MEMORY;
+    }
+    delete encoder_;
+    encoder_ = NULL;
+  }
+  if (config_ != NULL) {
+    delete config_;
+    config_ = NULL;
+  }
+  if (raw_ != NULL) {
+    vpx_img_free(raw_);
+    raw_ = NULL;
+  }
+  inited_ = false;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9EncoderImpl::SetRates(uint32_t new_bitrate_kbit,
+                             uint32_t new_framerate) {
+  if (!inited_) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  if (encoder_->err) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+  if (new_framerate < 1) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  // Update bit rate
+  if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) {
+    new_bitrate_kbit = codec_.maxBitrate;
+  }
+  config_->rc_target_bitrate = new_bitrate_kbit;
+  codec_.maxFramerate = new_framerate;
+  // Update encoder context
+  if (vpx_codec_enc_config_set(encoder_, config_)) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9EncoderImpl::InitEncode(const VideoCodec* inst,
+                               int number_of_cores,
+                               uint32_t /*max_payload_size*/) {
+  if (inst == NULL) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  if (inst->maxFramerate < 1) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  // Allow zero to represent an unspecified maxBitRate
+  if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  if (inst->width < 1 || inst->height < 1) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  if (number_of_cores < 1) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  int retVal = Release();
+  if (retVal < 0) {
+    return retVal;
+  }
+  if (encoder_ == NULL) {
+    encoder_ = new vpx_codec_ctx_t;
+  }
+  if (config_ == NULL) {
+    config_ = new vpx_codec_enc_cfg_t;
+  }
+  timestamp_ = 0;
+  if (&codec_ != inst) {
+    codec_ = *inst;
+  }
+  // Random start 16 bits is enough.
+  picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
+  // Allocate memory for encoded image
+  if (encoded_image_._buffer != NULL) {
+    delete [] encoded_image_._buffer;
+  }
+  encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height);
+  encoded_image_._buffer = new uint8_t[encoded_image_._size];
+  encoded_image_._completeFrame = true;
+  // Creating a wrapper to the image - setting image data to NULL. Actual
+  // pointer will be set in encode. Setting align to 1, as it is meaningless
+  // (actual memory is not allocated).
+  raw_ = vpx_img_wrap(NULL, VPX_IMG_FMT_I420, codec_.width, codec_.height,
+                      1, NULL);
+  // Populate encoder configuration with default values.
+  if (vpx_codec_enc_config_default(vpx_codec_vp9_cx(), config_, 0)) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+  config_->g_w = codec_.width;
+  config_->g_h = codec_.height;
+  config_->rc_target_bitrate = inst->startBitrate;  // in kbit/s
+  config_->g_error_resilient = 1;
+  // Setting the time base of the codec.
+  config_->g_timebase.num = 1;
+  config_->g_timebase.den = 90000;
+  config_->g_lag_in_frames = 0;  // 0- no frame lagging
+  config_->g_threads = 1;
+  // Rate control settings.
+  config_->rc_dropframe_thresh = inst->codecSpecific.VP9.frameDroppingOn ?
+      30 : 0;
+  config_->rc_end_usage = VPX_CBR;
+  config_->g_pass = VPX_RC_ONE_PASS;
+  config_->rc_min_quantizer = 2;
+  config_->rc_max_quantizer = 56;
+  config_->rc_undershoot_pct = 50;
+  config_->rc_overshoot_pct = 50;
+  config_->rc_buf_initial_sz = 500;
+  config_->rc_buf_optimal_sz = 600;
+  config_->rc_buf_sz = 1000;
+  // Set the maximum target size of any key-frame.
+  rc_max_intra_target_ = MaxIntraTarget(config_->rc_buf_optimal_sz);
+  if (inst->codecSpecific.VP9.keyFrameInterval  > 0) {
+    config_->kf_mode = VPX_KF_AUTO;
+    config_->kf_max_dist = inst->codecSpecific.VP9.keyFrameInterval;
+  } else {
+    config_->kf_mode = VPX_KF_DISABLED;
+  }
+  return InitAndSetControlSettings(inst);
+}
+
+int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) {
+  if (vpx_codec_enc_init(encoder_, vpx_codec_vp9_cx(), config_, 0)) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  // Only positive speeds, currently: 0 - 7.
+  // O means slowest/best quality, 7 means fastest/lowest quality.
+  // TODO(marpan): Speeds 5-7 are speed settings for real-time mode, on desktop.
+  // Currently set to 5, update to 6 (for faster encoding) after some subjective
+  // quality tests.
+  cpu_speed_ = 5;
+  // Note: some of these codec controls still use "VP8" in the control name.
+  // TODO(marpan): Update this in the next/future libvpx version.
+  vpx_codec_control(encoder_, VP8E_SET_CPUUSED, cpu_speed_);
+  vpx_codec_control(encoder_, VP8E_SET_MAX_INTRA_BITRATE_PCT,
+                    rc_max_intra_target_);
+  vpx_codec_control(encoder_, VP9E_SET_AQ_MODE,
+                    inst->codecSpecific.VP9.adaptiveQpMode ? 3 : 0);
+  // TODO(marpan): Enable in future libvpx roll: waiting for SSE2 optimization.
+// #if !defined(WEBRTC_ARCH_ARM)
+  // vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY,
+  //                   inst->codecSpecific.VP9.denoisingOn ? 1 : 0);
+// #endif
+  inited_ = true;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+uint32_t VP9EncoderImpl::MaxIntraTarget(uint32_t optimal_buffer_size) {
+  // Set max to the optimal buffer level (normalized by target BR),
+  // and scaled by a scale_par.
+  // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps].
+  // This value is presented in percentage of perFrameBw:
+  // perFrameBw = targetBR[Kbps] * 1000 / framerate.
+  // The target in % is as follows:
+  float scale_par = 0.5;
+  uint32_t target_pct =
+      optimal_buffer_size * scale_par * codec_.maxFramerate / 10;
+  // Don't go below 3 times the per frame bandwidth.
+  const uint32_t min_intra_size = 300;
+  return (target_pct < min_intra_size) ? min_intra_size: target_pct;
+}
+
+int VP9EncoderImpl::Encode(const I420VideoFrame& input_image,
+                           const CodecSpecificInfo* codec_specific_info,
+                           const std::vector<VideoFrameType>* frame_types) {
+  if (!inited_) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  if (input_image.IsZeroSize()) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  if (encoded_complete_callback_ == NULL) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  VideoFrameType frame_type = kDeltaFrame;
+  // We only support one stream at the moment.
+  if (frame_types && frame_types->size() > 0) {
+    frame_type = (*frame_types)[0];
+  }
+  // Image in vpx_image_t format.
+  // Input image is const. VPX's raw image is not defined as const.
+  raw_->planes[VPX_PLANE_Y] = const_cast<uint8_t*>(input_image.buffer(kYPlane));
+  raw_->planes[VPX_PLANE_U] = const_cast<uint8_t*>(input_image.buffer(kUPlane));
+  raw_->planes[VPX_PLANE_V] = const_cast<uint8_t*>(input_image.buffer(kVPlane));
+  raw_->stride[VPX_PLANE_Y] = input_image.stride(kYPlane);
+  raw_->stride[VPX_PLANE_U] = input_image.stride(kUPlane);
+  raw_->stride[VPX_PLANE_V] = input_image.stride(kVPlane);
+
+  int flags = 0;
+  bool send_keyframe = (frame_type == kKeyFrame);
+  if (send_keyframe) {
+    // Key frame request from caller.
+    flags = VPX_EFLAG_FORCE_KF;
+  }
+  assert(codec_.maxFramerate > 0);
+  uint32_t duration = 90000 / codec_.maxFramerate;
+  if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags,
+                       VPX_DL_REALTIME)) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+  timestamp_ += duration;
+  return GetEncodedPartitions(input_image);
+}
+
+void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
+                                       const vpx_codec_cx_pkt& pkt,
+                                       uint32_t timestamp) {
+  assert(codec_specific != NULL);
+  codec_specific->codecType = kVideoCodecVP9;
+  CodecSpecificInfoVP9 *vp9_info = &(codec_specific->codecSpecific.VP9);
+  vp9_info->pictureId = picture_id_;
+  vp9_info->keyIdx = kNoKeyIdx;
+  vp9_info->nonReference = (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
+  // TODO(marpan): Temporal layers are supported in the current VP9 version,
+  // but for now use 1 temporal layer encoding. Will update this when temporal
+  // layer support for VP9 is added in webrtc.
+  vp9_info->temporalIdx = kNoTemporalIdx;
+  vp9_info->layerSync = false;
+  vp9_info->tl0PicIdx = kNoTl0PicIdx;
+  picture_id_ = (picture_id_ + 1) & 0x7FFF;
+}
+
+int VP9EncoderImpl::GetEncodedPartitions(const I420VideoFrame& input_image) {
+  vpx_codec_iter_t iter = NULL;
+  encoded_image_._length = 0;
+  encoded_image_._frameType = kDeltaFrame;
+  RTPFragmentationHeader frag_info;
+  // Note: no data partitioning in VP9, so 1 partition only. We keep this
+  // fragmentation data for now, until VP9 packetizer is implemented.
+  frag_info.VerifyAndAllocateFragmentationHeader(1);
+  int part_idx = 0;
+  CodecSpecificInfo codec_specific;
+  const vpx_codec_cx_pkt_t *pkt = NULL;
+  while ((pkt = vpx_codec_get_cx_data(encoder_, &iter)) != NULL) {
+    switch (pkt->kind) {
+      case VPX_CODEC_CX_FRAME_PKT: {
+        memcpy(&encoded_image_._buffer[encoded_image_._length],
+               pkt->data.frame.buf,
+               pkt->data.frame.sz);
+        frag_info.fragmentationOffset[part_idx] = encoded_image_._length;
+        frag_info.fragmentationLength[part_idx] =
+            static_cast<uint32_t>(pkt->data.frame.sz);
+        frag_info.fragmentationPlType[part_idx] = 0;
+        frag_info.fragmentationTimeDiff[part_idx] = 0;
+        encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz);
+        assert(encoded_image_._length <= encoded_image_._size);
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    // End of frame.
+    if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
+      // Check if encoded frame is a key frame.
+      if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
+        encoded_image_._frameType = kKeyFrame;
+      }
+      PopulateCodecSpecific(&codec_specific, *pkt, input_image.timestamp());
+      break;
+    }
+  }
+  if (encoded_image_._length > 0) {
+    TRACE_COUNTER1("webrtc", "EncodedFrameSize", encoded_image_._length);
+    encoded_image_._timeStamp = input_image.timestamp();
+    encoded_image_.capture_time_ms_ = input_image.render_time_ms();
+    encoded_image_._encodedHeight = raw_->d_h;
+    encoded_image_._encodedWidth = raw_->d_w;
+    encoded_complete_callback_->Encoded(encoded_image_, &codec_specific,
+                                      &frag_info);
+  }
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9EncoderImpl::SetChannelParameters(uint32_t packet_loss, int rtt) {
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9EncoderImpl::RegisterEncodeCompleteCallback(
+    EncodedImageCallback* callback) {
+  encoded_complete_callback_ = callback;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+VP9Decoder* VP9Decoder::Create() {
+  return new VP9DecoderImpl();
+}
+
+VP9DecoderImpl::VP9DecoderImpl()
+    : decode_complete_callback_(NULL),
+      inited_(false),
+      decoder_(NULL),
+      key_frame_required_(true) {
+  memset(&codec_, 0, sizeof(codec_));
+}
+
+VP9DecoderImpl::~VP9DecoderImpl() {
+  inited_ = true;  // in order to do the actual release
+  Release();
+}
+
+int VP9DecoderImpl::Reset() {
+  if (!inited_) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  InitDecode(&codec_, 1);
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) {
+  if (inst == NULL) {
+    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+  }
+  int ret_val = Release();
+  if (ret_val < 0) {
+    return ret_val;
+  }
+  if (decoder_ == NULL) {
+    decoder_ = new vpx_dec_ctx_t;
+  }
+  vpx_codec_dec_cfg_t  cfg;
+  // Setting number of threads to a constant value (1)
+  cfg.threads = 1;
+  cfg.h = cfg.w = 0;  // set after decode
+  vpx_codec_flags_t flags = 0;
+  if (vpx_codec_dec_init(decoder_, vpx_codec_vp9_dx(), &cfg, flags)) {
+    return WEBRTC_VIDEO_CODEC_MEMORY;
+  }
+  if (&codec_ != inst) {
+    // Save VideoCodec instance for later; mainly for duplicating the decoder.
+    codec_ = *inst;
+  }
+  inited_ = true;
+  // Always start with a complete key frame.
+  key_frame_required_ = true;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9DecoderImpl::Decode(const EncodedImage& input_image,
+                           bool missing_frames,
+                           const RTPFragmentationHeader* fragmentation,
+                           const CodecSpecificInfo* codec_specific_info,
+                           int64_t /*render_time_ms*/) {
+  if (!inited_) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  if (decode_complete_callback_ == NULL) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  // Always start with a complete key frame.
+  if (key_frame_required_) {
+    if (input_image._frameType != kKeyFrame)
+      return WEBRTC_VIDEO_CODEC_ERROR;
+    // We have a key frame - is it complete?
+    if (input_image._completeFrame) {
+      key_frame_required_ = false;
+    } else {
+      return WEBRTC_VIDEO_CODEC_ERROR;
+    }
+  }
+  vpx_codec_iter_t iter = NULL;
+  vpx_image_t* img;
+  uint8_t* buffer = input_image._buffer;
+  if (input_image._length == 0) {
+    buffer = NULL;  // Triggers full frame concealment.
+  }
+  if (vpx_codec_decode(decoder_,
+                       buffer,
+                       input_image._length,
+                       0,
+                       VPX_DL_REALTIME)) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+  img = vpx_codec_get_frame(decoder_, &iter);
+  int ret = ReturnFrame(img, input_image._timeStamp);
+  if (ret != 0) {
+    return ret;
+  }
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9DecoderImpl::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) {
+  if (img == NULL) {
+    // Decoder OK and NULL image => No show frame.
+    return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
+  }
+  int half_height = (img->d_h + 1) / 2;
+  int size_y = img->stride[VPX_PLANE_Y] * img->d_h;
+  int size_u = img->stride[VPX_PLANE_U] * half_height;
+  int size_v = img->stride[VPX_PLANE_V] * half_height;
+  decoded_image_.CreateFrame(size_y, img->planes[VPX_PLANE_Y],
+                             size_u, img->planes[VPX_PLANE_U],
+                             size_v, img->planes[VPX_PLANE_V],
+                             img->d_w, img->d_h,
+                             img->stride[VPX_PLANE_Y],
+                             img->stride[VPX_PLANE_U],
+                             img->stride[VPX_PLANE_V]);
+  decoded_image_.set_timestamp(timestamp);
+  int ret = decode_complete_callback_->Decoded(decoded_image_);
+  if (ret != 0)
+    return ret;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9DecoderImpl::RegisterDecodeCompleteCallback(
+    DecodedImageCallback* callback) {
+  decode_complete_callback_ = callback;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int VP9DecoderImpl::Release() {
+  if (decoder_ != NULL) {
+    if (vpx_codec_destroy(decoder_)) {
+      return WEBRTC_VIDEO_CODEC_MEMORY;
+    }
+    delete decoder_;
+    decoder_ = NULL;
+  }
+  inited_ = false;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+}  // namespace webrtc
diff --git a/modules/video_coding/codecs/vp9/vp9_impl.h b/modules/video_coding/codecs/vp9/vp9_impl.h
new file mode 100644
index 0000000..94788db
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/vp9_impl.h
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_VP9_IMPL_H_
+#define WEBRTC_MODULES_VIDEO_CODING_CODECS_VP9_IMPL_H_
+
+#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
+
+// VPX forward declaration
+typedef struct vpx_codec_ctx vpx_codec_ctx_t;
+typedef struct vpx_codec_ctx vpx_dec_ctx_t;
+typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t;
+typedef struct vpx_image vpx_image_t;
+typedef struct vpx_ref_frame vpx_ref_frame_t;
+struct vpx_codec_cx_pkt;
+
+namespace webrtc {
+
+class VP9EncoderImpl : public VP9Encoder {
+ public:
+  VP9EncoderImpl();
+
+  virtual ~VP9EncoderImpl();
+
+  virtual int Release() OVERRIDE;
+
+  virtual int InitEncode(const VideoCodec* codec_settings,
+                         int number_of_cores,
+                         uint32_t max_payload_size) OVERRIDE;
+
+  virtual int Encode(const I420VideoFrame& input_image,
+                     const CodecSpecificInfo* codec_specific_info,
+                     const std::vector<VideoFrameType>* frame_types) OVERRIDE;
+
+  virtual int RegisterEncodeCompleteCallback(EncodedImageCallback* callback)
+  OVERRIDE;
+
+  virtual int SetChannelParameters(uint32_t packet_loss, int rtt) OVERRIDE;
+
+  virtual int SetRates(uint32_t new_bitrate_kbit, uint32_t frame_rate) OVERRIDE;
+
+ private:
+  // Call encoder initialize function and set control settings.
+  int InitAndSetControlSettings(const VideoCodec* inst);
+
+  void PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
+                             const vpx_codec_cx_pkt& pkt,
+                             uint32_t timestamp);
+
+  int GetEncodedPartitions(const I420VideoFrame& input_image);
+
+  // Determine maximum target for Intra frames
+  //
+  // Input:
+  //    - optimal_buffer_size : Optimal buffer size
+  // Return Value             : Max target size for Intra frames represented as
+  //                            percentage of the per frame bandwidth
+  uint32_t MaxIntraTarget(uint32_t optimal_buffer_size);
+
+  EncodedImage encoded_image_;
+  EncodedImageCallback* encoded_complete_callback_;
+  VideoCodec codec_;
+  bool inited_;
+  int64_t timestamp_;
+  uint16_t picture_id_;
+  int cpu_speed_;
+  uint32_t rc_max_intra_target_;
+  vpx_codec_ctx_t* encoder_;
+  vpx_codec_enc_cfg_t* config_;
+  vpx_image_t* raw_;
+};
+
+
+class VP9DecoderImpl : public VP9Decoder {
+ public:
+  VP9DecoderImpl();
+
+  virtual ~VP9DecoderImpl();
+
+  virtual int InitDecode(const VideoCodec* inst, int number_of_cores) OVERRIDE;
+
+  virtual int Decode(const EncodedImage& input_image,
+                     bool missing_frames,
+                     const RTPFragmentationHeader* fragmentation,
+                     const CodecSpecificInfo* codec_specific_info,
+                     int64_t /*render_time_ms*/) OVERRIDE;
+
+  virtual int RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
+  OVERRIDE;
+
+  virtual int Release() OVERRIDE;
+
+  virtual int Reset() OVERRIDE;
+
+ private:
+  int ReturnFrame(const vpx_image_t* img, uint32_t timeStamp);
+
+  I420VideoFrame decoded_image_;
+  DecodedImageCallback* decode_complete_callback_;
+  bool inited_;
+  vpx_dec_ctx_t* decoder_;
+  VideoCodec codec_;
+  bool key_frame_required_;
+};
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_VIDEO_CODING_CODECS_VP9_IMPL_H_
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-arm.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-arm.mk
new file mode 100644
index 0000000..f40975e
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-arm.mk
@@ -0,0 +1,287 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-tree-sra \
+	-fno-caller-saves \
+	-Wno-psabi \
+	-fno-partial-inlining \
+	-fno-early-inlining \
+	-fno-tree-copy-prop \
+	-fno-tree-loop-optimize \
+	-fno-move-loop-invariants \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_ARCH_ARM_V7' \
+	'-DWEBRTC_DETECT_ARM_NEON' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-tree-sra \
+	-fno-caller-saves \
+	-Wno-psabi \
+	-fno-partial-inlining \
+	-fno-early-inlining \
+	-fno-tree-copy-prop \
+	-fno-tree-loop-optimize \
+	-fno-move-loop-invariants \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_ARCH_ARM_V7' \
+	'-DWEBRTC_DETECT_ARM_NEON' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-arm64.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-arm64.mk
new file mode 100644
index 0000000..0adfcfa
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-arm64.mk
@@ -0,0 +1,259 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-mips.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-mips.mk
new file mode 100644
index 0000000..56334af
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-mips.mk
@@ -0,0 +1,271 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-mhard-float \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DMIPS32_LE' \
+	'-DMIPS_FPU_LE' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-mhard-float \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DMIPS32_LE' \
+	'-DMIPS_FPU_LE' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-mips64.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-mips64.mk
new file mode 100644
index 0000000..e752cbc
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-mips64.mk
@@ -0,0 +1,265 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-x86.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-x86.mk
new file mode 100644
index 0000000..3eba9b1
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-x86.mk
@@ -0,0 +1,269 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-msse2 \
+	-mfpmath=sse \
+	-mmmx \
+	-m32 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-fno-stack-protector \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-msse2 \
+	-mfpmath=sse \
+	-mmmx \
+	-m32 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-fno-stack-protector \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-x86_64.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-x86_64.mk
new file mode 100644
index 0000000..ee8824c
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.darwin-x86_64.mk
@@ -0,0 +1,267 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-m64 \
+	-march=x86-64 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-m64 \
+	-march=x86-64 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-arm.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-arm.mk
new file mode 100644
index 0000000..f40975e
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-arm.mk
@@ -0,0 +1,287 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-tree-sra \
+	-fno-caller-saves \
+	-Wno-psabi \
+	-fno-partial-inlining \
+	-fno-early-inlining \
+	-fno-tree-copy-prop \
+	-fno-tree-loop-optimize \
+	-fno-move-loop-invariants \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_ARCH_ARM_V7' \
+	'-DWEBRTC_DETECT_ARM_NEON' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-tree-sra \
+	-fno-caller-saves \
+	-Wno-psabi \
+	-fno-partial-inlining \
+	-fno-early-inlining \
+	-fno-tree-copy-prop \
+	-fno-tree-loop-optimize \
+	-fno-move-loop-invariants \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_ARCH_ARM_V7' \
+	'-DWEBRTC_DETECT_ARM_NEON' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-arm64.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-arm64.mk
new file mode 100644
index 0000000..0adfcfa
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-arm64.mk
@@ -0,0 +1,259 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-mips.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-mips.mk
new file mode 100644
index 0000000..56334af
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-mips.mk
@@ -0,0 +1,271 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-mhard-float \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DMIPS32_LE' \
+	'-DMIPS_FPU_LE' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-mhard-float \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DMIPS32_LE' \
+	'-DMIPS_FPU_LE' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-mips64.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-mips64.mk
new file mode 100644
index 0000000..e752cbc
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-mips64.mk
@@ -0,0 +1,265 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-x86.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-x86.mk
new file mode 100644
index 0000000..3eba9b1
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-x86.mk
@@ -0,0 +1,269 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-msse2 \
+	-mfpmath=sse \
+	-mmmx \
+	-m32 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-fno-stack-protector \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-msse2 \
+	-mfpmath=sse \
+	-mmmx \
+	-m32 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-fno-stack-protector \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-x86_64.mk b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-x86_64.mk
new file mode 100644
index 0000000..ee8824c
--- /dev/null
+++ b/modules/video_coding/codecs/vp9/webrtc_vp9.target.linux-x86_64.mk
@@ -0,0 +1,267 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-m64 \
+	-march=x86-64 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-m64 \
+	-march=x86-64 \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface \
+	$(LOCAL_PATH)/third_party/libvpx/source/libvpx
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_vp9
+webrtc_vp9: third_party_webrtc_modules_video_coding_codecs_vp9_webrtc_vp9_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/main/interface/video_coding_defines.h b/modules/video_coding/main/interface/video_coding_defines.h
index c5f93cb..efdc41b 100644
--- a/modules/video_coding/main/interface/video_coding_defines.h
+++ b/modules/video_coding/main/interface/video_coding_defines.h
@@ -39,9 +39,12 @@
 #define VCM_RED_PAYLOAD_TYPE        96
 #define VCM_ULPFEC_PAYLOAD_TYPE     97
 #define VCM_VP8_PAYLOAD_TYPE       100
+#define VCM_VP9_PAYLOAD_TYPE       101
 #define VCM_I420_PAYLOAD_TYPE      124
 #define VCM_H264_PAYLOAD_TYPE      127
 
+enum { kDefaultStartBitrateKbps = 300 };
+
 enum VCMVideoProtection {
   kProtectionNack,                // Both send-side and receive-side
   kProtectionNackSender,          // Send-side only
diff --git a/modules/video_coding/main/source/codec_database.cc b/modules/video_coding/main/source/codec_database.cc
index cd8f9d3..2fc9246 100644
--- a/modules/video_coding/main/source/codec_database.cc
+++ b/modules/video_coding/main/source/codec_database.cc
@@ -19,6 +19,9 @@
 #ifdef VIDEOCODEC_VP8
 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
 #endif
+#ifdef VIDEOCODEC_VP9
+#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
+#endif
 #include "webrtc/modules/video_coding/main/source/internal_defines.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 
@@ -39,6 +42,20 @@
   return vp8_settings;
 }
 
+VideoCodecVP9 VideoEncoder::GetDefaultVp9Settings() {
+  VideoCodecVP9 vp9_settings;
+  memset(&vp9_settings, 0, sizeof(vp9_settings));
+
+  vp9_settings.resilience = 1;
+  vp9_settings.numberOfTemporalLayers = 1;
+  vp9_settings.denoisingOn = false;
+  vp9_settings.frameDroppingOn = true;
+  vp9_settings.keyFrameInterval = 3000;
+  vp9_settings.adaptiveQpMode = true;
+
+  return vp9_settings;
+}
+
 VideoCodecH264 VideoEncoder::GetDefaultH264Settings() {
   VideoCodecH264 h264_settings;
   memset(&h264_settings, 0, sizeof(h264_settings));
@@ -114,7 +131,7 @@
       settings->codecType = kVideoCodecVP8;
       // 96 to 127 dynamic payload types for video codecs.
       settings->plType = VCM_VP8_PAYLOAD_TYPE;
-      settings->startBitrate = 100;
+      settings->startBitrate = kDefaultStartBitrateKbps;
       settings->minBitrate = VCM_MIN_BITRATE;
       settings->maxBitrate = 0;
       settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
@@ -126,13 +143,31 @@
       return true;
     }
 #endif
+#ifdef VIDEOCODEC_VP9
+    case VCM_VP9_IDX: {
+      strncpy(settings->plName, "VP9", 4);
+      settings->codecType = kVideoCodecVP9;
+      // 96 to 127 dynamic payload types for video codecs.
+      settings->plType = VCM_VP9_PAYLOAD_TYPE;
+      settings->startBitrate = 100;
+      settings->minBitrate = VCM_MIN_BITRATE;
+      settings->maxBitrate = 0;
+      settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
+      settings->width = VCM_DEFAULT_CODEC_WIDTH;
+      settings->height = VCM_DEFAULT_CODEC_HEIGHT;
+      settings->numberOfSimulcastStreams = 0;
+      settings->qpMax = 56;
+      settings->codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings();
+      return true;
+    }
+#endif
 #ifdef VIDEOCODEC_H264
     case VCM_H264_IDX: {
       strncpy(settings->plName, "H264", 5);
       settings->codecType = kVideoCodecH264;
       // 96 to 127 dynamic payload types for video codecs.
       settings->plType = VCM_H264_PAYLOAD_TYPE;
-      settings->startBitrate = 100;
+      settings->startBitrate = kDefaultStartBitrateKbps;
       settings->minBitrate = VCM_MIN_BITRATE;
       settings->maxBitrate = 0;
       settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
@@ -362,6 +397,13 @@
         return true;
       }
       break;
+    case kVideoCodecVP9:
+      if (memcmp(&new_send_codec.codecSpecific.VP9,
+                 &send_codec_.codecSpecific.VP9,
+                 sizeof(new_send_codec.codecSpecific.VP9)) != 0) {
+        return true;
+      }
+      break;
     case kVideoCodecH264:
       if (memcmp(&new_send_codec.codecSpecific.H264,
                  &send_codec_.codecSpecific.H264,
@@ -635,6 +677,10 @@
     case kVideoCodecVP8:
       return new VCMGenericEncoder(*(VP8Encoder::Create()));
 #endif
+#ifdef VIDEOCODEC_VP9
+    case kVideoCodecVP9:
+      return new VCMGenericEncoder(*(VP9Encoder::Create()));
+#endif
 #ifdef VIDEOCODEC_I420
     case kVideoCodecI420:
       return new VCMGenericEncoder(*(new I420Encoder));
@@ -662,6 +708,10 @@
     case kVideoCodecVP8:
       return new VCMGenericDecoder(*(VP8Decoder::Create()));
 #endif
+#ifdef VIDEOCODEC_VP9
+    case kVideoCodecVP9:
+      return new VCMGenericDecoder(*(VP9Decoder::Create()));
+#endif
 #ifdef VIDEOCODEC_I420
     case kVideoCodecI420:
       return new VCMGenericDecoder(*(new I420Decoder));
diff --git a/modules/video_coding/main/source/internal_defines.h b/modules/video_coding/main/source/internal_defines.h
index ef42c62..adc940f 100644
--- a/modules/video_coding/main/source/internal_defines.h
+++ b/modules/video_coding/main/source/internal_defines.h
@@ -39,10 +39,15 @@
 #else
   #define VCM_VP8_IDX VCM_NO_CODEC_IDX
 #endif
-#ifdef VIDEOCODEC_H264
-  #define VCM_H264_IDX (VCM_VP8_IDX + 1)
+#ifdef VIDEOCODEC_VP9
+  #define VCM_VP9_IDX (VCM_VP8_IDX + 1)
 #else
-  #define VCM_H264_IDX VCM_VP8_IDX
+  #define VCM_VP9_IDX VCM_VP8_IDX
+#endif
+#ifdef VIDEOCODEC_H264
+  #define VCM_H264_IDX (VCM_VP9_IDX + 1)
+#else
+  #define VCM_H264_IDX VCM_VP9_IDX
 #endif
 #ifdef VIDEOCODEC_I420
   #define VCM_I420_IDX (VCM_H264_IDX + 1)
diff --git a/modules/video_coding/main/source/jitter_buffer.cc b/modules/video_coding/main/source/jitter_buffer.cc
index d09fccd..e3a4a8a 100644
--- a/modules/video_coding/main/source/jitter_buffer.cc
+++ b/modules/video_coding/main/source/jitter_buffer.cc
@@ -25,6 +25,7 @@
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/event_wrapper.h"
 #include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/metrics.h"
 #include "webrtc/system_wrappers/interface/trace_event.h"
 
 namespace webrtc {
@@ -143,6 +144,8 @@
       drop_count_(0),
       num_consecutive_old_frames_(0),
       num_consecutive_old_packets_(0),
+      num_packets_(0),
+      num_duplicated_packets_(0),
       num_discarded_packets_(0),
       jitter_estimate_(clock),
       inter_frame_delay_(clock_->TimeInMilliseconds()),
@@ -190,6 +193,8 @@
     drop_count_ = rhs.drop_count_;
     num_consecutive_old_frames_ = rhs.num_consecutive_old_frames_;
     num_consecutive_old_packets_ = rhs.num_consecutive_old_packets_;
+    num_packets_ = rhs.num_packets_;
+    num_duplicated_packets_ = rhs.num_duplicated_packets_;
     num_discarded_packets_ = rhs.num_discarded_packets_;
     jitter_estimate_ = rhs.jitter_estimate_;
     inter_frame_delay_ = rhs.inter_frame_delay_;
@@ -238,6 +243,15 @@
   }
 }
 
+void VCMJitterBuffer::UpdateHistograms() {
+  if (num_packets_ > 0) {
+    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.DiscardedPacketsInPercent",
+        num_discarded_packets_ * 100 / num_packets_);
+    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.DuplicatedPacketsInPercent",
+        num_duplicated_packets_ * 100 / num_packets_);
+  }
+}
+
 void VCMJitterBuffer::Start() {
   CriticalSectionScoped cs(crit_sect_);
   running_ = true;
@@ -250,6 +264,8 @@
 
   num_consecutive_old_frames_ = 0;
   num_consecutive_old_packets_ = 0;
+  num_packets_ = 0;
+  num_duplicated_packets_ = 0;
   num_discarded_packets_ = 0;
 
   // Start in a non-signaled state.
@@ -265,6 +281,7 @@
 
 void VCMJitterBuffer::Stop() {
   crit_sect_->Enter();
+  UpdateHistograms();
   running_ = false;
   last_decoded_state_.Reset();
   free_frames_.clear();
@@ -313,6 +330,16 @@
   return receive_statistics_;
 }
 
+int VCMJitterBuffer::num_packets() const {
+  CriticalSectionScoped cs(crit_sect_);
+  return num_packets_;
+}
+
+int VCMJitterBuffer::num_duplicated_packets() const {
+  CriticalSectionScoped cs(crit_sect_);
+  return num_duplicated_packets_;
+}
+
 int VCMJitterBuffer::num_discarded_packets() const {
   CriticalSectionScoped cs(crit_sect_);
   return num_discarded_packets_;
@@ -543,6 +570,7 @@
 // Gets frame to use for this timestamp. If no match, get empty frame.
 VCMFrameBufferEnum VCMJitterBuffer::GetFrame(const VCMPacket& packet,
                                              VCMFrameBuffer** frame) {
+  ++num_packets_;
   // Does this packet belong to an old frame?
   if (last_decoded_state_.IsOldPacket(&packet)) {
     // Account only for media packets.
@@ -747,6 +775,7 @@
     case kNoError:
     case kOutOfBoundsPacket:
     case kDuplicatePacket: {
+      ++num_duplicated_packets_;
       break;
     }
     case kFlushIndicator:
diff --git a/modules/video_coding/main/source/jitter_buffer.h b/modules/video_coding/main/source/jitter_buffer.h
index 6ed9cfb..182b80b 100644
--- a/modules/video_coding/main/source/jitter_buffer.h
+++ b/modules/video_coding/main/source/jitter_buffer.h
@@ -103,6 +103,12 @@
   // won't be able to decode them.
   int num_not_decodable_packets() const;
 
+  // Gets number of packets received.
+  int num_packets() const;
+
+  // Gets number of duplicated packets received.
+  int num_duplicated_packets() const;
+
   // Gets number of packets discarded by the jitter buffer.
   int num_discarded_packets() const;
 
@@ -271,6 +277,8 @@
 
   uint16_t EstimatedLowSequenceNumber(const VCMFrameBuffer& frame) const;
 
+  void UpdateHistograms();
+
   Clock* clock_;
   // If we are running (have started) or not.
   bool running_;
@@ -303,6 +311,10 @@
   int num_consecutive_old_frames_;
   // Number of packets in a row that have been too old.
   int num_consecutive_old_packets_;
+  // Number of packets received.
+  int num_packets_;
+  // Number of duplicated packets received.
+  int num_duplicated_packets_;
   // Number of packets discarded by the jitter buffer.
   int num_discarded_packets_;
 
diff --git a/modules/video_coding/main/source/jitter_buffer_unittest.cc b/modules/video_coding/main/source/jitter_buffer_unittest.cc
index 0490658..899a3ee 100644
--- a/modules/video_coding/main/source/jitter_buffer_unittest.cc
+++ b/modules/video_coding/main/source/jitter_buffer_unittest.cc
@@ -512,6 +512,8 @@
   packet_->markerBit = false;
   packet_->seqNum = seq_num_;
   packet_->timestamp = timestamp_;
+  EXPECT_EQ(0, jitter_buffer_->num_packets());
+  EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets());
 
   bool retransmitted = false;
   EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(*packet_,
@@ -520,6 +522,8 @@
   VCMEncodedFrame* frame_out = DecodeCompleteFrame();
 
   EXPECT_TRUE(frame_out == NULL);
+  EXPECT_EQ(1, jitter_buffer_->num_packets());
+  EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets());
 
   packet_->isFirstPacket = false;
   packet_->markerBit = true;
@@ -527,6 +531,8 @@
   // Insert a packet into a frame.
   EXPECT_EQ(kDuplicatePacket, jitter_buffer_->InsertPacket(*packet_,
                                                            &retransmitted));
+  EXPECT_EQ(2, jitter_buffer_->num_packets());
+  EXPECT_EQ(1, jitter_buffer_->num_duplicated_packets());
 
   seq_num_++;
   packet_->seqNum = seq_num_;
@@ -539,6 +545,8 @@
   CheckOutFrame(frame_out, 2 * size_, false);
 
   EXPECT_EQ(kVideoFrameKey, frame_out->FrameType());
+  EXPECT_EQ(3, jitter_buffer_->num_packets());
+  EXPECT_EQ(1, jitter_buffer_->num_duplicated_packets());
 }
 
 TEST_F(TestBasicJitterBuffer, H264InsertStartCode) {
diff --git a/modules/video_coding/main/source/video_coding.gypi b/modules/video_coding/main/source/video_coding.gypi
index f19a585..02c5a5c 100644
--- a/modules/video_coding/main/source/video_coding.gypi
+++ b/modules/video_coding/main/source/video_coding.gypi
@@ -17,6 +17,7 @@
         '<(webrtc_root)/modules/video_coding/utility/video_coding_utility.gyp:video_coding_utility',
         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
         '<(webrtc_vp8_dir)/vp8.gyp:webrtc_vp8',
+        '<(webrtc_vp9_dir)/vp9.gyp:webrtc_vp9',
       ],
       'sources': [
         # interfaces
diff --git a/modules/video_coding/main/source/video_coding_impl.h b/modules/video_coding/main/source/video_coding_impl.h
index 5b3fe2e..ac7a1f4 100644
--- a/modules/video_coding/main/source/video_coding_impl.h
+++ b/modules/video_coding/main/source/video_coding_impl.h
@@ -186,7 +186,8 @@
   void RegisterPreDecodeImageCallback(EncodedImageCallback* observer);
 
  protected:
-  int32_t Decode(const webrtc::VCMEncodedFrame& frame);
+  int32_t Decode(const webrtc::VCMEncodedFrame& frame)
+      EXCLUSIVE_LOCKS_REQUIRED(_receiveCritSect);
   int32_t RequestKeyFrame();
   int32_t RequestSliceLossIndication(const uint64_t pictureID) const;
   int32_t NackList(uint16_t* nackList, uint16_t* size);
@@ -230,7 +231,7 @@
   size_t max_nack_list_size_ GUARDED_BY(process_crit_sect_);
   EncodedImageCallback* pre_decode_image_callback_ GUARDED_BY(_receiveCritSect);
 
-  VCMCodecDataBase _codecDataBase;
+  VCMCodecDataBase _codecDataBase GUARDED_BY(_receiveCritSect);
   VCMProcessTimer _receiveStatsTimer;
   VCMProcessTimer _retransmissionTimer;
   VCMProcessTimer _keyRequestTimer;
diff --git a/modules/video_coding/main/source/video_coding_test.gypi b/modules/video_coding/main/source/video_coding_test.gypi
index 64cb602..0c5641d 100644
--- a/modules/video_coding/main/source/video_coding_test.gypi
+++ b/modules/video_coding/main/source/video_coding_test.gypi
@@ -20,7 +20,7 @@
          '<(webrtc_root)/test/test.gyp:test_support',
          '<(webrtc_root)/test/metrics.gyp:metrics',
          '<(webrtc_root)/common_video/common_video.gyp:common_video',
-         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
          '<(webrtc_root)/test/webrtc_test_common.gyp:webrtc_test_common',
       ],
       'sources': [
diff --git a/modules/video_coding/main/source/video_receiver.cc b/modules/video_coding/main/source/video_receiver.cc
index 0b56124..a8de28b 100644
--- a/modules/video_coding/main/source/video_receiver.cc
+++ b/modules/video_coding/main/source/video_receiver.cc
@@ -280,11 +280,11 @@
   if (ret < 0) {
     return ret;
   }
-  _codecDataBase.ResetReceiver();
-  _timing.Reset();
 
   {
     CriticalSectionScoped receive_cs(_receiveCritSect);
+    _codecDataBase.ResetReceiver();
+    _timing.Reset();
     _receiverInited = true;
   }
 
@@ -369,6 +369,7 @@
 // Should be called as often as possible to get the most out of the decoder.
 int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) {
   int64_t nextRenderTimeMs;
+  bool supports_render_scheduling;
   {
     CriticalSectionScoped cs(_receiveCritSect);
     if (!_receiverInited) {
@@ -377,6 +378,7 @@
     if (!_codecDataBase.DecoderRegistered()) {
       return VCM_NO_CODEC_REGISTERED;
     }
+    supports_render_scheduling = _codecDataBase.SupportsRenderScheduling();
   }
 
   const bool dualReceiverEnabledNotReceiving = (
@@ -385,7 +387,7 @@
   VCMEncodedFrame* frame =
       _receiver.FrameForDecoding(maxWaitTimeMs,
                                  nextRenderTimeMs,
-                                 _codecDataBase.SupportsRenderScheduling(),
+                                 supports_render_scheduling,
                                  &_dualReceiver);
 
   if (dualReceiverEnabledNotReceiving && _dualReceiver.State() == kReceiving) {
diff --git a/modules/video_coding/main/test/normal_test.cc b/modules/video_coding/main/test/normal_test.cc
index f23682b..815c3ac 100644
--- a/modules/video_coding/main/test/normal_test.cc
+++ b/modules/video_coding/main/test/normal_test.cc
@@ -101,6 +101,9 @@
     rtpInfo.type.Video.codecHeader.VP8.pictureId =
         videoHdr->codecHeader.VP8.pictureId;
     break;
+  case kVideoCodecVP9:
+    // Leave for now, until we add kRtpVideoVp9 to RTP.
+    break;
   default:
     assert(false);
     return -1;
diff --git a/modules/video_coding/main/test/test_callbacks.cc b/modules/video_coding/main/test/test_callbacks.cc
index 710a06e..d68f994 100644
--- a/modules/video_coding/main/test/test_callbacks.cc
+++ b/modules/video_coding/main/test/test_callbacks.cc
@@ -82,6 +82,9 @@
         rtpInfo.type.Video.codecHeader.VP8.pictureId =
             videoHdr->codecHeader.VP8.pictureId;
         break;
+    case webrtc::kRtpVideoGeneric:
+      // Leave for now, until we add kRtpVideoVp9 to RTP.
+      break;
     default:
         assert(false);
         return -1;
diff --git a/modules/video_coding/main/test/test_util.cc b/modules/video_coding/main/test/test_util.cc
index 09ad991..d2b8f8c 100644
--- a/modules/video_coding/main/test/test_util.cc
+++ b/modules/video_coding/main/test/test_util.cc
@@ -151,6 +151,7 @@
   if (strncmp(plname,"VP8" , 3) == 0) {
     return webrtc::kRtpVideoVp8;
   } else {
-    return webrtc::kRtpVideoNone;  // Default value
+    // Default value.
+    return webrtc::kRtpVideoGeneric;
   }
 }
diff --git a/modules/video_coding/main/test/tester_main.cc b/modules/video_coding/main/test/tester_main.cc
index bf17ab2..874fa9e 100644
--- a/modules/video_coding/main/test/tester_main.cc
+++ b/modules/video_coding/main/test/tester_main.cc
@@ -63,6 +63,8 @@
   args.codecName = FLAGS_codec;
   if (args.codecName == "VP8") {
     args.codecType = kVideoCodecVP8;
+  } else if (args.codecName == "VP9") {
+    args.codecType = kVideoCodecVP9;
   } else if (args.codecName == "I420") {
     args.codecType = kVideoCodecI420;
   } else {
diff --git a/modules/video_coding/utility/video_coding_utility.target.darwin-arm.mk b/modules/video_coding/utility/video_coding_utility.target.darwin-arm.mk
index 13e70ad..9e10792 100644
--- a/modules/video_coding/utility/video_coding_utility.target.darwin-arm.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.darwin-arm.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -104,6 +106,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -197,11 +200,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -217,6 +222,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.darwin-arm64.mk b/modules/video_coding/utility/video_coding_utility.target.darwin-arm64.mk
index dc5453d..26c7a49 100644
--- a/modules/video_coding/utility/video_coding_utility.target.darwin-arm64.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.darwin-arm64.mk
@@ -73,11 +73,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -86,10 +88,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -171,11 +175,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -184,10 +190,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.darwin-mips.mk b/modules/video_coding/utility/video_coding_utility.target.darwin-mips.mk
index d697566..e6367b7 100644
--- a/modules/video_coding/utility/video_coding_utility.target.darwin-mips.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.darwin-mips.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -201,6 +206,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.darwin-mips64.mk b/modules/video_coding/utility/video_coding_utility.target.darwin-mips64.mk
new file mode 100644
index 0000000..71941bc
--- /dev/null
+++ b/modules/video_coding/utility/video_coding_utility.target.darwin-mips64.mk
@@ -0,0 +1,260 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_utility_video_coding_utility_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/utility/frame_dropper.cc \
+	third_party/webrtc/modules/video_coding/utility/quality_scaler.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_utility_video_coding_utility_gyp
+
+# Alias gyp target name.
+.PHONY: video_coding_utility
+video_coding_utility: third_party_webrtc_modules_video_coding_utility_video_coding_utility_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/utility/video_coding_utility.target.darwin-x86.mk b/modules/video_coding/utility/video_coding_utility.target.darwin-x86.mk
index 13bc1cc..b423cb2 100644
--- a/modules/video_coding/utility/video_coding_utility.target.darwin-x86.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.darwin-x86.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -183,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -200,6 +205,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.darwin-x86_64.mk b/modules/video_coding/utility/video_coding_utility.target.darwin-x86_64.mk
index 9a82081..17043fc 100644
--- a/modules/video_coding/utility/video_coding_utility.target.darwin-x86_64.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.darwin-x86_64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,6 +97,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.linux-arm.mk b/modules/video_coding/utility/video_coding_utility.target.linux-arm.mk
index 13e70ad..9e10792 100644
--- a/modules/video_coding/utility/video_coding_utility.target.linux-arm.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.linux-arm.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -104,6 +106,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -197,11 +200,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -217,6 +222,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.linux-arm64.mk b/modules/video_coding/utility/video_coding_utility.target.linux-arm64.mk
index dc5453d..26c7a49 100644
--- a/modules/video_coding/utility/video_coding_utility.target.linux-arm64.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.linux-arm64.mk
@@ -73,11 +73,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -86,10 +88,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -171,11 +175,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -184,10 +190,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.linux-mips.mk b/modules/video_coding/utility/video_coding_utility.target.linux-mips.mk
index d697566..e6367b7 100644
--- a/modules/video_coding/utility/video_coding_utility.target.linux-mips.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.linux-mips.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +185,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -201,6 +206,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.linux-mips64.mk b/modules/video_coding/utility/video_coding_utility.target.linux-mips64.mk
new file mode 100644
index 0000000..71941bc
--- /dev/null
+++ b/modules/video_coding/utility/video_coding_utility.target.linux-mips64.mk
@@ -0,0 +1,260 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_coding_utility_video_coding_utility_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/utility/frame_dropper.cc \
+	third_party/webrtc/modules/video_coding/utility/quality_scaler.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_coding_utility_video_coding_utility_gyp
+
+# Alias gyp target name.
+.PHONY: video_coding_utility
+video_coding_utility: third_party_webrtc_modules_video_coding_utility_video_coding_utility_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_coding/utility/video_coding_utility.target.linux-x86.mk b/modules/video_coding/utility/video_coding_utility.target.linux-x86.mk
index 13bc1cc..b423cb2 100644
--- a/modules/video_coding/utility/video_coding_utility.target.linux-x86.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.linux-x86.mk
@@ -79,11 +79,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -96,6 +98,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -183,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -200,6 +205,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_coding/utility/video_coding_utility.target.linux-x86_64.mk b/modules/video_coding/utility/video_coding_utility.target.linux-x86_64.mk
index 9a82081..17043fc 100644
--- a/modules/video_coding/utility/video_coding_utility.target.linux-x86_64.mk
+++ b/modules/video_coding/utility/video_coding_utility.target.linux-x86_64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,6 +97,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.darwin-arm.mk b/modules/video_processing.target.darwin-arm.mk
index df41d78..aa67383 100644
--- a/modules/video_processing.target.darwin-arm.mk
+++ b/modules/video_processing.target.darwin-arm.mk
@@ -95,11 +95,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -115,6 +117,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -217,11 +220,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.darwin-arm64.mk b/modules/video_processing.target.darwin-arm64.mk
index b0ac65b..603e166 100644
--- a/modules/video_processing.target.darwin-arm64.mk
+++ b/modules/video_processing.target.darwin-arm64.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,10 +99,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,10 +210,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.darwin-mips.mk b/modules/video_processing.target.darwin-mips.mk
index aef54e0..0c380a2 100644
--- a/modules/video_processing.target.darwin-mips.mk
+++ b/modules/video_processing.target.darwin-mips.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.darwin-mips64.mk b/modules/video_processing.target.darwin-mips64.mk
new file mode 100644
index 0000000..03b57c9
--- /dev/null
+++ b/modules/video_processing.target.darwin-mips64.mk
@@ -0,0 +1,285 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_processing_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_processing/main/source/brighten.cc \
+	third_party/webrtc/modules/video_processing/main/source/brightness_detection.cc \
+	third_party/webrtc/modules/video_processing/main/source/color_enhancement.cc \
+	third_party/webrtc/modules/video_processing/main/source/content_analysis.cc \
+	third_party/webrtc/modules/video_processing/main/source/deflickering.cc \
+	third_party/webrtc/modules/video_processing/main/source/frame_preprocessor.cc \
+	third_party/webrtc/modules/video_processing/main/source/spatial_resampler.cc \
+	third_party/webrtc/modules/video_processing/main/source/video_decimator.cc \
+	third_party/webrtc/modules/video_processing/main/source/video_processing_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_processing_gyp
+
+# Alias gyp target name.
+.PHONY: video_processing
+video_processing: third_party_webrtc_modules_video_processing_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_processing.target.darwin-x86.mk b/modules/video_processing.target.darwin-x86.mk
index bc7a899..be7e37c 100644
--- a/modules/video_processing.target.darwin-x86.mk
+++ b/modules/video_processing.target.darwin-x86.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -220,6 +225,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.darwin-x86_64.mk b/modules/video_processing.target.darwin-x86_64.mk
index a9851a4..fed3f29 100644
--- a/modules/video_processing.target.darwin-x86_64.mk
+++ b/modules/video_processing.target.darwin-x86_64.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +204,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -218,6 +223,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.linux-arm.mk b/modules/video_processing.target.linux-arm.mk
index df41d78..aa67383 100644
--- a/modules/video_processing.target.linux-arm.mk
+++ b/modules/video_processing.target.linux-arm.mk
@@ -95,11 +95,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -115,6 +117,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -217,11 +220,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -237,6 +242,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.linux-arm64.mk b/modules/video_processing.target.linux-arm64.mk
index b0ac65b..603e166 100644
--- a/modules/video_processing.target.linux-arm64.mk
+++ b/modules/video_processing.target.linux-arm64.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,10 +99,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,10 +210,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.linux-mips.mk b/modules/video_processing.target.linux-mips.mk
index aef54e0..0c380a2 100644
--- a/modules/video_processing.target.linux-mips.mk
+++ b/modules/video_processing.target.linux-mips.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.linux-mips64.mk b/modules/video_processing.target.linux-mips64.mk
new file mode 100644
index 0000000..03b57c9
--- /dev/null
+++ b/modules/video_processing.target.linux-mips64.mk
@@ -0,0 +1,285 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_processing_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_processing/main/source/brighten.cc \
+	third_party/webrtc/modules/video_processing/main/source/brightness_detection.cc \
+	third_party/webrtc/modules/video_processing/main/source/color_enhancement.cc \
+	third_party/webrtc/modules/video_processing/main/source/content_analysis.cc \
+	third_party/webrtc/modules/video_processing/main/source/deflickering.cc \
+	third_party/webrtc/modules/video_processing/main/source/frame_preprocessor.cc \
+	third_party/webrtc/modules/video_processing/main/source/spatial_resampler.cc \
+	third_party/webrtc/modules/video_processing/main/source/video_decimator.cc \
+	third_party/webrtc/modules/video_processing/main/source/video_processing_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_processing_gyp
+
+# Alias gyp target name.
+.PHONY: video_processing
+video_processing: third_party_webrtc_modules_video_processing_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_processing.target.linux-x86.mk b/modules/video_processing.target.linux-x86.mk
index bc7a899..be7e37c 100644
--- a/modules/video_processing.target.linux-x86.mk
+++ b/modules/video_processing.target.linux-x86.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -220,6 +225,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing.target.linux-x86_64.mk b/modules/video_processing.target.linux-x86_64.mk
index a9851a4..fed3f29 100644
--- a/modules/video_processing.target.linux-x86_64.mk
+++ b/modules/video_processing.target.linux-x86_64.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +108,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +204,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -218,6 +223,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing_sse2.target.darwin-x86.mk b/modules/video_processing_sse2.target.darwin-x86.mk
index bb8623f..863c65d 100644
--- a/modules/video_processing_sse2.target.darwin-x86.mk
+++ b/modules/video_processing_sse2.target.darwin-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing_sse2.target.darwin-x86_64.mk b/modules/video_processing_sse2.target.darwin-x86_64.mk
index a0a6b1e..2bb01c2 100644
--- a/modules/video_processing_sse2.target.darwin-x86_64.mk
+++ b/modules/video_processing_sse2.target.darwin-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing_sse2.target.linux-x86.mk b/modules/video_processing_sse2.target.linux-x86.mk
index bb8623f..863c65d 100644
--- a/modules/video_processing_sse2.target.linux-x86.mk
+++ b/modules/video_processing_sse2.target.linux-x86.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -208,6 +213,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_processing_sse2.target.linux-x86_64.mk b/modules/video_processing_sse2.target.linux-x86_64.mk
index a0a6b1e..2bb01c2 100644
--- a/modules/video_processing_sse2.target.linux-x86_64.mk
+++ b/modules/video_processing_sse2.target.linux-x86_64.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render/incoming_video_stream.cc b/modules/video_render/incoming_video_stream.cc
index 71f30c3..1770569 100644
--- a/modules/video_render/incoming_video_stream.cc
+++ b/modules/video_render/incoming_video_stream.cc
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "webrtc/modules/video_render//incoming_video_stream.h"
+#include "webrtc/modules/video_render/incoming_video_stream.h"
 
 #include <assert.h>
 
@@ -22,7 +22,7 @@
 #endif
 
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
-#include "webrtc/modules/video_render//video_render_frames.h"
+#include "webrtc/modules/video_render/video_render_frames.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/event_wrapper.h"
 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
diff --git a/modules/video_render/video_render.gypi b/modules/video_render/video_render.gypi
index 5db851d..38a7798 100644
--- a/modules/video_render/video_render.gypi
+++ b/modules/video_render/video_render.gypi
@@ -205,7 +205,6 @@
               ],
               'includes': [
                 '../../build/isolate.gypi',
-                'video_render_tests.isolate',
               ],
               'sources': [
                 'video_render_tests.isolate',
diff --git a/modules/video_render/video_render_tests.isolate b/modules/video_render/video_render_tests.isolate
index 15c8014..12bfecf 100644
--- a/modules/video_render/video_render_tests.isolate
+++ b/modules/video_render/video_render_tests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,13 +21,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/video_render_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/video_render_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/modules/video_render_module.target.darwin-arm.mk b/modules/video_render_module.target.darwin-arm.mk
index 5dada0f..4899832 100644
--- a/modules/video_render_module.target.darwin-arm.mk
+++ b/modules/video_render_module.target.darwin-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.darwin-arm64.mk b/modules/video_render_module.target.darwin-arm64.mk
index 0a91cbe..a5e3a50 100644
--- a/modules/video_render_module.target.darwin-arm64.mk
+++ b/modules/video_render_module.target.darwin-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.darwin-mips.mk b/modules/video_render_module.target.darwin-mips.mk
index 4417e7e..ea672a7 100644
--- a/modules/video_render_module.target.darwin-mips.mk
+++ b/modules/video_render_module.target.darwin-mips.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.darwin-mips64.mk b/modules/video_render_module.target.darwin-mips64.mk
new file mode 100644
index 0000000..a2a8914
--- /dev/null
+++ b/modules/video_render_module.target.darwin-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_render_module_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_render/external/video_render_external_impl.cc \
+	third_party/webrtc/modules/video_render/incoming_video_stream.cc \
+	third_party/webrtc/modules/video_render/video_render_frames.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_render_module_gyp
+
+# Alias gyp target name.
+.PHONY: video_render_module
+video_render_module: third_party_webrtc_modules_video_render_module_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_render_module.target.darwin-x86.mk b/modules/video_render_module.target.darwin-x86.mk
index 243df8f..16e78e2 100644
--- a/modules/video_render_module.target.darwin-x86.mk
+++ b/modules/video_render_module.target.darwin-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.darwin-x86_64.mk b/modules/video_render_module.target.darwin-x86_64.mk
index 23e262d..e91a36f 100644
--- a/modules/video_render_module.target.darwin-x86_64.mk
+++ b/modules/video_render_module.target.darwin-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.linux-arm.mk b/modules/video_render_module.target.linux-arm.mk
index 5dada0f..4899832 100644
--- a/modules/video_render_module.target.linux-arm.mk
+++ b/modules/video_render_module.target.linux-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -208,11 +211,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.linux-arm64.mk b/modules/video_render_module.target.linux-arm64.mk
index 0a91cbe..a5e3a50 100644
--- a/modules/video_render_module.target.linux-arm64.mk
+++ b/modules/video_render_module.target.linux-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -182,11 +186,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,10 +201,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.linux-mips.mk b/modules/video_render_module.target.linux-mips.mk
index 4417e7e..ea672a7 100644
--- a/modules/video_render_module.target.linux-mips.mk
+++ b/modules/video_render_module.target.linux-mips.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.linux-mips64.mk b/modules/video_render_module.target.linux-mips64.mk
new file mode 100644
index 0000000..a2a8914
--- /dev/null
+++ b/modules/video_render_module.target.linux-mips64.mk
@@ -0,0 +1,273 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_render_module_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_render/external/video_render_external_impl.cc \
+	third_party/webrtc/modules/video_render/incoming_video_stream.cc \
+	third_party/webrtc/modules/video_render/video_render_frames.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_render_module_gyp
+
+# Alias gyp target name.
+.PHONY: video_render_module
+video_render_module: third_party_webrtc_modules_video_render_module_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_render_module.target.linux-x86.mk b/modules/video_render_module.target.linux-x86.mk
index 243df8f..16e78e2 100644
--- a/modules/video_render_module.target.linux-x86.mk
+++ b/modules/video_render_module.target.linux-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -211,6 +216,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module.target.linux-x86_64.mk b/modules/video_render_module.target.linux-x86_64.mk
index 23e262d..e91a36f 100644
--- a/modules/video_render_module.target.linux-x86_64.mk
+++ b/modules/video_render_module.target.linux-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -192,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.darwin-arm.mk b/modules/video_render_module_impl.target.darwin-arm.mk
index 5bc5ef6..4b35778 100644
--- a/modules/video_render_module_impl.target.darwin-arm.mk
+++ b/modules/video_render_module_impl.target.darwin-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.darwin-arm64.mk b/modules/video_render_module_impl.target.darwin-arm64.mk
index dfd5ba2..b4b299c 100644
--- a/modules/video_render_module_impl.target.darwin-arm64.mk
+++ b/modules/video_render_module_impl.target.darwin-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -177,11 +181,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -190,10 +196,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.darwin-mips.mk b/modules/video_render_module_impl.target.darwin-mips.mk
index 81e7db7..7bf2537 100644
--- a/modules/video_render_module_impl.target.darwin-mips.mk
+++ b/modules/video_render_module_impl.target.darwin-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.darwin-mips64.mk b/modules/video_render_module_impl.target.darwin-mips64.mk
new file mode 100644
index 0000000..de890a7
--- /dev/null
+++ b/modules/video_render_module_impl.target.darwin-mips64.mk
@@ -0,0 +1,265 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_render_module_impl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_render/video_render_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_render_module_impl_gyp
+
+# Alias gyp target name.
+.PHONY: video_render_module_impl
+video_render_module_impl: third_party_webrtc_modules_video_render_module_impl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_render_module_impl.target.darwin-x86.mk b/modules/video_render_module_impl.target.darwin-x86.mk
index ff6157d..7b19afe 100644
--- a/modules/video_render_module_impl.target.darwin-x86.mk
+++ b/modules/video_render_module_impl.target.darwin-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.darwin-x86_64.mk b/modules/video_render_module_impl.target.darwin-x86_64.mk
index 93074eb..3b8d5fd 100644
--- a/modules/video_render_module_impl.target.darwin-x86_64.mk
+++ b/modules/video_render_module_impl.target.darwin-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.linux-arm.mk b/modules/video_render_module_impl.target.linux-arm.mk
index 5bc5ef6..4b35778 100644
--- a/modules/video_render_module_impl.target.linux-arm.mk
+++ b/modules/video_render_module_impl.target.linux-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.linux-arm64.mk b/modules/video_render_module_impl.target.linux-arm64.mk
index dfd5ba2..b4b299c 100644
--- a/modules/video_render_module_impl.target.linux-arm64.mk
+++ b/modules/video_render_module_impl.target.linux-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -177,11 +181,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -190,10 +196,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.linux-mips.mk b/modules/video_render_module_impl.target.linux-mips.mk
index 81e7db7..7bf2537 100644
--- a/modules/video_render_module_impl.target.linux-mips.mk
+++ b/modules/video_render_module_impl.target.linux-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -209,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.linux-mips64.mk b/modules/video_render_module_impl.target.linux-mips64.mk
new file mode 100644
index 0000000..de890a7
--- /dev/null
+++ b/modules/video_render_module_impl.target.linux-mips64.mk
@@ -0,0 +1,265 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_video_render_module_impl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_render/video_render_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_video_render_module_impl_gyp
+
+# Alias gyp target name.
+.PHONY: video_render_module_impl
+video_render_module_impl: third_party_webrtc_modules_video_render_module_impl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/video_render_module_impl.target.linux-x86.mk b/modules/video_render_module_impl.target.linux-x86.mk
index ff6157d..7b19afe 100644
--- a/modules/video_render_module_impl.target.linux-x86.mk
+++ b/modules/video_render_module_impl.target.linux-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -189,11 +192,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -206,6 +211,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/video_render_module_impl.target.linux-x86_64.mk b/modules/video_render_module_impl.target.linux-x86_64.mk
index 93074eb..3b8d5fd 100644
--- a/modules/video_render_module_impl.target.linux-x86_64.mk
+++ b/modules/video_render_module_impl.target.linux-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.darwin-arm.mk b/modules/webrtc_i420.target.darwin-arm.mk
index 3ba9f72..a8903e4 100644
--- a/modules/webrtc_i420.target.darwin-arm.mk
+++ b/modules/webrtc_i420.target.darwin-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.darwin-arm64.mk b/modules/webrtc_i420.target.darwin-arm64.mk
index 3719cfd..a38e7bd 100644
--- a/modules/webrtc_i420.target.darwin-arm64.mk
+++ b/modules/webrtc_i420.target.darwin-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.darwin-mips.mk b/modules/webrtc_i420.target.darwin-mips.mk
index b7a937b..dba3d27 100644
--- a/modules/webrtc_i420.target.darwin-mips.mk
+++ b/modules/webrtc_i420.target.darwin-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.darwin-mips64.mk b/modules/webrtc_i420.target.darwin-mips64.mk
new file mode 100644
index 0000000..29caed7
--- /dev/null
+++ b/modules/webrtc_i420.target.darwin-mips64.mk
@@ -0,0 +1,267 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_i420_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/i420/main/source/i420.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_i420_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_i420
+webrtc_i420: third_party_webrtc_modules_webrtc_i420_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_i420.target.darwin-x86.mk b/modules/webrtc_i420.target.darwin-x86.mk
index 7ca1aa4..2792e21 100644
--- a/modules/webrtc_i420.target.darwin-x86.mk
+++ b/modules/webrtc_i420.target.darwin-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.darwin-x86_64.mk b/modules/webrtc_i420.target.darwin-x86_64.mk
index 39edf25..4397a0c 100644
--- a/modules/webrtc_i420.target.darwin-x86_64.mk
+++ b/modules/webrtc_i420.target.darwin-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.linux-arm.mk b/modules/webrtc_i420.target.linux-arm.mk
index 3ba9f72..a8903e4 100644
--- a/modules/webrtc_i420.target.linux-arm.mk
+++ b/modules/webrtc_i420.target.linux-arm.mk
@@ -87,11 +87,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +229,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.linux-arm64.mk b/modules/webrtc_i420.target.linux-arm64.mk
index 3719cfd..a38e7bd 100644
--- a/modules/webrtc_i420.target.linux-arm64.mk
+++ b/modules/webrtc_i420.target.linux-arm64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -89,10 +91,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +197,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.linux-mips.mk b/modules/webrtc_i420.target.linux-mips.mk
index b7a937b..dba3d27 100644
--- a/modules/webrtc_i420.target.linux-mips.mk
+++ b/modules/webrtc_i420.target.linux-mips.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +194,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +215,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.linux-mips64.mk b/modules/webrtc_i420.target.linux-mips64.mk
new file mode 100644
index 0000000..29caed7
--- /dev/null
+++ b/modules/webrtc_i420.target.linux-mips64.mk
@@ -0,0 +1,267 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_i420_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/codecs/i420/main/source/i420.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_i420_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_i420
+webrtc_i420: third_party_webrtc_modules_webrtc_i420_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_i420.target.linux-x86.mk b/modules/webrtc_i420.target.linux-x86.mk
index 7ca1aa4..2792e21 100644
--- a/modules/webrtc_i420.target.linux-x86.mk
+++ b/modules/webrtc_i420.target.linux-x86.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_i420.target.linux-x86_64.mk b/modules/webrtc_i420.target.linux-x86_64.mk
index 39edf25..4397a0c 100644
--- a/modules/webrtc_i420.target.linux-x86_64.mk
+++ b/modules/webrtc_i420.target.linux-x86_64.mk
@@ -81,11 +81,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +100,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +191,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.darwin-arm.mk b/modules/webrtc_opus.target.darwin-arm.mk
index 035ca97..59323d3 100644
--- a/modules/webrtc_opus.target.darwin-arm.mk
+++ b/modules/webrtc_opus.target.darwin-arm.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -86,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +231,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.darwin-arm64.mk b/modules/webrtc_opus.target.darwin-arm64.mk
index 7282504..585e781 100644
--- a/modules/webrtc_opus.target.darwin-arm64.mk
+++ b/modules/webrtc_opus.target.darwin-arm64.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -75,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -88,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +199,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.darwin-mips.mk b/modules/webrtc_opus.target.darwin-mips.mk
index 27a6f00..e58c3e8 100644
--- a/modules/webrtc_opus.target.darwin-mips.mk
+++ b/modules/webrtc_opus.target.darwin-mips.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -80,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +217,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.darwin-mips64.mk b/modules/webrtc_opus.target.darwin-mips64.mk
new file mode 100644
index 0000000..284ce73
--- /dev/null
+++ b/modules/webrtc_opus.target.darwin-mips64.mk
@@ -0,0 +1,270 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_opus_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
+	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_opus_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_opus
+webrtc_opus: third_party_webrtc_modules_webrtc_opus_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_opus.target.darwin-x86.mk b/modules/webrtc_opus.target.darwin-x86.mk
index 475a30a..bc4258e 100644
--- a/modules/webrtc_opus.target.darwin-x86.mk
+++ b/modules/webrtc_opus.target.darwin-x86.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -81,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.darwin-x86_64.mk b/modules/webrtc_opus.target.darwin-x86_64.mk
index 1fa557c..01f2af3 100644
--- a/modules/webrtc_opus.target.darwin-x86_64.mk
+++ b/modules/webrtc_opus.target.darwin-x86_64.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -80,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.linux-arm.mk b/modules/webrtc_opus.target.linux-arm.mk
index 035ca97..59323d3 100644
--- a/modules/webrtc_opus.target.linux-arm.mk
+++ b/modules/webrtc_opus.target.linux-arm.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -86,11 +88,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -106,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -224,6 +231,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.linux-arm64.mk b/modules/webrtc_opus.target.linux-arm64.mk
index 7282504..585e781 100644
--- a/modules/webrtc_opus.target.linux-arm64.mk
+++ b/modules/webrtc_opus.target.linux-arm64.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -75,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -88,10 +92,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -191,10 +199,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.linux-mips.mk b/modules/webrtc_opus.target.linux-mips.mk
index 27a6f00..e58c3e8 100644
--- a/modules/webrtc_opus.target.linux-mips.mk
+++ b/modules/webrtc_opus.target.linux-mips.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -80,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -99,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -191,11 +196,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -210,6 +217,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.linux-mips64.mk b/modules/webrtc_opus.target.linux-mips64.mk
new file mode 100644
index 0000000..284ce73
--- /dev/null
+++ b/modules/webrtc_opus.target.linux-mips64.mk
@@ -0,0 +1,270 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_opus_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
+	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/opus/src/include
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_opus_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_opus
+webrtc_opus: third_party_webrtc_modules_webrtc_opus_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_opus.target.linux-x86.mk b/modules/webrtc_opus.target.linux-x86.mk
index 475a30a..bc4258e 100644
--- a/modules/webrtc_opus.target.linux-x86.mk
+++ b/modules/webrtc_opus.target.linux-x86.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -81,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -190,11 +195,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,6 +214,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_opus.target.linux-x86_64.mk b/modules/webrtc_opus.target.linux-x86_64.mk
index 1fa557c..01f2af3 100644
--- a/modules/webrtc_opus.target.linux-x86_64.mk
+++ b/modules/webrtc_opus.target.linux-x86_64.mk
@@ -18,11 +18,13 @@
 # Make sure our deps and generated files are built first.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
 
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_GENERATED_SOURCES :=
 
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc \
 	third_party/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
 
 
@@ -80,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -97,6 +101,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -188,11 +193,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +212,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.darwin-arm.mk b/modules/webrtc_utility.target.darwin-arm.mk
index db72003..44fd9c8 100644
--- a/modules/webrtc_utility.target.darwin-arm.mk
+++ b/modules/webrtc_utility.target.darwin-arm.mk
@@ -96,11 +96,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -116,6 +118,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -240,6 +245,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.darwin-arm64.mk b/modules/webrtc_utility.target.darwin-arm64.mk
index 1613ed9..d4c70e7 100644
--- a/modules/webrtc_utility.target.darwin-arm64.mk
+++ b/modules/webrtc_utility.target.darwin-arm64.mk
@@ -85,11 +85,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,10 +100,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,10 +213,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.darwin-mips.mk b/modules/webrtc_utility.target.darwin-mips.mk
index 6a67490..261b9e2 100644
--- a/modules/webrtc_utility.target.darwin-mips.mk
+++ b/modules/webrtc_utility.target.darwin-mips.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -207,11 +210,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -226,6 +231,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.darwin-mips64.mk b/modules/webrtc_utility.target.darwin-mips64.mk
new file mode 100644
index 0000000..b318dd8
--- /dev/null
+++ b/modules/webrtc_utility.target.darwin-mips64.mk
@@ -0,0 +1,290 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_utility_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/utility/source/audio_frame_operations.cc \
+	third_party/webrtc/modules/utility/source/coder.cc \
+	third_party/webrtc/modules/utility/source/file_player_impl.cc \
+	third_party/webrtc/modules/utility/source/file_recorder_impl.cc \
+	third_party/webrtc/modules/utility/source/helpers_android.cc \
+	third_party/webrtc/modules/utility/source/process_thread_impl.cc \
+	third_party/webrtc/modules/utility/source/rtp_dump_impl.cc \
+	third_party/webrtc/modules/utility/source/frame_scaler.cc \
+	third_party/webrtc/modules/utility/source/video_coder.cc \
+	third_party/webrtc/modules/utility/source/video_frames_queue.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_utility_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_utility
+webrtc_utility: third_party_webrtc_modules_webrtc_utility_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_utility.target.darwin-x86.mk b/modules/webrtc_utility.target.darwin-x86.mk
index f7c7ebc..dda4291 100644
--- a/modules/webrtc_utility.target.darwin-x86.mk
+++ b/modules/webrtc_utility.target.darwin-x86.mk
@@ -91,11 +91,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -206,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.darwin-x86_64.mk b/modules/webrtc_utility.target.darwin-x86_64.mk
index c679d4c..8934fe8 100644
--- a/modules/webrtc_utility.target.darwin-x86_64.mk
+++ b/modules/webrtc_utility.target.darwin-x86_64.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.linux-arm.mk b/modules/webrtc_utility.target.linux-arm.mk
index db72003..44fd9c8 100644
--- a/modules/webrtc_utility.target.linux-arm.mk
+++ b/modules/webrtc_utility.target.linux-arm.mk
@@ -96,11 +96,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -116,6 +118,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -220,11 +223,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -240,6 +245,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.linux-arm64.mk b/modules/webrtc_utility.target.linux-arm64.mk
index 1613ed9..d4c70e7 100644
--- a/modules/webrtc_utility.target.linux-arm64.mk
+++ b/modules/webrtc_utility.target.linux-arm64.mk
@@ -85,11 +85,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -98,10 +100,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -207,10 +213,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.linux-mips.mk b/modules/webrtc_utility.target.linux-mips.mk
index 6a67490..261b9e2 100644
--- a/modules/webrtc_utility.target.linux-mips.mk
+++ b/modules/webrtc_utility.target.linux-mips.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -207,11 +210,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -226,6 +231,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.linux-mips64.mk b/modules/webrtc_utility.target.linux-mips64.mk
new file mode 100644
index 0000000..b318dd8
--- /dev/null
+++ b/modules/webrtc_utility.target.linux-mips64.mk
@@ -0,0 +1,290 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_utility_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/utility/source/audio_frame_operations.cc \
+	third_party/webrtc/modules/utility/source/coder.cc \
+	third_party/webrtc/modules/utility/source/file_player_impl.cc \
+	third_party/webrtc/modules/utility/source/file_recorder_impl.cc \
+	third_party/webrtc/modules/utility/source/helpers_android.cc \
+	third_party/webrtc/modules/utility/source/process_thread_impl.cc \
+	third_party/webrtc/modules/utility/source/rtp_dump_impl.cc \
+	third_party/webrtc/modules/utility/source/frame_scaler.cc \
+	third_party/webrtc/modules/utility/source/video_coder.cc \
+	third_party/webrtc/modules/utility/source/video_frames_queue.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_utility_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_utility
+webrtc_utility: third_party_webrtc_modules_webrtc_utility_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_utility.target.linux-x86.mk b/modules/webrtc_utility.target.linux-x86.mk
index f7c7ebc..dda4291 100644
--- a/modules/webrtc_utility.target.linux-x86.mk
+++ b/modules/webrtc_utility.target.linux-x86.mk
@@ -91,11 +91,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -108,6 +110,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -206,11 +209,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -223,6 +228,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_utility.target.linux-x86_64.mk b/modules/webrtc_utility.target.linux-x86_64.mk
index c679d4c..8934fe8 100644
--- a/modules/webrtc_utility.target.linux-x86_64.mk
+++ b/modules/webrtc_utility.target.linux-x86_64.mk
@@ -90,11 +90,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -107,6 +109,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -204,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.darwin-arm.mk b/modules/webrtc_video_coding.target.darwin-arm.mk
index 9beb056..357b2fa 100644
--- a/modules/webrtc_video_coding.target.darwin-arm.mk
+++ b/modules/webrtc_video_coding.target.darwin-arm.mk
@@ -109,11 +109,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -129,6 +131,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -228,11 +231,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -248,6 +253,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.darwin-arm64.mk b/modules/webrtc_video_coding.target.darwin-arm64.mk
index 6cc9aec..e686d78 100644
--- a/modules/webrtc_video_coding.target.darwin-arm64.mk
+++ b/modules/webrtc_video_coding.target.darwin-arm64.mk
@@ -98,11 +98,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -111,10 +113,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -202,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,10 +221,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.darwin-mips.mk b/modules/webrtc_video_coding.target.darwin-mips.mk
index f121d0b..11689c1 100644
--- a/modules/webrtc_video_coding.target.darwin-mips.mk
+++ b/modules/webrtc_video_coding.target.darwin-mips.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -122,6 +124,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -215,11 +218,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -234,6 +239,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.darwin-mips64.mk b/modules/webrtc_video_coding.target.darwin-mips64.mk
new file mode 100644
index 0000000..837f913
--- /dev/null
+++ b/modules/webrtc_video_coding.target.darwin-mips64.mk
@@ -0,0 +1,293 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_video_coding_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/main/source/codec_database.cc \
+	third_party/webrtc/modules/video_coding/main/source/codec_timer.cc \
+	third_party/webrtc/modules/video_coding/main/source/content_metrics_processing.cc \
+	third_party/webrtc/modules/video_coding/main/source/decoding_state.cc \
+	third_party/webrtc/modules/video_coding/main/source/encoded_frame.cc \
+	third_party/webrtc/modules/video_coding/main/source/frame_buffer.cc \
+	third_party/webrtc/modules/video_coding/main/source/generic_decoder.cc \
+	third_party/webrtc/modules/video_coding/main/source/generic_encoder.cc \
+	third_party/webrtc/modules/video_coding/main/source/inter_frame_delay.cc \
+	third_party/webrtc/modules/video_coding/main/source/jitter_buffer.cc \
+	third_party/webrtc/modules/video_coding/main/source/jitter_estimator.cc \
+	third_party/webrtc/modules/video_coding/main/source/media_opt_util.cc \
+	third_party/webrtc/modules/video_coding/main/source/media_optimization.cc \
+	third_party/webrtc/modules/video_coding/main/source/packet.cc \
+	third_party/webrtc/modules/video_coding/main/source/qm_select.cc \
+	third_party/webrtc/modules/video_coding/main/source/receiver.cc \
+	third_party/webrtc/modules/video_coding/main/source/rtt_filter.cc \
+	third_party/webrtc/modules/video_coding/main/source/session_info.cc \
+	third_party/webrtc/modules/video_coding/main/source/timestamp_map.cc \
+	third_party/webrtc/modules/video_coding/main/source/timing.cc \
+	third_party/webrtc/modules/video_coding/main/source/video_coding_impl.cc \
+	third_party/webrtc/modules/video_coding/main/source/video_sender.cc \
+	third_party/webrtc/modules/video_coding/main/source/video_receiver.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_video_coding_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_video_coding
+webrtc_video_coding: third_party_webrtc_modules_webrtc_video_coding_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_video_coding.target.darwin-x86.mk b/modules/webrtc_video_coding.target.darwin-x86.mk
index 272271d..8f08b51 100644
--- a/modules/webrtc_video_coding.target.darwin-x86.mk
+++ b/modules/webrtc_video_coding.target.darwin-x86.mk
@@ -104,11 +104,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -121,6 +123,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -214,11 +217,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -231,6 +236,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.darwin-x86_64.mk b/modules/webrtc_video_coding.target.darwin-x86_64.mk
index b6dea83..b4732d8 100644
--- a/modules/webrtc_video_coding.target.darwin-x86_64.mk
+++ b/modules/webrtc_video_coding.target.darwin-x86_64.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -120,6 +122,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -212,11 +215,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -229,6 +234,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.linux-arm.mk b/modules/webrtc_video_coding.target.linux-arm.mk
index 9beb056..357b2fa 100644
--- a/modules/webrtc_video_coding.target.linux-arm.mk
+++ b/modules/webrtc_video_coding.target.linux-arm.mk
@@ -109,11 +109,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -129,6 +131,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -228,11 +231,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -248,6 +253,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.linux-arm64.mk b/modules/webrtc_video_coding.target.linux-arm64.mk
index 6cc9aec..e686d78 100644
--- a/modules/webrtc_video_coding.target.linux-arm64.mk
+++ b/modules/webrtc_video_coding.target.linux-arm64.mk
@@ -98,11 +98,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -111,10 +113,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -202,11 +206,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,10 +221,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.linux-mips.mk b/modules/webrtc_video_coding.target.linux-mips.mk
index f121d0b..11689c1 100644
--- a/modules/webrtc_video_coding.target.linux-mips.mk
+++ b/modules/webrtc_video_coding.target.linux-mips.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -122,6 +124,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -215,11 +218,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -234,6 +239,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.linux-mips64.mk b/modules/webrtc_video_coding.target.linux-mips64.mk
new file mode 100644
index 0000000..837f913
--- /dev/null
+++ b/modules/webrtc_video_coding.target.linux-mips64.mk
@@ -0,0 +1,293 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_modules_webrtc_video_coding_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/modules/video_coding/main/source/codec_database.cc \
+	third_party/webrtc/modules/video_coding/main/source/codec_timer.cc \
+	third_party/webrtc/modules/video_coding/main/source/content_metrics_processing.cc \
+	third_party/webrtc/modules/video_coding/main/source/decoding_state.cc \
+	third_party/webrtc/modules/video_coding/main/source/encoded_frame.cc \
+	third_party/webrtc/modules/video_coding/main/source/frame_buffer.cc \
+	third_party/webrtc/modules/video_coding/main/source/generic_decoder.cc \
+	third_party/webrtc/modules/video_coding/main/source/generic_encoder.cc \
+	third_party/webrtc/modules/video_coding/main/source/inter_frame_delay.cc \
+	third_party/webrtc/modules/video_coding/main/source/jitter_buffer.cc \
+	third_party/webrtc/modules/video_coding/main/source/jitter_estimator.cc \
+	third_party/webrtc/modules/video_coding/main/source/media_opt_util.cc \
+	third_party/webrtc/modules/video_coding/main/source/media_optimization.cc \
+	third_party/webrtc/modules/video_coding/main/source/packet.cc \
+	third_party/webrtc/modules/video_coding/main/source/qm_select.cc \
+	third_party/webrtc/modules/video_coding/main/source/receiver.cc \
+	third_party/webrtc/modules/video_coding/main/source/rtt_filter.cc \
+	third_party/webrtc/modules/video_coding/main/source/session_info.cc \
+	third_party/webrtc/modules/video_coding/main/source/timestamp_map.cc \
+	third_party/webrtc/modules/video_coding/main/source/timing.cc \
+	third_party/webrtc/modules/video_coding/main/source/video_coding_impl.cc \
+	third_party/webrtc/modules/video_coding/main/source/video_sender.cc \
+	third_party/webrtc/modules/video_coding/main/source/video_receiver.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_modules_webrtc_video_coding_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_video_coding
+webrtc_video_coding: third_party_webrtc_modules_webrtc_video_coding_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/modules/webrtc_video_coding.target.linux-x86.mk b/modules/webrtc_video_coding.target.linux-x86.mk
index 272271d..8f08b51 100644
--- a/modules/webrtc_video_coding.target.linux-x86.mk
+++ b/modules/webrtc_video_coding.target.linux-x86.mk
@@ -104,11 +104,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -121,6 +123,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -214,11 +217,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -231,6 +236,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/modules/webrtc_video_coding.target.linux-x86_64.mk b/modules/webrtc_video_coding.target.linux-x86_64.mk
index b6dea83..b4732d8 100644
--- a/modules/webrtc_video_coding.target.linux-x86_64.mk
+++ b/modules/webrtc_video_coding.target.linux-x86_64.mk
@@ -103,11 +103,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -120,6 +122,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -212,11 +215,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -229,6 +234,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/p2p/OWNERS b/p2p/OWNERS
new file mode 100644
index 0000000..1a24a6a
--- /dev/null
+++ b/p2p/OWNERS
@@ -0,0 +1,13 @@
+henrika@webrtc.org
+henrike@webrtc.org
+henrikg@webrtc.org
+hta@webrtc.org
+jiayl@webrtc.org
+juberti@webrtc.org
+mflodman@webrtc.org
+perkj@webrtc.org
+pthatcher@webrtc.org
+sergeyu@chromium.org
+tommi@webrtc.org
+
+per-file BUILD.gn=kjellander@webrtc.org
diff --git a/p2p/base/asyncstuntcpsocket.cc b/p2p/base/asyncstuntcpsocket.cc
new file mode 100644
index 0000000..2b1b693
--- /dev/null
+++ b/p2p/base/asyncstuntcpsocket.cc
@@ -0,0 +1,153 @@
+/*
+ *  Copyright 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/p2p/base/asyncstuntcpsocket.h"
+
+#include <string.h>
+
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+
+namespace cricket {
+
+static const size_t kMaxPacketSize = 64 * 1024;
+
+typedef uint16 PacketLength;
+static const size_t kPacketLenSize = sizeof(PacketLength);
+static const size_t kPacketLenOffset = 2;
+static const size_t kBufSize = kMaxPacketSize + kStunHeaderSize;
+static const size_t kTurnChannelDataHdrSize = 4;
+
+inline bool IsStunMessage(uint16 msg_type) {
+  // The first two bits of a channel data message are 0b01.
+  return (msg_type & 0xC000) ? false : true;
+}
+
+// AsyncStunTCPSocket
+// Binds and connects |socket| and creates AsyncTCPSocket for
+// it. Takes ownership of |socket|. Returns NULL if bind() or
+// connect() fail (|socket| is destroyed in that case).
+AsyncStunTCPSocket* AsyncStunTCPSocket::Create(
+    rtc::AsyncSocket* socket,
+    const rtc::SocketAddress& bind_address,
+    const rtc::SocketAddress& remote_address) {
+  return new AsyncStunTCPSocket(AsyncTCPSocketBase::ConnectSocket(
+      socket, bind_address, remote_address), false);
+}
+
+AsyncStunTCPSocket::AsyncStunTCPSocket(
+    rtc::AsyncSocket* socket, bool listen)
+    : rtc::AsyncTCPSocketBase(socket, listen, kBufSize) {
+}
+
+int AsyncStunTCPSocket::Send(const void *pv, size_t cb,
+                             const rtc::PacketOptions& options) {
+  if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) {
+    SetError(EMSGSIZE);
+    return -1;
+  }
+
+  // If we are blocking on send, then silently drop this packet
+  if (!IsOutBufferEmpty())
+    return static_cast<int>(cb);
+
+  int pad_bytes;
+  size_t expected_pkt_len = GetExpectedLength(pv, cb, &pad_bytes);
+
+  // Accepts only complete STUN/ChannelData packets.
+  if (cb != expected_pkt_len)
+    return -1;
+
+  AppendToOutBuffer(pv, cb);
+
+  ASSERT(pad_bytes < 4);
+  char padding[4] = {0};
+  AppendToOutBuffer(padding, pad_bytes);
+
+  int res = FlushOutBuffer();
+  if (res <= 0) {
+    // drop packet if we made no progress
+    ClearOutBuffer();
+    return res;
+  }
+
+  // We claim to have sent the whole thing, even if we only sent partial
+  return static_cast<int>(cb);
+}
+
+void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) {
+  rtc::SocketAddress remote_addr(GetRemoteAddress());
+  // STUN packet - First 4 bytes. Total header size is 20 bytes.
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // |0 0|     STUN Message Type     |         Message Length        |
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  // TURN ChannelData
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // |         Channel Number        |            Length             |
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  while (true) {
+    // We need at least 4 bytes to read the STUN or ChannelData packet length.
+    if (*len < kPacketLenOffset + kPacketLenSize)
+      return;
+
+    int pad_bytes;
+    size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes);
+    size_t actual_length = expected_pkt_len + pad_bytes;
+
+    if (*len < actual_length) {
+      return;
+    }
+
+    SignalReadPacket(this, data, expected_pkt_len, remote_addr,
+                     rtc::CreatePacketTime(0));
+
+    *len -= actual_length;
+    if (*len > 0) {
+      memmove(data, data + actual_length, *len);
+    }
+  }
+}
+
+void AsyncStunTCPSocket::HandleIncomingConnection(
+    rtc::AsyncSocket* socket) {
+  SignalNewConnection(this, new AsyncStunTCPSocket(socket, false));
+}
+
+size_t AsyncStunTCPSocket::GetExpectedLength(const void* data, size_t len,
+                                             int* pad_bytes) {
+  *pad_bytes = 0;
+  PacketLength pkt_len =
+      rtc::GetBE16(static_cast<const char*>(data) + kPacketLenOffset);
+  size_t expected_pkt_len;
+  uint16 msg_type = rtc::GetBE16(data);
+  if (IsStunMessage(msg_type)) {
+    // STUN message.
+    expected_pkt_len = kStunHeaderSize + pkt_len;
+  } else {
+    // TURN ChannelData message.
+    expected_pkt_len = kTurnChannelDataHdrSize + pkt_len;
+    // From RFC 5766 section 11.5
+    // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to
+    // a multiple of four bytes in order to ensure the alignment of
+    // subsequent messages.  The padding is not reflected in the length
+    // field of the ChannelData message, so the actual size of a ChannelData
+    // message (including padding) is (4 + Length) rounded up to the nearest
+    // multiple of 4.  Over UDP, the padding is not required but MAY be
+    // included.
+    if (expected_pkt_len % 4)
+      *pad_bytes = 4 - (expected_pkt_len % 4);
+  }
+  return expected_pkt_len;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/asyncstuntcpsocket.h b/p2p/base/asyncstuntcpsocket.h
new file mode 100644
index 0000000..4f53b03
--- /dev/null
+++ b/p2p/base/asyncstuntcpsocket.h
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 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_P2P_BASE_ASYNCSTUNTCPSOCKET_H_
+#define WEBRTC_P2P_BASE_ASYNCSTUNTCPSOCKET_H_
+
+#include "webrtc/base/asynctcpsocket.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketfactory.h"
+
+namespace cricket {
+
+class AsyncStunTCPSocket : public rtc::AsyncTCPSocketBase {
+ public:
+  // Binds and connects |socket| and creates AsyncTCPSocket for
+  // it. Takes ownership of |socket|. Returns NULL if bind() or
+  // connect() fail (|socket| is destroyed in that case).
+  static AsyncStunTCPSocket* Create(
+      rtc::AsyncSocket* socket,
+      const rtc::SocketAddress& bind_address,
+      const rtc::SocketAddress& remote_address);
+
+  AsyncStunTCPSocket(rtc::AsyncSocket* socket, bool listen);
+  virtual ~AsyncStunTCPSocket() {}
+
+  virtual int Send(const void* pv, size_t cb,
+                   const rtc::PacketOptions& options);
+  virtual void ProcessInput(char* data, size_t* len);
+  virtual void HandleIncomingConnection(rtc::AsyncSocket* socket);
+
+ private:
+  // This method returns the message hdr + length written in the header.
+  // This method also returns the number of padding bytes needed/added to the
+  // turn message. |pad_bytes| should be used only when |is_turn| is true.
+  size_t GetExpectedLength(const void* data, size_t len,
+                           int* pad_bytes);
+
+  DISALLOW_EVIL_CONSTRUCTORS(AsyncStunTCPSocket);
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_ASYNCSTUNTCPSOCKET_H_
diff --git a/p2p/base/asyncstuntcpsocket_unittest.cc b/p2p/base/asyncstuntcpsocket_unittest.cc
new file mode 100644
index 0000000..22c1b26
--- /dev/null
+++ b/p2p/base/asyncstuntcpsocket_unittest.cc
@@ -0,0 +1,263 @@
+/*
+ *  Copyright 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/p2p/base/asyncstuntcpsocket.h"
+#include "webrtc/base/asyncsocket.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+namespace cricket {
+
+static unsigned char kStunMessageWithZeroLength[] = {
+  0x00, 0x01, 0x00, 0x00,  // length of 0 (last 2 bytes)
+  0x21, 0x12, 0xA4, 0x42,
+  '0', '1', '2', '3',
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+};
+
+
+static unsigned char kTurnChannelDataMessageWithZeroLength[] = {
+  0x40, 0x00, 0x00, 0x00,  // length of 0 (last 2 bytes)
+};
+
+static unsigned char kTurnChannelDataMessage[] = {
+  0x40, 0x00, 0x00, 0x10,
+  0x21, 0x12, 0xA4, 0x42,
+  '0', '1', '2', '3',
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+};
+
+static unsigned char kStunMessageWithInvalidLength[] = {
+  0x00, 0x01, 0x00, 0x10,
+  0x21, 0x12, 0xA4, 0x42,
+  '0', '1', '2', '3',
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+};
+
+static unsigned char kTurnChannelDataMessageWithInvalidLength[] = {
+  0x80, 0x00, 0x00, 0x20,
+  0x21, 0x12, 0xA4, 0x42,
+  '0', '1', '2', '3',
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+};
+
+static unsigned char kTurnChannelDataMessageWithOddLength[] = {
+  0x40, 0x00, 0x00, 0x05,
+  0x21, 0x12, 0xA4, 0x42,
+  '0',
+};
+
+
+static const rtc::SocketAddress kClientAddr("11.11.11.11", 0);
+static const rtc::SocketAddress kServerAddr("22.22.22.22", 0);
+
+class AsyncStunTCPSocketTest : public testing::Test,
+                               public sigslot::has_slots<> {
+ protected:
+  AsyncStunTCPSocketTest()
+      : vss_(new rtc::VirtualSocketServer(NULL)),
+        ss_scope_(vss_.get()) {
+  }
+
+  virtual void SetUp() {
+    CreateSockets();
+  }
+
+  void CreateSockets() {
+    rtc::AsyncSocket* server = vss_->CreateAsyncSocket(
+        kServerAddr.family(), SOCK_STREAM);
+    server->Bind(kServerAddr);
+    recv_socket_.reset(new AsyncStunTCPSocket(server, true));
+    recv_socket_->SignalNewConnection.connect(
+        this, &AsyncStunTCPSocketTest::OnNewConnection);
+
+    rtc::AsyncSocket* client = vss_->CreateAsyncSocket(
+        kClientAddr.family(), SOCK_STREAM);
+    send_socket_.reset(AsyncStunTCPSocket::Create(
+        client, kClientAddr, recv_socket_->GetLocalAddress()));
+    ASSERT_TRUE(send_socket_.get() != NULL);
+    vss_->ProcessMessagesUntilIdle();
+  }
+
+  void OnReadPacket(rtc::AsyncPacketSocket* socket, const char* data,
+                    size_t len, const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time) {
+    recv_packets_.push_back(std::string(data, len));
+  }
+
+  void OnNewConnection(rtc::AsyncPacketSocket* server,
+                       rtc::AsyncPacketSocket* new_socket) {
+    listen_socket_.reset(new_socket);
+    new_socket->SignalReadPacket.connect(
+        this, &AsyncStunTCPSocketTest::OnReadPacket);
+  }
+
+  bool Send(const void* data, size_t len) {
+    rtc::PacketOptions options;
+    size_t ret = send_socket_->Send(
+        reinterpret_cast<const char*>(data), len, options);
+    vss_->ProcessMessagesUntilIdle();
+    return (ret == len);
+  }
+
+  bool CheckData(const void* data, int len) {
+    bool ret = false;
+    if (recv_packets_.size()) {
+      std::string packet =  recv_packets_.front();
+      recv_packets_.pop_front();
+      ret = (memcmp(data, packet.c_str(), len) == 0);
+    }
+    return ret;
+  }
+
+  rtc::scoped_ptr<rtc::VirtualSocketServer> vss_;
+  rtc::SocketServerScope ss_scope_;
+  rtc::scoped_ptr<AsyncStunTCPSocket> send_socket_;
+  rtc::scoped_ptr<AsyncStunTCPSocket> recv_socket_;
+  rtc::scoped_ptr<rtc::AsyncPacketSocket> listen_socket_;
+  std::list<std::string> recv_packets_;
+};
+
+// Testing a stun packet sent/recv properly.
+TEST_F(AsyncStunTCPSocketTest, TestSingleStunPacket) {
+  EXPECT_TRUE(Send(kStunMessageWithZeroLength,
+                   sizeof(kStunMessageWithZeroLength)));
+  EXPECT_EQ(1u, recv_packets_.size());
+  EXPECT_TRUE(CheckData(kStunMessageWithZeroLength,
+                        sizeof(kStunMessageWithZeroLength)));
+}
+
+// Verify sending multiple packets.
+TEST_F(AsyncStunTCPSocketTest, TestMultipleStunPackets) {
+  EXPECT_TRUE(Send(kStunMessageWithZeroLength,
+                   sizeof(kStunMessageWithZeroLength)));
+  EXPECT_TRUE(Send(kStunMessageWithZeroLength,
+                   sizeof(kStunMessageWithZeroLength)));
+  EXPECT_TRUE(Send(kStunMessageWithZeroLength,
+                   sizeof(kStunMessageWithZeroLength)));
+  EXPECT_TRUE(Send(kStunMessageWithZeroLength,
+                   sizeof(kStunMessageWithZeroLength)));
+  EXPECT_EQ(4u, recv_packets_.size());
+}
+
+// Verifying TURN channel data message with zero length.
+TEST_F(AsyncStunTCPSocketTest, TestTurnChannelDataWithZeroLength) {
+  EXPECT_TRUE(Send(kTurnChannelDataMessageWithZeroLength,
+                   sizeof(kTurnChannelDataMessageWithZeroLength)));
+  EXPECT_EQ(1u, recv_packets_.size());
+  EXPECT_TRUE(CheckData(kTurnChannelDataMessageWithZeroLength,
+                        sizeof(kTurnChannelDataMessageWithZeroLength)));
+}
+
+// Verifying TURN channel data message.
+TEST_F(AsyncStunTCPSocketTest, TestTurnChannelData) {
+  EXPECT_TRUE(Send(kTurnChannelDataMessage,
+                   sizeof(kTurnChannelDataMessage)));
+  EXPECT_EQ(1u, recv_packets_.size());
+  EXPECT_TRUE(CheckData(kTurnChannelDataMessage,
+                        sizeof(kTurnChannelDataMessage)));
+}
+
+// Verifying TURN channel messages which needs padding handled properly.
+TEST_F(AsyncStunTCPSocketTest, TestTurnChannelDataPadding) {
+  EXPECT_TRUE(Send(kTurnChannelDataMessageWithOddLength,
+                   sizeof(kTurnChannelDataMessageWithOddLength)));
+  EXPECT_EQ(1u, recv_packets_.size());
+  EXPECT_TRUE(CheckData(kTurnChannelDataMessageWithOddLength,
+                        sizeof(kTurnChannelDataMessageWithOddLength)));
+}
+
+// Verifying stun message with invalid length.
+TEST_F(AsyncStunTCPSocketTest, TestStunInvalidLength) {
+  EXPECT_FALSE(Send(kStunMessageWithInvalidLength,
+                    sizeof(kStunMessageWithInvalidLength)));
+  EXPECT_EQ(0u, recv_packets_.size());
+
+  // Modify the message length to larger value.
+  kStunMessageWithInvalidLength[2] = 0xFF;
+  kStunMessageWithInvalidLength[3] = 0xFF;
+  EXPECT_FALSE(Send(kStunMessageWithInvalidLength,
+                    sizeof(kStunMessageWithInvalidLength)));
+
+  // Modify the message length to smaller value.
+  kStunMessageWithInvalidLength[2] = 0x00;
+  kStunMessageWithInvalidLength[3] = 0x01;
+  EXPECT_FALSE(Send(kStunMessageWithInvalidLength,
+                    sizeof(kStunMessageWithInvalidLength)));
+}
+
+// Verifying TURN channel data message with invalid length.
+TEST_F(AsyncStunTCPSocketTest, TestTurnChannelDataWithInvalidLength) {
+  EXPECT_FALSE(Send(kTurnChannelDataMessageWithInvalidLength,
+                   sizeof(kTurnChannelDataMessageWithInvalidLength)));
+  // Modify the length to larger value.
+  kTurnChannelDataMessageWithInvalidLength[2] = 0xFF;
+  kTurnChannelDataMessageWithInvalidLength[3] = 0xF0;
+  EXPECT_FALSE(Send(kTurnChannelDataMessageWithInvalidLength,
+                   sizeof(kTurnChannelDataMessageWithInvalidLength)));
+
+  // Modify the length to smaller value.
+  kTurnChannelDataMessageWithInvalidLength[2] = 0x00;
+  kTurnChannelDataMessageWithInvalidLength[3] = 0x00;
+  EXPECT_FALSE(Send(kTurnChannelDataMessageWithInvalidLength,
+                   sizeof(kTurnChannelDataMessageWithInvalidLength)));
+}
+
+// Verifying a small buffer handled (dropped) properly. This will be
+// a common one for both stun and turn.
+TEST_F(AsyncStunTCPSocketTest, TestTooSmallMessageBuffer) {
+  char data[1];
+  EXPECT_FALSE(Send(data, sizeof(data)));
+}
+
+// Verifying a legal large turn message.
+TEST_F(AsyncStunTCPSocketTest, TestMaximumSizeTurnPacket) {
+  // We have problem in getting the SignalWriteEvent from the virtual socket
+  // server. So increasing the send buffer to 64k.
+  // TODO(mallinath) - Remove this setting after we fix vss issue.
+  vss_->set_send_buffer_capacity(64 * 1024);
+  unsigned char packet[65539];
+  packet[0] = 0x40;
+  packet[1] = 0x00;
+  packet[2] = 0xFF;
+  packet[3] = 0xFF;
+  EXPECT_TRUE(Send(packet, sizeof(packet)));
+}
+
+// Verifying a legal large stun message.
+TEST_F(AsyncStunTCPSocketTest, TestMaximumSizeStunPacket) {
+  // We have problem in getting the SignalWriteEvent from the virtual socket
+  // server. So increasing the send buffer to 64k.
+  // TODO(mallinath) - Remove this setting after we fix vss issue.
+  vss_->set_send_buffer_capacity(64 * 1024);
+  unsigned char packet[65552];
+  packet[0] = 0x00;
+  packet[1] = 0x01;
+  packet[2] = 0xFF;
+  packet[3] = 0xFC;
+  EXPECT_TRUE(Send(packet, sizeof(packet)));
+}
+
+// Investigate why WriteEvent is not signaled from VSS.
+TEST_F(AsyncStunTCPSocketTest, DISABLED_TestWithSmallSendBuffer) {
+  vss_->set_send_buffer_capacity(1);
+  Send(kTurnChannelDataMessageWithOddLength,
+       sizeof(kTurnChannelDataMessageWithOddLength));
+  EXPECT_EQ(1u, recv_packets_.size());
+  EXPECT_TRUE(CheckData(kTurnChannelDataMessageWithOddLength,
+                        sizeof(kTurnChannelDataMessageWithOddLength)));
+}
+
+}  // namespace cricket
diff --git a/p2p/base/basicpacketsocketfactory.cc b/p2p/base/basicpacketsocketfactory.cc
new file mode 100644
index 0000000..06dfe76
--- /dev/null
+++ b/p2p/base/basicpacketsocketfactory.cc
@@ -0,0 +1,204 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/p2p/base/basicpacketsocketfactory.h"
+
+#include "webrtc/p2p/base/asyncstuntcpsocket.h"
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/asynctcpsocket.h"
+#include "webrtc/base/asyncudpsocket.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/nethelpers.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketadapters.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/thread.h"
+
+namespace rtc {
+
+BasicPacketSocketFactory::BasicPacketSocketFactory()
+    : thread_(Thread::Current()),
+      socket_factory_(NULL) {
+}
+
+BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread)
+    : thread_(thread),
+      socket_factory_(NULL) {
+}
+
+BasicPacketSocketFactory::BasicPacketSocketFactory(
+    SocketFactory* socket_factory)
+    : thread_(NULL),
+      socket_factory_(socket_factory) {
+}
+
+BasicPacketSocketFactory::~BasicPacketSocketFactory() {
+}
+
+AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
+    const SocketAddress& address, int min_port, int max_port) {
+  // UDP sockets are simple.
+  rtc::AsyncSocket* socket =
+      socket_factory()->CreateAsyncSocket(
+          address.family(), SOCK_DGRAM);
+  if (!socket) {
+    return NULL;
+  }
+  if (BindSocket(socket, address, min_port, max_port) < 0) {
+    LOG(LS_ERROR) << "UDP bind failed with error "
+                    << socket->GetError();
+    delete socket;
+    return NULL;
+  }
+  return new rtc::AsyncUDPSocket(socket);
+}
+
+AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket(
+    const SocketAddress& local_address, int min_port, int max_port, int opts) {
+
+  // Fail if TLS is required.
+  if (opts & PacketSocketFactory::OPT_TLS) {
+    LOG(LS_ERROR) << "TLS support currently is not available.";
+    return NULL;
+  }
+
+  rtc::AsyncSocket* socket =
+      socket_factory()->CreateAsyncSocket(local_address.family(),
+                                          SOCK_STREAM);
+  if (!socket) {
+    return NULL;
+  }
+
+  if (BindSocket(socket, local_address, min_port, max_port) < 0) {
+    LOG(LS_ERROR) << "TCP bind failed with error "
+                  << socket->GetError();
+    delete socket;
+    return NULL;
+  }
+
+  // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
+  if (opts & PacketSocketFactory::OPT_SSLTCP) {
+    ASSERT(!(opts & PacketSocketFactory::OPT_TLS));
+    socket = new rtc::AsyncSSLSocket(socket);
+  }
+
+  // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
+  // See http://go/gtalktcpnodelayexperiment
+  socket->SetOption(rtc::Socket::OPT_NODELAY, 1);
+
+  if (opts & PacketSocketFactory::OPT_STUN)
+    return new cricket::AsyncStunTCPSocket(socket, true);
+
+  return new rtc::AsyncTCPSocket(socket, true);
+}
+
+AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
+    const SocketAddress& local_address, const SocketAddress& remote_address,
+    const ProxyInfo& proxy_info, const std::string& user_agent, int opts) {
+
+  rtc::AsyncSocket* socket =
+      socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM);
+  if (!socket) {
+    return NULL;
+  }
+
+  if (BindSocket(socket, local_address, 0, 0) < 0) {
+    LOG(LS_ERROR) << "TCP bind failed with error "
+                  << socket->GetError();
+    delete socket;
+    return NULL;
+  }
+
+  // If using a proxy, wrap the socket in a proxy socket.
+  if (proxy_info.type == rtc::PROXY_SOCKS5) {
+    socket = new rtc::AsyncSocksProxySocket(
+        socket, proxy_info.address, proxy_info.username, proxy_info.password);
+  } else if (proxy_info.type == rtc::PROXY_HTTPS) {
+    socket = new rtc::AsyncHttpsProxySocket(
+        socket, user_agent, proxy_info.address,
+        proxy_info.username, proxy_info.password);
+  }
+
+  // If using TLS, wrap the socket in an SSL adapter.
+  if (opts & PacketSocketFactory::OPT_TLS) {
+    ASSERT(!(opts & PacketSocketFactory::OPT_SSLTCP));
+
+    rtc::SSLAdapter* ssl_adapter = rtc::SSLAdapter::Create(socket);
+    if (!ssl_adapter) {
+      return NULL;
+    }
+
+    socket = ssl_adapter;
+
+    if (ssl_adapter->StartSSL(remote_address.hostname().c_str(), false) != 0) {
+      delete ssl_adapter;
+      return NULL;
+    }
+
+  // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
+  } else if (opts & PacketSocketFactory::OPT_SSLTCP) {
+    ASSERT(!(opts & PacketSocketFactory::OPT_TLS));
+    socket = new rtc::AsyncSSLSocket(socket);
+  }
+
+  if (socket->Connect(remote_address) < 0) {
+    LOG(LS_ERROR) << "TCP connect failed with error "
+                  << socket->GetError();
+    delete socket;
+    return NULL;
+  }
+
+  // Finally, wrap that socket in a TCP or STUN TCP packet socket.
+  AsyncPacketSocket* tcp_socket;
+  if (opts & PacketSocketFactory::OPT_STUN) {
+    tcp_socket = new cricket::AsyncStunTCPSocket(socket, false);
+  } else {
+    tcp_socket = new rtc::AsyncTCPSocket(socket, false);
+  }
+
+  // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
+  // See http://go/gtalktcpnodelayexperiment
+  tcp_socket->SetOption(rtc::Socket::OPT_NODELAY, 1);
+
+  return tcp_socket;
+}
+
+AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() {
+  return new rtc::AsyncResolver();
+}
+
+int BasicPacketSocketFactory::BindSocket(
+    AsyncSocket* socket, const SocketAddress& local_address,
+    int min_port, int max_port) {
+  int ret = -1;
+  if (min_port == 0 && max_port == 0) {
+    // If there's no port range, let the OS pick a port for us.
+    ret = socket->Bind(local_address);
+  } else {
+    // Otherwise, try to find a port in the provided range.
+    for (int port = min_port; ret < 0 && port <= max_port; ++port) {
+      ret = socket->Bind(rtc::SocketAddress(local_address.ipaddr(),
+                                                  port));
+    }
+  }
+  return ret;
+}
+
+SocketFactory* BasicPacketSocketFactory::socket_factory() {
+  if (thread_) {
+    ASSERT(thread_ == Thread::Current());
+    return thread_->socketserver();
+  } else {
+    return socket_factory_;
+  }
+}
+
+}  // namespace rtc
diff --git a/p2p/base/basicpacketsocketfactory.h b/p2p/base/basicpacketsocketfactory.h
new file mode 100644
index 0000000..fb3a526
--- /dev/null
+++ b/p2p/base/basicpacketsocketfactory.h
@@ -0,0 +1,51 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_P2P_BASE_BASICPACKETSOCKETFACTORY_H_
+#define WEBRTC_P2P_BASE_BASICPACKETSOCKETFACTORY_H_
+
+#include "webrtc/p2p/base/packetsocketfactory.h"
+
+namespace rtc {
+
+class AsyncSocket;
+class SocketFactory;
+class Thread;
+
+class BasicPacketSocketFactory : public PacketSocketFactory {
+ public:
+  BasicPacketSocketFactory();
+  explicit BasicPacketSocketFactory(Thread* thread);
+  explicit BasicPacketSocketFactory(SocketFactory* socket_factory);
+  virtual ~BasicPacketSocketFactory();
+
+  virtual AsyncPacketSocket* CreateUdpSocket(
+      const SocketAddress& local_address, int min_port, int max_port);
+  virtual AsyncPacketSocket* CreateServerTcpSocket(
+      const SocketAddress& local_address, int min_port, int max_port, int opts);
+  virtual AsyncPacketSocket* CreateClientTcpSocket(
+      const SocketAddress& local_address, const SocketAddress& remote_address,
+      const ProxyInfo& proxy_info, const std::string& user_agent, int opts);
+
+  virtual AsyncResolverInterface* CreateAsyncResolver();
+
+ private:
+  int BindSocket(AsyncSocket* socket, const SocketAddress& local_address,
+                 int min_port, int max_port);
+
+  SocketFactory* socket_factory();
+
+  Thread* thread_;
+  SocketFactory* socket_factory_;
+};
+
+}  // namespace rtc
+
+#endif  // WEBRTC_P2P_BASE_BASICPACKETSOCKETFACTORY_H_
diff --git a/p2p/base/candidate.h b/p2p/base/candidate.h
new file mode 100644
index 0000000..72bc69e
--- /dev/null
+++ b/p2p/base/candidate.h
@@ -0,0 +1,212 @@
+/*
+ *  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_P2P_BASE_CANDIDATE_H_
+#define WEBRTC_P2P_BASE_CANDIDATE_H_
+
+#include <limits.h>
+#include <math.h>
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace cricket {
+
+// Candidate for ICE based connection discovery.
+
+class Candidate {
+ public:
+  // TODO: Match the ordering and param list as per RFC 5245
+  // candidate-attribute syntax. http://tools.ietf.org/html/rfc5245#section-15.1
+  Candidate() : component_(0), priority_(0), generation_(0) {}
+  Candidate(const std::string& id, int component, const std::string& protocol,
+            const rtc::SocketAddress& address, uint32 priority,
+            const std::string& username, const std::string& password,
+            const std::string& type, const std::string& network_name,
+            uint32 generation, const std::string& foundation)
+      : id_(id), component_(component), protocol_(protocol), address_(address),
+        priority_(priority), username_(username), password_(password),
+        type_(type), network_name_(network_name), generation_(generation),
+        foundation_(foundation) {
+  }
+
+  const std::string & id() const { return id_; }
+  void set_id(const std::string & id) { id_ = id; }
+
+  int component() const { return component_; }
+  void set_component(int component) { component_ = component; }
+
+  const std::string & protocol() const { return protocol_; }
+  void set_protocol(const std::string & protocol) { protocol_ = protocol; }
+
+  const rtc::SocketAddress & address() const { return address_; }
+  void set_address(const rtc::SocketAddress & address) {
+    address_ = address;
+  }
+
+  uint32 priority() const { return priority_; }
+  void set_priority(const uint32 priority) { priority_ = priority; }
+
+//  void set_type_preference(uint32 type_preference) {
+//    priority_ = GetPriority(type_preference);
+//  }
+
+  // Maps old preference (which was 0.0-1.0) to match priority (which
+  // is 0-2^32-1) to to match RFC 5245, section 4.1.2.1.  Also see
+  // https://docs.google.com/a/google.com/document/d/
+  // 1iNQDiwDKMh0NQOrCqbj3DKKRT0Dn5_5UJYhmZO-t7Uc/edit
+  float preference() const {
+    // The preference value is clamped to two decimal precision.
+    return static_cast<float>(((priority_ >> 24) * 100 / 127) / 100.0);
+  }
+
+  void set_preference(float preference) {
+    // Limiting priority to UINT_MAX when value exceeds uint32 max.
+    // This can happen for e.g. when preference = 3.
+    uint64 prio_val = static_cast<uint64>(preference * 127) << 24;
+    priority_ = static_cast<uint32>(
+      rtc::_min(prio_val, static_cast<uint64>(UINT_MAX)));
+  }
+
+  const std::string & username() const { return username_; }
+  void set_username(const std::string & username) { username_ = username; }
+
+  const std::string & password() const { return password_; }
+  void set_password(const std::string & password) { password_ = password; }
+
+  const std::string & type() const { return type_; }
+  void set_type(const std::string & type) { type_ = type; }
+
+  const std::string & network_name() const { return network_name_; }
+  void set_network_name(const std::string & network_name) {
+    network_name_ = network_name;
+  }
+
+  // Candidates in a new generation replace those in the old generation.
+  uint32 generation() const { return generation_; }
+  void set_generation(uint32 generation) { generation_ = generation; }
+  const std::string generation_str() const {
+    std::ostringstream ost;
+    ost << generation_;
+    return ost.str();
+  }
+  void set_generation_str(const std::string& str) {
+    std::istringstream ist(str);
+    ist >> generation_;
+  }
+
+  const std::string& foundation() const {
+    return foundation_;
+  }
+
+  void set_foundation(const std::string& foundation) {
+    foundation_ = foundation;
+  }
+
+  const rtc::SocketAddress & related_address() const {
+    return related_address_;
+  }
+  void set_related_address(
+      const rtc::SocketAddress & related_address) {
+    related_address_ = related_address;
+  }
+  const std::string& tcptype() const { return tcptype_; }
+  void set_tcptype(const std::string& tcptype){
+    tcptype_ = tcptype;
+  }
+
+  // Determines whether this candidate is equivalent to the given one.
+  bool IsEquivalent(const Candidate& c) const {
+    // We ignore the network name, since that is just debug information, and
+    // the priority, since that should be the same if the rest is (and it's
+    // a float so equality checking is always worrisome).
+    return (id_ == c.id_) &&
+           (component_ == c.component_) &&
+           (protocol_ == c.protocol_) &&
+           (address_ == c.address_) &&
+           (username_ == c.username_) &&
+           (password_ == c.password_) &&
+           (type_ == c.type_) &&
+           (generation_ == c.generation_) &&
+           (foundation_ == c.foundation_) &&
+           (related_address_ == c.related_address_);
+  }
+
+  std::string ToString() const {
+    return ToStringInternal(false);
+  }
+
+  std::string ToSensitiveString() const {
+    return ToStringInternal(true);
+  }
+
+  uint32 GetPriority(uint32 type_preference,
+                     int network_adapter_preference,
+                     int relay_preference) const {
+    // RFC 5245 - 4.1.2.1.
+    // priority = (2^24)*(type preference) +
+    //            (2^8)*(local preference) +
+    //            (2^0)*(256 - component ID)
+
+    // |local_preference| length is 2 bytes, 0-65535 inclusive.
+    // In our implemenation we will partion local_preference into
+    //              0                 1
+    //       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+    //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //      |  NIC Pref     |    Addr Pref  |
+    //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    // NIC Type - Type of the network adapter e.g. 3G/Wifi/Wired.
+    // Addr Pref - Address preference value as per RFC 3484.
+    // local preference =  (NIC Type << 8 | Addr_Pref) - relay preference.
+
+    int addr_pref = IPAddressPrecedence(address_.ipaddr());
+    int local_preference = ((network_adapter_preference << 8) | addr_pref) +
+        relay_preference;
+
+    return (type_preference << 24) |
+           (local_preference << 8) |
+           (256 - component_);
+  }
+
+ private:
+  std::string ToStringInternal(bool sensitive) const {
+    std::ostringstream ost;
+    std::string address = sensitive ? address_.ToSensitiveString() :
+                                      address_.ToString();
+    ost << "Cand[" << foundation_ << ":" << component_ << ":"
+        << protocol_ << ":" << priority_ << ":"
+        << address << ":" << type_ << ":" << related_address_ << ":"
+        << username_ << ":" << password_ << "]";
+    return ost.str();
+  }
+
+  std::string id_;
+  int component_;
+  std::string protocol_;
+  rtc::SocketAddress address_;
+  uint32 priority_;
+  std::string username_;
+  std::string password_;
+  std::string type_;
+  std::string network_name_;
+  uint32 generation_;
+  std::string foundation_;
+  rtc::SocketAddress related_address_;
+  std::string tcptype_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_CANDIDATE_H_
diff --git a/p2p/base/common.h b/p2p/base/common.h
new file mode 100644
index 0000000..8a3178c
--- /dev/null
+++ b/p2p/base/common.h
@@ -0,0 +1,20 @@
+/*
+ *  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_P2P_BASE_COMMON_H_
+#define WEBRTC_P2P_BASE_COMMON_H_
+
+#include "webrtc/base/logging.h"
+
+// Common log description format for jingle messages
+#define LOG_J(sev, obj) LOG(sev) << "Jingle:" << obj->ToString() << ": "
+#define LOG_JV(sev, obj) LOG_V(sev) << "Jingle:" << obj->ToString() << ": "
+
+#endif  // WEBRTC_P2P_BASE_COMMON_H_
diff --git a/p2p/base/constants.cc b/p2p/base/constants.cc
new file mode 100644
index 0000000..84c9ea2
--- /dev/null
+++ b/p2p/base/constants.cc
@@ -0,0 +1,257 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/constants.h"
+
+#include <string>
+
+#include "webrtc/libjingle/xmllite/qname.h"
+
+namespace cricket {
+
+const char NS_EMPTY[] = "";
+const char NS_JINGLE[] = "urn:xmpp:jingle:1";
+const char NS_JINGLE_DRAFT[] = "google:jingle";
+const char NS_GINGLE[] = "http://www.google.com/session";
+
+// actions (aka <session> or <jingle>)
+const buzz::StaticQName QN_ACTION = { NS_EMPTY, "action" };
+const char LN_INITIATOR[] = "initiator";
+const buzz::StaticQName QN_INITIATOR = { NS_EMPTY, LN_INITIATOR };
+const buzz::StaticQName QN_CREATOR = { NS_EMPTY, "creator" };
+
+const buzz::StaticQName QN_JINGLE = { NS_JINGLE, "jingle" };
+const buzz::StaticQName QN_JINGLE_CONTENT = { NS_JINGLE, "content" };
+const buzz::StaticQName QN_JINGLE_CONTENT_NAME = { NS_EMPTY, "name" };
+const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA = { NS_EMPTY, "media" };
+const buzz::StaticQName QN_JINGLE_REASON = { NS_JINGLE, "reason" };
+const buzz::StaticQName QN_JINGLE_DRAFT_GROUP = { NS_JINGLE_DRAFT, "group" };
+const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE = { NS_EMPTY, "type" };
+const char JINGLE_CONTENT_MEDIA_AUDIO[] = "audio";
+const char JINGLE_CONTENT_MEDIA_VIDEO[] = "video";
+const char JINGLE_CONTENT_MEDIA_DATA[] = "data";
+const char JINGLE_ACTION_SESSION_INITIATE[] = "session-initiate";
+const char JINGLE_ACTION_SESSION_INFO[] = "session-info";
+const char JINGLE_ACTION_SESSION_ACCEPT[] = "session-accept";
+const char JINGLE_ACTION_SESSION_TERMINATE[] = "session-terminate";
+const char JINGLE_ACTION_TRANSPORT_INFO[] = "transport-info";
+const char JINGLE_ACTION_TRANSPORT_ACCEPT[] = "transport-accept";
+const char JINGLE_ACTION_DESCRIPTION_INFO[] = "description-info";
+
+const buzz::StaticQName QN_GINGLE_SESSION = { NS_GINGLE, "session" };
+const char GINGLE_ACTION_INITIATE[] = "initiate";
+const char GINGLE_ACTION_INFO[] = "info";
+const char GINGLE_ACTION_ACCEPT[] = "accept";
+const char GINGLE_ACTION_REJECT[] = "reject";
+const char GINGLE_ACTION_TERMINATE[] = "terminate";
+const char GINGLE_ACTION_CANDIDATES[] = "candidates";
+const char GINGLE_ACTION_UPDATE[] = "update";
+
+const char LN_ERROR[] = "error";
+const buzz::StaticQName QN_GINGLE_REDIRECT = { NS_GINGLE, "redirect" };
+const char STR_REDIRECT_PREFIX[] = "xmpp:";
+
+// Session Contents (aka Gingle <session><description>
+//                   or Jingle <content><description>)
+const char LN_DESCRIPTION[] = "description";
+const char LN_PAYLOADTYPE[] = "payload-type";
+const buzz::StaticQName QN_ID = { NS_EMPTY, "id" };
+const buzz::StaticQName QN_SID = { NS_EMPTY, "sid" };
+const buzz::StaticQName QN_NAME = { NS_EMPTY, "name" };
+const buzz::StaticQName QN_CLOCKRATE = { NS_EMPTY, "clockrate" };
+const buzz::StaticQName QN_BITRATE = { NS_EMPTY, "bitrate" };
+const buzz::StaticQName QN_CHANNELS = { NS_EMPTY, "channels" };
+const buzz::StaticQName QN_WIDTH = { NS_EMPTY, "width" };
+const buzz::StaticQName QN_HEIGHT = { NS_EMPTY, "height" };
+const buzz::StaticQName QN_FRAMERATE = { NS_EMPTY, "framerate" };
+const char LN_NAME[] = "name";
+const char LN_VALUE[] = "value";
+const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME = { NS_EMPTY, LN_NAME };
+const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE = { NS_EMPTY, LN_VALUE };
+const char PAYLOADTYPE_PARAMETER_BITRATE[] = "bitrate";
+const char PAYLOADTYPE_PARAMETER_HEIGHT[] = "height";
+const char PAYLOADTYPE_PARAMETER_WIDTH[] = "width";
+const char PAYLOADTYPE_PARAMETER_FRAMERATE[] = "framerate";
+const char LN_BANDWIDTH[] = "bandwidth";
+
+const char CN_AUDIO[] = "audio";
+const char CN_VIDEO[] = "video";
+const char CN_DATA[] = "data";
+const char CN_OTHER[] = "main";
+// other SDP related strings
+const char GROUP_TYPE_BUNDLE[] = "BUNDLE";
+
+const char NS_JINGLE_RTP[] = "urn:xmpp:jingle:apps:rtp:1";
+const buzz::StaticQName QN_JINGLE_RTP_CONTENT =
+    { NS_JINGLE_RTP, LN_DESCRIPTION };
+const buzz::StaticQName QN_SSRC = { NS_EMPTY, "ssrc" };
+const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE =
+    { NS_JINGLE_RTP, LN_PAYLOADTYPE };
+const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH =
+    { NS_JINGLE_RTP, LN_BANDWIDTH };
+const buzz::StaticQName QN_JINGLE_RTCP_MUX = { NS_JINGLE_RTP, "rtcp-mux" };
+const buzz::StaticQName QN_JINGLE_RTCP_FB = { NS_JINGLE_RTP, "rtcp-fb" };
+const buzz::StaticQName QN_SUBTYPE = { NS_EMPTY, "subtype" };
+const buzz::StaticQName QN_PARAMETER = { NS_JINGLE_RTP, "parameter" };
+const buzz::StaticQName QN_JINGLE_RTP_HDREXT =
+    { NS_JINGLE_RTP, "rtp-hdrext" };
+const buzz::StaticQName QN_URI = { NS_EMPTY, "uri" };
+
+const char NS_JINGLE_DRAFT_SCTP[] = "google:jingle:sctp";
+const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT =
+    { NS_JINGLE_DRAFT_SCTP, LN_DESCRIPTION };
+const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM =
+    { NS_JINGLE_DRAFT_SCTP, "stream" };
+
+const char NS_GINGLE_AUDIO[] = "http://www.google.com/session/phone";
+const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT =
+    { NS_GINGLE_AUDIO, LN_DESCRIPTION };
+const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE =
+    { NS_GINGLE_AUDIO, LN_PAYLOADTYPE };
+const buzz::StaticQName QN_GINGLE_AUDIO_SRCID = { NS_GINGLE_AUDIO, "src-id" };
+const char NS_GINGLE_VIDEO[] = "http://www.google.com/session/video";
+const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT =
+    { NS_GINGLE_VIDEO, LN_DESCRIPTION };
+const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE =
+    { NS_GINGLE_VIDEO, LN_PAYLOADTYPE };
+const buzz::StaticQName QN_GINGLE_VIDEO_SRCID = { NS_GINGLE_VIDEO, "src-id" };
+const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH =
+    { NS_GINGLE_VIDEO, LN_BANDWIDTH };
+
+// Crypto support.
+const buzz::StaticQName QN_ENCRYPTION = { NS_JINGLE_RTP, "encryption" };
+const buzz::StaticQName QN_ENCRYPTION_REQUIRED = { NS_EMPTY, "required" };
+const buzz::StaticQName QN_CRYPTO = { NS_JINGLE_RTP, "crypto" };
+const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE =
+    { NS_GINGLE_AUDIO, "usage" };
+const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE =
+    { NS_GINGLE_VIDEO, "usage" };
+const buzz::StaticQName QN_CRYPTO_SUITE = { NS_EMPTY, "crypto-suite" };
+const buzz::StaticQName QN_CRYPTO_KEY_PARAMS = { NS_EMPTY, "key-params" };
+const buzz::StaticQName QN_CRYPTO_TAG = { NS_EMPTY, "tag" };
+const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS =
+    { NS_EMPTY, "session-params" };
+
+// Transports and candidates.
+const char LN_TRANSPORT[] = "transport";
+const char LN_CANDIDATE[] = "candidate";
+const buzz::StaticQName QN_UFRAG = { cricket::NS_EMPTY, "ufrag" };
+const buzz::StaticQName QN_PWD = { cricket::NS_EMPTY, "pwd" };
+const buzz::StaticQName QN_COMPONENT = { cricket::NS_EMPTY, "component" };
+const buzz::StaticQName QN_IP = { cricket::NS_EMPTY, "ip" };
+const buzz::StaticQName QN_PORT = { cricket::NS_EMPTY, "port" };
+const buzz::StaticQName QN_NETWORK = { cricket::NS_EMPTY, "network" };
+const buzz::StaticQName QN_GENERATION = { cricket::NS_EMPTY, "generation" };
+const buzz::StaticQName QN_PRIORITY = { cricket::NS_EMPTY, "priority" };
+const buzz::StaticQName QN_PROTOCOL = { cricket::NS_EMPTY, "protocol" };
+const char ICE_CANDIDATE_TYPE_PEER_STUN[] = "prflx";
+const char ICE_CANDIDATE_TYPE_SERVER_STUN[] = "srflx";
+// Minimum ufrag length is 4 characters as per RFC5245. We chose 16 because
+// some internal systems expect username to be 16 bytes.
+const int ICE_UFRAG_LENGTH = 16;
+// Minimum password length of 22 characters as per RFC5245. We chose 24 because
+// some internal systems expect password to be multiple of 4.
+const int ICE_PWD_LENGTH = 24;
+const size_t ICE_UFRAG_MIN_LENGTH = 4;
+const size_t ICE_PWD_MIN_LENGTH = 22;
+const size_t ICE_UFRAG_MAX_LENGTH = 255;
+const size_t ICE_PWD_MAX_LENGTH = 256;
+// TODO: This is media-specific, so might belong
+// somewhere like media/base/constants.h
+const int ICE_CANDIDATE_COMPONENT_RTP = 1;
+const int ICE_CANDIDATE_COMPONENT_RTCP = 2;
+const int ICE_CANDIDATE_COMPONENT_DEFAULT = 1;
+
+const buzz::StaticQName QN_FINGERPRINT = { cricket::NS_EMPTY, "fingerprint" };
+const buzz::StaticQName QN_FINGERPRINT_ALGORITHM =
+    { cricket::NS_EMPTY, "algorithm" };
+const buzz::StaticQName QN_FINGERPRINT_DIGEST = { cricket::NS_EMPTY, "digest" };
+
+const char NS_JINGLE_ICE_UDP[] = "urn:xmpp:jingle:transports:ice-udp:1";
+
+const char ICE_OPTION_GICE[] = "google-ice";
+const char NS_GINGLE_P2P[] = "http://www.google.com/transport/p2p";
+const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT =
+    { NS_GINGLE_P2P, LN_TRANSPORT };
+const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE =
+    { NS_GINGLE_P2P, LN_CANDIDATE };
+const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME =
+    { NS_GINGLE_P2P, "unknown-channel-name" };
+const buzz::StaticQName QN_GINGLE_CANDIDATE = { NS_GINGLE, LN_CANDIDATE };
+const buzz::StaticQName QN_ADDRESS = { cricket::NS_EMPTY, "address" };
+const buzz::StaticQName QN_USERNAME = { cricket::NS_EMPTY, "username" };
+const buzz::StaticQName QN_PASSWORD = { cricket::NS_EMPTY, "password" };
+const buzz::StaticQName QN_PREFERENCE = { cricket::NS_EMPTY, "preference" };
+const char GICE_CHANNEL_NAME_RTP[] = "rtp";
+const char GICE_CHANNEL_NAME_RTCP[] = "rtcp";
+const char GICE_CHANNEL_NAME_VIDEO_RTP[] = "video_rtp";
+const char GICE_CHANNEL_NAME_VIDEO_RTCP[] = "video_rtcp";
+const char GICE_CHANNEL_NAME_DATA_RTP[] = "data_rtp";
+const char GICE_CHANNEL_NAME_DATA_RTCP[] = "data_rtcp";
+
+// terminate reasons and errors
+const char JINGLE_ERROR_BAD_REQUEST[] = "bad-request";
+const char JINGLE_ERROR_OUT_OF_ORDER[] = "out-of-order";
+const char JINGLE_ERROR_UNKNOWN_SESSION[] = "unknown-session";
+
+// Call terminate reasons from XEP-166
+const char STR_TERMINATE_DECLINE[] = "decline";
+const char STR_TERMINATE_SUCCESS[] = "success";
+const char STR_TERMINATE_ERROR[] = "general-error";
+const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[] = "incompatible-parameters";
+
+// Old terminate reasons used by cricket
+const char STR_TERMINATE_CALL_ENDED[] = "call-ended";
+const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[] = "recipient-unavailable";
+const char STR_TERMINATE_RECIPIENT_BUSY[] = "recipient-busy";
+const char STR_TERMINATE_INSUFFICIENT_FUNDS[] = "insufficient-funds";
+const char STR_TERMINATE_NUMBER_MALFORMED[] = "number-malformed";
+const char STR_TERMINATE_NUMBER_DISALLOWED[] = "number-disallowed";
+const char STR_TERMINATE_PROTOCOL_ERROR[] = "protocol-error";
+const char STR_TERMINATE_INTERNAL_SERVER_ERROR[] = "internal-server-error";
+const char STR_TERMINATE_UNKNOWN_ERROR[] = "unknown-error";
+
+// Draft view and notify messages.
+const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[] = "video";
+const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[] = "audio";
+const buzz::StaticQName QN_NICK = { cricket::NS_EMPTY, "nick" };
+const buzz::StaticQName QN_TYPE = { cricket::NS_EMPTY, "type" };
+const buzz::StaticQName QN_JINGLE_DRAFT_VIEW = { NS_JINGLE_DRAFT, "view" };
+const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[] = "none";
+const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[] = "static";
+const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS = { NS_JINGLE_DRAFT, "params" };
+const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS = { NS_JINGLE_DRAFT, "streams" };
+const buzz::StaticQName QN_JINGLE_DRAFT_STREAM = { NS_JINGLE_DRAFT, "stream" };
+const buzz::StaticQName QN_DISPLAY = { cricket::NS_EMPTY, "display" };
+const buzz::StaticQName QN_CNAME = { cricket::NS_EMPTY, "cname" };
+const buzz::StaticQName QN_JINGLE_DRAFT_SSRC = { NS_JINGLE_DRAFT, "ssrc" };
+const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP =
+    { NS_JINGLE_DRAFT, "ssrc-group" };
+const buzz::StaticQName QN_SEMANTICS = { cricket::NS_EMPTY, "semantics" };
+const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY = { NS_JINGLE_DRAFT, "notify" };
+const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE = { NS_JINGLE_DRAFT, "source" };
+
+const char NS_GINGLE_RAW[] = "http://www.google.com/transport/raw-udp";
+const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT = { NS_GINGLE_RAW, "transport" };
+const buzz::StaticQName QN_GINGLE_RAW_CHANNEL = { NS_GINGLE_RAW, "channel" };
+
+// old stuff
+#ifdef FEATURE_ENABLE_VOICEMAIL
+const char NS_VOICEMAIL[] = "http://www.google.com/session/voicemail";
+const buzz::StaticQName QN_VOICEMAIL_REGARDING = { NS_VOICEMAIL, "regarding" };
+#endif
+
+// From RFC 4145, SDP setup attribute values.
+const char CONNECTIONROLE_ACTIVE_STR[] = "active";
+const char CONNECTIONROLE_PASSIVE_STR[] = "passive";
+const char CONNECTIONROLE_ACTPASS_STR[] = "actpass";
+const char CONNECTIONROLE_HOLDCONN_STR[] = "holdconn";
+
+}  // namespace cricket
diff --git a/p2p/base/constants.h b/p2p/base/constants.h
new file mode 100644
index 0000000..57423f5
--- /dev/null
+++ b/p2p/base/constants.h
@@ -0,0 +1,259 @@
+/*
+ *  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_P2P_BASE_CONSTANTS_H_
+#define WEBRTC_P2P_BASE_CONSTANTS_H_
+
+#include <string>
+#include "webrtc/libjingle/xmllite/qname.h"
+
+// This file contains constants related to signaling that are used in various
+// classes in this directory.
+
+namespace cricket {
+
+// NS_ == namespace
+// QN_ == buzz::QName (namespace + name)
+// LN_ == "local name" == QName::LocalPart()
+//   these are useful when you need to find a tag
+//   that has different namespaces (like <description> or <transport>)
+
+extern const char NS_EMPTY[];
+extern const char NS_JINGLE[];
+extern const char NS_JINGLE_DRAFT[];
+extern const char NS_GINGLE[];
+
+enum SignalingProtocol {
+  PROTOCOL_JINGLE,
+  PROTOCOL_GINGLE,
+  PROTOCOL_HYBRID,
+};
+
+// actions (aka Gingle <session> or Jingle <jingle>)
+extern const buzz::StaticQName QN_ACTION;
+extern const char LN_INITIATOR[];
+extern const buzz::StaticQName QN_INITIATOR;
+extern const buzz::StaticQName QN_CREATOR;
+
+extern const buzz::StaticQName QN_JINGLE;
+extern const buzz::StaticQName QN_JINGLE_CONTENT;
+extern const buzz::StaticQName QN_JINGLE_CONTENT_NAME;
+extern const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA;
+extern const buzz::StaticQName QN_JINGLE_REASON;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE;
+extern const char JINGLE_CONTENT_MEDIA_AUDIO[];
+extern const char JINGLE_CONTENT_MEDIA_VIDEO[];
+extern const char JINGLE_CONTENT_MEDIA_DATA[];
+extern const char JINGLE_ACTION_SESSION_INITIATE[];
+extern const char JINGLE_ACTION_SESSION_INFO[];
+extern const char JINGLE_ACTION_SESSION_ACCEPT[];
+extern const char JINGLE_ACTION_SESSION_TERMINATE[];
+extern const char JINGLE_ACTION_TRANSPORT_INFO[];
+extern const char JINGLE_ACTION_TRANSPORT_ACCEPT[];
+extern const char JINGLE_ACTION_DESCRIPTION_INFO[];
+
+extern const buzz::StaticQName QN_GINGLE_SESSION;
+extern const char GINGLE_ACTION_INITIATE[];
+extern const char GINGLE_ACTION_INFO[];
+extern const char GINGLE_ACTION_ACCEPT[];
+extern const char GINGLE_ACTION_REJECT[];
+extern const char GINGLE_ACTION_TERMINATE[];
+extern const char GINGLE_ACTION_CANDIDATES[];
+extern const char GINGLE_ACTION_UPDATE[];
+
+extern const char LN_ERROR[];
+extern const buzz::StaticQName QN_GINGLE_REDIRECT;
+extern const char STR_REDIRECT_PREFIX[];
+
+// Session Contents (aka Gingle <session><description>
+//                   or Jingle <content><description>)
+extern const char LN_DESCRIPTION[];
+extern const char LN_PAYLOADTYPE[];
+extern const buzz::StaticQName QN_ID;
+extern const buzz::StaticQName QN_SID;
+extern const buzz::StaticQName QN_NAME;
+extern const buzz::StaticQName QN_CLOCKRATE;
+extern const buzz::StaticQName QN_BITRATE;
+extern const buzz::StaticQName QN_CHANNELS;
+extern const buzz::StaticQName QN_PARAMETER;
+extern const char LN_NAME[];
+extern const char LN_VALUE[];
+extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME;
+extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE;
+extern const char PAYLOADTYPE_PARAMETER_BITRATE[];
+extern const char PAYLOADTYPE_PARAMETER_HEIGHT[];
+extern const char PAYLOADTYPE_PARAMETER_WIDTH[];
+extern const char PAYLOADTYPE_PARAMETER_FRAMERATE[];
+extern const char LN_BANDWIDTH[];
+
+// CN_ == "content name".  When we initiate a session, we choose the
+// name, and when we receive a Gingle session, we provide default
+// names (since Gingle has no content names).  But when we receive a
+// Jingle call, the content name can be anything, so don't rely on
+// these values being the same as the ones received.
+extern const char CN_AUDIO[];
+extern const char CN_VIDEO[];
+extern const char CN_DATA[];
+extern const char CN_OTHER[];
+// other SDP related strings
+// GN stands for group name
+extern const char GROUP_TYPE_BUNDLE[];
+
+extern const char NS_JINGLE_RTP[];
+extern const buzz::StaticQName QN_JINGLE_RTP_CONTENT;
+extern const buzz::StaticQName QN_SSRC;
+extern const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE;
+extern const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH;
+extern const buzz::StaticQName QN_JINGLE_RTCP_MUX;
+extern const buzz::StaticQName QN_JINGLE_RTCP_FB;
+extern const buzz::StaticQName QN_SUBTYPE;
+extern const buzz::StaticQName QN_JINGLE_RTP_HDREXT;
+extern const buzz::StaticQName QN_URI;
+
+extern const char NS_JINGLE_DRAFT_SCTP[];
+extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM;
+
+extern const char NS_GINGLE_AUDIO[];
+extern const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT;
+extern const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE;
+extern const buzz::StaticQName QN_GINGLE_AUDIO_SRCID;
+extern const char NS_GINGLE_VIDEO[];
+extern const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT;
+extern const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE;
+extern const buzz::StaticQName QN_GINGLE_VIDEO_SRCID;
+extern const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH;
+
+// Crypto support.
+extern const buzz::StaticQName QN_ENCRYPTION;
+extern const buzz::StaticQName QN_ENCRYPTION_REQUIRED;
+extern const buzz::StaticQName QN_CRYPTO;
+extern const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE;
+extern const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE;
+extern const buzz::StaticQName QN_CRYPTO_SUITE;
+extern const buzz::StaticQName QN_CRYPTO_KEY_PARAMS;
+extern const buzz::StaticQName QN_CRYPTO_TAG;
+extern const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS;
+
+// Transports and candidates.
+extern const char LN_TRANSPORT[];
+extern const char LN_CANDIDATE[];
+extern const buzz::StaticQName QN_JINGLE_P2P_TRANSPORT;
+extern const buzz::StaticQName QN_JINGLE_P2P_CANDIDATE;
+extern const buzz::StaticQName QN_UFRAG;
+extern const buzz::StaticQName QN_COMPONENT;
+extern const buzz::StaticQName QN_PWD;
+extern const buzz::StaticQName QN_IP;
+extern const buzz::StaticQName QN_PORT;
+extern const buzz::StaticQName QN_NETWORK;
+extern const buzz::StaticQName QN_GENERATION;
+extern const buzz::StaticQName QN_PRIORITY;
+extern const buzz::StaticQName QN_PROTOCOL;
+extern const char ICE_CANDIDATE_TYPE_PEER_STUN[];
+extern const char ICE_CANDIDATE_TYPE_SERVER_STUN[];
+extern const int ICE_UFRAG_LENGTH;
+extern const int ICE_PWD_LENGTH;
+extern const size_t ICE_UFRAG_MIN_LENGTH;
+extern const size_t ICE_PWD_MIN_LENGTH;
+extern const size_t ICE_UFRAG_MAX_LENGTH;
+extern const size_t ICE_PWD_MAX_LENGTH;
+extern const int ICE_CANDIDATE_COMPONENT_RTP;
+extern const int ICE_CANDIDATE_COMPONENT_RTCP;
+extern const int ICE_CANDIDATE_COMPONENT_DEFAULT;
+
+extern const buzz::StaticQName QN_FINGERPRINT;
+extern const buzz::StaticQName QN_FINGERPRINT_ALGORITHM;
+extern const buzz::StaticQName QN_FINGERPRINT_DIGEST;
+
+extern const char NS_JINGLE_ICE_UDP[];
+
+extern const char ICE_OPTION_GICE[];
+extern const char NS_GINGLE_P2P[];
+extern const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT;
+extern const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE;
+extern const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME;
+extern const buzz::StaticQName QN_GINGLE_CANDIDATE;
+extern const buzz::StaticQName QN_ADDRESS;
+extern const buzz::StaticQName QN_USERNAME;
+extern const buzz::StaticQName QN_PASSWORD;
+extern const buzz::StaticQName QN_PREFERENCE;
+extern const char GINGLE_CANDIDATE_TYPE_STUN[];
+extern const char GICE_CHANNEL_NAME_RTP[];
+extern const char GICE_CHANNEL_NAME_RTCP[];
+extern const char GICE_CHANNEL_NAME_VIDEO_RTP[];
+extern const char GICE_CHANNEL_NAME_VIDEO_RTCP[];
+extern const char GICE_CHANNEL_NAME_DATA_RTP[];
+extern const char GICE_CHANNEL_NAME_DATA_RTCP[];
+
+extern const char NS_GINGLE_RAW[];
+extern const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT;
+extern const buzz::StaticQName QN_GINGLE_RAW_CHANNEL;
+
+// terminate reasons and errors: see http://xmpp.org/extensions/xep-0166.html
+extern const char JINGLE_ERROR_BAD_REQUEST[];  // like parse error
+// got transport-info before session-initiate, for example
+extern const char JINGLE_ERROR_OUT_OF_ORDER[];
+extern const char JINGLE_ERROR_UNKNOWN_SESSION[];
+
+// Call terminate reasons from XEP-166
+extern const char STR_TERMINATE_DECLINE[];  // polite reject
+extern const char STR_TERMINATE_SUCCESS[];  // polite hangup
+extern const char STR_TERMINATE_ERROR[];  // something bad happened
+extern const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[];  // no codecs?
+
+// Old terminate reasons used by cricket
+extern const char STR_TERMINATE_CALL_ENDED[];
+extern const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[];
+extern const char STR_TERMINATE_RECIPIENT_BUSY[];
+extern const char STR_TERMINATE_INSUFFICIENT_FUNDS[];
+extern const char STR_TERMINATE_NUMBER_MALFORMED[];
+extern const char STR_TERMINATE_NUMBER_DISALLOWED[];
+extern const char STR_TERMINATE_PROTOCOL_ERROR[];
+extern const char STR_TERMINATE_INTERNAL_SERVER_ERROR[];
+extern const char STR_TERMINATE_UNKNOWN_ERROR[];
+
+// Draft view and notify messages.
+extern const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[];
+extern const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[];
+extern const buzz::StaticQName QN_NICK;
+extern const buzz::StaticQName QN_TYPE;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW;
+extern const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[];
+extern const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[];
+extern const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS;
+extern const buzz::StaticQName QN_WIDTH;
+extern const buzz::StaticQName QN_HEIGHT;
+extern const buzz::StaticQName QN_FRAMERATE;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAM;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS;
+extern const buzz::StaticQName QN_DISPLAY;
+extern const buzz::StaticQName QN_CNAME;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP;
+extern const buzz::StaticQName QN_SEMANTICS;
+extern const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY;
+extern const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE;
+
+// old stuff
+#ifdef FEATURE_ENABLE_VOICEMAIL
+extern const char NS_VOICEMAIL[];
+extern const buzz::StaticQName QN_VOICEMAIL_REGARDING;
+#endif
+
+// RFC 4145, SDP setup attribute values.
+extern const char CONNECTIONROLE_ACTIVE_STR[];
+extern const char CONNECTIONROLE_PASSIVE_STR[];
+extern const char CONNECTIONROLE_ACTPASS_STR[];
+extern const char CONNECTIONROLE_HOLDCONN_STR[];
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_CONSTANTS_H_
diff --git a/p2p/base/dtlstransport.h b/p2p/base/dtlstransport.h
new file mode 100644
index 0000000..bb80dc8
--- /dev/null
+++ b/p2p/base/dtlstransport.h
@@ -0,0 +1,240 @@
+/*
+ *  Copyright 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_P2P_BASE_DTLSTRANSPORT_H_
+#define WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
+
+#include "webrtc/p2p/base/dtlstransportchannel.h"
+#include "webrtc/p2p/base/transport.h"
+
+namespace rtc {
+class SSLIdentity;
+}
+
+namespace cricket {
+
+class PortAllocator;
+
+// Base should be a descendant of cricket::Transport
+template<class Base>
+class DtlsTransport : public Base {
+ public:
+  DtlsTransport(rtc::Thread* signaling_thread,
+                rtc::Thread* worker_thread,
+                const std::string& content_name,
+                PortAllocator* allocator,
+                rtc::SSLIdentity* identity)
+      : Base(signaling_thread, worker_thread, content_name, allocator),
+        identity_(identity),
+        secure_role_(rtc::SSL_CLIENT) {
+  }
+
+  ~DtlsTransport() {
+    Base::DestroyAllChannels();
+  }
+  virtual void SetIdentity_w(rtc::SSLIdentity* identity) {
+    identity_ = identity;
+  }
+  virtual bool GetIdentity_w(rtc::SSLIdentity** identity) {
+    if (!identity_)
+      return false;
+
+    *identity = identity_->GetReference();
+    return true;
+  }
+
+  virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
+                                                std::string* error_desc) {
+    rtc::SSLFingerprint* local_fp =
+        Base::local_description()->identity_fingerprint.get();
+
+    if (local_fp) {
+      // Sanity check local fingerprint.
+      if (identity_) {
+        rtc::scoped_ptr<rtc::SSLFingerprint> local_fp_tmp(
+            rtc::SSLFingerprint::Create(local_fp->algorithm,
+                                              identity_));
+        ASSERT(local_fp_tmp.get() != NULL);
+        if (!(*local_fp_tmp == *local_fp)) {
+          std::ostringstream desc;
+          desc << "Local fingerprint does not match identity. Expected: ";
+          desc << local_fp_tmp->ToString();
+          desc << " Got: " << local_fp->ToString();
+          return BadTransportDescription(desc.str(), error_desc);
+        }
+      } else {
+        return BadTransportDescription(
+            "Local fingerprint provided but no identity available.",
+            error_desc);
+      }
+    } else {
+      identity_ = NULL;
+    }
+
+    if (!channel->SetLocalIdentity(identity_)) {
+      return BadTransportDescription("Failed to set local identity.",
+                                     error_desc);
+    }
+
+    // Apply the description in the base class.
+    return Base::ApplyLocalTransportDescription_w(channel, error_desc);
+  }
+
+  virtual bool NegotiateTransportDescription_w(ContentAction local_role,
+                                               std::string* error_desc) {
+    if (!Base::local_description() || !Base::remote_description()) {
+      const std::string msg = "Local and Remote description must be set before "
+                              "transport descriptions are negotiated";
+      return BadTransportDescription(msg, error_desc);
+    }
+
+    rtc::SSLFingerprint* local_fp =
+        Base::local_description()->identity_fingerprint.get();
+    rtc::SSLFingerprint* remote_fp =
+        Base::remote_description()->identity_fingerprint.get();
+
+    if (remote_fp && local_fp) {
+      remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp));
+
+      // From RFC 4145, section-4.1, The following are the values that the
+      // 'setup' attribute can take in an offer/answer exchange:
+      //       Offer      Answer
+      //      ________________
+      //      active     passive / holdconn
+      //      passive    active / holdconn
+      //      actpass    active / passive / holdconn
+      //      holdconn   holdconn
+      //
+      // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
+      // The endpoint MUST use the setup attribute defined in [RFC4145].
+      // The endpoint that is the offerer MUST use the setup attribute
+      // value of setup:actpass and be prepared to receive a client_hello
+      // before it receives the answer.  The answerer MUST use either a
+      // setup attribute value of setup:active or setup:passive.  Note that
+      // if the answerer uses setup:passive, then the DTLS handshake will
+      // not begin until the answerer is received, which adds additional
+      // latency. setup:active allows the answer and the DTLS handshake to
+      // occur in parallel.  Thus, setup:active is RECOMMENDED.  Whichever
+      // party is active MUST initiate a DTLS handshake by sending a
+      // ClientHello over each flow (host/port quartet).
+      // IOW - actpass and passive modes should be treated as server and
+      // active as client.
+      ConnectionRole local_connection_role =
+          Base::local_description()->connection_role;
+      ConnectionRole remote_connection_role =
+          Base::remote_description()->connection_role;
+
+      bool is_remote_server = false;
+      if (local_role == CA_OFFER) {
+        if (local_connection_role != CONNECTIONROLE_ACTPASS) {
+          return BadTransportDescription(
+              "Offerer must use actpass value for setup attribute.",
+              error_desc);
+        }
+
+        if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
+            remote_connection_role == CONNECTIONROLE_PASSIVE ||
+            remote_connection_role == CONNECTIONROLE_NONE) {
+          is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
+        } else {
+          const std::string msg =
+              "Answerer must use either active or passive value "
+              "for setup attribute.";
+          return BadTransportDescription(msg, error_desc);
+        }
+        // If remote is NONE or ACTIVE it will act as client.
+      } else {
+        if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
+            remote_connection_role != CONNECTIONROLE_NONE) {
+          return BadTransportDescription(
+              "Offerer must use actpass value for setup attribute.",
+              error_desc);
+        }
+
+        if (local_connection_role == CONNECTIONROLE_ACTIVE ||
+            local_connection_role == CONNECTIONROLE_PASSIVE) {
+          is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
+        } else {
+          const std::string msg =
+              "Answerer must use either active or passive value "
+              "for setup attribute.";
+          return BadTransportDescription(msg, error_desc);
+        }
+
+        // If local is passive, local will act as server.
+      }
+
+      secure_role_ = is_remote_server ? rtc::SSL_CLIENT :
+                                        rtc::SSL_SERVER;
+
+    } else if (local_fp && (local_role == CA_ANSWER)) {
+      return BadTransportDescription(
+          "Local fingerprint supplied when caller didn't offer DTLS.",
+          error_desc);
+    } else {
+      // We are not doing DTLS
+      remote_fingerprint_.reset(new rtc::SSLFingerprint(
+          "", NULL, 0));
+    }
+
+    // Now run the negotiation for the base class.
+    return Base::NegotiateTransportDescription_w(local_role, error_desc);
+  }
+
+  virtual DtlsTransportChannelWrapper* CreateTransportChannel(int component) {
+    return new DtlsTransportChannelWrapper(
+        this, Base::CreateTransportChannel(component));
+  }
+
+  virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
+    // Kind of ugly, but this lets us do the exact inverse of the create.
+    DtlsTransportChannelWrapper* dtls_channel =
+        static_cast<DtlsTransportChannelWrapper*>(channel);
+    TransportChannelImpl* base_channel = dtls_channel->channel();
+    delete dtls_channel;
+    Base::DestroyTransportChannel(base_channel);
+  }
+
+  virtual bool GetSslRole_w(rtc::SSLRole* ssl_role) const {
+    ASSERT(ssl_role != NULL);
+    *ssl_role = secure_role_;
+    return true;
+  }
+
+ private:
+  virtual bool ApplyNegotiatedTransportDescription_w(
+      TransportChannelImpl* channel,
+      std::string* error_desc) {
+    // Set ssl role. Role must be set before fingerprint is applied, which
+    // initiates DTLS setup.
+    if (!channel->SetSslRole(secure_role_)) {
+      return BadTransportDescription("Failed to set ssl role for the channel.",
+                                     error_desc);
+    }
+    // Apply remote fingerprint.
+    if (!channel->SetRemoteFingerprint(
+        remote_fingerprint_->algorithm,
+        reinterpret_cast<const uint8 *>(remote_fingerprint_->
+                                    digest.data()),
+        remote_fingerprint_->digest.length())) {
+      return BadTransportDescription("Failed to apply remote fingerprint.",
+                                     error_desc);
+    }
+    return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc);
+  }
+
+  rtc::SSLIdentity* identity_;
+  rtc::SSLRole secure_role_;
+  rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
diff --git a/p2p/base/dtlstransportchannel.cc b/p2p/base/dtlstransportchannel.cc
new file mode 100644
index 0000000..9cceca3
--- /dev/null
+++ b/p2p/base/dtlstransportchannel.cc
@@ -0,0 +1,623 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/p2p/base/dtlstransportchannel.h"
+
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/base/dscp.h"
+#include "webrtc/base/messagequeue.h"
+#include "webrtc/base/sslstreamadapter.h"
+#include "webrtc/base/stream.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+// We don't pull the RTP constants from rtputils.h, to avoid a layer violation.
+static const size_t kDtlsRecordHeaderLen = 13;
+static const size_t kMaxDtlsPacketLen = 2048;
+static const size_t kMinRtpPacketLen = 12;
+
+static bool IsDtlsPacket(const char* data, size_t len) {
+  const uint8* u = reinterpret_cast<const uint8*>(data);
+  return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64));
+}
+static bool IsRtpPacket(const char* data, size_t len) {
+  const uint8* u = reinterpret_cast<const uint8*>(data);
+  return (len >= kMinRtpPacketLen && (u[0] & 0xC0) == 0x80);
+}
+
+rtc::StreamResult StreamInterfaceChannel::Read(void* buffer,
+                                                     size_t buffer_len,
+                                                     size_t* read,
+                                                     int* error) {
+  if (state_ == rtc::SS_CLOSED)
+    return rtc::SR_EOS;
+  if (state_ == rtc::SS_OPENING)
+    return rtc::SR_BLOCK;
+
+  return fifo_.Read(buffer, buffer_len, read, error);
+}
+
+rtc::StreamResult StreamInterfaceChannel::Write(const void* data,
+                                                      size_t data_len,
+                                                      size_t* written,
+                                                      int* error) {
+  // Always succeeds, since this is an unreliable transport anyway.
+  // TODO: Should this block if channel_'s temporarily unwritable?
+  rtc::PacketOptions packet_options;
+  channel_->SendPacket(static_cast<const char*>(data), data_len,
+                       packet_options);
+  if (written) {
+    *written = data_len;
+  }
+  return rtc::SR_SUCCESS;
+}
+
+bool StreamInterfaceChannel::OnPacketReceived(const char* data, size_t size) {
+  // We force a read event here to ensure that we don't overflow our FIFO.
+  // Under high packet rate this can occur if we wait for the FIFO to post its
+  // own SE_READ.
+  bool ret = (fifo_.WriteAll(data, size, NULL, NULL) == rtc::SR_SUCCESS);
+  if (ret) {
+    SignalEvent(this, rtc::SE_READ, 0);
+  }
+  return ret;
+}
+
+void StreamInterfaceChannel::OnEvent(rtc::StreamInterface* stream,
+                                     int sig, int err) {
+  SignalEvent(this, sig, err);
+}
+
+DtlsTransportChannelWrapper::DtlsTransportChannelWrapper(
+                                           Transport* transport,
+                                           TransportChannelImpl* channel)
+    : TransportChannelImpl(channel->content_name(), channel->component()),
+      transport_(transport),
+      worker_thread_(rtc::Thread::Current()),
+      channel_(channel),
+      downward_(NULL),
+      dtls_state_(STATE_NONE),
+      local_identity_(NULL),
+      ssl_role_(rtc::SSL_CLIENT) {
+  channel_->SignalReadableState.connect(this,
+      &DtlsTransportChannelWrapper::OnReadableState);
+  channel_->SignalWritableState.connect(this,
+      &DtlsTransportChannelWrapper::OnWritableState);
+  channel_->SignalReadPacket.connect(this,
+      &DtlsTransportChannelWrapper::OnReadPacket);
+  channel_->SignalReadyToSend.connect(this,
+      &DtlsTransportChannelWrapper::OnReadyToSend);
+  channel_->SignalRequestSignaling.connect(this,
+      &DtlsTransportChannelWrapper::OnRequestSignaling);
+  channel_->SignalCandidateReady.connect(this,
+      &DtlsTransportChannelWrapper::OnCandidateReady);
+  channel_->SignalCandidatesAllocationDone.connect(this,
+      &DtlsTransportChannelWrapper::OnCandidatesAllocationDone);
+  channel_->SignalRoleConflict.connect(this,
+      &DtlsTransportChannelWrapper::OnRoleConflict);
+  channel_->SignalRouteChange.connect(this,
+      &DtlsTransportChannelWrapper::OnRouteChange);
+  channel_->SignalConnectionRemoved.connect(this,
+      &DtlsTransportChannelWrapper::OnConnectionRemoved);
+}
+
+DtlsTransportChannelWrapper::~DtlsTransportChannelWrapper() {
+}
+
+void DtlsTransportChannelWrapper::Connect() {
+  // We should only get a single call to Connect.
+  ASSERT(dtls_state_ == STATE_NONE ||
+         dtls_state_ == STATE_OFFERED ||
+         dtls_state_ == STATE_ACCEPTED);
+  channel_->Connect();
+}
+
+void DtlsTransportChannelWrapper::Reset() {
+  channel_->Reset();
+  set_writable(false);
+  set_readable(false);
+
+  // Re-call SetupDtls()
+  if (!SetupDtls()) {
+    LOG_J(LS_ERROR, this) << "Error re-initializing DTLS";
+    dtls_state_ = STATE_CLOSED;
+    return;
+  }
+
+  dtls_state_ = STATE_ACCEPTED;
+}
+
+bool DtlsTransportChannelWrapper::SetLocalIdentity(
+    rtc::SSLIdentity* identity) {
+  if (dtls_state_ != STATE_NONE) {
+    if (identity == local_identity_) {
+      // This may happen during renegotiation.
+      LOG_J(LS_INFO, this) << "Ignoring identical DTLS identity";
+      return true;
+    } else {
+      LOG_J(LS_ERROR, this) << "Can't change DTLS local identity in this state";
+      return false;
+    }
+  }
+
+  if (identity) {
+    local_identity_ = identity;
+    dtls_state_ = STATE_OFFERED;
+  } else {
+    LOG_J(LS_INFO, this) << "NULL DTLS identity supplied. Not doing DTLS";
+  }
+
+  return true;
+}
+
+bool DtlsTransportChannelWrapper::GetLocalIdentity(
+    rtc::SSLIdentity** identity) const {
+  if (!local_identity_)
+    return false;
+
+  *identity = local_identity_->GetReference();
+  return true;
+}
+
+bool DtlsTransportChannelWrapper::SetSslRole(rtc::SSLRole role) {
+  if (dtls_state_ == STATE_OPEN) {
+    if (ssl_role_ != role) {
+      LOG(LS_ERROR) << "SSL Role can't be reversed after the session is setup.";
+      return false;
+    }
+    return true;
+  }
+
+  ssl_role_ = role;
+  return true;
+}
+
+bool DtlsTransportChannelWrapper::GetSslRole(rtc::SSLRole* role) const {
+  *role = ssl_role_;
+  return true;
+}
+
+bool DtlsTransportChannelWrapper::SetRemoteFingerprint(
+    const std::string& digest_alg,
+    const uint8* digest,
+    size_t digest_len) {
+
+  rtc::Buffer remote_fingerprint_value(digest, digest_len);
+
+  if (dtls_state_ != STATE_NONE &&
+      remote_fingerprint_value_ == remote_fingerprint_value &&
+      !digest_alg.empty()) {
+    // This may happen during renegotiation.
+    LOG_J(LS_INFO, this) << "Ignoring identical remote DTLS fingerprint";
+    return true;
+  }
+
+  // Allow SetRemoteFingerprint with a NULL digest even if SetLocalIdentity
+  // hasn't been called.
+  if (dtls_state_ > STATE_OFFERED ||
+      (dtls_state_ == STATE_NONE && !digest_alg.empty())) {
+    LOG_J(LS_ERROR, this) << "Can't set DTLS remote settings in this state.";
+    return false;
+  }
+
+  if (digest_alg.empty()) {
+    LOG_J(LS_INFO, this) << "Other side didn't support DTLS.";
+    dtls_state_ = STATE_NONE;
+    return true;
+  }
+
+  // At this point we know we are doing DTLS
+  remote_fingerprint_value.TransferTo(&remote_fingerprint_value_);
+  remote_fingerprint_algorithm_ = digest_alg;
+
+  if (!SetupDtls()) {
+    dtls_state_ = STATE_CLOSED;
+    return false;
+  }
+
+  dtls_state_ = STATE_ACCEPTED;
+  return true;
+}
+
+bool DtlsTransportChannelWrapper::GetRemoteCertificate(
+    rtc::SSLCertificate** cert) const {
+  if (!dtls_)
+    return false;
+
+  return dtls_->GetPeerCertificate(cert);
+}
+
+bool DtlsTransportChannelWrapper::SetupDtls() {
+  StreamInterfaceChannel* downward =
+      new StreamInterfaceChannel(worker_thread_, channel_);
+
+  dtls_.reset(rtc::SSLStreamAdapter::Create(downward));
+  if (!dtls_) {
+    LOG_J(LS_ERROR, this) << "Failed to create DTLS adapter.";
+    delete downward;
+    return false;
+  }
+
+  downward_ = downward;
+
+  dtls_->SetIdentity(local_identity_->GetReference());
+  dtls_->SetMode(rtc::SSL_MODE_DTLS);
+  dtls_->SetServerRole(ssl_role_);
+  dtls_->SignalEvent.connect(this, &DtlsTransportChannelWrapper::OnDtlsEvent);
+  if (!dtls_->SetPeerCertificateDigest(
+          remote_fingerprint_algorithm_,
+          reinterpret_cast<unsigned char *>(remote_fingerprint_value_.data()),
+          remote_fingerprint_value_.length())) {
+    LOG_J(LS_ERROR, this) << "Couldn't set DTLS certificate digest.";
+    return false;
+  }
+
+  // Set up DTLS-SRTP, if it's been enabled.
+  if (!srtp_ciphers_.empty()) {
+    if (!dtls_->SetDtlsSrtpCiphers(srtp_ciphers_)) {
+      LOG_J(LS_ERROR, this) << "Couldn't set DTLS-SRTP ciphers.";
+      return false;
+    }
+  } else {
+    LOG_J(LS_INFO, this) << "Not using DTLS.";
+  }
+
+  LOG_J(LS_INFO, this) << "DTLS setup complete.";
+  return true;
+}
+
+bool DtlsTransportChannelWrapper::SetSrtpCiphers(
+    const std::vector<std::string>& ciphers) {
+  if (srtp_ciphers_ == ciphers)
+    return true;
+
+  if (dtls_state_ == STATE_STARTED) {
+    LOG(LS_WARNING) << "Ignoring new SRTP ciphers while DTLS is negotiating";
+    return true;
+  }
+
+  if (dtls_state_ == STATE_OPEN) {
+    // We don't support DTLS renegotiation currently. If new set of srtp ciphers
+    // are different than what's being used currently, we will not use it.
+    // So for now, let's be happy (or sad) with a warning message.
+    std::string current_srtp_cipher;
+    if (!dtls_->GetDtlsSrtpCipher(&current_srtp_cipher)) {
+      LOG(LS_ERROR) << "Failed to get the current SRTP cipher for DTLS channel";
+      return false;
+    }
+    const std::vector<std::string>::const_iterator iter =
+        std::find(ciphers.begin(), ciphers.end(), current_srtp_cipher);
+    if (iter == ciphers.end()) {
+      std::string requested_str;
+      for (size_t i = 0; i < ciphers.size(); ++i) {
+        requested_str.append(" ");
+        requested_str.append(ciphers[i]);
+        requested_str.append(" ");
+      }
+      LOG(LS_WARNING) << "Ignoring new set of SRTP ciphers, as DTLS "
+                      << "renegotiation is not supported currently "
+                      << "current cipher = " << current_srtp_cipher << " and "
+                      << "requested = " << "[" << requested_str << "]";
+    }
+    return true;
+  }
+
+  if (dtls_state_ != STATE_NONE &&
+      dtls_state_ != STATE_OFFERED &&
+      dtls_state_ != STATE_ACCEPTED) {
+    ASSERT(false);
+    return false;
+  }
+
+  srtp_ciphers_ = ciphers;
+  return true;
+}
+
+bool DtlsTransportChannelWrapper::GetSrtpCipher(std::string* cipher) {
+  if (dtls_state_ != STATE_OPEN) {
+    return false;
+  }
+
+  return dtls_->GetDtlsSrtpCipher(cipher);
+}
+
+
+// Called from upper layers to send a media packet.
+int DtlsTransportChannelWrapper::SendPacket(
+    const char* data, size_t size,
+    const rtc::PacketOptions& options, int flags) {
+  int result = -1;
+
+  switch (dtls_state_) {
+    case STATE_OFFERED:
+      // We don't know if we are doing DTLS yet, so we can't send a packet.
+      // TODO(ekr@rtfm.com): assert here?
+      result = -1;
+      break;
+
+    case STATE_STARTED:
+    case STATE_ACCEPTED:
+      // Can't send data until the connection is active
+      result = -1;
+      break;
+
+    case STATE_OPEN:
+      if (flags & PF_SRTP_BYPASS) {
+        ASSERT(!srtp_ciphers_.empty());
+        if (!IsRtpPacket(data, size)) {
+          result = -1;
+          break;
+        }
+
+        result = channel_->SendPacket(data, size, options);
+      } else {
+        result = (dtls_->WriteAll(data, size, NULL, NULL) ==
+          rtc::SR_SUCCESS) ? static_cast<int>(size) : -1;
+      }
+      break;
+      // Not doing DTLS.
+    case STATE_NONE:
+      result = channel_->SendPacket(data, size, options);
+      break;
+
+    case STATE_CLOSED:  // Can't send anything when we're closed.
+      return -1;
+  }
+
+  return result;
+}
+
+// The state transition logic here is as follows:
+// (1) If we're not doing DTLS-SRTP, then the state is just the
+//     state of the underlying impl()
+// (2) If we're doing DTLS-SRTP:
+//     - Prior to the DTLS handshake, the state is neither readable or
+//       writable
+//     - When the impl goes writable for the first time we
+//       start the DTLS handshake
+//     - Once the DTLS handshake completes, the state is that of the
+//       impl again
+void DtlsTransportChannelWrapper::OnReadableState(TransportChannel* channel) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == channel_);
+  LOG_J(LS_VERBOSE, this)
+      << "DTLSTransportChannelWrapper: channel readable state changed.";
+
+  if (dtls_state_ == STATE_NONE || dtls_state_ == STATE_OPEN) {
+    set_readable(channel_->readable());
+    // Note: SignalReadableState fired by set_readable.
+  }
+}
+
+void DtlsTransportChannelWrapper::OnWritableState(TransportChannel* channel) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == channel_);
+  LOG_J(LS_VERBOSE, this)
+      << "DTLSTransportChannelWrapper: channel writable state changed.";
+
+  switch (dtls_state_) {
+    case STATE_NONE:
+    case STATE_OPEN:
+      set_writable(channel_->writable());
+      // Note: SignalWritableState fired by set_writable.
+      break;
+
+    case STATE_OFFERED:
+      // Do nothing
+      break;
+
+    case STATE_ACCEPTED:
+      if (!MaybeStartDtls()) {
+        // This should never happen:
+        // Because we are operating in a nonblocking mode and all
+        // incoming packets come in via OnReadPacket(), which rejects
+        // packets in this state, the incoming queue must be empty. We
+        // ignore write errors, thus any errors must be because of
+        // configuration and therefore are our fault.
+        // Note that in non-debug configurations, failure in
+        // MaybeStartDtls() changes the state to STATE_CLOSED.
+        ASSERT(false);
+      }
+      break;
+
+    case STATE_STARTED:
+      // Do nothing
+      break;
+
+    case STATE_CLOSED:
+      // Should not happen. Do nothing
+      break;
+  }
+}
+
+void DtlsTransportChannelWrapper::OnReadPacket(
+    TransportChannel* channel, const char* data, size_t size,
+    const rtc::PacketTime& packet_time, int flags) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == channel_);
+  ASSERT(flags == 0);
+
+  switch (dtls_state_) {
+    case STATE_NONE:
+      // We are not doing DTLS
+      SignalReadPacket(this, data, size, packet_time, 0);
+      break;
+
+    case STATE_OFFERED:
+      // Currently drop the packet, but we might in future
+      // decide to take this as evidence that the other
+      // side is ready to do DTLS and start the handshake
+      // on our end
+      LOG_J(LS_WARNING, this) << "Received packet before we know if we are "
+                              << "doing DTLS or not; dropping.";
+      break;
+
+    case STATE_ACCEPTED:
+      // Drop packets received before DTLS has actually started
+      LOG_J(LS_INFO, this) << "Dropping packet received before DTLS started.";
+      break;
+
+    case STATE_STARTED:
+    case STATE_OPEN:
+      // We should only get DTLS or SRTP packets; STUN's already been demuxed.
+      // Is this potentially a DTLS packet?
+      if (IsDtlsPacket(data, size)) {
+        if (!HandleDtlsPacket(data, size)) {
+          LOG_J(LS_ERROR, this) << "Failed to handle DTLS packet.";
+          return;
+        }
+      } else {
+        // Not a DTLS packet; our handshake should be complete by now.
+        if (dtls_state_ != STATE_OPEN) {
+          LOG_J(LS_ERROR, this) << "Received non-DTLS packet before DTLS "
+                                << "complete.";
+          return;
+        }
+
+        // And it had better be a SRTP packet.
+        if (!IsRtpPacket(data, size)) {
+          LOG_J(LS_ERROR, this) << "Received unexpected non-DTLS packet.";
+          return;
+        }
+
+        // Sanity check.
+        ASSERT(!srtp_ciphers_.empty());
+
+        // Signal this upwards as a bypass packet.
+        SignalReadPacket(this, data, size, packet_time, PF_SRTP_BYPASS);
+      }
+      break;
+    case STATE_CLOSED:
+      // This shouldn't be happening. Drop the packet
+      break;
+  }
+}
+
+void DtlsTransportChannelWrapper::OnReadyToSend(TransportChannel* channel) {
+  if (writable()) {
+    SignalReadyToSend(this);
+  }
+}
+
+void DtlsTransportChannelWrapper::OnDtlsEvent(rtc::StreamInterface* dtls,
+                                              int sig, int err) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(dtls == dtls_.get());
+  if (sig & rtc::SE_OPEN) {
+    // This is the first time.
+    LOG_J(LS_INFO, this) << "DTLS handshake complete.";
+    if (dtls_->GetState() == rtc::SS_OPEN) {
+      // The check for OPEN shouldn't be necessary but let's make
+      // sure we don't accidentally frob the state if it's closed.
+      dtls_state_ = STATE_OPEN;
+
+      set_readable(true);
+      set_writable(true);
+    }
+  }
+  if (sig & rtc::SE_READ) {
+    char buf[kMaxDtlsPacketLen];
+    size_t read;
+    if (dtls_->Read(buf, sizeof(buf), &read, NULL) == rtc::SR_SUCCESS) {
+      SignalReadPacket(this, buf, read, rtc::CreatePacketTime(0), 0);
+    }
+  }
+  if (sig & rtc::SE_CLOSE) {
+    ASSERT(sig == rtc::SE_CLOSE);  // SE_CLOSE should be by itself.
+    if (!err) {
+      LOG_J(LS_INFO, this) << "DTLS channel closed";
+    } else {
+      LOG_J(LS_INFO, this) << "DTLS channel error, code=" << err;
+    }
+
+    set_readable(false);
+    set_writable(false);
+    dtls_state_ = STATE_CLOSED;
+  }
+}
+
+bool DtlsTransportChannelWrapper::MaybeStartDtls() {
+  if (channel_->writable()) {
+    if (dtls_->StartSSLWithPeer()) {
+      LOG_J(LS_ERROR, this) << "Couldn't start DTLS handshake";
+      dtls_state_ = STATE_CLOSED;
+      return false;
+    }
+    LOG_J(LS_INFO, this)
+      << "DtlsTransportChannelWrapper: Started DTLS handshake";
+
+    dtls_state_ = STATE_STARTED;
+  }
+  return true;
+}
+
+// Called from OnReadPacket when a DTLS packet is received.
+bool DtlsTransportChannelWrapper::HandleDtlsPacket(const char* data,
+                                                   size_t size) {
+  // Sanity check we're not passing junk that
+  // just looks like DTLS.
+  const uint8* tmp_data = reinterpret_cast<const uint8* >(data);
+  size_t tmp_size = size;
+  while (tmp_size > 0) {
+    if (tmp_size < kDtlsRecordHeaderLen)
+      return false;  // Too short for the header
+
+    size_t record_len = (tmp_data[11] << 8) | (tmp_data[12]);
+    if ((record_len + kDtlsRecordHeaderLen) > tmp_size)
+      return false;  // Body too short
+
+    tmp_data += record_len + kDtlsRecordHeaderLen;
+    tmp_size -= record_len + kDtlsRecordHeaderLen;
+  }
+
+  // Looks good. Pass to the SIC which ends up being passed to
+  // the DTLS stack.
+  return downward_->OnPacketReceived(data, size);
+}
+
+void DtlsTransportChannelWrapper::OnRequestSignaling(
+    TransportChannelImpl* channel) {
+  ASSERT(channel == channel_);
+  SignalRequestSignaling(this);
+}
+
+void DtlsTransportChannelWrapper::OnCandidateReady(
+    TransportChannelImpl* channel, const Candidate& c) {
+  ASSERT(channel == channel_);
+  SignalCandidateReady(this, c);
+}
+
+void DtlsTransportChannelWrapper::OnCandidatesAllocationDone(
+    TransportChannelImpl* channel) {
+  ASSERT(channel == channel_);
+  SignalCandidatesAllocationDone(this);
+}
+
+void DtlsTransportChannelWrapper::OnRoleConflict(
+    TransportChannelImpl* channel) {
+  ASSERT(channel == channel_);
+  SignalRoleConflict(this);
+}
+
+void DtlsTransportChannelWrapper::OnRouteChange(
+    TransportChannel* channel, const Candidate& candidate) {
+  ASSERT(channel == channel_);
+  SignalRouteChange(this, candidate);
+}
+
+void DtlsTransportChannelWrapper::OnConnectionRemoved(
+    TransportChannelImpl* channel) {
+  ASSERT(channel == channel_);
+  SignalConnectionRemoved(this);
+}
+
+}  // namespace cricket
diff --git a/p2p/base/dtlstransportchannel.h b/p2p/base/dtlstransportchannel.h
new file mode 100644
index 0000000..d12f724
--- /dev/null
+++ b/p2p/base/dtlstransportchannel.h
@@ -0,0 +1,246 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_P2P_BASE_DTLSTRANSPORTCHANNEL_H_
+#define WEBRTC_P2P_BASE_DTLSTRANSPORTCHANNEL_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sslstreamadapter.h"
+#include "webrtc/base/stream.h"
+
+namespace cricket {
+
+// A bridge between a packet-oriented/channel-type interface on
+// the bottom and a StreamInterface on the top.
+class StreamInterfaceChannel : public rtc::StreamInterface,
+                               public sigslot::has_slots<> {
+ public:
+  StreamInterfaceChannel(rtc::Thread* owner, TransportChannel* channel)
+      : channel_(channel),
+        state_(rtc::SS_OPEN),
+        fifo_(kFifoSize, owner) {
+    fifo_.SignalEvent.connect(this, &StreamInterfaceChannel::OnEvent);
+  }
+
+  // Push in a packet; this gets pulled out from Read().
+  bool OnPacketReceived(const char* data, size_t size);
+
+  // Implementations of StreamInterface
+  virtual rtc::StreamState GetState() const { return state_; }
+  virtual void Close() { state_ = rtc::SS_CLOSED; }
+  virtual rtc::StreamResult Read(void* buffer, size_t buffer_len,
+                                       size_t* read, int* error);
+  virtual rtc::StreamResult Write(const void* data, size_t data_len,
+                                        size_t* written, int* error);
+
+ private:
+  static const size_t kFifoSize = 8192;
+
+  // Forward events
+  virtual void OnEvent(rtc::StreamInterface* stream, int sig, int err);
+
+  TransportChannel* channel_;  // owned by DtlsTransportChannelWrapper
+  rtc::StreamState state_;
+  rtc::FifoBuffer fifo_;
+
+  DISALLOW_COPY_AND_ASSIGN(StreamInterfaceChannel);
+};
+
+
+// This class provides a DTLS SSLStreamAdapter inside a TransportChannel-style
+// packet-based interface, wrapping an existing TransportChannel instance
+// (e.g a P2PTransportChannel)
+// Here's the way this works:
+//
+//   DtlsTransportChannelWrapper {
+//       SSLStreamAdapter* dtls_ {
+//           StreamInterfaceChannel downward_ {
+//               TransportChannelImpl* channel_;
+//           }
+//       }
+//   }
+//
+//   - Data which comes into DtlsTransportChannelWrapper from the underlying
+//     channel_ via OnReadPacket() is checked for whether it is DTLS
+//     or not, and if it is, is passed to DtlsTransportChannelWrapper::
+//     HandleDtlsPacket, which pushes it into to downward_.
+//     dtls_ is listening for events on downward_, so it immediately calls
+//     downward_->Read().
+//
+//   - Data written to DtlsTransportChannelWrapper is passed either to
+//      downward_ or directly to channel_, depending on whether DTLS is
+//     negotiated and whether the flags include PF_SRTP_BYPASS
+//
+//   - The SSLStreamAdapter writes to downward_->Write()
+//     which translates it into packet writes on channel_.
+class DtlsTransportChannelWrapper : public TransportChannelImpl {
+ public:
+    enum State {
+      STATE_NONE,      // No state or rejected.
+      STATE_OFFERED,   // Our identity has been set.
+      STATE_ACCEPTED,  // The other side sent a fingerprint.
+      STATE_STARTED,   // We are negotiating.
+      STATE_OPEN,      // Negotiation complete.
+      STATE_CLOSED     // Connection closed.
+    };
+
+  // The parameters here are:
+  // transport -- the DtlsTransport that created us
+  // channel -- the TransportChannel we are wrapping
+  DtlsTransportChannelWrapper(Transport* transport,
+                              TransportChannelImpl* channel);
+  virtual ~DtlsTransportChannelWrapper();
+
+  virtual void SetIceRole(IceRole role) {
+    channel_->SetIceRole(role);
+  }
+  virtual IceRole GetIceRole() const {
+    return channel_->GetIceRole();
+  }
+  virtual size_t GetConnectionCount() const {
+    return channel_->GetConnectionCount();
+  }
+  virtual bool SetLocalIdentity(rtc::SSLIdentity *identity);
+  virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const;
+
+  virtual bool SetRemoteFingerprint(const std::string& digest_alg,
+                                    const uint8* digest,
+                                    size_t digest_len);
+  virtual bool IsDtlsActive() const { return dtls_state_ != STATE_NONE; }
+
+  // Called to send a packet (via DTLS, if turned on).
+  virtual int SendPacket(const char* data, size_t size,
+                         const rtc::PacketOptions& options,
+                         int flags);
+
+  // TransportChannel calls that we forward to the wrapped transport.
+  virtual int SetOption(rtc::Socket::Option opt, int value) {
+    return channel_->SetOption(opt, value);
+  }
+  virtual int GetError() {
+    return channel_->GetError();
+  }
+  virtual bool GetStats(ConnectionInfos* infos) {
+    return channel_->GetStats(infos);
+  }
+  virtual const std::string SessionId() const {
+    return channel_->SessionId();
+  }
+
+  // Set up the ciphers to use for DTLS-SRTP. If this method is not called
+  // before DTLS starts, or |ciphers| is empty, SRTP keys won't be negotiated.
+  // This method should be called before SetupDtls.
+  virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers);
+
+  // Find out which DTLS-SRTP cipher was negotiated
+  virtual bool GetSrtpCipher(std::string* cipher);
+
+  virtual bool GetSslRole(rtc::SSLRole* role) const;
+  virtual bool SetSslRole(rtc::SSLRole role);
+
+  // Once DTLS has been established, this method retrieves the certificate in
+  // use by the remote peer, for use in external identity verification.
+  virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const;
+
+  // Once DTLS has established (i.e., this channel is writable), this method
+  // extracts the keys negotiated during the DTLS handshake, for use in external
+  // encryption. DTLS-SRTP uses this to extract the needed SRTP keys.
+  // See the SSLStreamAdapter documentation for info on the specific parameters.
+  virtual bool ExportKeyingMaterial(const std::string& label,
+                                    const uint8* context,
+                                    size_t context_len,
+                                    bool use_context,
+                                    uint8* result,
+                                    size_t result_len) {
+    return (dtls_.get()) ? dtls_->ExportKeyingMaterial(label, context,
+                                                       context_len,
+                                                       use_context,
+                                                       result, result_len)
+        : false;
+  }
+
+  // TransportChannelImpl calls.
+  virtual Transport* GetTransport() {
+    return transport_;
+  }
+  virtual void SetIceTiebreaker(uint64 tiebreaker) {
+    channel_->SetIceTiebreaker(tiebreaker);
+  }
+  virtual bool GetIceProtocolType(IceProtocolType* type) const {
+    return channel_->GetIceProtocolType(type);
+  }
+  virtual void SetIceProtocolType(IceProtocolType type) {
+    channel_->SetIceProtocolType(type);
+  }
+  virtual void SetIceCredentials(const std::string& ice_ufrag,
+                                 const std::string& ice_pwd) {
+    channel_->SetIceCredentials(ice_ufrag, ice_pwd);
+  }
+  virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
+                                       const std::string& ice_pwd) {
+    channel_->SetRemoteIceCredentials(ice_ufrag, ice_pwd);
+  }
+  virtual void SetRemoteIceMode(IceMode mode) {
+    channel_->SetRemoteIceMode(mode);
+  }
+
+  virtual void Connect();
+  virtual void Reset();
+
+  virtual void OnSignalingReady() {
+    channel_->OnSignalingReady();
+  }
+  virtual void OnCandidate(const Candidate& candidate) {
+    channel_->OnCandidate(candidate);
+  }
+
+  // Needed by DtlsTransport.
+  TransportChannelImpl* channel() { return channel_; }
+
+ private:
+  void OnReadableState(TransportChannel* channel);
+  void OnWritableState(TransportChannel* channel);
+  void OnReadPacket(TransportChannel* channel, const char* data, size_t size,
+                    const rtc::PacketTime& packet_time, int flags);
+  void OnReadyToSend(TransportChannel* channel);
+  void OnDtlsEvent(rtc::StreamInterface* stream_, int sig, int err);
+  bool SetupDtls();
+  bool MaybeStartDtls();
+  bool HandleDtlsPacket(const char* data, size_t size);
+  void OnRequestSignaling(TransportChannelImpl* channel);
+  void OnCandidateReady(TransportChannelImpl* channel, const Candidate& c);
+  void OnCandidatesAllocationDone(TransportChannelImpl* channel);
+  void OnRoleConflict(TransportChannelImpl* channel);
+  void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
+  void OnConnectionRemoved(TransportChannelImpl* channel);
+
+  Transport* transport_;  // The transport_ that created us.
+  rtc::Thread* worker_thread_;  // Everything should occur on this thread.
+  TransportChannelImpl* channel_;  // Underlying channel, owned by transport_.
+  rtc::scoped_ptr<rtc::SSLStreamAdapter> dtls_;  // The DTLS stream
+  StreamInterfaceChannel* downward_;  // Wrapper for channel_, owned by dtls_.
+  std::vector<std::string> srtp_ciphers_;  // SRTP ciphers to use with DTLS.
+  State dtls_state_;
+  rtc::SSLIdentity* local_identity_;
+  rtc::SSLRole ssl_role_;
+  rtc::Buffer remote_fingerprint_value_;
+  std::string remote_fingerprint_algorithm_;
+
+  DISALLOW_COPY_AND_ASSIGN(DtlsTransportChannelWrapper);
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_DTLSTRANSPORTCHANNEL_H_
diff --git a/p2p/base/dtlstransportchannel_unittest.cc b/p2p/base/dtlstransportchannel_unittest.cc
new file mode 100644
index 0000000..52f8c1e
--- /dev/null
+++ b/p2p/base/dtlstransportchannel_unittest.cc
@@ -0,0 +1,823 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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 <set>
+
+#include "webrtc/p2p/base/dtlstransport.h"
+#include "webrtc/p2p/base/fakesession.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/dscp.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/sslidentity.h"
+#include "webrtc/base/sslstreamadapter.h"
+#include "webrtc/base/stringutils.h"
+#include "webrtc/base/thread.h"
+
+#define MAYBE_SKIP_TEST(feature)                    \
+  if (!(rtc::SSLStreamAdapter::feature())) {  \
+    LOG(LS_INFO) << "Feature disabled... skipping"; \
+    return;                                         \
+  }
+
+static const char AES_CM_128_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80";
+static const char kIceUfrag1[] = "TESTICEUFRAG0001";
+static const char kIcePwd1[] = "TESTICEPWD00000000000001";
+static const size_t kPacketNumOffset = 8;
+static const size_t kPacketHeaderLen = 12;
+
+static bool IsRtpLeadByte(uint8 b) {
+  return ((b & 0xC0) == 0x80);
+}
+
+using cricket::ConnectionRole;
+
+enum Flags { NF_REOFFER = 0x1, NF_EXPECT_FAILURE = 0x2 };
+
+class DtlsTestClient : public sigslot::has_slots<> {
+ public:
+  DtlsTestClient(const std::string& name,
+                 rtc::Thread* signaling_thread,
+                 rtc::Thread* worker_thread) :
+      name_(name),
+      signaling_thread_(signaling_thread),
+      worker_thread_(worker_thread),
+      protocol_(cricket::ICEPROTO_GOOGLE),
+      packet_size_(0),
+      use_dtls_srtp_(false),
+      negotiated_dtls_(false),
+      received_dtls_client_hello_(false),
+      received_dtls_server_hello_(false) {
+  }
+  void SetIceProtocol(cricket::TransportProtocol proto) {
+    protocol_ = proto;
+  }
+  void CreateIdentity() {
+    identity_.reset(rtc::SSLIdentity::Generate(name_));
+  }
+  rtc::SSLIdentity* identity() { return identity_.get(); }
+  void SetupSrtp() {
+    ASSERT(identity_.get() != NULL);
+    use_dtls_srtp_ = true;
+  }
+  void SetupChannels(int count, cricket::IceRole role) {
+    transport_.reset(new cricket::DtlsTransport<cricket::FakeTransport>(
+        signaling_thread_, worker_thread_, "dtls content name", NULL,
+        identity_.get()));
+    transport_->SetAsync(true);
+    transport_->SetIceRole(role);
+    transport_->SetIceTiebreaker(
+        (role == cricket::ICEROLE_CONTROLLING) ? 1 : 2);
+    transport_->SignalWritableState.connect(this,
+        &DtlsTestClient::OnTransportWritableState);
+
+    for (int i = 0; i < count; ++i) {
+      cricket::DtlsTransportChannelWrapper* channel =
+          static_cast<cricket::DtlsTransportChannelWrapper*>(
+              transport_->CreateChannel(i));
+      ASSERT_TRUE(channel != NULL);
+      channel->SignalWritableState.connect(this,
+        &DtlsTestClient::OnTransportChannelWritableState);
+      channel->SignalReadPacket.connect(this,
+        &DtlsTestClient::OnTransportChannelReadPacket);
+      channels_.push_back(channel);
+
+      // Hook the raw packets so that we can verify they are encrypted.
+      channel->channel()->SignalReadPacket.connect(
+          this, &DtlsTestClient::OnFakeTransportChannelReadPacket);
+    }
+  }
+
+  cricket::Transport* transport() { return transport_.get(); }
+
+  cricket::FakeTransportChannel* GetFakeChannel(int component) {
+    cricket::TransportChannelImpl* ch = transport_->GetChannel(component);
+    cricket::DtlsTransportChannelWrapper* wrapper =
+        static_cast<cricket::DtlsTransportChannelWrapper*>(ch);
+    return (wrapper) ?
+        static_cast<cricket::FakeTransportChannel*>(wrapper->channel()) : NULL;
+  }
+
+  // Offer DTLS if we have an identity; pass in a remote fingerprint only if
+  // both sides support DTLS.
+  void Negotiate(DtlsTestClient* peer, cricket::ContentAction action,
+                 ConnectionRole local_role, ConnectionRole remote_role,
+                 int flags) {
+    Negotiate(identity_.get(), (identity_) ? peer->identity_.get() : NULL,
+              action, local_role, remote_role, flags);
+  }
+
+  // Allow any DTLS configuration to be specified (including invalid ones).
+  void Negotiate(rtc::SSLIdentity* local_identity,
+                 rtc::SSLIdentity* remote_identity,
+                 cricket::ContentAction action,
+                 ConnectionRole local_role,
+                 ConnectionRole remote_role,
+                 int flags) {
+    rtc::scoped_ptr<rtc::SSLFingerprint> local_fingerprint;
+    rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint;
+    if (local_identity) {
+      local_fingerprint.reset(rtc::SSLFingerprint::Create(
+          rtc::DIGEST_SHA_1, local_identity));
+      ASSERT_TRUE(local_fingerprint.get() != NULL);
+    }
+    if (remote_identity) {
+      remote_fingerprint.reset(rtc::SSLFingerprint::Create(
+          rtc::DIGEST_SHA_1, remote_identity));
+      ASSERT_TRUE(remote_fingerprint.get() != NULL);
+    }
+
+    if (use_dtls_srtp_ && !(flags & NF_REOFFER)) {
+      // SRTP ciphers will be set only in the beginning.
+      for (std::vector<cricket::DtlsTransportChannelWrapper*>::iterator it =
+           channels_.begin(); it != channels_.end(); ++it) {
+        std::vector<std::string> ciphers;
+        ciphers.push_back(AES_CM_128_HMAC_SHA1_80);
+        ASSERT_TRUE((*it)->SetSrtpCiphers(ciphers));
+      }
+    }
+
+    std::string transport_type = (protocol_ == cricket::ICEPROTO_GOOGLE) ?
+        cricket::NS_GINGLE_P2P : cricket::NS_JINGLE_ICE_UDP;
+    cricket::TransportDescription local_desc(
+        transport_type, std::vector<std::string>(), kIceUfrag1, kIcePwd1,
+        cricket::ICEMODE_FULL, local_role,
+         // If remote if the offerer and has no DTLS support, answer will be
+        // without any fingerprint.
+        (action == cricket::CA_ANSWER && !remote_identity) ?
+            NULL : local_fingerprint.get(),
+        cricket::Candidates());
+
+    cricket::TransportDescription remote_desc(
+        transport_type, std::vector<std::string>(), kIceUfrag1, kIcePwd1,
+        cricket::ICEMODE_FULL, remote_role, remote_fingerprint.get(),
+        cricket::Candidates());
+
+    bool expect_success = (flags & NF_EXPECT_FAILURE) ? false : true;
+    // If |expect_success| is false, expect SRTD or SLTD to fail when
+    // content action is CA_ANSWER.
+    if (action == cricket::CA_OFFER) {
+      ASSERT_TRUE(transport_->SetLocalTransportDescription(
+          local_desc, cricket::CA_OFFER, NULL));
+      ASSERT_EQ(expect_success, transport_->SetRemoteTransportDescription(
+          remote_desc, cricket::CA_ANSWER, NULL));
+    } else {
+      ASSERT_TRUE(transport_->SetRemoteTransportDescription(
+          remote_desc, cricket::CA_OFFER, NULL));
+      ASSERT_EQ(expect_success, transport_->SetLocalTransportDescription(
+          local_desc, cricket::CA_ANSWER, NULL));
+    }
+    negotiated_dtls_ = (local_identity && remote_identity);
+  }
+
+  bool Connect(DtlsTestClient* peer) {
+    transport_->ConnectChannels();
+    transport_->SetDestination(peer->transport_.get());
+    return true;
+  }
+
+  bool writable() const { return transport_->writable(); }
+
+  void CheckRole(rtc::SSLRole role) {
+    if (role == rtc::SSL_CLIENT) {
+      ASSERT_FALSE(received_dtls_client_hello_);
+      ASSERT_TRUE(received_dtls_server_hello_);
+    } else {
+      ASSERT_TRUE(received_dtls_client_hello_);
+      ASSERT_FALSE(received_dtls_server_hello_);
+    }
+  }
+
+  void CheckSrtp(const std::string& expected_cipher) {
+    for (std::vector<cricket::DtlsTransportChannelWrapper*>::iterator it =
+           channels_.begin(); it != channels_.end(); ++it) {
+      std::string cipher;
+
+      bool rv = (*it)->GetSrtpCipher(&cipher);
+      if (negotiated_dtls_ && !expected_cipher.empty()) {
+        ASSERT_TRUE(rv);
+
+        ASSERT_EQ(cipher, expected_cipher);
+      } else {
+        ASSERT_FALSE(rv);
+      }
+    }
+  }
+
+  void SendPackets(size_t channel, size_t size, size_t count, bool srtp) {
+    ASSERT(channel < channels_.size());
+    rtc::scoped_ptr<char[]> packet(new char[size]);
+    size_t sent = 0;
+    do {
+      // Fill the packet with a known value and a sequence number to check
+      // against, and make sure that it doesn't look like DTLS.
+      memset(packet.get(), sent & 0xff, size);
+      packet[0] = (srtp) ? 0x80 : 0x00;
+      rtc::SetBE32(packet.get() + kPacketNumOffset,
+                         static_cast<uint32>(sent));
+
+      // Only set the bypass flag if we've activated DTLS.
+      int flags = (identity_.get() && srtp) ? cricket::PF_SRTP_BYPASS : 0;
+      rtc::PacketOptions packet_options;
+      int rv = channels_[channel]->SendPacket(
+          packet.get(), size, packet_options, flags);
+      ASSERT_GT(rv, 0);
+      ASSERT_EQ(size, static_cast<size_t>(rv));
+      ++sent;
+    } while (sent < count);
+  }
+
+  int SendInvalidSrtpPacket(size_t channel, size_t size) {
+    ASSERT(channel < channels_.size());
+    rtc::scoped_ptr<char[]> packet(new char[size]);
+    // Fill the packet with 0 to form an invalid SRTP packet.
+    memset(packet.get(), 0, size);
+
+    rtc::PacketOptions packet_options;
+    return channels_[channel]->SendPacket(
+        packet.get(), size, packet_options, cricket::PF_SRTP_BYPASS);
+  }
+
+  void ExpectPackets(size_t channel, size_t size) {
+    packet_size_ = size;
+    received_.clear();
+  }
+
+  size_t NumPacketsReceived() {
+    return received_.size();
+  }
+
+  bool VerifyPacket(const char* data, size_t size, uint32* out_num) {
+    if (size != packet_size_ ||
+        (data[0] != 0 && static_cast<uint8>(data[0]) != 0x80)) {
+      return false;
+    }
+    uint32 packet_num = rtc::GetBE32(data + kPacketNumOffset);
+    for (size_t i = kPacketHeaderLen; i < size; ++i) {
+      if (static_cast<uint8>(data[i]) != (packet_num & 0xff)) {
+        return false;
+      }
+    }
+    if (out_num) {
+      *out_num = packet_num;
+    }
+    return true;
+  }
+  bool VerifyEncryptedPacket(const char* data, size_t size) {
+    // This is an encrypted data packet; let's make sure it's mostly random;
+    // less than 10% of the bytes should be equal to the cleartext packet.
+    if (size <= packet_size_) {
+      return false;
+    }
+    uint32 packet_num = rtc::GetBE32(data + kPacketNumOffset);
+    int num_matches = 0;
+    for (size_t i = kPacketNumOffset; i < size; ++i) {
+      if (static_cast<uint8>(data[i]) == (packet_num & 0xff)) {
+        ++num_matches;
+      }
+    }
+    return (num_matches < ((static_cast<int>(size) - 5) / 10));
+  }
+
+  // Transport callbacks
+  void OnTransportWritableState(cricket::Transport* transport) {
+    LOG(LS_INFO) << name_ << ": is writable";
+  }
+
+  // Transport channel callbacks
+  void OnTransportChannelWritableState(cricket::TransportChannel* channel) {
+    LOG(LS_INFO) << name_ << ": Channel '" << channel->component()
+                 << "' is writable";
+  }
+
+  void OnTransportChannelReadPacket(cricket::TransportChannel* channel,
+                                    const char* data, size_t size,
+                                    const rtc::PacketTime& packet_time,
+                                    int flags) {
+    uint32 packet_num = 0;
+    ASSERT_TRUE(VerifyPacket(data, size, &packet_num));
+    received_.insert(packet_num);
+    // Only DTLS-SRTP packets should have the bypass flag set.
+    int expected_flags = (identity_.get() && IsRtpLeadByte(data[0])) ?
+        cricket::PF_SRTP_BYPASS : 0;
+    ASSERT_EQ(expected_flags, flags);
+  }
+
+  // Hook into the raw packet stream to make sure DTLS packets are encrypted.
+  void OnFakeTransportChannelReadPacket(cricket::TransportChannel* channel,
+                                        const char* data, size_t size,
+                                        const rtc::PacketTime& time,
+                                        int flags) {
+    // Flags shouldn't be set on the underlying TransportChannel packets.
+    ASSERT_EQ(0, flags);
+
+    // Look at the handshake packets to see what role we played.
+    // Check that non-handshake packets are DTLS data or SRTP bypass.
+    if (negotiated_dtls_) {
+      if (data[0] == 22 && size > 17) {
+        if (data[13] == 1) {
+          received_dtls_client_hello_ = true;
+        } else if (data[13] == 2) {
+          received_dtls_server_hello_ = true;
+        }
+      } else if (!(data[0] >= 20 && data[0] <= 22)) {
+        ASSERT_TRUE(data[0] == 23 || IsRtpLeadByte(data[0]));
+        if (data[0] == 23) {
+          ASSERT_TRUE(VerifyEncryptedPacket(data, size));
+        } else if (IsRtpLeadByte(data[0])) {
+          ASSERT_TRUE(VerifyPacket(data, size, NULL));
+        }
+      }
+    }
+  }
+
+ private:
+  std::string name_;
+  rtc::Thread* signaling_thread_;
+  rtc::Thread* worker_thread_;
+  cricket::TransportProtocol protocol_;
+  rtc::scoped_ptr<rtc::SSLIdentity> identity_;
+  rtc::scoped_ptr<cricket::FakeTransport> transport_;
+  std::vector<cricket::DtlsTransportChannelWrapper*> channels_;
+  size_t packet_size_;
+  std::set<int> received_;
+  bool use_dtls_srtp_;
+  bool negotiated_dtls_;
+  bool received_dtls_client_hello_;
+  bool received_dtls_server_hello_;
+};
+
+
+class DtlsTransportChannelTest : public testing::Test {
+ public:
+  DtlsTransportChannelTest() :
+      client1_("P1", rtc::Thread::Current(),
+               rtc::Thread::Current()),
+      client2_("P2", rtc::Thread::Current(),
+               rtc::Thread::Current()),
+      channel_ct_(1),
+      use_dtls_(false),
+      use_dtls_srtp_(false) {
+  }
+
+  void SetChannelCount(size_t channel_ct) {
+    channel_ct_ = static_cast<int>(channel_ct);
+  }
+  void PrepareDtls(bool c1, bool c2) {
+    if (c1) {
+      client1_.CreateIdentity();
+    }
+    if (c2) {
+      client2_.CreateIdentity();
+    }
+    if (c1 && c2)
+      use_dtls_ = true;
+  }
+  void PrepareDtlsSrtp(bool c1, bool c2) {
+    if (!use_dtls_)
+      return;
+
+    if (c1)
+      client1_.SetupSrtp();
+    if (c2)
+      client2_.SetupSrtp();
+
+    if (c1 && c2)
+      use_dtls_srtp_ = true;
+  }
+
+  bool Connect(ConnectionRole client1_role, ConnectionRole client2_role) {
+    Negotiate(client1_role, client2_role);
+
+    bool rv = client1_.Connect(&client2_);
+    EXPECT_TRUE(rv);
+    if (!rv)
+      return false;
+
+    EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000);
+    if (!client1_.writable() || !client2_.writable())
+      return false;
+
+    // Check that we used the right roles.
+    if (use_dtls_) {
+      rtc::SSLRole client1_ssl_role =
+          (client1_role == cricket::CONNECTIONROLE_ACTIVE ||
+           (client2_role == cricket::CONNECTIONROLE_PASSIVE &&
+            client1_role == cricket::CONNECTIONROLE_ACTPASS)) ?
+              rtc::SSL_CLIENT : rtc::SSL_SERVER;
+
+      rtc::SSLRole client2_ssl_role =
+          (client2_role == cricket::CONNECTIONROLE_ACTIVE ||
+           (client1_role == cricket::CONNECTIONROLE_PASSIVE &&
+            client2_role == cricket::CONNECTIONROLE_ACTPASS)) ?
+              rtc::SSL_CLIENT : rtc::SSL_SERVER;
+
+      client1_.CheckRole(client1_ssl_role);
+      client2_.CheckRole(client2_ssl_role);
+    }
+
+    // Check that we negotiated the right ciphers.
+    if (use_dtls_srtp_) {
+      client1_.CheckSrtp(AES_CM_128_HMAC_SHA1_80);
+      client2_.CheckSrtp(AES_CM_128_HMAC_SHA1_80);
+    } else {
+      client1_.CheckSrtp("");
+      client2_.CheckSrtp("");
+    }
+
+    return true;
+  }
+
+  bool Connect() {
+    // By default, Client1 will be Server and Client2 will be Client.
+    return Connect(cricket::CONNECTIONROLE_ACTPASS,
+                   cricket::CONNECTIONROLE_ACTIVE);
+  }
+
+  void Negotiate() {
+    Negotiate(cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTIVE);
+  }
+
+  void Negotiate(ConnectionRole client1_role, ConnectionRole client2_role) {
+    client1_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLING);
+    client2_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLED);
+    // Expect success from SLTD and SRTD.
+    client1_.Negotiate(&client2_, cricket::CA_OFFER,
+                       client1_role, client2_role, 0);
+    client2_.Negotiate(&client1_, cricket::CA_ANSWER,
+                       client2_role, client1_role, 0);
+  }
+
+  // Negotiate with legacy client |client2|. Legacy client doesn't use setup
+  // attributes, except NONE.
+  void NegotiateWithLegacy() {
+    client1_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLING);
+    client2_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLED);
+    // Expect success from SLTD and SRTD.
+    client1_.Negotiate(&client2_, cricket::CA_OFFER,
+                       cricket::CONNECTIONROLE_ACTPASS,
+                       cricket::CONNECTIONROLE_NONE, 0);
+    client2_.Negotiate(&client1_, cricket::CA_ANSWER,
+                       cricket::CONNECTIONROLE_ACTIVE,
+                       cricket::CONNECTIONROLE_NONE, 0);
+  }
+
+  void Renegotiate(DtlsTestClient* reoffer_initiator,
+                   ConnectionRole client1_role, ConnectionRole client2_role,
+                   int flags) {
+    if (reoffer_initiator == &client1_) {
+      client1_.Negotiate(&client2_, cricket::CA_OFFER,
+                         client1_role, client2_role, flags);
+      client2_.Negotiate(&client1_, cricket::CA_ANSWER,
+                         client2_role, client1_role, flags);
+    } else {
+      client2_.Negotiate(&client1_, cricket::CA_OFFER,
+                         client2_role, client1_role, flags);
+      client1_.Negotiate(&client2_, cricket::CA_ANSWER,
+                         client1_role, client2_role, flags);
+    }
+  }
+
+  void TestTransfer(size_t channel, size_t size, size_t count, bool srtp) {
+    LOG(LS_INFO) << "Expect packets, size=" << size;
+    client2_.ExpectPackets(channel, size);
+    client1_.SendPackets(channel, size, count, srtp);
+    EXPECT_EQ_WAIT(count, client2_.NumPacketsReceived(), 10000);
+  }
+
+ protected:
+  DtlsTestClient client1_;
+  DtlsTestClient client2_;
+  int channel_ct_;
+  bool use_dtls_;
+  bool use_dtls_srtp_;
+};
+
+// Test that transport negotiation of ICE, no DTLS works properly.
+TEST_F(DtlsTransportChannelTest, TestChannelSetupIce) {
+  client1_.SetIceProtocol(cricket::ICEPROTO_RFC5245);
+  client2_.SetIceProtocol(cricket::ICEPROTO_RFC5245);
+  Negotiate();
+  cricket::FakeTransportChannel* channel1 = client1_.GetFakeChannel(0);
+  cricket::FakeTransportChannel* channel2 = client2_.GetFakeChannel(0);
+  ASSERT_TRUE(channel1 != NULL);
+  ASSERT_TRUE(channel2 != NULL);
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel1->GetIceRole());
+  EXPECT_EQ(1U, channel1->IceTiebreaker());
+  EXPECT_EQ(cricket::ICEPROTO_RFC5245, channel1->protocol());
+  EXPECT_EQ(kIceUfrag1, channel1->ice_ufrag());
+  EXPECT_EQ(kIcePwd1, channel1->ice_pwd());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel2->GetIceRole());
+  EXPECT_EQ(2U, channel2->IceTiebreaker());
+  EXPECT_EQ(cricket::ICEPROTO_RFC5245, channel2->protocol());
+}
+
+// Test that transport negotiation of GICE, no DTLS works properly.
+TEST_F(DtlsTransportChannelTest, TestChannelSetupGice) {
+  client1_.SetIceProtocol(cricket::ICEPROTO_GOOGLE);
+  client2_.SetIceProtocol(cricket::ICEPROTO_GOOGLE);
+  Negotiate();
+  cricket::FakeTransportChannel* channel1 = client1_.GetFakeChannel(0);
+  cricket::FakeTransportChannel* channel2 = client2_.GetFakeChannel(0);
+  ASSERT_TRUE(channel1 != NULL);
+  ASSERT_TRUE(channel2 != NULL);
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel1->GetIceRole());
+  EXPECT_EQ(1U, channel1->IceTiebreaker());
+  EXPECT_EQ(cricket::ICEPROTO_GOOGLE, channel1->protocol());
+  EXPECT_EQ(kIceUfrag1, channel1->ice_ufrag());
+  EXPECT_EQ(kIcePwd1, channel1->ice_pwd());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel2->GetIceRole());
+  EXPECT_EQ(2U, channel2->IceTiebreaker());
+  EXPECT_EQ(cricket::ICEPROTO_GOOGLE, channel2->protocol());
+}
+
+// Connect without DTLS, and transfer some data.
+TEST_F(DtlsTransportChannelTest, TestTransfer) {
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, false);
+}
+
+// Create two channels without DTLS, and transfer some data.
+TEST_F(DtlsTransportChannelTest, TestTransferTwoChannels) {
+  SetChannelCount(2);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, false);
+  TestTransfer(1, 1000, 100, false);
+}
+
+// Connect without DTLS, and transfer SRTP data.
+TEST_F(DtlsTransportChannelTest, TestTransferSrtp) {
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, true);
+}
+
+// Create two channels without DTLS, and transfer SRTP data.
+TEST_F(DtlsTransportChannelTest, TestTransferSrtpTwoChannels) {
+  SetChannelCount(2);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+}
+
+// Connect with DTLS, and transfer some data.
+TEST_F(DtlsTransportChannelTest, TestTransferDtls) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  PrepareDtls(true, true);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, false);
+}
+
+// Create two channels with DTLS, and transfer some data.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsTwoChannels) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, false);
+  TestTransfer(1, 1000, 100, false);
+}
+
+// Connect with A doing DTLS and B not, and transfer some data.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsRejected) {
+  PrepareDtls(true, false);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, false);
+}
+
+// Connect with B doing DTLS and A not, and transfer some data.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsNotOffered) {
+  PrepareDtls(false, true);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, false);
+}
+
+// Connect with DTLS, negotiate DTLS-SRTP, and transfer SRTP using bypass.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtp) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, true);
+}
+
+// Connect with DTLS-SRTP, transfer an invalid SRTP packet, and expects -1
+// returned.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsInvalidSrtpPacket) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  ASSERT_TRUE(Connect());
+  int result = client1_.SendInvalidSrtpPacket(0, 100);
+  ASSERT_EQ(-1, result);
+}
+
+// Connect with DTLS. A does DTLS-SRTP but B does not.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpRejected) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, false);
+  ASSERT_TRUE(Connect());
+}
+
+// Connect with DTLS. B does DTLS-SRTP but A does not.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpNotOffered) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(false, true);
+  ASSERT_TRUE(Connect());
+}
+
+// Create two channels with DTLS, negotiate DTLS-SRTP, and transfer bypass SRTP.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpTwoChannels) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+}
+
+// Create a single channel with DTLS, and send normal data and SRTP data on it.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpDemux) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  ASSERT_TRUE(Connect());
+  TestTransfer(0, 1000, 100, false);
+  TestTransfer(0, 1000, 100, true);
+}
+
+// Testing when the remote is passive.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsAnswererIsPassive) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS,
+                      cricket::CONNECTIONROLE_PASSIVE));
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+}
+
+// Testing with the legacy DTLS client which doesn't use setup attribute.
+// In this case legacy is the answerer.
+TEST_F(DtlsTransportChannelTest, TestDtlsSetupWithLegacyAsAnswerer) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  PrepareDtls(true, true);
+  NegotiateWithLegacy();
+  rtc::SSLRole channel1_role;
+  rtc::SSLRole channel2_role;
+  EXPECT_TRUE(client1_.transport()->GetSslRole(&channel1_role));
+  EXPECT_TRUE(client2_.transport()->GetSslRole(&channel2_role));
+  EXPECT_EQ(rtc::SSL_SERVER, channel1_role);
+  EXPECT_EQ(rtc::SSL_CLIENT, channel2_role);
+}
+
+// Testing re offer/answer after the session is estbalished. Roles will be
+// kept same as of the previous negotiation.
+TEST_F(DtlsTransportChannelTest, TestDtlsReOfferFromOfferer) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  // Initial role for client1 is ACTPASS and client2 is ACTIVE.
+  ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS,
+                      cricket::CONNECTIONROLE_ACTIVE));
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+  // Using input roles for the re-offer.
+  Renegotiate(&client1_, cricket::CONNECTIONROLE_ACTPASS,
+              cricket::CONNECTIONROLE_ACTIVE, NF_REOFFER);
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+}
+
+TEST_F(DtlsTransportChannelTest, TestDtlsReOfferFromAnswerer) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  // Initial role for client1 is ACTPASS and client2 is ACTIVE.
+  ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS,
+                      cricket::CONNECTIONROLE_ACTIVE));
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+  // Using input roles for the re-offer.
+  Renegotiate(&client2_, cricket::CONNECTIONROLE_PASSIVE,
+              cricket::CONNECTIONROLE_ACTPASS, NF_REOFFER);
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+}
+
+// Test that any change in role after the intial setup will result in failure.
+TEST_F(DtlsTransportChannelTest, TestDtlsRoleReversal) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS,
+                      cricket::CONNECTIONROLE_PASSIVE));
+
+  // Renegotiate from client2 with actpass and client1 as active.
+  Renegotiate(&client2_, cricket::CONNECTIONROLE_ACTPASS,
+              cricket::CONNECTIONROLE_ACTIVE,
+              NF_REOFFER | NF_EXPECT_FAILURE);
+}
+
+// Test that using different setup attributes which results in similar ssl
+// role as the initial negotiation will result in success.
+TEST_F(DtlsTransportChannelTest, TestDtlsReOfferWithDifferentSetupAttr) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS,
+                      cricket::CONNECTIONROLE_PASSIVE));
+  // Renegotiate from client2 with actpass and client1 as active.
+  Renegotiate(&client2_, cricket::CONNECTIONROLE_ACTIVE,
+              cricket::CONNECTIONROLE_ACTPASS, NF_REOFFER);
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+}
+
+// Test that re-negotiation can be started before the clients become connected
+// in the first negotiation.
+TEST_F(DtlsTransportChannelTest, TestRenegotiateBeforeConnect) {
+  MAYBE_SKIP_TEST(HaveDtlsSrtp);
+  SetChannelCount(2);
+  PrepareDtls(true, true);
+  PrepareDtlsSrtp(true, true);
+  Negotiate();
+
+  Renegotiate(&client1_, cricket::CONNECTIONROLE_ACTPASS,
+              cricket::CONNECTIONROLE_ACTIVE, NF_REOFFER);
+  bool rv = client1_.Connect(&client2_);
+  EXPECT_TRUE(rv);
+  EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000);
+
+  TestTransfer(0, 1000, 100, true);
+  TestTransfer(1, 1000, 100, true);
+}
+
+// Test Certificates state after negotiation but before connection.
+TEST_F(DtlsTransportChannelTest, TestCertificatesBeforeConnect) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  PrepareDtls(true, true);
+  Negotiate();
+
+  rtc::scoped_ptr<rtc::SSLIdentity> identity1;
+  rtc::scoped_ptr<rtc::SSLIdentity> identity2;
+  rtc::scoped_ptr<rtc::SSLCertificate> remote_cert1;
+  rtc::scoped_ptr<rtc::SSLCertificate> remote_cert2;
+
+  // After negotiation, each side has a distinct local certificate, but still no
+  // remote certificate, because connection has not yet occurred.
+  ASSERT_TRUE(client1_.transport()->GetIdentity(identity1.accept()));
+  ASSERT_TRUE(client2_.transport()->GetIdentity(identity2.accept()));
+  ASSERT_NE(identity1->certificate().ToPEMString(),
+            identity2->certificate().ToPEMString());
+  ASSERT_FALSE(
+      client1_.transport()->GetRemoteCertificate(remote_cert1.accept()));
+  ASSERT_FALSE(remote_cert1 != NULL);
+  ASSERT_FALSE(
+      client2_.transport()->GetRemoteCertificate(remote_cert2.accept()));
+  ASSERT_FALSE(remote_cert2 != NULL);
+}
+
+// Test Certificates state after connection.
+TEST_F(DtlsTransportChannelTest, TestCertificatesAfterConnect) {
+  MAYBE_SKIP_TEST(HaveDtls);
+  PrepareDtls(true, true);
+  ASSERT_TRUE(Connect());
+
+  rtc::scoped_ptr<rtc::SSLIdentity> identity1;
+  rtc::scoped_ptr<rtc::SSLIdentity> identity2;
+  rtc::scoped_ptr<rtc::SSLCertificate> remote_cert1;
+  rtc::scoped_ptr<rtc::SSLCertificate> remote_cert2;
+
+  // After connection, each side has a distinct local certificate.
+  ASSERT_TRUE(client1_.transport()->GetIdentity(identity1.accept()));
+  ASSERT_TRUE(client2_.transport()->GetIdentity(identity2.accept()));
+  ASSERT_NE(identity1->certificate().ToPEMString(),
+            identity2->certificate().ToPEMString());
+
+  // Each side's remote certificate is the other side's local certificate.
+  ASSERT_TRUE(
+      client1_.transport()->GetRemoteCertificate(remote_cert1.accept()));
+  ASSERT_EQ(remote_cert1->ToPEMString(),
+            identity2->certificate().ToPEMString());
+  ASSERT_TRUE(
+      client2_.transport()->GetRemoteCertificate(remote_cert2.accept()));
+  ASSERT_EQ(remote_cert2->ToPEMString(),
+            identity1->certificate().ToPEMString());
+}
diff --git a/p2p/base/fakesession.h b/p2p/base/fakesession.h
new file mode 100644
index 0000000..30bc981
--- /dev/null
+++ b/p2p/base/fakesession.h
@@ -0,0 +1,492 @@
+/*
+ *  Copyright 2009 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_P2P_BASE_FAKESESSION_H_
+#define WEBRTC_P2P_BASE_FAKESESSION_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/session.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannel.h"
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/base/fakesslidentity.h"
+#include "webrtc/base/messagequeue.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/sslfingerprint.h"
+
+namespace cricket {
+
+class FakeTransport;
+
+struct PacketMessageData : public rtc::MessageData {
+  PacketMessageData(const char* data, size_t len) : packet(data, len) {
+  }
+  rtc::Buffer packet;
+};
+
+// Fake transport channel class, which can be passed to anything that needs a
+// transport channel. Can be informed of another FakeTransportChannel via
+// SetDestination.
+class FakeTransportChannel : public TransportChannelImpl,
+                             public rtc::MessageHandler {
+ public:
+  explicit FakeTransportChannel(Transport* transport,
+                                const std::string& content_name,
+                                int component)
+      : TransportChannelImpl(content_name, component),
+        transport_(transport),
+        dest_(NULL),
+        state_(STATE_INIT),
+        async_(false),
+        identity_(NULL),
+        do_dtls_(false),
+        role_(ICEROLE_UNKNOWN),
+        tiebreaker_(0),
+        ice_proto_(ICEPROTO_HYBRID),
+        remote_ice_mode_(ICEMODE_FULL),
+        dtls_fingerprint_("", NULL, 0),
+        ssl_role_(rtc::SSL_CLIENT),
+        connection_count_(0) {
+  }
+  ~FakeTransportChannel() {
+    Reset();
+  }
+
+  uint64 IceTiebreaker() const { return tiebreaker_; }
+  TransportProtocol protocol() const { return ice_proto_; }
+  IceMode remote_ice_mode() const { return remote_ice_mode_; }
+  const std::string& ice_ufrag() const { return ice_ufrag_; }
+  const std::string& ice_pwd() const { return ice_pwd_; }
+  const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; }
+  const std::string& remote_ice_pwd() const { return remote_ice_pwd_; }
+  const rtc::SSLFingerprint& dtls_fingerprint() const {
+    return dtls_fingerprint_;
+  }
+
+  void SetAsync(bool async) {
+    async_ = async;
+  }
+
+  virtual Transport* GetTransport() {
+    return transport_;
+  }
+
+  virtual void SetIceRole(IceRole role) { role_ = role; }
+  virtual IceRole GetIceRole() const { return role_; }
+  virtual size_t GetConnectionCount() const { return connection_count_; }
+  virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
+  virtual bool GetIceProtocolType(IceProtocolType* type) const {
+    *type = ice_proto_;
+    return true;
+  }
+  virtual void SetIceProtocolType(IceProtocolType type) { ice_proto_ = type; }
+  virtual void SetIceCredentials(const std::string& ice_ufrag,
+                                 const std::string& ice_pwd) {
+    ice_ufrag_ = ice_ufrag;
+    ice_pwd_ = ice_pwd;
+  }
+  virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
+                                       const std::string& ice_pwd) {
+    remote_ice_ufrag_ = ice_ufrag;
+    remote_ice_pwd_ = ice_pwd;
+  }
+
+  virtual void SetRemoteIceMode(IceMode mode) { remote_ice_mode_ = mode; }
+  virtual bool SetRemoteFingerprint(const std::string& alg, const uint8* digest,
+                                    size_t digest_len) {
+    dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len);
+    return true;
+  }
+  virtual bool SetSslRole(rtc::SSLRole role) {
+    ssl_role_ = role;
+    return true;
+  }
+  virtual bool GetSslRole(rtc::SSLRole* role) const {
+    *role = ssl_role_;
+    return true;
+  }
+
+  virtual void Connect() {
+    if (state_ == STATE_INIT) {
+      state_ = STATE_CONNECTING;
+    }
+  }
+  virtual void Reset() {
+    if (state_ != STATE_INIT) {
+      state_ = STATE_INIT;
+      if (dest_) {
+        dest_->state_ = STATE_INIT;
+        dest_->dest_ = NULL;
+        dest_ = NULL;
+      }
+    }
+  }
+
+  void SetWritable(bool writable) {
+    set_writable(writable);
+  }
+
+  void SetDestination(FakeTransportChannel* dest) {
+    if (state_ == STATE_CONNECTING && dest) {
+      // This simulates the delivery of candidates.
+      dest_ = dest;
+      dest_->dest_ = this;
+      if (identity_ && dest_->identity_) {
+        do_dtls_ = true;
+        dest_->do_dtls_ = true;
+        NegotiateSrtpCiphers();
+      }
+      state_ = STATE_CONNECTED;
+      dest_->state_ = STATE_CONNECTED;
+      set_writable(true);
+      dest_->set_writable(true);
+    } else if (state_ == STATE_CONNECTED && !dest) {
+      // Simulates loss of connectivity, by asymmetrically forgetting dest_.
+      dest_ = NULL;
+      state_ = STATE_CONNECTING;
+      set_writable(false);
+    }
+  }
+
+  void SetConnectionCount(size_t connection_count) {
+    size_t old_connection_count = connection_count_;
+    connection_count_ = connection_count;
+    if (connection_count_ < old_connection_count)
+      SignalConnectionRemoved(this);
+  }
+
+  virtual int SendPacket(const char* data, size_t len,
+                         const rtc::PacketOptions& options, int flags) {
+    if (state_ != STATE_CONNECTED) {
+      return -1;
+    }
+
+    if (flags != PF_SRTP_BYPASS && flags != 0) {
+      return -1;
+    }
+
+    PacketMessageData* packet = new PacketMessageData(data, len);
+    if (async_) {
+      rtc::Thread::Current()->Post(this, 0, packet);
+    } else {
+      rtc::Thread::Current()->Send(this, 0, packet);
+    }
+    return static_cast<int>(len);
+  }
+  virtual int SetOption(rtc::Socket::Option opt, int value) {
+    return true;
+  }
+  virtual int GetError() {
+    return 0;
+  }
+
+  virtual void OnSignalingReady() {
+  }
+  virtual void OnCandidate(const Candidate& candidate) {
+  }
+
+  virtual void OnMessage(rtc::Message* msg) {
+    PacketMessageData* data = static_cast<PacketMessageData*>(
+        msg->pdata);
+    dest_->SignalReadPacket(dest_, data->packet.data(),
+                            data->packet.length(),
+                            rtc::CreatePacketTime(0), 0);
+    delete data;
+  }
+
+  bool SetLocalIdentity(rtc::SSLIdentity* identity) {
+    identity_ = identity;
+    return true;
+  }
+
+
+  void SetRemoteCertificate(rtc::FakeSSLCertificate* cert) {
+    remote_cert_ = cert;
+  }
+
+  virtual bool IsDtlsActive() const {
+    return do_dtls_;
+  }
+
+  virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) {
+    srtp_ciphers_ = ciphers;
+    return true;
+  }
+
+  virtual bool GetSrtpCipher(std::string* cipher) {
+    if (!chosen_srtp_cipher_.empty()) {
+      *cipher = chosen_srtp_cipher_;
+      return true;
+    }
+    return false;
+  }
+
+  virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const {
+    if (!identity_)
+      return false;
+
+    *identity = identity_->GetReference();
+    return true;
+  }
+
+  virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const {
+    if (!remote_cert_)
+      return false;
+
+    *cert = remote_cert_->GetReference();
+    return true;
+  }
+
+  virtual bool ExportKeyingMaterial(const std::string& label,
+                                    const uint8* context,
+                                    size_t context_len,
+                                    bool use_context,
+                                    uint8* result,
+                                    size_t result_len) {
+    if (!chosen_srtp_cipher_.empty()) {
+      memset(result, 0xff, result_len);
+      return true;
+    }
+
+    return false;
+  }
+
+  virtual void NegotiateSrtpCiphers() {
+    for (std::vector<std::string>::const_iterator it1 = srtp_ciphers_.begin();
+        it1 != srtp_ciphers_.end(); ++it1) {
+      for (std::vector<std::string>::const_iterator it2 =
+              dest_->srtp_ciphers_.begin();
+          it2 != dest_->srtp_ciphers_.end(); ++it2) {
+        if (*it1 == *it2) {
+          chosen_srtp_cipher_ = *it1;
+          dest_->chosen_srtp_cipher_ = *it2;
+          return;
+        }
+      }
+    }
+  }
+
+  virtual bool GetStats(ConnectionInfos* infos) OVERRIDE {
+    ConnectionInfo info;
+    infos->clear();
+    infos->push_back(info);
+    return true;
+  }
+
+ private:
+  enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED };
+  Transport* transport_;
+  FakeTransportChannel* dest_;
+  State state_;
+  bool async_;
+  rtc::SSLIdentity* identity_;
+  rtc::FakeSSLCertificate* remote_cert_;
+  bool do_dtls_;
+  std::vector<std::string> srtp_ciphers_;
+  std::string chosen_srtp_cipher_;
+  IceRole role_;
+  uint64 tiebreaker_;
+  IceProtocolType ice_proto_;
+  std::string ice_ufrag_;
+  std::string ice_pwd_;
+  std::string remote_ice_ufrag_;
+  std::string remote_ice_pwd_;
+  IceMode remote_ice_mode_;
+  rtc::SSLFingerprint dtls_fingerprint_;
+  rtc::SSLRole ssl_role_;
+  size_t connection_count_;
+};
+
+// Fake transport class, which can be passed to anything that needs a Transport.
+// Can be informed of another FakeTransport via SetDestination (low-tech way
+// of doing candidates)
+class FakeTransport : public Transport {
+ public:
+  typedef std::map<int, FakeTransportChannel*> ChannelMap;
+  FakeTransport(rtc::Thread* signaling_thread,
+                rtc::Thread* worker_thread,
+                const std::string& content_name,
+                PortAllocator* alllocator = NULL)
+      : Transport(signaling_thread, worker_thread,
+                  content_name, "test_type", NULL),
+      dest_(NULL),
+      async_(false),
+      identity_(NULL) {
+  }
+  ~FakeTransport() {
+    DestroyAllChannels();
+  }
+
+  const ChannelMap& channels() const { return channels_; }
+
+  void SetAsync(bool async) { async_ = async; }
+  void SetDestination(FakeTransport* dest) {
+    dest_ = dest;
+    for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
+         ++it) {
+      it->second->SetLocalIdentity(identity_);
+      SetChannelDestination(it->first, it->second);
+    }
+  }
+
+  void SetWritable(bool writable) {
+    for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
+         ++it) {
+      it->second->SetWritable(writable);
+    }
+  }
+
+  void set_identity(rtc::SSLIdentity* identity) {
+    identity_ = identity;
+  }
+
+  using Transport::local_description;
+  using Transport::remote_description;
+
+ protected:
+  virtual TransportChannelImpl* CreateTransportChannel(int component) {
+    if (channels_.find(component) != channels_.end()) {
+      return NULL;
+    }
+    FakeTransportChannel* channel =
+        new FakeTransportChannel(this, content_name(), component);
+    channel->SetAsync(async_);
+    SetChannelDestination(component, channel);
+    channels_[component] = channel;
+    return channel;
+  }
+  virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
+    channels_.erase(channel->component());
+    delete channel;
+  }
+  virtual void SetIdentity_w(rtc::SSLIdentity* identity) {
+    identity_ = identity;
+  }
+  virtual bool GetIdentity_w(rtc::SSLIdentity** identity) {
+    if (!identity_)
+      return false;
+
+    *identity = identity_->GetReference();
+    return true;
+  }
+
+ private:
+  FakeTransportChannel* GetFakeChannel(int component) {
+    ChannelMap::iterator it = channels_.find(component);
+    return (it != channels_.end()) ? it->second : NULL;
+  }
+  void SetChannelDestination(int component,
+                             FakeTransportChannel* channel) {
+    FakeTransportChannel* dest_channel = NULL;
+    if (dest_) {
+      dest_channel = dest_->GetFakeChannel(component);
+      if (dest_channel) {
+        dest_channel->SetLocalIdentity(dest_->identity_);
+      }
+    }
+    channel->SetDestination(dest_channel);
+  }
+
+  // Note, this is distinct from the Channel map owned by Transport.
+  // This map just tracks the FakeTransportChannels created by this class.
+  ChannelMap channels_;
+  FakeTransport* dest_;
+  bool async_;
+  rtc::SSLIdentity* identity_;
+};
+
+// Fake session class, which can be passed into a BaseChannel object for
+// test purposes. Can be connected to other FakeSessions via Connect().
+class FakeSession : public BaseSession {
+ public:
+  explicit FakeSession()
+      : BaseSession(rtc::Thread::Current(),
+                    rtc::Thread::Current(),
+                    NULL, "", "", true),
+      fail_create_channel_(false) {
+  }
+  explicit FakeSession(bool initiator)
+      : BaseSession(rtc::Thread::Current(),
+                    rtc::Thread::Current(),
+                    NULL, "", "", initiator),
+      fail_create_channel_(false) {
+  }
+  FakeSession(rtc::Thread* worker_thread, bool initiator)
+      : BaseSession(rtc::Thread::Current(),
+                    worker_thread,
+                    NULL, "", "", initiator),
+      fail_create_channel_(false) {
+  }
+
+  FakeTransport* GetTransport(const std::string& content_name) {
+    return static_cast<FakeTransport*>(
+        BaseSession::GetTransport(content_name));
+  }
+
+  void Connect(FakeSession* dest) {
+    // Simulate the exchange of candidates.
+    CompleteNegotiation();
+    dest->CompleteNegotiation();
+    for (TransportMap::const_iterator it = transport_proxies().begin();
+        it != transport_proxies().end(); ++it) {
+      static_cast<FakeTransport*>(it->second->impl())->SetDestination(
+          dest->GetTransport(it->first));
+    }
+  }
+
+  virtual TransportChannel* CreateChannel(
+      const std::string& content_name,
+      const std::string& channel_name,
+      int component) {
+    if (fail_create_channel_) {
+      return NULL;
+    }
+    return BaseSession::CreateChannel(content_name, channel_name, component);
+  }
+
+  void set_fail_channel_creation(bool fail_channel_creation) {
+    fail_create_channel_ = fail_channel_creation;
+  }
+
+  // TODO: Hoist this into Session when we re-work the Session code.
+  void set_ssl_identity(rtc::SSLIdentity* identity) {
+    for (TransportMap::const_iterator it = transport_proxies().begin();
+        it != transport_proxies().end(); ++it) {
+      // We know that we have a FakeTransport*
+
+      static_cast<FakeTransport*>(it->second->impl())->set_identity
+          (identity);
+    }
+  }
+
+ protected:
+  virtual Transport* CreateTransport(const std::string& content_name) {
+    return new FakeTransport(signaling_thread(), worker_thread(), content_name);
+  }
+
+  void CompleteNegotiation() {
+    for (TransportMap::const_iterator it = transport_proxies().begin();
+        it != transport_proxies().end(); ++it) {
+      it->second->CompleteNegotiation();
+      it->second->ConnectChannels();
+    }
+  }
+
+ private:
+  bool fail_create_channel_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_FAKESESSION_H_
diff --git a/p2p/base/p2ptransport.cc b/p2p/base/p2ptransport.cc
new file mode 100644
index 0000000..e873756
--- /dev/null
+++ b/p2p/base/p2ptransport.cc
@@ -0,0 +1,246 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/p2ptransport.h"
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/p2ptransportchannel.h"
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/p2p/base/sessionmessages.h"
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/base64.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/stringencode.h"
+#include "webrtc/base/stringutils.h"
+
+namespace {
+
+// Limits for GICE and ICE username sizes.
+const size_t kMaxGiceUsernameSize = 16;
+const size_t kMaxIceUsernameSize = 512;
+
+}  // namespace
+
+namespace cricket {
+
+static buzz::XmlElement* NewTransportElement(const std::string& name) {
+  return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true);
+}
+
+P2PTransport::P2PTransport(rtc::Thread* signaling_thread,
+                           rtc::Thread* worker_thread,
+                           const std::string& content_name,
+                           PortAllocator* allocator)
+    : Transport(signaling_thread, worker_thread,
+                content_name, NS_GINGLE_P2P, allocator) {
+}
+
+P2PTransport::~P2PTransport() {
+  DestroyAllChannels();
+}
+
+TransportChannelImpl* P2PTransport::CreateTransportChannel(int component) {
+  return new P2PTransportChannel(content_name(), component, this,
+                                 port_allocator());
+}
+
+void P2PTransport::DestroyTransportChannel(TransportChannelImpl* channel) {
+  delete channel;
+}
+
+bool P2PTransportParser::ParseTransportDescription(
+    const buzz::XmlElement* elem,
+    const CandidateTranslator* translator,
+    TransportDescription* desc,
+    ParseError* error) {
+  ASSERT(elem->Name().LocalPart() == LN_TRANSPORT);
+  desc->transport_type = elem->Name().Namespace();
+  if (desc->transport_type != NS_GINGLE_P2P)
+    return BadParse("Unsupported transport type", error);
+
+  for (const buzz::XmlElement* candidate_elem = elem->FirstElement();
+       candidate_elem != NULL;
+       candidate_elem = candidate_elem->NextElement()) {
+    // Only look at local part because the namespace might (eventually)
+    // be NS_GINGLE_P2P or NS_JINGLE_ICE_UDP.
+    if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) {
+      Candidate candidate;
+      if (!ParseCandidate(ICEPROTO_GOOGLE, candidate_elem, translator,
+                          &candidate, error)) {
+        return false;
+      }
+
+      desc->candidates.push_back(candidate);
+    }
+  }
+  return true;
+}
+
+bool P2PTransportParser::WriteTransportDescription(
+    const TransportDescription& desc,
+    const CandidateTranslator* translator,
+    buzz::XmlElement** out_elem,
+    WriteError* error) {
+  TransportProtocol proto = TransportProtocolFromDescription(&desc);
+  rtc::scoped_ptr<buzz::XmlElement> trans_elem(
+      NewTransportElement(desc.transport_type));
+
+  // Fail if we get HYBRID or ICE right now.
+  // TODO(juberti): Add ICE and HYBRID serialization.
+  if (proto != ICEPROTO_GOOGLE) {
+    LOG(LS_ERROR) << "Failed to serialize non-GICE TransportDescription";
+    return false;
+  }
+
+  for (std::vector<Candidate>::const_iterator iter = desc.candidates.begin();
+       iter != desc.candidates.end(); ++iter) {
+    rtc::scoped_ptr<buzz::XmlElement> cand_elem(
+        new buzz::XmlElement(QN_GINGLE_P2P_CANDIDATE));
+    if (!WriteCandidate(proto, *iter, translator, cand_elem.get(), error)) {
+      return false;
+    }
+    trans_elem->AddElement(cand_elem.release());
+  }
+
+  *out_elem = trans_elem.release();
+  return true;
+}
+
+bool P2PTransportParser::ParseGingleCandidate(
+    const buzz::XmlElement* elem,
+    const CandidateTranslator* translator,
+    Candidate* candidate,
+    ParseError* error) {
+  return ParseCandidate(ICEPROTO_GOOGLE, elem, translator, candidate, error);
+}
+
+bool P2PTransportParser::WriteGingleCandidate(
+    const Candidate& candidate,
+    const CandidateTranslator* translator,
+    buzz::XmlElement** out_elem,
+    WriteError* error) {
+  rtc::scoped_ptr<buzz::XmlElement> elem(
+      new buzz::XmlElement(QN_GINGLE_CANDIDATE));                                     
+  bool ret = WriteCandidate(ICEPROTO_GOOGLE, candidate, translator, elem.get(),
+                            error);
+  if (ret) {
+    *out_elem = elem.release();
+  }
+  return ret;
+}
+
+bool P2PTransportParser::VerifyUsernameFormat(TransportProtocol proto,
+                                              const std::string& username,
+                                              ParseError* error) {
+  if (proto == ICEPROTO_GOOGLE || proto == ICEPROTO_HYBRID) {
+    if (username.size() > kMaxGiceUsernameSize)
+      return BadParse("candidate username is too long", error);
+    if (!rtc::Base64::IsBase64Encoded(username))
+      return BadParse("candidate username has non-base64 encoded characters",
+                      error);
+  } else if (proto == ICEPROTO_RFC5245) {
+    if (username.size() > kMaxIceUsernameSize)
+      return BadParse("candidate username is too long", error);
+  }
+  return true;
+}
+
+bool P2PTransportParser::ParseCandidate(TransportProtocol proto,
+                                        const buzz::XmlElement* elem,
+                                        const CandidateTranslator* translator,
+                                        Candidate* candidate,
+                                        ParseError* error) {
+  ASSERT(proto == ICEPROTO_GOOGLE);
+  ASSERT(translator != NULL);
+
+  if (!elem->HasAttr(buzz::QN_NAME) ||
+      !elem->HasAttr(QN_ADDRESS) ||
+      !elem->HasAttr(QN_PORT) ||
+      !elem->HasAttr(QN_USERNAME) ||
+      !elem->HasAttr(QN_PROTOCOL) ||
+      !elem->HasAttr(QN_GENERATION)) {
+    return BadParse("candidate missing required attribute", error);
+  }
+
+  rtc::SocketAddress address;
+  if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, &address, error))
+    return false;
+
+  std::string channel_name = elem->Attr(buzz::QN_NAME);
+  int component = 0;
+  if (!translator ||
+      !translator->GetComponentFromChannelName(channel_name, &component)) {
+    return BadParse("candidate has unknown channel name " + channel_name,
+                    error);
+  }
+
+  float preference = 0.0;
+  if (!GetXmlAttr(elem, QN_PREFERENCE, 0.0f, &preference)) {
+    return BadParse("candidate has unknown preference", error);
+  }
+
+  candidate->set_component(component);
+  candidate->set_address(address);
+  candidate->set_username(elem->Attr(QN_USERNAME));
+  candidate->set_preference(preference);
+  candidate->set_protocol(elem->Attr(QN_PROTOCOL));
+  candidate->set_generation_str(elem->Attr(QN_GENERATION));
+  if (elem->HasAttr(QN_PASSWORD))
+    candidate->set_password(elem->Attr(QN_PASSWORD));
+  if (elem->HasAttr(buzz::QN_TYPE))
+    candidate->set_type(elem->Attr(buzz::QN_TYPE));
+  if (elem->HasAttr(QN_NETWORK))
+    candidate->set_network_name(elem->Attr(QN_NETWORK));
+
+  if (!VerifyUsernameFormat(proto, candidate->username(), error))
+    return false;
+
+  return true;
+}
+
+bool P2PTransportParser::WriteCandidate(TransportProtocol proto,
+                                        const Candidate& candidate,
+                                        const CandidateTranslator* translator,
+                                        buzz::XmlElement* elem,
+                                        WriteError* error) {
+  ASSERT(proto == ICEPROTO_GOOGLE);
+  ASSERT(translator != NULL);
+
+  std::string channel_name;
+  if (!translator ||
+      !translator->GetChannelNameFromComponent(
+          candidate.component(), &channel_name)) {
+    return BadWrite("Cannot write candidate because of unknown component.",
+                    error);
+  }
+
+  elem->SetAttr(buzz::QN_NAME, channel_name);
+  elem->SetAttr(QN_ADDRESS, candidate.address().ipaddr().ToString());
+  elem->SetAttr(QN_PORT, candidate.address().PortAsString());
+  AddXmlAttr(elem, QN_PREFERENCE, candidate.preference());
+  elem->SetAttr(QN_USERNAME, candidate.username());
+  elem->SetAttr(QN_PROTOCOL, candidate.protocol());
+  elem->SetAttr(QN_GENERATION, candidate.generation_str());
+  if (!candidate.password().empty())
+    elem->SetAttr(QN_PASSWORD, candidate.password());
+  elem->SetAttr(buzz::QN_TYPE, candidate.type());
+  if (!candidate.network_name().empty())
+    elem->SetAttr(QN_NETWORK, candidate.network_name());
+
+  return true;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/p2ptransport.h b/p2p/base/p2ptransport.h
new file mode 100644
index 0000000..efc6599
--- /dev/null
+++ b/p2p/base/p2ptransport.h
@@ -0,0 +1,86 @@
+/*
+ *  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_P2P_BASE_P2PTRANSPORT_H_
+#define WEBRTC_P2P_BASE_P2PTRANSPORT_H_
+
+#include <string>
+#include <vector>
+#include "webrtc/p2p/base/transport.h"
+
+namespace cricket {
+
+class P2PTransport : public Transport {
+ public:
+  P2PTransport(rtc::Thread* signaling_thread,
+               rtc::Thread* worker_thread,
+               const std::string& content_name,
+               PortAllocator* allocator);
+  virtual ~P2PTransport();
+
+ protected:
+  // Creates and destroys P2PTransportChannel.
+  virtual TransportChannelImpl* CreateTransportChannel(int component);
+  virtual void DestroyTransportChannel(TransportChannelImpl* channel);
+
+  friend class P2PTransportChannel;
+
+  DISALLOW_EVIL_CONSTRUCTORS(P2PTransport);
+};
+
+class P2PTransportParser : public TransportParser {
+ public:
+  P2PTransportParser() {}
+  // Translator may be null, in which case ParseCandidates should
+  // return false if there are candidates to parse.  We can't not call
+  // ParseCandidates because there's no way to know ahead of time if
+  // there are candidates or not.
+
+  // Jingle-specific functions; can be used with either ICE, GICE, or HYBRID.
+  virtual bool ParseTransportDescription(const buzz::XmlElement* elem,
+                                         const CandidateTranslator* translator,
+                                         TransportDescription* desc,
+                                         ParseError* error);
+  virtual bool WriteTransportDescription(const TransportDescription& desc,
+                                         const CandidateTranslator* translator,
+                                         buzz::XmlElement** elem,
+                                         WriteError* error);
+
+  // Legacy Gingle functions; only can be used with GICE.
+  virtual bool ParseGingleCandidate(const buzz::XmlElement* elem,
+                                    const CandidateTranslator* translator,
+                                    Candidate* candidate,
+                                    ParseError* error);
+  virtual bool WriteGingleCandidate(const Candidate& candidate,
+                                    const CandidateTranslator* translator,
+                                    buzz::XmlElement** elem,
+                                    WriteError* error);
+
+ private:
+  bool ParseCandidate(TransportProtocol proto,
+                      const buzz::XmlElement* elem,
+                      const CandidateTranslator* translator,
+                      Candidate* candidate,
+                      ParseError* error);
+  bool WriteCandidate(TransportProtocol proto,
+                      const Candidate& candidate,
+                      const CandidateTranslator* translator,
+                      buzz::XmlElement* elem,
+                      WriteError* error);
+  bool VerifyUsernameFormat(TransportProtocol proto,
+                            const std::string& username,
+                            ParseError* error);
+
+  DISALLOW_EVIL_CONSTRUCTORS(P2PTransportParser);
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_P2PTRANSPORT_H_
diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc
new file mode 100644
index 0000000..84a2420
--- /dev/null
+++ b/p2p/base/p2ptransportchannel.cc
@@ -0,0 +1,1274 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/p2ptransportchannel.h"
+
+#include <set>
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/relayport.h"  // For RELAY_PORT_TYPE.
+#include "webrtc/p2p/base/stunport.h"  // For STUN_PORT_TYPE.
+#include "webrtc/base/common.h"
+#include "webrtc/base/crc32.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/stringencode.h"
+
+namespace {
+
+// messages for queuing up work for ourselves
+enum {
+  MSG_SORT = 1,
+  MSG_PING,
+};
+
+// When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
+// for pinging.  When the socket is writable, we will use only 1 Kbps because
+// we don't want to degrade the quality on a modem.  These numbers should work
+// well on a 28.8K modem, which is the slowest connection on which the voice
+// quality is reasonable at all.
+static const uint32 PING_PACKET_SIZE = 60 * 8;
+static const uint32 WRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 1000;  // 480ms
+static const uint32 UNWRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 10000;  // 50ms
+
+// If there is a current writable connection, then we will also try hard to
+// make sure it is pinged at this rate.
+static const uint32 MAX_CURRENT_WRITABLE_DELAY = 900;  // 2*WRITABLE_DELAY - bit
+
+// The minimum improvement in RTT that justifies a switch.
+static const double kMinImprovement = 10;
+
+cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port,
+                                         cricket::PortInterface* origin_port) {
+  if (!origin_port)
+    return cricket::PortInterface::ORIGIN_MESSAGE;
+  else if (port == origin_port)
+    return cricket::PortInterface::ORIGIN_THIS_PORT;
+  else
+    return cricket::PortInterface::ORIGIN_OTHER_PORT;
+}
+
+// Compares two connections based only on static information about them.
+int CompareConnectionCandidates(cricket::Connection* a,
+                                cricket::Connection* b) {
+  // Compare connection priority. Lower values get sorted last.
+  if (a->priority() > b->priority())
+    return 1;
+  if (a->priority() < b->priority())
+    return -1;
+
+  // If we're still tied at this point, prefer a younger generation.
+  return (a->remote_candidate().generation() + a->port()->generation()) -
+         (b->remote_candidate().generation() + b->port()->generation());
+}
+
+// Compare two connections based on their writability and static preferences.
+int CompareConnections(cricket::Connection *a, cricket::Connection *b) {
+  // Sort based on write-state.  Better states have lower values.
+  if (a->write_state() < b->write_state())
+    return 1;
+  if (a->write_state() > b->write_state())
+    return -1;
+
+  // Compare the candidate information.
+  return CompareConnectionCandidates(a, b);
+}
+
+// Wraps the comparison connection into a less than operator that puts higher
+// priority writable connections first.
+class ConnectionCompare {
+ public:
+  bool operator()(const cricket::Connection *ca,
+                  const cricket::Connection *cb) {
+    cricket::Connection* a = const_cast<cricket::Connection*>(ca);
+    cricket::Connection* b = const_cast<cricket::Connection*>(cb);
+
+    ASSERT(a->port()->IceProtocol() == b->port()->IceProtocol());
+
+    // Compare first on writability and static preferences.
+    int cmp = CompareConnections(a, b);
+    if (cmp > 0)
+      return true;
+    if (cmp < 0)
+      return false;
+
+    // Otherwise, sort based on latency estimate.
+    return a->rtt() < b->rtt();
+
+    // Should we bother checking for the last connection that last received
+    // data? It would help rendezvous on the connection that is also receiving
+    // packets.
+    //
+    // TODO: Yes we should definitely do this.  The TCP protocol gains
+    // efficiency by being used bidirectionally, as opposed to two separate
+    // unidirectional streams.  This test should probably occur before
+    // comparison of local prefs (assuming combined prefs are the same).  We
+    // need to be careful though, not to bounce back and forth with both sides
+    // trying to rendevous with the other.
+  }
+};
+
+// Determines whether we should switch between two connections, based first on
+// static preferences and then (if those are equal) on latency estimates.
+bool ShouldSwitch(cricket::Connection* a_conn, cricket::Connection* b_conn) {
+  if (a_conn == b_conn)
+    return false;
+
+  if (!a_conn || !b_conn)  // don't think the latter should happen
+    return true;
+
+  int prefs_cmp = CompareConnections(a_conn, b_conn);
+  if (prefs_cmp < 0)
+    return true;
+  if (prefs_cmp > 0)
+    return false;
+
+  return b_conn->rtt() <= a_conn->rtt() + kMinImprovement;
+}
+
+}  // unnamed namespace
+
+namespace cricket {
+
+P2PTransportChannel::P2PTransportChannel(const std::string& content_name,
+                                         int component,
+                                         P2PTransport* transport,
+                                         PortAllocator *allocator) :
+    TransportChannelImpl(content_name, component),
+    transport_(transport),
+    allocator_(allocator),
+    worker_thread_(rtc::Thread::Current()),
+    incoming_only_(false),
+    waiting_for_signaling_(false),
+    error_(0),
+    best_connection_(NULL),
+    pending_best_connection_(NULL),
+    sort_dirty_(false),
+    was_writable_(false),
+    protocol_type_(ICEPROTO_HYBRID),
+    remote_ice_mode_(ICEMODE_FULL),
+    ice_role_(ICEROLE_UNKNOWN),
+    tiebreaker_(0),
+    remote_candidate_generation_(0) {
+}
+
+P2PTransportChannel::~P2PTransportChannel() {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
+    delete allocator_sessions_[i];
+}
+
+// Add the allocator session to our list so that we know which sessions
+// are still active.
+void P2PTransportChannel::AddAllocatorSession(PortAllocatorSession* session) {
+  session->set_generation(static_cast<uint32>(allocator_sessions_.size()));
+  allocator_sessions_.push_back(session);
+
+  // We now only want to apply new candidates that we receive to the ports
+  // created by this new session because these are replacing those of the
+  // previous sessions.
+  ports_.clear();
+
+  session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady);
+  session->SignalCandidatesReady.connect(
+      this, &P2PTransportChannel::OnCandidatesReady);
+  session->SignalCandidatesAllocationDone.connect(
+      this, &P2PTransportChannel::OnCandidatesAllocationDone);
+  session->StartGettingPorts();
+}
+
+void P2PTransportChannel::AddConnection(Connection* connection) {
+  connections_.push_back(connection);
+  connection->set_remote_ice_mode(remote_ice_mode_);
+  connection->SignalReadPacket.connect(
+      this, &P2PTransportChannel::OnReadPacket);
+  connection->SignalReadyToSend.connect(
+      this, &P2PTransportChannel::OnReadyToSend);
+  connection->SignalStateChange.connect(
+      this, &P2PTransportChannel::OnConnectionStateChange);
+  connection->SignalDestroyed.connect(
+      this, &P2PTransportChannel::OnConnectionDestroyed);
+  connection->SignalUseCandidate.connect(
+      this, &P2PTransportChannel::OnUseCandidate);
+}
+
+void P2PTransportChannel::SetIceRole(IceRole ice_role) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  if (ice_role_ != ice_role) {
+    ice_role_ = ice_role;
+    for (std::vector<PortInterface *>::iterator it = ports_.begin();
+         it != ports_.end(); ++it) {
+      (*it)->SetIceRole(ice_role);
+    }
+  }
+}
+
+void P2PTransportChannel::SetIceTiebreaker(uint64 tiebreaker) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  if (!ports_.empty()) {
+    LOG(LS_ERROR)
+        << "Attempt to change tiebreaker after Port has been allocated.";
+    return;
+  }
+
+  tiebreaker_ = tiebreaker;
+}
+
+bool P2PTransportChannel::GetIceProtocolType(IceProtocolType* type) const {
+  *type = protocol_type_;
+  return true;
+}
+
+void P2PTransportChannel::SetIceProtocolType(IceProtocolType type) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  protocol_type_ = type;
+  for (std::vector<PortInterface *>::iterator it = ports_.begin();
+       it != ports_.end(); ++it) {
+    (*it)->SetIceProtocolType(protocol_type_);
+  }
+}
+
+void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag,
+                                            const std::string& ice_pwd) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  bool ice_restart = false;
+  if (!ice_ufrag_.empty() && !ice_pwd_.empty()) {
+    // Restart candidate allocation if there is any change in either
+    // ice ufrag or password.
+    ice_restart =
+        IceCredentialsChanged(ice_ufrag_, ice_pwd_, ice_ufrag, ice_pwd);
+  }
+
+  ice_ufrag_ = ice_ufrag;
+  ice_pwd_ = ice_pwd;
+
+  if (ice_restart) {
+    // Restart candidate gathering.
+    Allocate();
+  }
+}
+
+void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag,
+                                                  const std::string& ice_pwd) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  bool ice_restart = false;
+  if (!remote_ice_ufrag_.empty() && !remote_ice_pwd_.empty()) {
+    ice_restart = (remote_ice_ufrag_ != ice_ufrag) ||
+                  (remote_ice_pwd_!= ice_pwd);
+  }
+
+  remote_ice_ufrag_ = ice_ufrag;
+  remote_ice_pwd_ = ice_pwd;
+
+  if (ice_restart) {
+    // |candidate.generation()| is not signaled in ICEPROTO_RFC5245.
+    // Therefore we need to keep track of the remote ice restart so
+    // newer connections are prioritized over the older.
+    ++remote_candidate_generation_;
+  }
+}
+
+void P2PTransportChannel::SetRemoteIceMode(IceMode mode) {
+  remote_ice_mode_ = mode;
+}
+
+// Go into the state of processing candidates, and running in general
+void P2PTransportChannel::Connect() {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  if (ice_ufrag_.empty() || ice_pwd_.empty()) {
+    ASSERT(false);
+    LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the "
+                  << "ice_pwd_ are not set.";
+    return;
+  }
+
+  // Kick off an allocator session
+  Allocate();
+
+  // Start pinging as the ports come in.
+  thread()->Post(this, MSG_PING);
+}
+
+// Reset the socket, clear up any previous allocations and start over
+void P2PTransportChannel::Reset() {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Get rid of all the old allocators.  This should clean up everything.
+  for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
+    delete allocator_sessions_[i];
+
+  allocator_sessions_.clear();
+  ports_.clear();
+  connections_.clear();
+  best_connection_ = NULL;
+
+  // Forget about all of the candidates we got before.
+  remote_candidates_.clear();
+
+  // Revert to the initial state.
+  set_readable(false);
+  set_writable(false);
+
+  // Reinitialize the rest of our state.
+  waiting_for_signaling_ = false;
+  sort_dirty_ = false;
+
+  // If we allocated before, start a new one now.
+  if (transport_->connect_requested())
+    Allocate();
+
+  // Start pinging as the ports come in.
+  thread()->Clear(this);
+  thread()->Post(this, MSG_PING);
+}
+
+// A new port is available, attempt to make connections for it
+void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
+                                      PortInterface* port) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Set in-effect options on the new port
+  for (OptionMap::const_iterator it = options_.begin();
+       it != options_.end();
+       ++it) {
+    int val = port->SetOption(it->first, it->second);
+    if (val < 0) {
+      LOG_J(LS_WARNING, port) << "SetOption(" << it->first
+                              << ", " << it->second
+                              << ") failed: " << port->GetError();
+    }
+  }
+
+  // Remember the ports and candidates, and signal that candidates are ready.
+  // The session will handle this, and send an initiate/accept/modify message
+  // if one is pending.
+
+  port->SetIceProtocolType(protocol_type_);
+  port->SetIceRole(ice_role_);
+  port->SetIceTiebreaker(tiebreaker_);
+  ports_.push_back(port);
+  port->SignalUnknownAddress.connect(
+      this, &P2PTransportChannel::OnUnknownAddress);
+  port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed);
+  port->SignalRoleConflict.connect(
+      this, &P2PTransportChannel::OnRoleConflict);
+
+  // Attempt to create a connection from this new port to all of the remote
+  // candidates that we were given so far.
+
+  std::vector<RemoteCandidate>::iterator iter;
+  for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
+       ++iter) {
+    CreateConnection(port, *iter, iter->origin_port(), false);
+  }
+
+  SortConnections();
+}
+
+// A new candidate is available, let listeners know
+void P2PTransportChannel::OnCandidatesReady(
+    PortAllocatorSession *session, const std::vector<Candidate>& candidates) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  for (size_t i = 0; i < candidates.size(); ++i) {
+    SignalCandidateReady(this, candidates[i]);
+  }
+}
+
+void P2PTransportChannel::OnCandidatesAllocationDone(
+    PortAllocatorSession* session) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  SignalCandidatesAllocationDone(this);
+}
+
+// Handle stun packets
+void P2PTransportChannel::OnUnknownAddress(
+    PortInterface* port,
+    const rtc::SocketAddress& address, ProtocolType proto,
+    IceMessage* stun_msg, const std::string &remote_username,
+    bool port_muxed) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Port has received a valid stun packet from an address that no Connection
+  // is currently available for. See if we already have a candidate with the
+  // address. If it isn't we need to create new candidate for it.
+
+  // Determine if the remote candidates use shared ufrag.
+  bool ufrag_per_port = false;
+  std::vector<RemoteCandidate>::iterator it;
+  if (remote_candidates_.size() > 0) {
+    it = remote_candidates_.begin();
+    std::string username = it->username();
+    for (; it != remote_candidates_.end(); ++it) {
+      if (it->username() != username) {
+        ufrag_per_port = true;
+        break;
+      }
+    }
+  }
+
+  const Candidate* candidate = NULL;
+  bool known_username = false;
+  std::string remote_password;
+  for (it = remote_candidates_.begin(); it != remote_candidates_.end(); ++it) {
+    if (it->username() == remote_username) {
+      remote_password = it->password();
+      known_username = true;
+      if (ufrag_per_port ||
+          (it->address() == address &&
+           it->protocol() == ProtoToString(proto))) {
+        candidate = &(*it);
+        break;
+      }
+      // We don't want to break here because we may find a match of the address
+      // later.
+    }
+  }
+
+  if (!known_username) {
+    if (port_muxed) {
+      // When Ports are muxed, SignalUnknownAddress is delivered to all
+      // P2PTransportChannel belong to a session. Return from here will
+      // save us from sending stun binding error message from incorrect channel.
+      return;
+    }
+    // Don't know about this username, the request is bogus
+    // This sometimes happens if a binding response comes in before the ACCEPT
+    // message.  It is totally valid; the retry state machine will try again.
+    port->SendBindingErrorResponse(stun_msg, address,
+        STUN_ERROR_STALE_CREDENTIALS, STUN_ERROR_REASON_STALE_CREDENTIALS);
+    return;
+  }
+
+  Candidate new_remote_candidate;
+  if (candidate != NULL) {
+    new_remote_candidate = *candidate;
+    if (ufrag_per_port) {
+      new_remote_candidate.set_address(address);
+    }
+  } else {
+    // Create a new candidate with this address.
+    std::string type;
+    if (port->IceProtocol() == ICEPROTO_RFC5245) {
+      type = PRFLX_PORT_TYPE;
+    } else {
+      // G-ICE doesn't support prflx candidate.
+      // We set candidate type to STUN_PORT_TYPE if the binding request comes
+      // from a relay port or the shared socket is used. Otherwise we use the
+      // port's type as the candidate type.
+      if (port->Type() == RELAY_PORT_TYPE || port->SharedSocket()) {
+        type = STUN_PORT_TYPE;
+      } else {
+        type = port->Type();
+      }
+    }
+
+    std::string id = rtc::CreateRandomString(8);
+    new_remote_candidate = Candidate(
+        id, component(), ProtoToString(proto), address,
+        0, remote_username, remote_password, type,
+        port->Network()->name(), 0U,
+        rtc::ToString<uint32>(rtc::ComputeCrc32(id)));
+    new_remote_candidate.set_priority(
+        new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX,
+                                         port->Network()->preference(), 0));
+  }
+
+  if (port->IceProtocol() == ICEPROTO_RFC5245) {
+    // RFC 5245
+    // If the source transport address of the request does not match any
+    // existing remote candidates, it represents a new peer reflexive remote
+    // candidate.
+
+    // The priority of the candidate is set to the PRIORITY attribute
+    // from the request.
+    const StunUInt32Attribute* priority_attr =
+        stun_msg->GetUInt32(STUN_ATTR_PRIORITY);
+    if (!priority_attr) {
+      LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - "
+                      << "No STUN_ATTR_PRIORITY found in the "
+                      << "stun request message";
+      port->SendBindingErrorResponse(stun_msg, address,
+                                     STUN_ERROR_BAD_REQUEST,
+                                     STUN_ERROR_REASON_BAD_REQUEST);
+      return;
+    }
+    new_remote_candidate.set_priority(priority_attr->value());
+
+    // RFC5245, the agent constructs a pair whose local candidate is equal to
+    // the transport address on which the STUN request was received, and a
+    // remote candidate equal to the source transport address where the
+    // request came from.
+
+    // There shouldn't be an existing connection with this remote address.
+    // When ports are muxed, this channel might get multiple unknown address
+    // signals. In that case if the connection is already exists, we should
+    // simply ignore the signal othewise send server error.
+    if (port->GetConnection(new_remote_candidate.address())) {
+      if (port_muxed) {
+        LOG(LS_INFO) << "Connection already exists for peer reflexive "
+                     << "candidate: " << new_remote_candidate.ToString();
+        return;
+      } else {
+        ASSERT(false);
+        port->SendBindingErrorResponse(stun_msg, address,
+                                       STUN_ERROR_SERVER_ERROR,
+                                       STUN_ERROR_REASON_SERVER_ERROR);
+        return;
+      }
+    }
+
+    Connection* connection = port->CreateConnection(
+        new_remote_candidate, cricket::PortInterface::ORIGIN_THIS_PORT);
+    if (!connection) {
+      ASSERT(false);
+      port->SendBindingErrorResponse(stun_msg, address,
+                                     STUN_ERROR_SERVER_ERROR,
+                                     STUN_ERROR_REASON_SERVER_ERROR);
+      return;
+    }
+
+    AddConnection(connection);
+    connection->ReceivedPing();
+
+    // Send the pinger a successful stun response.
+    port->SendBindingResponse(stun_msg, address);
+
+    // Update the list of connections since we just added another.  We do this
+    // after sending the response since it could (in principle) delete the
+    // connection in question.
+    SortConnections();
+  } else {
+    // Check for connectivity to this address. Create connections
+    // to this address across all local ports. First, add this as a new remote
+    // address
+    if (!CreateConnections(new_remote_candidate, port, true)) {
+      // Hopefully this won't occur, because changing a destination address
+      // shouldn't cause a new connection to fail
+      ASSERT(false);
+      port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
+          STUN_ERROR_REASON_SERVER_ERROR);
+      return;
+    }
+
+    // Send the pinger a successful stun response.
+    port->SendBindingResponse(stun_msg, address);
+
+    // Update the list of connections since we just added another.  We do this
+    // after sending the response since it could (in principle) delete the
+    // connection in question.
+    SortConnections();
+  }
+}
+
+void P2PTransportChannel::OnRoleConflict(PortInterface* port) {
+  SignalRoleConflict(this);  // STUN ping will be sent when SetRole is called
+                             // from Transport.
+}
+
+// When the signalling channel is ready, we can really kick off the allocator
+void P2PTransportChannel::OnSignalingReady() {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  if (waiting_for_signaling_) {
+    waiting_for_signaling_ = false;
+    AddAllocatorSession(allocator_->CreateSession(
+        SessionId(), content_name(), component(), ice_ufrag_, ice_pwd_));
+  }
+}
+
+void P2PTransportChannel::OnUseCandidate(Connection* conn) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  ASSERT(ice_role_ == ICEROLE_CONTROLLED);
+  ASSERT(protocol_type_ == ICEPROTO_RFC5245);
+  if (conn->write_state() == Connection::STATE_WRITABLE) {
+    if (best_connection_ != conn) {
+      pending_best_connection_ = NULL;
+      SwitchBestConnectionTo(conn);
+      // Now we have selected the best connection, time to prune other existing
+      // connections and update the read/write state of the channel.
+      RequestSort();
+    }
+  } else {
+    pending_best_connection_ = conn;
+  }
+}
+
+void P2PTransportChannel::OnCandidate(const Candidate& candidate) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Create connections to this remote candidate.
+  CreateConnections(candidate, NULL, false);
+
+  // Resort the connections list, which may have new elements.
+  SortConnections();
+}
+
+// Creates connections from all of the ports that we care about to the given
+// remote candidate.  The return value is true if we created a connection from
+// the origin port.
+bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
+                                            PortInterface* origin_port,
+                                            bool readable) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  Candidate new_remote_candidate(remote_candidate);
+  new_remote_candidate.set_generation(
+      GetRemoteCandidateGeneration(remote_candidate));
+  // ICE candidates don't need to have username and password set, but
+  // the code below this (specifically, ConnectionRequest::Prepare in
+  // port.cc) uses the remote candidates's username.  So, we set it
+  // here.
+  if (remote_candidate.username().empty()) {
+    new_remote_candidate.set_username(remote_ice_ufrag_);
+  }
+  if (remote_candidate.password().empty()) {
+    new_remote_candidate.set_password(remote_ice_pwd_);
+  }
+
+  // If we've already seen the new remote candidate (in the current candidate
+  // generation), then we shouldn't try creating connections for it.
+  // We either already have a connection for it, or we previously created one
+  // and then later pruned it. If we don't return, the channel will again
+  // re-create any connections that were previously pruned, which will then
+  // immediately be re-pruned, churning the network for no purpose.
+  // This only applies to candidates received over signaling (i.e. origin_port
+  // is NULL).
+  if (!origin_port && IsDuplicateRemoteCandidate(new_remote_candidate)) {
+    // return true to indicate success, without creating any new connections.
+    return true;
+  }
+
+  // Add a new connection for this candidate to every port that allows such a
+  // connection (i.e., if they have compatible protocols) and that does not
+  // already have a connection to an equivalent candidate.  We must be careful
+  // to make sure that the origin port is included, even if it was pruned,
+  // since that may be the only port that can create this connection.
+  bool created = false;
+  std::vector<PortInterface *>::reverse_iterator it;
+  for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
+    if (CreateConnection(*it, new_remote_candidate, origin_port, readable)) {
+      if (*it == origin_port)
+        created = true;
+    }
+  }
+
+  if ((origin_port != NULL) &&
+      std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
+    if (CreateConnection(
+        origin_port, new_remote_candidate, origin_port, readable))
+      created = true;
+  }
+
+  // Remember this remote candidate so that we can add it to future ports.
+  RememberRemoteCandidate(new_remote_candidate, origin_port);
+
+  return created;
+}
+
+// Setup a connection object for the local and remote candidate combination.
+// And then listen to connection object for changes.
+bool P2PTransportChannel::CreateConnection(PortInterface* port,
+                                           const Candidate& remote_candidate,
+                                           PortInterface* origin_port,
+                                           bool readable) {
+  // Look for an existing connection with this remote address.  If one is not
+  // found, then we can create a new connection for this address.
+  Connection* connection = port->GetConnection(remote_candidate.address());
+  if (connection != NULL) {
+    // It is not legal to try to change any of the parameters of an existing
+    // connection; however, the other side can send a duplicate candidate.
+    if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
+      LOG(INFO) << "Attempt to change a remote candidate."
+                << " Existing remote candidate: "
+                << connection->remote_candidate().ToString()
+                << "New remote candidate: "
+                << remote_candidate.ToString();
+      return false;
+    }
+  } else {
+    PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port);
+
+    // Don't create connection if this is a candidate we received in a
+    // message and we are not allowed to make outgoing connections.
+    if (origin == cricket::PortInterface::ORIGIN_MESSAGE && incoming_only_)
+      return false;
+
+    connection = port->CreateConnection(remote_candidate, origin);
+    if (!connection)
+      return false;
+
+    AddConnection(connection);
+
+    LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", ("
+                         << connections_.size() << " total)";
+  }
+
+  // If we are readable, it is because we are creating this in response to a
+  // ping from the other side.  This will cause the state to become readable.
+  if (readable)
+    connection->ReceivedPing();
+
+  return true;
+}
+
+bool P2PTransportChannel::FindConnection(
+    cricket::Connection* connection) const {
+  std::vector<Connection*>::const_iterator citer =
+      std::find(connections_.begin(), connections_.end(), connection);
+  return citer != connections_.end();
+}
+
+uint32 P2PTransportChannel::GetRemoteCandidateGeneration(
+    const Candidate& candidate) {
+  if (protocol_type_ == ICEPROTO_GOOGLE) {
+    // The Candidate.generation() can be trusted. Nothing needs to be done.
+    return candidate.generation();
+  }
+  // |candidate.generation()| is not signaled in ICEPROTO_RFC5245.
+  // Therefore we need to keep track of the remote ice restart so
+  // newer connections are prioritized over the older.
+  ASSERT(candidate.generation() == 0 ||
+         candidate.generation() == remote_candidate_generation_);
+  return remote_candidate_generation_;
+}
+
+// Check if remote candidate is already cached.
+bool P2PTransportChannel::IsDuplicateRemoteCandidate(
+    const Candidate& candidate) {
+  for (uint32 i = 0; i < remote_candidates_.size(); ++i) {
+    if (remote_candidates_[i].IsEquivalent(candidate)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Maintain our remote candidate list, adding this new remote one.
+void P2PTransportChannel::RememberRemoteCandidate(
+    const Candidate& remote_candidate, PortInterface* origin_port) {
+  // Remove any candidates whose generation is older than this one.  The
+  // presence of a new generation indicates that the old ones are not useful.
+  uint32 i = 0;
+  while (i < remote_candidates_.size()) {
+    if (remote_candidates_[i].generation() < remote_candidate.generation()) {
+      LOG(INFO) << "Pruning candidate from old generation: "
+                << remote_candidates_[i].address().ToSensitiveString();
+      remote_candidates_.erase(remote_candidates_.begin() + i);
+    } else {
+      i += 1;
+    }
+  }
+
+  // Make sure this candidate is not a duplicate.
+  if (IsDuplicateRemoteCandidate(remote_candidate)) {
+    LOG(INFO) << "Duplicate candidate: " << remote_candidate.ToString();
+    return;
+  }
+
+  // Try this candidate for all future ports.
+  remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
+}
+
+// Set options on ourselves is simply setting options on all of our available
+// port objects.
+int P2PTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
+  OptionMap::iterator it = options_.find(opt);
+  if (it == options_.end()) {
+    options_.insert(std::make_pair(opt, value));
+  } else if (it->second == value) {
+    return 0;
+  } else {
+    it->second = value;
+  }
+
+  for (uint32 i = 0; i < ports_.size(); ++i) {
+    int val = ports_[i]->SetOption(opt, value);
+    if (val < 0) {
+      // Because this also occurs deferred, probably no point in reporting an
+      // error
+      LOG(WARNING) << "SetOption(" << opt << ", " << value << ") failed: "
+                   << ports_[i]->GetError();
+    }
+  }
+  return 0;
+}
+
+// Send data to the other side, using our best connection.
+int P2PTransportChannel::SendPacket(const char *data, size_t len,
+                                    const rtc::PacketOptions& options,
+                                    int flags) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  if (flags != 0) {
+    error_ = EINVAL;
+    return -1;
+  }
+  if (best_connection_ == NULL) {
+    error_ = EWOULDBLOCK;
+    return -1;
+  }
+
+  int sent = best_connection_->Send(data, len, options);
+  if (sent <= 0) {
+    ASSERT(sent < 0);
+    error_ = best_connection_->GetError();
+  }
+  return sent;
+}
+
+bool P2PTransportChannel::GetStats(ConnectionInfos *infos) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  // Gather connection infos.
+  infos->clear();
+
+  std::vector<Connection *>::const_iterator it;
+  for (it = connections_.begin(); it != connections_.end(); ++it) {
+    Connection *connection = *it;
+    ConnectionInfo info;
+    info.best_connection = (best_connection_ == connection);
+    info.readable =
+        (connection->read_state() == Connection::STATE_READABLE);
+    info.writable =
+        (connection->write_state() == Connection::STATE_WRITABLE);
+    info.timeout =
+        (connection->write_state() == Connection::STATE_WRITE_TIMEOUT);
+    info.new_connection = !connection->reported();
+    connection->set_reported(true);
+    info.rtt = connection->rtt();
+    info.sent_total_bytes = connection->sent_total_bytes();
+    info.sent_bytes_second = connection->sent_bytes_second();
+    info.recv_total_bytes = connection->recv_total_bytes();
+    info.recv_bytes_second = connection->recv_bytes_second();
+    info.local_candidate = connection->local_candidate();
+    info.remote_candidate = connection->remote_candidate();
+    info.key = connection;
+    infos->push_back(info);
+  }
+
+  return true;
+}
+
+rtc::DiffServCodePoint P2PTransportChannel::DefaultDscpValue() const {
+  OptionMap::const_iterator it = options_.find(rtc::Socket::OPT_DSCP);
+  if (it == options_.end()) {
+    return rtc::DSCP_NO_CHANGE;
+  }
+  return static_cast<rtc::DiffServCodePoint> (it->second);
+}
+
+// Begin allocate (or immediately re-allocate, if MSG_ALLOCATE pending)
+void P2PTransportChannel::Allocate() {
+  // Time for a new allocator, lets make sure we have a signalling channel
+  // to communicate candidates through first.
+  waiting_for_signaling_ = true;
+  SignalRequestSignaling(this);
+}
+
+// Monitor connection states.
+void P2PTransportChannel::UpdateConnectionStates() {
+  uint32 now = rtc::Time();
+
+  // We need to copy the list of connections since some may delete themselves
+  // when we call UpdateState.
+  for (uint32 i = 0; i < connections_.size(); ++i)
+    connections_[i]->UpdateState(now);
+}
+
+// Prepare for best candidate sorting.
+void P2PTransportChannel::RequestSort() {
+  if (!sort_dirty_) {
+    worker_thread_->Post(this, MSG_SORT);
+    sort_dirty_ = true;
+  }
+}
+
+// Sort the available connections to find the best one.  We also monitor
+// the number of available connections and the current state.
+void P2PTransportChannel::SortConnections() {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Make sure the connection states are up-to-date since this affects how they
+  // will be sorted.
+  UpdateConnectionStates();
+
+  if (protocol_type_ == ICEPROTO_HYBRID) {
+    // If we are in hybrid mode, we are not sending any ping requests, so there
+    // is no point in sorting the connections. In hybrid state, ports can have
+    // different protocol than hybrid and protocol may differ from one another.
+    // Instead just update the state of this channel
+    UpdateChannelState();
+    return;
+  }
+
+  // Any changes after this point will require a re-sort.
+  sort_dirty_ = false;
+
+  // Get a list of the networks that we are using.
+  std::set<rtc::Network*> networks;
+  for (uint32 i = 0; i < connections_.size(); ++i)
+    networks.insert(connections_[i]->port()->Network());
+
+  // Find the best alternative connection by sorting.  It is important to note
+  // that amongst equal preference, writable connections, this will choose the
+  // one whose estimated latency is lowest.  So it is the only one that we
+  // need to consider switching to.
+
+  ConnectionCompare cmp;
+  std::stable_sort(connections_.begin(), connections_.end(), cmp);
+  LOG(LS_VERBOSE) << "Sorting available connections:";
+  for (uint32 i = 0; i < connections_.size(); ++i) {
+    LOG(LS_VERBOSE) << connections_[i]->ToString();
+  }
+
+  Connection* top_connection = NULL;
+  if (connections_.size() > 0)
+    top_connection = connections_[0];
+
+  // We don't want to pick the best connections if channel is using RFC5245
+  // and it's mode is CONTROLLED, as connections will be selected by the
+  // CONTROLLING agent.
+
+  // If necessary, switch to the new choice.
+  if (protocol_type_ != ICEPROTO_RFC5245 || ice_role_ == ICEROLE_CONTROLLING) {
+    if (ShouldSwitch(best_connection_, top_connection))
+      SwitchBestConnectionTo(top_connection);
+  }
+
+  // We can prune any connection for which there is a writable connection on
+  // the same network with better or equal priority.  We leave those with
+  // better priority just in case they become writable later (at which point,
+  // we would prune out the current best connection).  We leave connections on
+  // other networks because they may not be using the same resources and they
+  // may represent very distinct paths over which we can switch.
+  std::set<rtc::Network*>::iterator network;
+  for (network = networks.begin(); network != networks.end(); ++network) {
+    Connection* primier = GetBestConnectionOnNetwork(*network);
+    if (!primier || (primier->write_state() != Connection::STATE_WRITABLE))
+      continue;
+
+    for (uint32 i = 0; i < connections_.size(); ++i) {
+      if ((connections_[i] != primier) &&
+          (connections_[i]->port()->Network() == *network) &&
+          (CompareConnectionCandidates(primier, connections_[i]) >= 0)) {
+        connections_[i]->Prune();
+      }
+    }
+  }
+
+  // Check if all connections are timedout.
+  bool all_connections_timedout = true;
+  for (uint32 i = 0; i < connections_.size(); ++i) {
+    if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) {
+      all_connections_timedout = false;
+      break;
+    }
+  }
+
+  // Now update the writable state of the channel with the information we have
+  // so far.
+  if (best_connection_ && best_connection_->writable()) {
+    HandleWritable();
+  } else if (all_connections_timedout) {
+    HandleAllTimedOut();
+  } else {
+    HandleNotWritable();
+  }
+
+  // Update the state of this channel.  This method is called whenever the
+  // state of any connection changes, so this is a good place to do this.
+  UpdateChannelState();
+}
+
+
+// Track the best connection, and let listeners know
+void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) {
+  // Note: if conn is NULL, the previous best_connection_ has been destroyed,
+  // so don't use it.
+  Connection* old_best_connection = best_connection_;
+  best_connection_ = conn;
+  if (best_connection_) {
+    if (old_best_connection) {
+      LOG_J(LS_INFO, this) << "Previous best connection: "
+                           << old_best_connection->ToString();
+    }
+    LOG_J(LS_INFO, this) << "New best connection: "
+                         << best_connection_->ToString();
+    SignalRouteChange(this, best_connection_->remote_candidate());
+  } else {
+    LOG_J(LS_INFO, this) << "No best connection";
+  }
+}
+
+void P2PTransportChannel::UpdateChannelState() {
+  // The Handle* functions already set the writable state.  We'll just double-
+  // check it here.
+  bool writable = ((best_connection_ != NULL)  &&
+      (best_connection_->write_state() ==
+      Connection::STATE_WRITABLE));
+  ASSERT(writable == this->writable());
+  if (writable != this->writable())
+    LOG(LS_ERROR) << "UpdateChannelState: writable state mismatch";
+
+  bool readable = false;
+  for (uint32 i = 0; i < connections_.size(); ++i) {
+    if (connections_[i]->read_state() == Connection::STATE_READABLE) {
+      readable = true;
+      break;
+    }
+  }
+  set_readable(readable);
+}
+
+// We checked the status of our connections and we had at least one that
+// was writable, go into the writable state.
+void P2PTransportChannel::HandleWritable() {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  if (!writable()) {
+    for (uint32 i = 0; i < allocator_sessions_.size(); ++i) {
+      if (allocator_sessions_[i]->IsGettingPorts()) {
+        allocator_sessions_[i]->StopGettingPorts();
+      }
+    }
+  }
+
+  was_writable_ = true;
+  set_writable(true);
+}
+
+// Notify upper layer about channel not writable state, if it was before.
+void P2PTransportChannel::HandleNotWritable() {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+  if (was_writable_) {
+    was_writable_ = false;
+    set_writable(false);
+  }
+}
+
+void P2PTransportChannel::HandleAllTimedOut() {
+  // Currently we are treating this as channel not writable.
+  HandleNotWritable();
+}
+
+// If we have a best connection, return it, otherwise return top one in the
+// list (later we will mark it best).
+Connection* P2PTransportChannel::GetBestConnectionOnNetwork(
+    rtc::Network* network) {
+  // If the best connection is on this network, then it wins.
+  if (best_connection_ && (best_connection_->port()->Network() == network))
+    return best_connection_;
+
+  // Otherwise, we return the top-most in sorted order.
+  for (uint32 i = 0; i < connections_.size(); ++i) {
+    if (connections_[i]->port()->Network() == network)
+      return connections_[i];
+  }
+
+  return NULL;
+}
+
+// Handle any queued up requests
+void P2PTransportChannel::OnMessage(rtc::Message *pmsg) {
+  switch (pmsg->message_id) {
+    case MSG_SORT:
+      OnSort();
+      break;
+    case MSG_PING:
+      OnPing();
+      break;
+    default:
+      ASSERT(false);
+      break;
+  }
+}
+
+// Handle queued up sort request
+void P2PTransportChannel::OnSort() {
+  // Resort the connections based on the new statistics.
+  SortConnections();
+}
+
+// Handle queued up ping request
+void P2PTransportChannel::OnPing() {
+  // Make sure the states of the connections are up-to-date (since this affects
+  // which ones are pingable).
+  UpdateConnectionStates();
+
+  // Find the oldest pingable connection and have it do a ping.
+  Connection* conn = FindNextPingableConnection();
+  if (conn)
+    PingConnection(conn);
+
+  // Post ourselves a message to perform the next ping.
+  uint32 delay = writable() ? WRITABLE_DELAY : UNWRITABLE_DELAY;
+  thread()->PostDelayed(delay, this, MSG_PING);
+}
+
+// Is the connection in a state for us to even consider pinging the other side?
+bool P2PTransportChannel::IsPingable(Connection* conn) {
+  // An unconnected connection cannot be written to at all, so pinging is out
+  // of the question.
+  if (!conn->connected())
+    return false;
+
+  if (writable()) {
+    // If we are writable, then we only want to ping connections that could be
+    // better than this one, i.e., the ones that were not pruned.
+    return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT);
+  } else {
+    // If we are not writable, then we need to try everything that might work.
+    // This includes both connections that do not have write timeout as well as
+    // ones that do not have read timeout.  A connection could be readable but
+    // be in write-timeout if we pruned it before.  Since the other side is
+    // still pinging it, it very well might still work.
+    return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) ||
+           (conn->read_state() != Connection::STATE_READ_TIMEOUT);
+  }
+}
+
+// Returns the next pingable connection to ping.  This will be the oldest
+// pingable connection unless we have a writable connection that is past the
+// maximum acceptable ping delay.
+Connection* P2PTransportChannel::FindNextPingableConnection() {
+  uint32 now = rtc::Time();
+  if (best_connection_ &&
+      (best_connection_->write_state() == Connection::STATE_WRITABLE) &&
+      (best_connection_->last_ping_sent()
+       + MAX_CURRENT_WRITABLE_DELAY <= now)) {
+    return best_connection_;
+  }
+
+  Connection* oldest_conn = NULL;
+  uint32 oldest_time = 0xFFFFFFFF;
+  for (uint32 i = 0; i < connections_.size(); ++i) {
+    if (IsPingable(connections_[i])) {
+      if (connections_[i]->last_ping_sent() < oldest_time) {
+        oldest_time = connections_[i]->last_ping_sent();
+        oldest_conn = connections_[i];
+      }
+    }
+  }
+  return oldest_conn;
+}
+
+// Apart from sending ping from |conn| this method also updates
+// |use_candidate_attr| flag. The criteria to update this flag is
+// explained below.
+// Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND
+//    a) Channel is in FULL ICE AND
+//      a.1) |conn| is the best connection OR
+//      a.2) there is no best connection OR
+//      a.3) the best connection is unwritable OR
+//      a.4) |conn| has higher priority than best_connection.
+//    b) we're doing LITE ICE AND
+//      b.1) |conn| is the best_connection AND
+//      b.2) |conn| is writable.
+void P2PTransportChannel::PingConnection(Connection* conn) {
+  bool use_candidate = false;
+  if (protocol_type_ == ICEPROTO_RFC5245) {
+    if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) {
+      use_candidate = (conn == best_connection_) ||
+                      (best_connection_ == NULL) ||
+                      (!best_connection_->writable()) ||
+                      (conn->priority() > best_connection_->priority());
+    } else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) {
+      use_candidate = best_connection_->writable();
+    }
+  }
+  conn->set_use_candidate_attr(use_candidate);
+  conn->Ping(rtc::Time());
+}
+
+// When a connection's state changes, we need to figure out who to use as
+// the best connection again.  It could have become usable, or become unusable.
+void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Update the best connection if the state change is from pending best
+  // connection and role is controlled.
+  if (protocol_type_ == ICEPROTO_RFC5245 && ice_role_ == ICEROLE_CONTROLLED) {
+    if (connection == pending_best_connection_ && connection->writable()) {
+      pending_best_connection_ = NULL;
+      SwitchBestConnectionTo(connection);
+    }
+  }
+
+  // We have to unroll the stack before doing this because we may be changing
+  // the state of connections while sorting.
+  RequestSort();
+}
+
+// When a connection is removed, edit it out, and then update our best
+// connection.
+void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Note: the previous best_connection_ may be destroyed by now, so don't
+  // use it.
+
+  // Remove this connection from the list.
+  std::vector<Connection*>::iterator iter =
+      std::find(connections_.begin(), connections_.end(), connection);
+  ASSERT(iter != connections_.end());
+  connections_.erase(iter);
+
+  LOG_J(LS_INFO, this) << "Removed connection ("
+    << static_cast<int>(connections_.size()) << " remaining)";
+
+  if (pending_best_connection_ == connection) {
+    pending_best_connection_ = NULL;
+  }
+
+  // If this is currently the best connection, then we need to pick a new one.
+  // The call to SortConnections will pick a new one.  It looks at the current
+  // best connection in order to avoid switching between fairly similar ones.
+  // Since this connection is no longer an option, we can just set best to NULL
+  // and re-choose a best assuming that there was no best connection.
+  if (best_connection_ == connection) {
+    SwitchBestConnectionTo(NULL);
+    RequestSort();
+  }
+
+  SignalConnectionRemoved(this);
+}
+
+// When a port is destroyed remove it from our list of ports to use for
+// connection attempts.
+void P2PTransportChannel::OnPortDestroyed(PortInterface* port) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Remove this port from the list (if we didn't drop it already).
+  std::vector<PortInterface*>::iterator iter =
+      std::find(ports_.begin(), ports_.end(), port);
+  if (iter != ports_.end())
+    ports_.erase(iter);
+
+  LOG(INFO) << "Removed port from p2p socket: "
+            << static_cast<int>(ports_.size()) << " remaining";
+}
+
+// We data is available, let listeners know
+void P2PTransportChannel::OnReadPacket(
+    Connection *connection, const char *data, size_t len,
+    const rtc::PacketTime& packet_time) {
+  ASSERT(worker_thread_ == rtc::Thread::Current());
+
+  // Do not deliver, if packet doesn't belong to the correct transport channel.
+  if (!FindConnection(connection))
+    return;
+
+  // Let the client know of an incoming packet
+  SignalReadPacket(this, data, len, packet_time, 0);
+}
+
+void P2PTransportChannel::OnReadyToSend(Connection* connection) {
+  if (connection == best_connection_ && writable()) {
+    SignalReadyToSend(this);
+  }
+}
+
+}  // namespace cricket
diff --git a/p2p/base/p2ptransportchannel.h b/p2p/base/p2ptransportchannel.h
new file mode 100644
index 0000000..8e3d50d
--- /dev/null
+++ b/p2p/base/p2ptransportchannel.h
@@ -0,0 +1,242 @@
+/*
+ *  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.
+ */
+
+// P2PTransportChannel wraps up the state management of the connection between
+// two P2P clients.  Clients have candidate ports for connecting, and
+// connections which are combinations of candidates from each end (Alice and
+// Bob each have candidates, one candidate from Alice and one candidate from
+// Bob are used to make a connection, repeat to make many connections).
+//
+// When all of the available connections become invalid (non-writable), we
+// kick off a process of determining more candidates and more connections.
+//
+#ifndef WEBRTC_P2P_BASE_P2PTRANSPORTCHANNEL_H_
+#define WEBRTC_P2P_BASE_P2PTRANSPORTCHANNEL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/p2ptransport.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/portinterface.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/sigslot.h"
+
+namespace cricket {
+
+// Adds the port on which the candidate originated.
+class RemoteCandidate : public Candidate {
+ public:
+  RemoteCandidate(const Candidate& c, PortInterface* origin_port)
+      : Candidate(c), origin_port_(origin_port) {}
+
+  PortInterface* origin_port() { return origin_port_; }
+
+ private:
+  PortInterface* origin_port_;
+};
+
+// P2PTransportChannel manages the candidates and connection process to keep
+// two P2P clients connected to each other.
+class P2PTransportChannel : public TransportChannelImpl,
+                            public rtc::MessageHandler {
+ public:
+  P2PTransportChannel(const std::string& content_name,
+                      int component,
+                      P2PTransport* transport,
+                      PortAllocator *allocator);
+  virtual ~P2PTransportChannel();
+
+  // From TransportChannelImpl:
+  virtual Transport* GetTransport() { return transport_; }
+  virtual void SetIceRole(IceRole role);
+  virtual IceRole GetIceRole() const { return ice_role_; }
+  virtual void SetIceTiebreaker(uint64 tiebreaker);
+  virtual size_t GetConnectionCount() const { return connections_.size(); }
+  virtual bool GetIceProtocolType(IceProtocolType* type) const;
+  virtual void SetIceProtocolType(IceProtocolType type);
+  virtual void SetIceCredentials(const std::string& ice_ufrag,
+                                 const std::string& ice_pwd);
+  virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
+                                       const std::string& ice_pwd);
+  virtual void SetRemoteIceMode(IceMode mode);
+  virtual void Connect();
+  virtual void Reset();
+  virtual void OnSignalingReady();
+  virtual void OnCandidate(const Candidate& candidate);
+
+  // From TransportChannel:
+  virtual int SendPacket(const char *data, size_t len,
+                         const rtc::PacketOptions& options, int flags);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetError() { return error_; }
+  virtual bool GetStats(std::vector<ConnectionInfo>* stats);
+
+  const Connection* best_connection() const { return best_connection_; }
+  void set_incoming_only(bool value) { incoming_only_ = value; }
+
+  // Note: This is only for testing purpose.
+  // |ports_| should not be changed from outside.
+  const std::vector<PortInterface *>& ports() { return ports_; }
+
+  IceMode remote_ice_mode() const { return remote_ice_mode_; }
+
+  // DTLS methods.
+  virtual bool IsDtlsActive() const { return false; }
+
+  // Default implementation.
+  virtual bool GetSslRole(rtc::SSLRole* role) const {
+    return false;
+  }
+
+  virtual bool SetSslRole(rtc::SSLRole role) {
+    return false;
+  }
+
+  // Set up the ciphers to use for DTLS-SRTP.
+  virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) {
+    return false;
+  }
+
+  // Find out which DTLS-SRTP cipher was negotiated
+  virtual bool GetSrtpCipher(std::string* cipher) {
+    return false;
+  }
+
+  // Returns false because the channel is not encrypted by default.
+  virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const {
+    return false;
+  }
+
+  virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const {
+    return false;
+  }
+
+  // Allows key material to be extracted for external encryption.
+  virtual bool ExportKeyingMaterial(
+      const std::string& label,
+      const uint8* context,
+      size_t context_len,
+      bool use_context,
+      uint8* result,
+      size_t result_len) {
+    return false;
+  }
+
+  virtual bool SetLocalIdentity(rtc::SSLIdentity* identity) {
+    return false;
+  }
+
+  // Set DTLS Remote fingerprint. Must be after local identity set.
+  virtual bool SetRemoteFingerprint(
+    const std::string& digest_alg,
+    const uint8* digest,
+    size_t digest_len) {
+    return false;
+  }
+
+  // Helper method used only in unittest.
+  rtc::DiffServCodePoint DefaultDscpValue() const;
+
+ private:
+  rtc::Thread* thread() { return worker_thread_; }
+  PortAllocatorSession* allocator_session() {
+    return allocator_sessions_.back();
+  }
+
+  void Allocate();
+  void UpdateConnectionStates();
+  void RequestSort();
+  void SortConnections();
+  void SwitchBestConnectionTo(Connection* conn);
+  void UpdateChannelState();
+  void HandleWritable();
+  void HandleNotWritable();
+  void HandleAllTimedOut();
+
+  Connection* GetBestConnectionOnNetwork(rtc::Network* network);
+  bool CreateConnections(const Candidate &remote_candidate,
+                         PortInterface* origin_port, bool readable);
+  bool CreateConnection(PortInterface* port, const Candidate& remote_candidate,
+                        PortInterface* origin_port, bool readable);
+  bool FindConnection(cricket::Connection* connection) const;
+
+  uint32 GetRemoteCandidateGeneration(const Candidate& candidate);
+  bool IsDuplicateRemoteCandidate(const Candidate& candidate);
+  void RememberRemoteCandidate(const Candidate& remote_candidate,
+                               PortInterface* origin_port);
+  bool IsPingable(Connection* conn);
+  Connection* FindNextPingableConnection();
+  void PingConnection(Connection* conn);
+  void AddAllocatorSession(PortAllocatorSession* session);
+  void AddConnection(Connection* connection);
+
+  void OnPortReady(PortAllocatorSession *session, PortInterface* port);
+  void OnCandidatesReady(PortAllocatorSession *session,
+                         const std::vector<Candidate>& candidates);
+  void OnCandidatesAllocationDone(PortAllocatorSession* session);
+  void OnUnknownAddress(PortInterface* port,
+                        const rtc::SocketAddress& addr,
+                        ProtocolType proto,
+                        IceMessage* stun_msg,
+                        const std::string& remote_username,
+                        bool port_muxed);
+  void OnPortDestroyed(PortInterface* port);
+  void OnRoleConflict(PortInterface* port);
+
+  void OnConnectionStateChange(Connection* connection);
+  void OnReadPacket(Connection *connection, const char *data, size_t len,
+                    const rtc::PacketTime& packet_time);
+  void OnReadyToSend(Connection* connection);
+  void OnConnectionDestroyed(Connection *connection);
+
+  void OnUseCandidate(Connection* conn);
+
+  virtual void OnMessage(rtc::Message *pmsg);
+  void OnSort();
+  void OnPing();
+
+  P2PTransport* transport_;
+  PortAllocator *allocator_;
+  rtc::Thread *worker_thread_;
+  bool incoming_only_;
+  bool waiting_for_signaling_;
+  int error_;
+  std::vector<PortAllocatorSession*> allocator_sessions_;
+  std::vector<PortInterface *> ports_;
+  std::vector<Connection *> connections_;
+  Connection* best_connection_;
+  // Connection selected by the controlling agent. This should be used only
+  // at controlled side when protocol type is RFC5245.
+  Connection* pending_best_connection_;
+  std::vector<RemoteCandidate> remote_candidates_;
+  bool sort_dirty_;  // indicates whether another sort is needed right now
+  bool was_writable_;
+  typedef std::map<rtc::Socket::Option, int> OptionMap;
+  OptionMap options_;
+  std::string ice_ufrag_;
+  std::string ice_pwd_;
+  std::string remote_ice_ufrag_;
+  std::string remote_ice_pwd_;
+  IceProtocolType protocol_type_;
+  IceMode remote_ice_mode_;
+  IceRole ice_role_;
+  uint64 tiebreaker_;
+  uint32 remote_candidate_generation_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(P2PTransportChannel);
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_P2PTRANSPORTCHANNEL_H_
diff --git a/p2p/base/p2ptransportchannel_unittest.cc b/p2p/base/p2ptransportchannel_unittest.cc
new file mode 100644
index 0000000..4f32719
--- /dev/null
+++ b/p2p/base/p2ptransportchannel_unittest.cc
@@ -0,0 +1,1702 @@
+/*
+ *  Copyright 2009 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/p2p/base/p2ptransportchannel.h"
+#include "webrtc/p2p/base/testrelayserver.h"
+#include "webrtc/p2p/base/teststunserver.h"
+#include "webrtc/p2p/base/testturnserver.h"
+#include "webrtc/p2p/client/basicportallocator.h"
+#include "webrtc/base/dscp.h"
+#include "webrtc/base/fakenetwork.h"
+#include "webrtc/base/firewallsocketserver.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/natserver.h"
+#include "webrtc/base/natsocketfactory.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/proxyserver.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+using cricket::kDefaultPortAllocatorFlags;
+using cricket::kMinimumStepDelay;
+using cricket::kDefaultStepDelay;
+using cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG;
+using cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
+using cricket::ServerAddresses;
+using rtc::SocketAddress;
+
+static const int kDefaultTimeout = 1000;
+static const int kOnlyLocalPorts = cricket::PORTALLOCATOR_DISABLE_STUN |
+                                   cricket::PORTALLOCATOR_DISABLE_RELAY |
+                                   cricket::PORTALLOCATOR_DISABLE_TCP;
+// Addresses on the public internet.
+static const SocketAddress kPublicAddrs[2] =
+    { SocketAddress("11.11.11.11", 0), SocketAddress("22.22.22.22", 0) };
+// IPv6 Addresses on the public internet.
+static const SocketAddress kIPv6PublicAddrs[2] = {
+    SocketAddress("2400:4030:1:2c00:be30:abcd:efab:cdef", 0),
+    SocketAddress("2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0)
+};
+// For configuring multihomed clients.
+static const SocketAddress kAlternateAddrs[2] =
+    { SocketAddress("11.11.11.101", 0), SocketAddress("22.22.22.202", 0) };
+// Addresses for HTTP proxy servers.
+static const SocketAddress kHttpsProxyAddrs[2] =
+    { SocketAddress("11.11.11.1", 443), SocketAddress("22.22.22.1", 443) };
+// Addresses for SOCKS proxy servers.
+static const SocketAddress kSocksProxyAddrs[2] =
+    { SocketAddress("11.11.11.1", 1080), SocketAddress("22.22.22.1", 1080) };
+// Internal addresses for NAT boxes.
+static const SocketAddress kNatAddrs[2] =
+    { SocketAddress("192.168.1.1", 0), SocketAddress("192.168.2.1", 0) };
+// Private addresses inside the NAT private networks.
+static const SocketAddress kPrivateAddrs[2] =
+    { SocketAddress("192.168.1.11", 0), SocketAddress("192.168.2.22", 0) };
+// For cascaded NATs, the internal addresses of the inner NAT boxes.
+static const SocketAddress kCascadedNatAddrs[2] =
+    { SocketAddress("192.168.10.1", 0), SocketAddress("192.168.20.1", 0) };
+// For cascaded NATs, private addresses inside the inner private networks.
+static const SocketAddress kCascadedPrivateAddrs[2] =
+    { SocketAddress("192.168.10.11", 0), SocketAddress("192.168.20.22", 0) };
+// The address of the public STUN server.
+static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
+// The addresses for the public relay server.
+static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000);
+static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001);
+static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002);
+static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003);
+static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004);
+static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005);
+// The addresses for the public turn server.
+static const SocketAddress kTurnUdpIntAddr("99.99.99.4",
+                                           cricket::STUN_SERVER_PORT);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
+static const cricket::RelayCredentials kRelayCredentials("test", "test");
+
+// Based on ICE_UFRAG_LENGTH
+static const char* kIceUfrag[4] = {"TESTICEUFRAG0000", "TESTICEUFRAG0001",
+                                   "TESTICEUFRAG0002", "TESTICEUFRAG0003"};
+// Based on ICE_PWD_LENGTH
+static const char* kIcePwd[4] = {"TESTICEPWD00000000000000",
+                                 "TESTICEPWD00000000000001",
+                                 "TESTICEPWD00000000000002",
+                                 "TESTICEPWD00000000000003"};
+
+static const uint64 kTiebreaker1 = 11111;
+static const uint64 kTiebreaker2 = 22222;
+
+// This test simulates 2 P2P endpoints that want to establish connectivity
+// with each other over various network topologies and conditions, which can be
+// specified in each individial test.
+// A virtual network (via VirtualSocketServer) along with virtual firewalls and
+// NATs (via Firewall/NATSocketServer) are used to simulate the various network
+// conditions. We can configure the IP addresses of the endpoints,
+// block various types of connectivity, or add arbitrary levels of NAT.
+// We also run a STUN server and a relay server on the virtual network to allow
+// our typical P2P mechanisms to do their thing.
+// For each case, we expect the P2P stack to eventually settle on a specific
+// form of connectivity to the other side. The test checks that the P2P
+// negotiation successfully establishes connectivity within a certain time,
+// and that the result is what we expect.
+// Note that this class is a base class for use by other tests, who will provide
+// specialized test behavior.
+class P2PTransportChannelTestBase : public testing::Test,
+                                    public rtc::MessageHandler,
+                                    public sigslot::has_slots<> {
+ public:
+  P2PTransportChannelTestBase()
+      : main_(rtc::Thread::Current()),
+        pss_(new rtc::PhysicalSocketServer),
+        vss_(new rtc::VirtualSocketServer(pss_.get())),
+        nss_(new rtc::NATSocketServer(vss_.get())),
+        ss_(new rtc::FirewallSocketServer(nss_.get())),
+        ss_scope_(ss_.get()),
+        stun_server_(cricket::TestStunServer::Create(main_, kStunAddr)),
+        turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr),
+        relay_server_(main_, kRelayUdpIntAddr, kRelayUdpExtAddr,
+                      kRelayTcpIntAddr, kRelayTcpExtAddr,
+                      kRelaySslTcpIntAddr, kRelaySslTcpExtAddr),
+        socks_server1_(ss_.get(), kSocksProxyAddrs[0],
+                       ss_.get(), kSocksProxyAddrs[0]),
+        socks_server2_(ss_.get(), kSocksProxyAddrs[1],
+                       ss_.get(), kSocksProxyAddrs[1]),
+        clear_remote_candidates_ufrag_pwd_(false),
+        force_relay_(false) {
+    ep1_.role_ = cricket::ICEROLE_CONTROLLING;
+    ep2_.role_ = cricket::ICEROLE_CONTROLLED;
+
+    ServerAddresses stun_servers;
+    stun_servers.insert(kStunAddr);
+    ep1_.allocator_.reset(new cricket::BasicPortAllocator(
+        &ep1_.network_manager_,
+        stun_servers, kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr));
+    ep2_.allocator_.reset(new cricket::BasicPortAllocator(
+        &ep2_.network_manager_,
+        stun_servers, kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr));
+  }
+
+ protected:
+  enum Config {
+    OPEN,                           // Open to the Internet
+    NAT_FULL_CONE,                  // NAT, no filtering
+    NAT_ADDR_RESTRICTED,            // NAT, must send to an addr to recv
+    NAT_PORT_RESTRICTED,            // NAT, must send to an addr+port to recv
+    NAT_SYMMETRIC,                  // NAT, endpoint-dependent bindings
+    NAT_DOUBLE_CONE,                // Double NAT, both cone
+    NAT_SYMMETRIC_THEN_CONE,        // Double NAT, symmetric outer, cone inner
+    BLOCK_UDP,                      // Firewall, UDP in/out blocked
+    BLOCK_UDP_AND_INCOMING_TCP,     // Firewall, UDP in/out and TCP in blocked
+    BLOCK_ALL_BUT_OUTGOING_HTTP,    // Firewall, only TCP out on 80/443
+    PROXY_HTTPS,                    // All traffic through HTTPS proxy
+    PROXY_SOCKS,                    // All traffic through SOCKS proxy
+    NUM_CONFIGS
+  };
+
+  struct Result {
+    Result(const std::string& lt, const std::string& lp,
+           const std::string& rt, const std::string& rp,
+           const std::string& lt2, const std::string& lp2,
+           const std::string& rt2, const std::string& rp2, int wait)
+        : local_type(lt), local_proto(lp), remote_type(rt), remote_proto(rp),
+          local_type2(lt2), local_proto2(lp2), remote_type2(rt2),
+          remote_proto2(rp2), connect_wait(wait) {
+    }
+    std::string local_type;
+    std::string local_proto;
+    std::string remote_type;
+    std::string remote_proto;
+    std::string local_type2;
+    std::string local_proto2;
+    std::string remote_type2;
+    std::string remote_proto2;
+    int connect_wait;
+  };
+
+  struct ChannelData {
+    bool CheckData(const char* data, int len) {
+      bool ret = false;
+      if (!ch_packets_.empty()) {
+        std::string packet =  ch_packets_.front();
+        ret = (packet == std::string(data, len));
+        ch_packets_.pop_front();
+      }
+      return ret;
+    }
+
+    std::string name_;  // TODO - Currently not used.
+    std::list<std::string> ch_packets_;
+    rtc::scoped_ptr<cricket::P2PTransportChannel> ch_;
+  };
+
+  struct Endpoint {
+    Endpoint() : signaling_delay_(0), role_(cricket::ICEROLE_UNKNOWN),
+        tiebreaker_(0), role_conflict_(false),
+        protocol_type_(cricket::ICEPROTO_GOOGLE) {}
+    bool HasChannel(cricket::TransportChannel* ch) {
+      return (ch == cd1_.ch_.get() || ch == cd2_.ch_.get());
+    }
+    ChannelData* GetChannelData(cricket::TransportChannel* ch) {
+      if (!HasChannel(ch)) return NULL;
+      if (cd1_.ch_.get() == ch)
+        return &cd1_;
+      else
+        return &cd2_;
+    }
+    void SetSignalingDelay(int delay) { signaling_delay_ = delay; }
+
+    void SetIceRole(cricket::IceRole role) { role_ = role; }
+    cricket::IceRole ice_role() { return role_; }
+    void SetIceProtocolType(cricket::IceProtocolType type) {
+      protocol_type_ = type;
+    }
+    cricket::IceProtocolType protocol_type() { return protocol_type_; }
+    void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
+    uint64 GetIceTiebreaker() { return tiebreaker_; }
+    void OnRoleConflict(bool role_conflict) { role_conflict_ = role_conflict; }
+    bool role_conflict() { return role_conflict_; }
+    void SetAllocationStepDelay(uint32 delay) {
+      allocator_->set_step_delay(delay);
+    }
+    void SetAllowTcpListen(bool allow_tcp_listen) {
+      allocator_->set_allow_tcp_listen(allow_tcp_listen);
+    }
+
+    rtc::FakeNetworkManager network_manager_;
+    rtc::scoped_ptr<cricket::BasicPortAllocator> allocator_;
+    ChannelData cd1_;
+    ChannelData cd2_;
+    int signaling_delay_;
+    cricket::IceRole role_;
+    uint64 tiebreaker_;
+    bool role_conflict_;
+    cricket::IceProtocolType protocol_type_;
+  };
+
+  struct CandidateData : public rtc::MessageData {
+    CandidateData(cricket::TransportChannel* ch, const cricket::Candidate& c)
+        : channel(ch), candidate(c) {
+    }
+    cricket::TransportChannel* channel;
+    cricket::Candidate candidate;
+  };
+
+  ChannelData* GetChannelData(cricket::TransportChannel* channel) {
+    if (ep1_.HasChannel(channel))
+      return ep1_.GetChannelData(channel);
+    else
+      return ep2_.GetChannelData(channel);
+  }
+
+  void CreateChannels(int num) {
+    std::string ice_ufrag_ep1_cd1_ch = kIceUfrag[0];
+    std::string ice_pwd_ep1_cd1_ch = kIcePwd[0];
+    std::string ice_ufrag_ep2_cd1_ch = kIceUfrag[1];
+    std::string ice_pwd_ep2_cd1_ch = kIcePwd[1];
+    ep1_.cd1_.ch_.reset(CreateChannel(
+        0, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT,
+        ice_ufrag_ep1_cd1_ch, ice_pwd_ep1_cd1_ch,
+        ice_ufrag_ep2_cd1_ch, ice_pwd_ep2_cd1_ch));
+    ep2_.cd1_.ch_.reset(CreateChannel(
+        1, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT,
+        ice_ufrag_ep2_cd1_ch, ice_pwd_ep2_cd1_ch,
+        ice_ufrag_ep1_cd1_ch, ice_pwd_ep1_cd1_ch));
+    if (num == 2) {
+      std::string ice_ufrag_ep1_cd2_ch = kIceUfrag[2];
+      std::string ice_pwd_ep1_cd2_ch = kIcePwd[2];
+      std::string ice_ufrag_ep2_cd2_ch = kIceUfrag[3];
+      std::string ice_pwd_ep2_cd2_ch = kIcePwd[3];
+      // In BUNDLE each endpoint must share common ICE credentials.
+      if (ep1_.allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE) {
+        ice_ufrag_ep1_cd2_ch = ice_ufrag_ep1_cd1_ch;
+        ice_pwd_ep1_cd2_ch = ice_pwd_ep1_cd1_ch;
+      }
+      if (ep2_.allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE) {
+        ice_ufrag_ep2_cd2_ch = ice_ufrag_ep2_cd1_ch;
+        ice_pwd_ep2_cd2_ch = ice_pwd_ep2_cd1_ch;
+      }
+      ep1_.cd2_.ch_.reset(CreateChannel(
+          0, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT,
+          ice_ufrag_ep1_cd2_ch, ice_pwd_ep1_cd2_ch,
+          ice_ufrag_ep2_cd2_ch, ice_pwd_ep2_cd2_ch));
+      ep2_.cd2_.ch_.reset(CreateChannel(
+          1, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT,
+          ice_ufrag_ep2_cd2_ch, ice_pwd_ep2_cd2_ch,
+          ice_ufrag_ep1_cd2_ch, ice_pwd_ep1_cd2_ch));
+    }
+  }
+  cricket::P2PTransportChannel* CreateChannel(
+      int endpoint,
+      int component,
+      const std::string& local_ice_ufrag,
+      const std::string& local_ice_pwd,
+      const std::string& remote_ice_ufrag,
+      const std::string& remote_ice_pwd) {
+    cricket::P2PTransportChannel* channel = new cricket::P2PTransportChannel(
+        "test content name", component, NULL, GetAllocator(endpoint));
+    channel->SignalRequestSignaling.connect(
+        this, &P2PTransportChannelTestBase::OnChannelRequestSignaling);
+    channel->SignalCandidateReady.connect(this,
+        &P2PTransportChannelTestBase::OnCandidate);
+    channel->SignalReadPacket.connect(
+        this, &P2PTransportChannelTestBase::OnReadPacket);
+    channel->SignalRoleConflict.connect(
+        this, &P2PTransportChannelTestBase::OnRoleConflict);
+    channel->SetIceProtocolType(GetEndpoint(endpoint)->protocol_type());
+    channel->SetIceCredentials(local_ice_ufrag, local_ice_pwd);
+    if (clear_remote_candidates_ufrag_pwd_) {
+      // This only needs to be set if we're clearing them from the
+      // candidates.  Some unit tests rely on this not being set.
+      channel->SetRemoteIceCredentials(remote_ice_ufrag, remote_ice_pwd);
+    }
+    channel->SetIceRole(GetEndpoint(endpoint)->ice_role());
+    channel->SetIceTiebreaker(GetEndpoint(endpoint)->GetIceTiebreaker());
+    channel->Connect();
+    return channel;
+  }
+  void DestroyChannels() {
+    ep1_.cd1_.ch_.reset();
+    ep2_.cd1_.ch_.reset();
+    ep1_.cd2_.ch_.reset();
+    ep2_.cd2_.ch_.reset();
+  }
+  cricket::P2PTransportChannel* ep1_ch1() { return ep1_.cd1_.ch_.get(); }
+  cricket::P2PTransportChannel* ep1_ch2() { return ep1_.cd2_.ch_.get(); }
+  cricket::P2PTransportChannel* ep2_ch1() { return ep2_.cd1_.ch_.get(); }
+  cricket::P2PTransportChannel* ep2_ch2() { return ep2_.cd2_.ch_.get(); }
+
+  // Common results.
+  static const Result kLocalUdpToLocalUdp;
+  static const Result kLocalUdpToStunUdp;
+  static const Result kLocalUdpToPrflxUdp;
+  static const Result kPrflxUdpToLocalUdp;
+  static const Result kStunUdpToLocalUdp;
+  static const Result kStunUdpToStunUdp;
+  static const Result kPrflxUdpToStunUdp;
+  static const Result kLocalUdpToRelayUdp;
+  static const Result kPrflxUdpToRelayUdp;
+  static const Result kLocalTcpToLocalTcp;
+  static const Result kLocalTcpToPrflxTcp;
+  static const Result kPrflxTcpToLocalTcp;
+
+  rtc::NATSocketServer* nat() { return nss_.get(); }
+  rtc::FirewallSocketServer* fw() { return ss_.get(); }
+
+  Endpoint* GetEndpoint(int endpoint) {
+    if (endpoint == 0) {
+      return &ep1_;
+    } else if (endpoint == 1) {
+      return &ep2_;
+    } else {
+      return NULL;
+    }
+  }
+  cricket::PortAllocator* GetAllocator(int endpoint) {
+    return GetEndpoint(endpoint)->allocator_.get();
+  }
+  void AddAddress(int endpoint, const SocketAddress& addr) {
+    GetEndpoint(endpoint)->network_manager_.AddInterface(addr);
+  }
+  void RemoveAddress(int endpoint, const SocketAddress& addr) {
+    GetEndpoint(endpoint)->network_manager_.RemoveInterface(addr);
+  }
+  void SetProxy(int endpoint, rtc::ProxyType type) {
+    rtc::ProxyInfo info;
+    info.type = type;
+    info.address = (type == rtc::PROXY_HTTPS) ?
+        kHttpsProxyAddrs[endpoint] : kSocksProxyAddrs[endpoint];
+    GetAllocator(endpoint)->set_proxy("unittest/1.0", info);
+  }
+  void SetAllocatorFlags(int endpoint, int flags) {
+    GetAllocator(endpoint)->set_flags(flags);
+  }
+  void SetSignalingDelay(int endpoint, int delay) {
+    GetEndpoint(endpoint)->SetSignalingDelay(delay);
+  }
+  void SetIceProtocol(int endpoint, cricket::IceProtocolType type) {
+    GetEndpoint(endpoint)->SetIceProtocolType(type);
+  }
+  void SetIceRole(int endpoint, cricket::IceRole role) {
+    GetEndpoint(endpoint)->SetIceRole(role);
+  }
+  void SetIceTiebreaker(int endpoint, uint64 tiebreaker) {
+    GetEndpoint(endpoint)->SetIceTiebreaker(tiebreaker);
+  }
+  bool GetRoleConflict(int endpoint) {
+    return GetEndpoint(endpoint)->role_conflict();
+  }
+  void SetAllocationStepDelay(int endpoint, uint32 delay) {
+    return GetEndpoint(endpoint)->SetAllocationStepDelay(delay);
+  }
+  void SetAllowTcpListen(int endpoint, bool allow_tcp_listen) {
+    return GetEndpoint(endpoint)->SetAllowTcpListen(allow_tcp_listen);
+  }
+
+  void Test(const Result& expected) {
+    int32 connect_start = rtc::Time(), connect_time;
+
+    // Create the channels and wait for them to connect.
+    CreateChannels(1);
+    EXPECT_TRUE_WAIT_MARGIN(ep1_ch1() != NULL &&
+                            ep2_ch1() != NULL &&
+                            ep1_ch1()->readable() &&
+                            ep1_ch1()->writable() &&
+                            ep2_ch1()->readable() &&
+                            ep2_ch1()->writable(),
+                            expected.connect_wait,
+                            1000);
+    connect_time = rtc::TimeSince(connect_start);
+    if (connect_time < expected.connect_wait) {
+      LOG(LS_INFO) << "Connect time: " << connect_time << " ms";
+    } else {
+      LOG(LS_INFO) << "Connect time: " << "TIMEOUT ("
+                   << expected.connect_wait << " ms)";
+    }
+
+    // Allow a few turns of the crank for the best connections to emerge.
+    // This may take up to 2 seconds.
+    if (ep1_ch1()->best_connection() &&
+        ep2_ch1()->best_connection()) {
+      int32 converge_start = rtc::Time(), converge_time;
+      int converge_wait = 2000;
+      EXPECT_TRUE_WAIT_MARGIN(
+          LocalCandidate(ep1_ch1())->type() == expected.local_type &&
+          LocalCandidate(ep1_ch1())->protocol() == expected.local_proto &&
+          RemoteCandidate(ep1_ch1())->type() == expected.remote_type &&
+          RemoteCandidate(ep1_ch1())->protocol() == expected.remote_proto,
+          converge_wait,
+          converge_wait);
+
+      // Also do EXPECT_EQ on each part so that failures are more verbose.
+      EXPECT_EQ(expected.local_type, LocalCandidate(ep1_ch1())->type());
+      EXPECT_EQ(expected.local_proto, LocalCandidate(ep1_ch1())->protocol());
+      EXPECT_EQ(expected.remote_type, RemoteCandidate(ep1_ch1())->type());
+      EXPECT_EQ(expected.remote_proto, RemoteCandidate(ep1_ch1())->protocol());
+
+      // Verifying remote channel best connection information. This is done
+      // only for the RFC 5245 as controlled agent will use USE-CANDIDATE
+      // from controlling (ep1) agent. We can easily predict from EP1 result
+      // matrix.
+      if (ep2_.protocol_type_ == cricket::ICEPROTO_RFC5245) {
+        // Checking for best connection candidates information at remote.
+        EXPECT_TRUE_WAIT(
+            LocalCandidate(ep2_ch1())->type() == expected.local_type2 &&
+            LocalCandidate(ep2_ch1())->protocol() == expected.local_proto2 &&
+            RemoteCandidate(ep2_ch1())->protocol() == expected.remote_proto2,
+            kDefaultTimeout);
+
+        // For verbose
+        EXPECT_EQ(expected.local_type2, LocalCandidate(ep2_ch1())->type());
+        EXPECT_EQ(expected.local_proto2, LocalCandidate(ep2_ch1())->protocol());
+        EXPECT_EQ(expected.remote_proto2,
+                  RemoteCandidate(ep2_ch1())->protocol());
+        // Removed remote_type comparision aginst best connection remote
+        // candidate. This is done to handle remote type discrepancy from
+        // local to stun based on the test type.
+        // For example in case of Open -> NAT, ep2 channels will have LULU
+        // and in other cases like NAT -> NAT it will be LUSU. To avoid these
+        // mismatches and we are doing comparision in different way.
+        // i.e. when don't match its remote type is either local or stun.
+        // TODO(ronghuawu): Refine the test criteria.
+        // https://code.google.com/p/webrtc/issues/detail?id=1953
+        if (expected.remote_type2 != RemoteCandidate(ep2_ch1())->type()) {
+          EXPECT_TRUE(expected.remote_type2 == cricket::LOCAL_PORT_TYPE ||
+                      expected.remote_type2 == cricket::STUN_PORT_TYPE);
+          EXPECT_TRUE(
+              RemoteCandidate(ep2_ch1())->type() == cricket::LOCAL_PORT_TYPE ||
+              RemoteCandidate(ep2_ch1())->type() == cricket::STUN_PORT_TYPE ||
+              RemoteCandidate(ep2_ch1())->type() == cricket::PRFLX_PORT_TYPE);
+        }
+      }
+
+      converge_time = rtc::TimeSince(converge_start);
+      if (converge_time < converge_wait) {
+        LOG(LS_INFO) << "Converge time: " << converge_time << " ms";
+      } else {
+        LOG(LS_INFO) << "Converge time: " << "TIMEOUT ("
+                     << converge_wait << " ms)";
+      }
+    }
+    // Try sending some data to other end.
+    TestSendRecv(1);
+
+    // Destroy the channels, and wait for them to be fully cleaned up.
+    DestroyChannels();
+  }
+
+  void TestSendRecv(int channels) {
+    for (int i = 0; i < 10; ++i) {
+    const char* data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+      int len = static_cast<int>(strlen(data));
+      // local_channel1 <==> remote_channel1
+      EXPECT_EQ_WAIT(len, SendData(ep1_ch1(), data, len), 1000);
+      EXPECT_TRUE_WAIT(CheckDataOnChannel(ep2_ch1(), data, len), 1000);
+      EXPECT_EQ_WAIT(len, SendData(ep2_ch1(), data, len), 1000);
+      EXPECT_TRUE_WAIT(CheckDataOnChannel(ep1_ch1(), data, len), 1000);
+      if (channels == 2 && ep1_ch2() && ep2_ch2()) {
+        // local_channel2 <==> remote_channel2
+        EXPECT_EQ_WAIT(len, SendData(ep1_ch2(), data, len), 1000);
+        EXPECT_TRUE_WAIT(CheckDataOnChannel(ep2_ch2(), data, len), 1000);
+        EXPECT_EQ_WAIT(len, SendData(ep2_ch2(), data, len), 1000);
+        EXPECT_TRUE_WAIT(CheckDataOnChannel(ep1_ch2(), data, len), 1000);
+      }
+    }
+  }
+
+  // This test waits for the transport to become readable and writable on both
+  // end points. Once they are, the end points set new local ice credentials to
+  // restart the ice gathering. Finally it waits for the transport to select a
+  // new connection using the newly generated ice candidates.
+  // Before calling this function the end points must be configured.
+  void TestHandleIceUfragPasswordChanged() {
+    ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
+    ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[0], kIcePwd[0]);
+    EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                            ep2_ch1()->readable() && ep2_ch1()->writable(),
+                            1000, 1000);
+
+    const cricket::Candidate* old_local_candidate1 = LocalCandidate(ep1_ch1());
+    const cricket::Candidate* old_local_candidate2 = LocalCandidate(ep2_ch1());
+    const cricket::Candidate* old_remote_candidate1 =
+        RemoteCandidate(ep1_ch1());
+    const cricket::Candidate* old_remote_candidate2 =
+        RemoteCandidate(ep2_ch1());
+
+    ep1_ch1()->SetIceCredentials(kIceUfrag[2], kIcePwd[2]);
+    ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
+    ep2_ch1()->SetIceCredentials(kIceUfrag[3], kIcePwd[3]);
+    ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
+
+    EXPECT_TRUE_WAIT_MARGIN(LocalCandidate(ep1_ch1())->generation() !=
+                            old_local_candidate1->generation(),
+                            1000, 1000);
+    EXPECT_TRUE_WAIT_MARGIN(LocalCandidate(ep2_ch1())->generation() !=
+                            old_local_candidate2->generation(),
+                            1000, 1000);
+    EXPECT_TRUE_WAIT_MARGIN(RemoteCandidate(ep1_ch1())->generation() !=
+                            old_remote_candidate1->generation(),
+                            1000, 1000);
+    EXPECT_TRUE_WAIT_MARGIN(RemoteCandidate(ep2_ch1())->generation() !=
+                            old_remote_candidate2->generation(),
+                            1000, 1000);
+    EXPECT_EQ(1u, RemoteCandidate(ep2_ch1())->generation());
+    EXPECT_EQ(1u, RemoteCandidate(ep1_ch1())->generation());
+  }
+
+  void TestSignalRoleConflict() {
+    SetIceProtocol(0, cricket::ICEPROTO_RFC5245);
+    SetIceTiebreaker(0, kTiebreaker1);  // Default EP1 is in controlling state.
+
+    SetIceProtocol(1, cricket::ICEPROTO_RFC5245);
+    SetIceRole(1, cricket::ICEROLE_CONTROLLING);
+    SetIceTiebreaker(1, kTiebreaker2);
+
+    // Creating channels with both channels role set to CONTROLLING.
+    CreateChannels(1);
+    // Since both the channels initiated with controlling state and channel2
+    // has higher tiebreaker value, channel1 should receive SignalRoleConflict.
+    EXPECT_TRUE_WAIT(GetRoleConflict(0), 1000);
+    EXPECT_FALSE(GetRoleConflict(1));
+
+    EXPECT_TRUE_WAIT(ep1_ch1()->readable() &&
+                     ep1_ch1()->writable() &&
+                     ep2_ch1()->readable() &&
+                     ep2_ch1()->writable(),
+                     1000);
+
+    EXPECT_TRUE(ep1_ch1()->best_connection() &&
+                ep2_ch1()->best_connection());
+
+    TestSendRecv(1);
+  }
+
+  void TestHybridConnectivity(cricket::IceProtocolType proto) {
+    AddAddress(0, kPublicAddrs[0]);
+    AddAddress(1, kPublicAddrs[1]);
+
+    SetAllocationStepDelay(0, kMinimumStepDelay);
+    SetAllocationStepDelay(1, kMinimumStepDelay);
+
+    SetIceRole(0, cricket::ICEROLE_CONTROLLING);
+    SetIceProtocol(0, cricket::ICEPROTO_HYBRID);
+    SetIceTiebreaker(0, kTiebreaker1);
+    SetIceRole(1, cricket::ICEROLE_CONTROLLED);
+    SetIceProtocol(1, proto);
+    SetIceTiebreaker(1, kTiebreaker2);
+
+    CreateChannels(1);
+    // When channel is in hybrid and it's controlling agent, channel will
+    // receive ping request from the remote. Hence connection is readable.
+    // Since channel is in hybrid, it will not send any pings, so no writable
+    // connection. Since channel2 is in controlled state, it will not have
+    // any connections which are readable or writable, as it didn't received
+    // pings (or none) with USE-CANDIDATE attribute.
+    EXPECT_TRUE_WAIT(ep1_ch1()->readable(), 1000);
+
+    // Set real protocol type.
+    ep1_ch1()->SetIceProtocolType(proto);
+
+    // Channel should able to send ping requests and connections become writable
+    // in both directions.
+    EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                     ep2_ch1()->readable() && ep2_ch1()->writable(),
+                     1000);
+    EXPECT_TRUE(
+        ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+        LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+        RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+
+    TestSendRecv(1);
+    DestroyChannels();
+  }
+
+  void OnChannelRequestSignaling(cricket::TransportChannelImpl* channel) {
+    channel->OnSignalingReady();
+  }
+  // We pass the candidates directly to the other side.
+  void OnCandidate(cricket::TransportChannelImpl* ch,
+                   const cricket::Candidate& c) {
+    if (force_relay_ && c.type() != cricket::RELAY_PORT_TYPE)
+      return;
+
+    main_->PostDelayed(GetEndpoint(ch)->signaling_delay_, this, 0,
+                       new CandidateData(ch, c));
+  }
+  void OnMessage(rtc::Message* msg) {
+    rtc::scoped_ptr<CandidateData> data(
+        static_cast<CandidateData*>(msg->pdata));
+    cricket::P2PTransportChannel* rch = GetRemoteChannel(data->channel);
+    cricket::Candidate c = data->candidate;
+    if (clear_remote_candidates_ufrag_pwd_) {
+      c.set_username("");
+      c.set_password("");
+    }
+    LOG(LS_INFO) << "Candidate(" << data->channel->component() << "->"
+                 << rch->component() << "): " << c.type() << ", " << c.protocol()
+                 << ", " << c.address().ToString() << ", " << c.username()
+                 << ", " << c.generation();
+    rch->OnCandidate(c);
+  }
+  void OnReadPacket(cricket::TransportChannel* channel, const char* data,
+                    size_t len, const rtc::PacketTime& packet_time,
+                    int flags) {
+    std::list<std::string>& packets = GetPacketList(channel);
+    packets.push_front(std::string(data, len));
+  }
+  void OnRoleConflict(cricket::TransportChannelImpl* channel) {
+    GetEndpoint(channel)->OnRoleConflict(true);
+    cricket::IceRole new_role =
+        GetEndpoint(channel)->ice_role() == cricket::ICEROLE_CONTROLLING ?
+            cricket::ICEROLE_CONTROLLED : cricket::ICEROLE_CONTROLLING;
+    channel->SetIceRole(new_role);
+  }
+  int SendData(cricket::TransportChannel* channel,
+               const char* data, size_t len) {
+    rtc::PacketOptions options;
+    return channel->SendPacket(data, len, options, 0);
+  }
+  bool CheckDataOnChannel(cricket::TransportChannel* channel,
+                          const char* data, int len) {
+    return GetChannelData(channel)->CheckData(data, len);
+  }
+  static const cricket::Candidate* LocalCandidate(
+      cricket::P2PTransportChannel* ch) {
+    return (ch && ch->best_connection()) ?
+        &ch->best_connection()->local_candidate() : NULL;
+  }
+  static const cricket::Candidate* RemoteCandidate(
+      cricket::P2PTransportChannel* ch) {
+    return (ch && ch->best_connection()) ?
+        &ch->best_connection()->remote_candidate() : NULL;
+  }
+  Endpoint* GetEndpoint(cricket::TransportChannel* ch) {
+    if (ep1_.HasChannel(ch)) {
+      return &ep1_;
+    } else if (ep2_.HasChannel(ch)) {
+      return &ep2_;
+    } else {
+      return NULL;
+    }
+  }
+  cricket::P2PTransportChannel* GetRemoteChannel(
+      cricket::TransportChannel* ch) {
+    if (ch == ep1_ch1())
+      return ep2_ch1();
+    else if (ch == ep1_ch2())
+      return ep2_ch2();
+    else if (ch == ep2_ch1())
+      return ep1_ch1();
+    else if (ch == ep2_ch2())
+      return ep1_ch2();
+    else
+      return NULL;
+  }
+  std::list<std::string>& GetPacketList(cricket::TransportChannel* ch) {
+    return GetChannelData(ch)->ch_packets_;
+  }
+
+  void set_clear_remote_candidates_ufrag_pwd(bool clear) {
+    clear_remote_candidates_ufrag_pwd_ = clear;
+  }
+
+  void set_force_relay(bool relay) {
+    force_relay_ = relay;
+  }
+
+ private:
+  rtc::Thread* main_;
+  rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> vss_;
+  rtc::scoped_ptr<rtc::NATSocketServer> nss_;
+  rtc::scoped_ptr<rtc::FirewallSocketServer> ss_;
+  rtc::SocketServerScope ss_scope_;
+  rtc::scoped_ptr<cricket::TestStunServer> stun_server_;
+  cricket::TestTurnServer turn_server_;
+  cricket::TestRelayServer relay_server_;
+  rtc::SocksProxyServer socks_server1_;
+  rtc::SocksProxyServer socks_server2_;
+  Endpoint ep1_;
+  Endpoint ep2_;
+  bool clear_remote_candidates_ufrag_pwd_;
+  bool force_relay_;
+};
+
+// The tests have only a few outcomes, which we predefine.
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kLocalUdpToLocalUdp("local", "udp", "local", "udp",
+                        "local", "udp", "local", "udp", 1000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kLocalUdpToStunUdp("local", "udp", "stun", "udp",
+                       "local", "udp", "stun", "udp", 1000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kLocalUdpToPrflxUdp("local", "udp", "prflx", "udp",
+                        "prflx", "udp", "local", "udp", 1000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kPrflxUdpToLocalUdp("prflx", "udp", "local", "udp",
+                        "local", "udp", "prflx", "udp", 1000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kStunUdpToLocalUdp("stun", "udp", "local", "udp",
+                       "local", "udp", "stun", "udp", 1000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kStunUdpToStunUdp("stun", "udp", "stun", "udp",
+                      "stun", "udp", "stun", "udp", 1000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kPrflxUdpToStunUdp("prflx", "udp", "stun", "udp",
+                       "local", "udp", "prflx", "udp", 1000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kLocalUdpToRelayUdp("local", "udp", "relay", "udp",
+                        "relay", "udp", "local", "udp", 2000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kPrflxUdpToRelayUdp("prflx", "udp", "relay", "udp",
+                        "relay", "udp", "prflx", "udp", 2000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kLocalTcpToLocalTcp("local", "tcp", "local", "tcp",
+                        "local", "tcp", "local", "tcp", 3000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kLocalTcpToPrflxTcp("local", "tcp", "prflx", "tcp",
+                        "prflx", "tcp", "local", "tcp", 3000);
+const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase::
+    kPrflxTcpToLocalTcp("prflx", "tcp", "local", "tcp",
+                        "local", "tcp", "prflx", "tcp", 3000);
+
+// Test the matrix of all the connectivity types we expect to see in the wild.
+// Just test every combination of the configs in the Config enum.
+class P2PTransportChannelTest : public P2PTransportChannelTestBase {
+ protected:
+  static const Result* kMatrix[NUM_CONFIGS][NUM_CONFIGS];
+  static const Result* kMatrixSharedUfrag[NUM_CONFIGS][NUM_CONFIGS];
+  static const Result* kMatrixSharedSocketAsGice[NUM_CONFIGS][NUM_CONFIGS];
+  static const Result* kMatrixSharedSocketAsIce[NUM_CONFIGS][NUM_CONFIGS];
+  void ConfigureEndpoints(Config config1, Config config2,
+      int allocator_flags1, int allocator_flags2,
+      int delay1, int delay2,
+      cricket::IceProtocolType type) {
+    // Ideally we want to use TURN server for both GICE and ICE, but in case
+    // of GICE, TURN server usage is not producing results reliabally.
+    // TODO(mallinath): Remove Relay and use TURN server for all tests.
+    ServerAddresses stun_servers;
+    stun_servers.insert(kStunAddr);
+    GetEndpoint(0)->allocator_.reset(
+        new cricket::BasicPortAllocator(&(GetEndpoint(0)->network_manager_),
+        stun_servers,
+        rtc::SocketAddress(), rtc::SocketAddress(),
+        rtc::SocketAddress()));
+    GetEndpoint(1)->allocator_.reset(
+        new cricket::BasicPortAllocator(&(GetEndpoint(1)->network_manager_),
+        stun_servers,
+        rtc::SocketAddress(), rtc::SocketAddress(),
+        rtc::SocketAddress()));
+
+    cricket::RelayServerConfig relay_server(cricket::RELAY_GTURN);
+    if (type == cricket::ICEPROTO_RFC5245) {
+      relay_server.type = cricket::RELAY_TURN;
+      relay_server.credentials = kRelayCredentials;
+      relay_server.ports.push_back(cricket::ProtocolAddress(
+          kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+    } else {
+      relay_server.ports.push_back(cricket::ProtocolAddress(
+          kRelayUdpIntAddr, cricket::PROTO_UDP, false));
+      relay_server.ports.push_back(cricket::ProtocolAddress(
+          kRelayTcpIntAddr, cricket::PROTO_TCP, false));
+      relay_server.ports.push_back(cricket::ProtocolAddress(
+          kRelaySslTcpIntAddr, cricket::PROTO_SSLTCP, false));
+    }
+    GetEndpoint(0)->allocator_->AddRelay(relay_server);
+    GetEndpoint(1)->allocator_->AddRelay(relay_server);
+
+    ConfigureEndpoint(0, config1);
+    SetIceProtocol(0, type);
+    SetAllocatorFlags(0, allocator_flags1);
+    SetAllocationStepDelay(0, delay1);
+    ConfigureEndpoint(1, config2);
+    SetIceProtocol(1, type);
+    SetAllocatorFlags(1, allocator_flags2);
+    SetAllocationStepDelay(1, delay2);
+  }
+  void ConfigureEndpoint(int endpoint, Config config) {
+    switch (config) {
+      case OPEN:
+        AddAddress(endpoint, kPublicAddrs[endpoint]);
+        break;
+      case NAT_FULL_CONE:
+      case NAT_ADDR_RESTRICTED:
+      case NAT_PORT_RESTRICTED:
+      case NAT_SYMMETRIC:
+        AddAddress(endpoint, kPrivateAddrs[endpoint]);
+        // Add a single NAT of the desired type
+        nat()->AddTranslator(kPublicAddrs[endpoint], kNatAddrs[endpoint],
+            static_cast<rtc::NATType>(config - NAT_FULL_CONE))->
+            AddClient(kPrivateAddrs[endpoint]);
+        break;
+      case NAT_DOUBLE_CONE:
+      case NAT_SYMMETRIC_THEN_CONE:
+        AddAddress(endpoint, kCascadedPrivateAddrs[endpoint]);
+        // Add a two cascaded NATs of the desired types
+        nat()->AddTranslator(kPublicAddrs[endpoint], kNatAddrs[endpoint],
+            (config == NAT_DOUBLE_CONE) ?
+                rtc::NAT_OPEN_CONE : rtc::NAT_SYMMETRIC)->
+            AddTranslator(kPrivateAddrs[endpoint], kCascadedNatAddrs[endpoint],
+                rtc::NAT_OPEN_CONE)->
+                AddClient(kCascadedPrivateAddrs[endpoint]);
+        break;
+      case BLOCK_UDP:
+      case BLOCK_UDP_AND_INCOMING_TCP:
+      case BLOCK_ALL_BUT_OUTGOING_HTTP:
+      case PROXY_HTTPS:
+      case PROXY_SOCKS:
+        AddAddress(endpoint, kPublicAddrs[endpoint]);
+        // Block all UDP
+        fw()->AddRule(false, rtc::FP_UDP, rtc::FD_ANY,
+                      kPublicAddrs[endpoint]);
+        if (config == BLOCK_UDP_AND_INCOMING_TCP) {
+          // Block TCP inbound to the endpoint
+          fw()->AddRule(false, rtc::FP_TCP, SocketAddress(),
+                        kPublicAddrs[endpoint]);
+        } else if (config == BLOCK_ALL_BUT_OUTGOING_HTTP) {
+          // Block all TCP to/from the endpoint except 80/443 out
+          fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint],
+                        SocketAddress(rtc::IPAddress(INADDR_ANY), 80));
+          fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint],
+                        SocketAddress(rtc::IPAddress(INADDR_ANY), 443));
+          fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
+                        kPublicAddrs[endpoint]);
+        } else if (config == PROXY_HTTPS) {
+          // Block all TCP to/from the endpoint except to the proxy server
+          fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint],
+                        kHttpsProxyAddrs[endpoint]);
+          fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
+                        kPublicAddrs[endpoint]);
+          SetProxy(endpoint, rtc::PROXY_HTTPS);
+        } else if (config == PROXY_SOCKS) {
+          // Block all TCP to/from the endpoint except to the proxy server
+          fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint],
+                        kSocksProxyAddrs[endpoint]);
+          fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
+                        kPublicAddrs[endpoint]);
+          SetProxy(endpoint, rtc::PROXY_SOCKS5);
+        }
+        break;
+      default:
+        break;
+    }
+  }
+};
+
+// Shorthands for use in the test matrix.
+#define LULU &kLocalUdpToLocalUdp
+#define LUSU &kLocalUdpToStunUdp
+#define LUPU &kLocalUdpToPrflxUdp
+#define PULU &kPrflxUdpToLocalUdp
+#define SULU &kStunUdpToLocalUdp
+#define SUSU &kStunUdpToStunUdp
+#define PUSU &kPrflxUdpToStunUdp
+#define LURU &kLocalUdpToRelayUdp
+#define PURU &kPrflxUdpToRelayUdp
+#define LTLT &kLocalTcpToLocalTcp
+#define LTPT &kLocalTcpToPrflxTcp
+#define PTLT &kPrflxTcpToLocalTcp
+// TODO: Enable these once TestRelayServer can accept external TCP.
+#define LTRT NULL
+#define LSRS NULL
+
+// Test matrix. Originator behavior defined by rows, receiever by columns.
+
+// Currently the p2ptransportchannel.cc (specifically the
+// P2PTransportChannel::OnUnknownAddress) operates in 2 modes depend on the
+// remote candidates - ufrag per port or shared ufrag.
+// For example, if the remote candidates have the shared ufrag, for the unknown
+// address reaches the OnUnknownAddress, we will try to find the matched
+// remote candidate based on the address and protocol, if not found, a new
+// remote candidate will be created for this address. But if the remote
+// candidates have different ufrags, we will try to find the matched remote
+// candidate by comparing the ufrag. If not found, an error will be returned.
+// Because currently the shared ufrag feature is under the experiment and will
+// be rolled out gradually. We want to test the different combinations of peers
+// with/without the shared ufrag enabled. And those different combinations have
+// different expectation of the best connection. For example in the OpenToCONE
+// case, an unknown address will be updated to a "host" remote candidate if the
+// remote peer uses different ufrag per port. But in the shared ufrag case,
+// a "stun" (should be peer-reflexive eventually) candidate will be created for
+// that. So the expected best candidate will be LUSU instead of LULU.
+// With all these, we have to keep 2 test matrixes for the tests:
+// kMatrix - for the tests that the remote peer uses different ufrag per port.
+// kMatrixSharedUfrag - for the tests that remote peer uses shared ufrag.
+// The different between the two matrixes are on:
+// OPToCONE, OPTo2CON,
+// COToCONE, COToADDR, COToPORT, COToSYMM, COTo2CON, COToSCON,
+// ADToCONE, ADToADDR, ADTo2CON,
+// POToADDR,
+// SYToADDR,
+// 2CToCONE, 2CToADDR, 2CToPORT, 2CToSYMM, 2CTo2CON, 2CToSCON,
+// SCToADDR,
+
+// TODO: Fix NULLs caused by lack of TCP support in NATSocket.
+// TODO: Fix NULLs caused by no HTTP proxy support.
+// TODO: Rearrange rows/columns from best to worst.
+// TODO(ronghuawu): Keep only one test matrix once the shared ufrag is enabled.
+const P2PTransportChannelTest::Result*
+    P2PTransportChannelTest::kMatrix[NUM_CONFIGS][NUM_CONFIGS] = {
+//      OPEN  CONE  ADDR  PORT  SYMM  2CON  SCON  !UDP  !TCP  HTTP  PRXH  PRXS
+/*OP*/ {LULU, LULU, LULU, LULU, LULU, LULU, LULU, LTLT, LTLT, LSRS, NULL, LTLT},
+/*CO*/ {LULU, LULU, LULU, SULU, SULU, LULU, SULU, NULL, NULL, LSRS, NULL, LTRT},
+/*AD*/ {LULU, LULU, LULU, SUSU, SUSU, LULU, SUSU, NULL, NULL, LSRS, NULL, LTRT},
+/*PO*/ {LULU, LUSU, LUSU, SUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*SY*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*2C*/ {LULU, LULU, LULU, SULU, SULU, LULU, SULU, NULL, NULL, LSRS, NULL, LTRT},
+/*SC*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*!U*/ {LTLT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTLT, LSRS, NULL, LTRT},
+/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTRT, LSRS, NULL, LTRT},
+/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS},
+/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT},
+};
+const P2PTransportChannelTest::Result*
+    P2PTransportChannelTest::kMatrixSharedUfrag[NUM_CONFIGS][NUM_CONFIGS] = {
+//      OPEN  CONE  ADDR  PORT  SYMM  2CON  SCON  !UDP  !TCP  HTTP  PRXH  PRXS
+/*OP*/ {LULU, LUSU, LULU, LULU, LULU, LUSU, LULU, LTLT, LTLT, LSRS, NULL, LTLT},
+/*CO*/ {LULU, LUSU, LUSU, SUSU, SUSU, LUSU, SUSU, NULL, NULL, LSRS, NULL, LTRT},
+/*AD*/ {LULU, LUSU, LUSU, SUSU, SUSU, LUSU, SUSU, NULL, NULL, LSRS, NULL, LTRT},
+/*PO*/ {LULU, LUSU, LUSU, SUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*SY*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*2C*/ {LULU, LUSU, LUSU, SUSU, SUSU, LUSU, SUSU, NULL, NULL, LSRS, NULL, LTRT},
+/*SC*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*!U*/ {LTLT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTLT, LSRS, NULL, LTRT},
+/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTRT, LSRS, NULL, LTRT},
+/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS},
+/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT},
+};
+const P2PTransportChannelTest::Result*
+    P2PTransportChannelTest::kMatrixSharedSocketAsGice
+        [NUM_CONFIGS][NUM_CONFIGS] = {
+//      OPEN  CONE  ADDR  PORT  SYMM  2CON  SCON  !UDP  !TCP  HTTP  PRXH  PRXS
+/*OP*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, LTLT, LTLT, LSRS, NULL, LTLT},
+/*CO*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, NULL, NULL, LSRS, NULL, LTRT},
+/*AD*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, NULL, NULL, LSRS, NULL, LTRT},
+/*PO*/ {LULU, LUSU, LUSU, LUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*SY*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*2C*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, NULL, NULL, LSRS, NULL, LTRT},
+/*SC*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*!U*/ {LTLT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTLT, LSRS, NULL, LTRT},
+/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTRT, LSRS, NULL, LTRT},
+/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS},
+/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT},
+};
+const P2PTransportChannelTest::Result*
+    P2PTransportChannelTest::kMatrixSharedSocketAsIce
+        [NUM_CONFIGS][NUM_CONFIGS] = {
+//      OPEN  CONE  ADDR  PORT  SYMM  2CON  SCON  !UDP  !TCP  HTTP  PRXH  PRXS
+/*OP*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, PTLT, LTPT, LSRS, NULL, PTLT},
+/*CO*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, NULL, NULL, LSRS, NULL, LTRT},
+/*AD*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, NULL, NULL, LSRS, NULL, LTRT},
+/*PO*/ {LULU, LUSU, LUSU, LUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT},
+/*SY*/ {PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL, LTRT},
+/*2C*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, NULL, NULL, LSRS, NULL, LTRT},
+/*SC*/ {PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL, LTRT},
+/*!U*/ {PTLT, NULL, NULL, NULL, NULL, NULL, NULL, PTLT, LTPT, LSRS, NULL, LTRT},
+/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, PTLT, LTRT, LSRS, NULL, LTRT},
+/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS},
+/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT},
+};
+
+// The actual tests that exercise all the various configurations.
+// Test names are of the form P2PTransportChannelTest_TestOPENToNAT_FULL_CONE
+// Same test case is run in both GICE and ICE mode.
+// kDefaultStepDelay - is used for all Gice cases.
+// kMinimumStepDelay - is used when both end points have
+//                     PORTALLOCATOR_ENABLE_SHARED_UFRAG flag enabled.
+// Technically we should be able to use kMinimumStepDelay irrespective of
+// protocol type. But which might need modifications to current result matrices
+// for tests in this file.
+#define P2P_TEST_DECLARATION(x, y, z) \
+  TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceNoneSharedUfrag) { \
+    ConfigureEndpoints(x, y, kDefaultPortAllocatorFlags, \
+                       kDefaultPortAllocatorFlags, \
+                       kDefaultStepDelay, kDefaultStepDelay, \
+                       cricket::ICEPROTO_GOOGLE); \
+    if (kMatrix[x][y] != NULL) \
+      Test(*kMatrix[x][y]); \
+    else \
+      LOG(LS_WARNING) << "Not yet implemented"; \
+  } \
+  TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceP0SharedUfrag) { \
+    ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG, \
+                       kDefaultPortAllocatorFlags, \
+                       kDefaultStepDelay, kDefaultStepDelay, \
+                       cricket::ICEPROTO_GOOGLE); \
+    if (kMatrix[x][y] != NULL) \
+      Test(*kMatrix[x][y]); \
+    else \
+      LOG(LS_WARNING) << "Not yet implemented"; \
+  } \
+  TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceP1SharedUfrag) { \
+    ConfigureEndpoints(x, y, kDefaultPortAllocatorFlags, \
+                       PORTALLOCATOR_ENABLE_SHARED_UFRAG, \
+                       kDefaultStepDelay, kDefaultStepDelay, \
+                       cricket::ICEPROTO_GOOGLE); \
+    if (kMatrixSharedUfrag[x][y] != NULL) \
+      Test(*kMatrixSharedUfrag[x][y]); \
+    else \
+      LOG(LS_WARNING) << "Not yet implemented"; \
+  } \
+  TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceBothSharedUfrag) { \
+    ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG, \
+                       PORTALLOCATOR_ENABLE_SHARED_UFRAG, \
+                       kDefaultStepDelay, kDefaultStepDelay, \
+                       cricket::ICEPROTO_GOOGLE); \
+    if (kMatrixSharedUfrag[x][y] != NULL) \
+      Test(*kMatrixSharedUfrag[x][y]); \
+    else \
+      LOG(LS_WARNING) << "Not yet implemented"; \
+  } \
+  TEST_F(P2PTransportChannelTest, \
+         z##Test##x##To##y##AsGiceBothSharedUfragWithMinimumStepDelay) { \
+    ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG, \
+                       PORTALLOCATOR_ENABLE_SHARED_UFRAG, \
+                       kMinimumStepDelay, kMinimumStepDelay, \
+                       cricket::ICEPROTO_GOOGLE); \
+    if (kMatrixSharedUfrag[x][y] != NULL) \
+      Test(*kMatrixSharedUfrag[x][y]); \
+    else \
+      LOG(LS_WARNING) << "Not yet implemented"; \
+  } \
+  TEST_F(P2PTransportChannelTest, \
+         z##Test##x##To##y##AsGiceBothSharedUfragSocket) { \
+    ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG | \
+                       PORTALLOCATOR_ENABLE_SHARED_SOCKET, \
+                       PORTALLOCATOR_ENABLE_SHARED_UFRAG | \
+                       PORTALLOCATOR_ENABLE_SHARED_SOCKET, \
+                       kMinimumStepDelay, kMinimumStepDelay, \
+                       cricket::ICEPROTO_GOOGLE); \
+    if (kMatrixSharedSocketAsGice[x][y] != NULL) \
+      Test(*kMatrixSharedSocketAsGice[x][y]); \
+    else \
+    LOG(LS_WARNING) << "Not yet implemented"; \
+  } \
+  TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsIce) { \
+    ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG | \
+                       PORTALLOCATOR_ENABLE_SHARED_SOCKET, \
+                       PORTALLOCATOR_ENABLE_SHARED_UFRAG | \
+                       PORTALLOCATOR_ENABLE_SHARED_SOCKET, \
+                       kMinimumStepDelay, kMinimumStepDelay, \
+                       cricket::ICEPROTO_RFC5245); \
+    if (kMatrixSharedSocketAsIce[x][y] != NULL) \
+      Test(*kMatrixSharedSocketAsIce[x][y]); \
+    else \
+    LOG(LS_WARNING) << "Not yet implemented"; \
+  }
+
+#define P2P_TEST(x, y) \
+  P2P_TEST_DECLARATION(x, y,)
+
+#define FLAKY_P2P_TEST(x, y) \
+  P2P_TEST_DECLARATION(x, y, DISABLED_)
+
+// TODO(holmer): Disabled due to randomly failing on webrtc buildbots.
+// Issue: webrtc/2383
+#define P2P_TEST_SET(x) \
+  P2P_TEST(x, OPEN) \
+  FLAKY_P2P_TEST(x, NAT_FULL_CONE) \
+  FLAKY_P2P_TEST(x, NAT_ADDR_RESTRICTED) \
+  FLAKY_P2P_TEST(x, NAT_PORT_RESTRICTED) \
+  P2P_TEST(x, NAT_SYMMETRIC) \
+  FLAKY_P2P_TEST(x, NAT_DOUBLE_CONE) \
+  P2P_TEST(x, NAT_SYMMETRIC_THEN_CONE) \
+  P2P_TEST(x, BLOCK_UDP) \
+  P2P_TEST(x, BLOCK_UDP_AND_INCOMING_TCP) \
+  P2P_TEST(x, BLOCK_ALL_BUT_OUTGOING_HTTP) \
+  P2P_TEST(x, PROXY_HTTPS) \
+  P2P_TEST(x, PROXY_SOCKS)
+
+#define FLAKY_P2P_TEST_SET(x) \
+  P2P_TEST(x, OPEN) \
+  P2P_TEST(x, NAT_FULL_CONE) \
+  P2P_TEST(x, NAT_ADDR_RESTRICTED) \
+  P2P_TEST(x, NAT_PORT_RESTRICTED) \
+  P2P_TEST(x, NAT_SYMMETRIC) \
+  P2P_TEST(x, NAT_DOUBLE_CONE) \
+  P2P_TEST(x, NAT_SYMMETRIC_THEN_CONE) \
+  P2P_TEST(x, BLOCK_UDP) \
+  P2P_TEST(x, BLOCK_UDP_AND_INCOMING_TCP) \
+  P2P_TEST(x, BLOCK_ALL_BUT_OUTGOING_HTTP) \
+  P2P_TEST(x, PROXY_HTTPS) \
+  P2P_TEST(x, PROXY_SOCKS)
+
+P2P_TEST_SET(OPEN)
+P2P_TEST_SET(NAT_FULL_CONE)
+P2P_TEST_SET(NAT_ADDR_RESTRICTED)
+P2P_TEST_SET(NAT_PORT_RESTRICTED)
+P2P_TEST_SET(NAT_SYMMETRIC)
+P2P_TEST_SET(NAT_DOUBLE_CONE)
+P2P_TEST_SET(NAT_SYMMETRIC_THEN_CONE)
+P2P_TEST_SET(BLOCK_UDP)
+P2P_TEST_SET(BLOCK_UDP_AND_INCOMING_TCP)
+P2P_TEST_SET(BLOCK_ALL_BUT_OUTGOING_HTTP)
+P2P_TEST_SET(PROXY_HTTPS)
+P2P_TEST_SET(PROXY_SOCKS)
+
+// Test that we restart candidate allocation when local ufrag&pwd changed.
+// Standard Ice protocol is used.
+TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsIce) {
+  ConfigureEndpoints(OPEN, OPEN,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     kMinimumStepDelay, kMinimumStepDelay,
+                     cricket::ICEPROTO_RFC5245);
+  CreateChannels(1);
+  TestHandleIceUfragPasswordChanged();
+  DestroyChannels();
+}
+
+// Test that we restart candidate allocation when local ufrag&pwd changed.
+// Standard Ice protocol is used.
+TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsIce) {
+  ConfigureEndpoints(OPEN, OPEN,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     kMinimumStepDelay, kMinimumStepDelay,
+                     cricket::ICEPROTO_RFC5245);
+  SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+  SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+
+  CreateChannels(2);
+  TestHandleIceUfragPasswordChanged();
+  DestroyChannels();
+}
+
+// Test that we restart candidate allocation when local ufrag&pwd changed.
+// Google Ice protocol is used.
+TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsGice) {
+  ConfigureEndpoints(OPEN, OPEN,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     kDefaultStepDelay, kDefaultStepDelay,
+                     cricket::ICEPROTO_GOOGLE);
+  CreateChannels(1);
+  TestHandleIceUfragPasswordChanged();
+  DestroyChannels();
+}
+
+// Test that ICE restart works when bundle is enabled.
+// Google Ice protocol is used.
+TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsGice) {
+  ConfigureEndpoints(OPEN, OPEN,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     kDefaultStepDelay, kDefaultStepDelay,
+                     cricket::ICEPROTO_GOOGLE);
+  SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+  SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+
+  CreateChannels(2);
+  TestHandleIceUfragPasswordChanged();
+  DestroyChannels();
+}
+
+// Test the operation of GetStats.
+TEST_F(P2PTransportChannelTest, GetStats) {
+  ConfigureEndpoints(OPEN, OPEN,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultStepDelay, kDefaultStepDelay,
+                     cricket::ICEPROTO_GOOGLE);
+  CreateChannels(1);
+  EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                          ep2_ch1()->readable() && ep2_ch1()->writable(),
+                          1000, 1000);
+  TestSendRecv(1);
+  cricket::ConnectionInfos infos;
+  ASSERT_TRUE(ep1_ch1()->GetStats(&infos));
+  ASSERT_EQ(1U, infos.size());
+  EXPECT_TRUE(infos[0].new_connection);
+  EXPECT_TRUE(infos[0].best_connection);
+  EXPECT_TRUE(infos[0].readable);
+  EXPECT_TRUE(infos[0].writable);
+  EXPECT_FALSE(infos[0].timeout);
+  EXPECT_EQ(10 * 36U, infos[0].sent_total_bytes);
+  EXPECT_EQ(10 * 36U, infos[0].recv_total_bytes);
+  EXPECT_GT(infos[0].rtt, 0U);
+  DestroyChannels();
+}
+
+// Test that we properly handle getting a STUN error due to slow signaling.
+TEST_F(P2PTransportChannelTest, DISABLED_SlowSignaling) {
+  ConfigureEndpoints(OPEN, NAT_SYMMETRIC,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultStepDelay, kDefaultStepDelay,
+                     cricket::ICEPROTO_GOOGLE);
+  // Make signaling from the callee take 500ms, so that the initial STUN pings
+  // from the callee beat the signaling, and so the caller responds with a
+  // unknown username error. We should just eat that and carry on; mishandling
+  // this will instead cause all the callee's connections to be discarded.
+  SetSignalingDelay(1, 1000);
+  CreateChannels(1);
+  const cricket::Connection* best_connection = NULL;
+  // Wait until the callee's connections are created.
+  WAIT((best_connection = ep2_ch1()->best_connection()) != NULL, 1000);
+  // Wait to see if they get culled; they shouldn't.
+  WAIT(ep2_ch1()->best_connection() != best_connection, 1000);
+  EXPECT_TRUE(ep2_ch1()->best_connection() == best_connection);
+  DestroyChannels();
+}
+
+// Test that if remote candidates don't have ufrag and pwd, we still work.
+TEST_F(P2PTransportChannelTest, RemoteCandidatesWithoutUfragPwd) {
+  set_clear_remote_candidates_ufrag_pwd(true);
+  ConfigureEndpoints(OPEN, OPEN,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     kMinimumStepDelay, kMinimumStepDelay,
+                     cricket::ICEPROTO_GOOGLE);
+  CreateChannels(1);
+  const cricket::Connection* best_connection = NULL;
+  // Wait until the callee's connections are created.
+  WAIT((best_connection = ep2_ch1()->best_connection()) != NULL, 1000);
+  // Wait to see if they get culled; they shouldn't.
+  WAIT(ep2_ch1()->best_connection() != best_connection, 1000);
+  EXPECT_TRUE(ep2_ch1()->best_connection() == best_connection);
+  DestroyChannels();
+}
+
+// Test that a host behind NAT cannot be reached when incoming_only
+// is set to true.
+TEST_F(P2PTransportChannelTest, IncomingOnlyBlocked) {
+  ConfigureEndpoints(NAT_FULL_CONE, OPEN,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultStepDelay, kDefaultStepDelay,
+                     cricket::ICEPROTO_GOOGLE);
+
+  SetAllocatorFlags(0, kOnlyLocalPorts);
+  CreateChannels(1);
+  ep1_ch1()->set_incoming_only(true);
+
+  // Pump for 1 second and verify that the channels are not connected.
+  rtc::Thread::Current()->ProcessMessages(1000);
+
+  EXPECT_FALSE(ep1_ch1()->readable());
+  EXPECT_FALSE(ep1_ch1()->writable());
+  EXPECT_FALSE(ep2_ch1()->readable());
+  EXPECT_FALSE(ep2_ch1()->writable());
+
+  DestroyChannels();
+}
+
+// Test that a peer behind NAT can connect to a peer that has
+// incoming_only flag set.
+TEST_F(P2PTransportChannelTest, IncomingOnlyOpen) {
+  ConfigureEndpoints(OPEN, NAT_FULL_CONE,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultPortAllocatorFlags,
+                     kDefaultStepDelay, kDefaultStepDelay,
+                     cricket::ICEPROTO_GOOGLE);
+
+  SetAllocatorFlags(0, kOnlyLocalPorts);
+  CreateChannels(1);
+  ep1_ch1()->set_incoming_only(true);
+
+  EXPECT_TRUE_WAIT_MARGIN(ep1_ch1() != NULL && ep2_ch1() != NULL &&
+                          ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                          ep2_ch1()->readable() && ep2_ch1()->writable(),
+                          1000, 1000);
+
+  DestroyChannels();
+}
+
+TEST_F(P2PTransportChannelTest, TestTcpConnectionsFromActiveToPassive) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+
+  SetAllocationStepDelay(0, kMinimumStepDelay);
+  SetAllocationStepDelay(1, kMinimumStepDelay);
+
+  int kOnlyLocalTcpPorts = cricket::PORTALLOCATOR_DISABLE_UDP |
+                           cricket::PORTALLOCATOR_DISABLE_STUN |
+                           cricket::PORTALLOCATOR_DISABLE_RELAY |
+                           cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG;
+  // Disable all protocols except TCP.
+  SetAllocatorFlags(0, kOnlyLocalTcpPorts);
+  SetAllocatorFlags(1, kOnlyLocalTcpPorts);
+
+  SetAllowTcpListen(0, true);   // actpass.
+  SetAllowTcpListen(1, false);  // active.
+
+  CreateChannels(1);
+
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() && ep2_ch1()->writable(),
+                   1000);
+  EXPECT_TRUE(
+      ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+      RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+
+  std::string kTcpProtocol = "tcp";
+  EXPECT_EQ(kTcpProtocol, RemoteCandidate(ep1_ch1())->protocol());
+  EXPECT_EQ(kTcpProtocol, LocalCandidate(ep1_ch1())->protocol());
+  EXPECT_EQ(kTcpProtocol, RemoteCandidate(ep2_ch1())->protocol());
+  EXPECT_EQ(kTcpProtocol, LocalCandidate(ep2_ch1())->protocol());
+
+  TestSendRecv(1);
+  DestroyChannels();
+}
+
+TEST_F(P2PTransportChannelTest, TestBundleAllocatorToBundleAllocator) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+  SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+
+  CreateChannels(2);
+
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() &&
+                   ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() &&
+                   ep2_ch1()->writable(),
+                   1000);
+  EXPECT_TRUE(ep1_ch1()->best_connection() &&
+              ep2_ch1()->best_connection());
+
+  EXPECT_FALSE(ep1_ch2()->readable());
+  EXPECT_FALSE(ep1_ch2()->writable());
+  EXPECT_FALSE(ep2_ch2()->readable());
+  EXPECT_FALSE(ep2_ch2()->writable());
+
+  TestSendRecv(1);  // Only 1 channel is writable per Endpoint.
+  DestroyChannels();
+}
+
+TEST_F(P2PTransportChannelTest, TestBundleAllocatorToNonBundleAllocator) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  // Enable BUNDLE flag at one side.
+  SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+
+  CreateChannels(2);
+
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() &&
+                   ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() &&
+                   ep2_ch1()->writable(),
+                   1000);
+  EXPECT_TRUE_WAIT(ep1_ch2()->readable() &&
+                   ep1_ch2()->writable() &&
+                   ep2_ch2()->readable() &&
+                   ep2_ch2()->writable(),
+                   1000);
+
+  EXPECT_TRUE(ep1_ch1()->best_connection() &&
+              ep2_ch1()->best_connection());
+  EXPECT_TRUE(ep1_ch2()->best_connection() &&
+              ep2_ch2()->best_connection());
+
+  TestSendRecv(2);
+  DestroyChannels();
+}
+
+TEST_F(P2PTransportChannelTest, TestIceRoleConflictWithoutBundle) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  TestSignalRoleConflict();
+}
+
+TEST_F(P2PTransportChannelTest, TestIceRoleConflictWithBundle) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+  SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+  TestSignalRoleConflict();
+}
+
+// Tests that the ice configs (protocol, tiebreaker and role) can be passed
+// down to ports.
+TEST_F(P2PTransportChannelTest, TestIceConfigWillPassDownToPort) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+
+  SetIceRole(0, cricket::ICEROLE_CONTROLLING);
+  SetIceProtocol(0, cricket::ICEPROTO_GOOGLE);
+  SetIceTiebreaker(0, kTiebreaker1);
+  SetIceRole(1, cricket::ICEROLE_CONTROLLING);
+  SetIceProtocol(1, cricket::ICEPROTO_RFC5245);
+  SetIceTiebreaker(1, kTiebreaker2);
+
+  CreateChannels(1);
+
+  EXPECT_EQ_WAIT(2u, ep1_ch1()->ports().size(), 1000);
+
+  const std::vector<cricket::PortInterface *> ports_before = ep1_ch1()->ports();
+  for (size_t i = 0; i < ports_before.size(); ++i) {
+    EXPECT_EQ(cricket::ICEROLE_CONTROLLING, ports_before[i]->GetIceRole());
+    EXPECT_EQ(cricket::ICEPROTO_GOOGLE, ports_before[i]->IceProtocol());
+    EXPECT_EQ(kTiebreaker1, ports_before[i]->IceTiebreaker());
+  }
+
+  ep1_ch1()->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  ep1_ch1()->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+  ep1_ch1()->SetIceTiebreaker(kTiebreaker2);
+
+  const std::vector<cricket::PortInterface *> ports_after = ep1_ch1()->ports();
+  for (size_t i = 0; i < ports_after.size(); ++i) {
+    EXPECT_EQ(cricket::ICEROLE_CONTROLLED, ports_before[i]->GetIceRole());
+    EXPECT_EQ(cricket::ICEPROTO_RFC5245, ports_before[i]->IceProtocol());
+    // SetIceTiebreaker after Connect() has been called will fail. So expect the
+    // original value.
+    EXPECT_EQ(kTiebreaker1, ports_before[i]->IceTiebreaker());
+  }
+
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() &&
+                   ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() &&
+                   ep2_ch1()->writable(),
+                   1000);
+
+  EXPECT_TRUE(ep1_ch1()->best_connection() &&
+              ep2_ch1()->best_connection());
+
+  TestSendRecv(1);
+  DestroyChannels();
+}
+
+// This test verifies channel can handle ice messages when channel is in
+// hybrid mode.
+TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandIce) {
+  TestHybridConnectivity(cricket::ICEPROTO_RFC5245);
+}
+
+// This test verifies channel can handle Gice messages when channel is in
+// hybrid mode.
+TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandGice) {
+  TestHybridConnectivity(cricket::ICEPROTO_GOOGLE);
+}
+
+// Verify that we can set DSCP value and retrieve properly from P2PTC.
+TEST_F(P2PTransportChannelTest, TestDefaultDscpValue) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+
+  CreateChannels(1);
+  EXPECT_EQ(rtc::DSCP_NO_CHANGE,
+            GetEndpoint(0)->cd1_.ch_->DefaultDscpValue());
+  EXPECT_EQ(rtc::DSCP_NO_CHANGE,
+            GetEndpoint(1)->cd1_.ch_->DefaultDscpValue());
+  GetEndpoint(0)->cd1_.ch_->SetOption(
+      rtc::Socket::OPT_DSCP, rtc::DSCP_CS6);
+  GetEndpoint(1)->cd1_.ch_->SetOption(
+      rtc::Socket::OPT_DSCP, rtc::DSCP_CS6);
+  EXPECT_EQ(rtc::DSCP_CS6,
+            GetEndpoint(0)->cd1_.ch_->DefaultDscpValue());
+  EXPECT_EQ(rtc::DSCP_CS6,
+            GetEndpoint(1)->cd1_.ch_->DefaultDscpValue());
+  GetEndpoint(0)->cd1_.ch_->SetOption(
+      rtc::Socket::OPT_DSCP, rtc::DSCP_AF41);
+  GetEndpoint(1)->cd1_.ch_->SetOption(
+      rtc::Socket::OPT_DSCP, rtc::DSCP_AF41);
+  EXPECT_EQ(rtc::DSCP_AF41,
+            GetEndpoint(0)->cd1_.ch_->DefaultDscpValue());
+  EXPECT_EQ(rtc::DSCP_AF41,
+            GetEndpoint(1)->cd1_.ch_->DefaultDscpValue());
+}
+
+// Verify IPv6 connection is preferred over IPv4.
+// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3317
+TEST_F(P2PTransportChannelTest, DISABLED_TestIPv6Connections) {
+  AddAddress(0, kIPv6PublicAddrs[0]);
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kIPv6PublicAddrs[1]);
+  AddAddress(1, kPublicAddrs[1]);
+
+  SetAllocationStepDelay(0, kMinimumStepDelay);
+  SetAllocationStepDelay(1, kMinimumStepDelay);
+
+  // Enable IPv6
+  SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_IPV6);
+  SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_IPV6);
+
+  CreateChannels(1);
+
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() && ep2_ch1()->writable(),
+                   1000);
+  EXPECT_TRUE(
+      ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[0]) &&
+      RemoteCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[1]));
+
+  TestSendRecv(1);
+  DestroyChannels();
+}
+
+// Testing forceful TURN connections.
+TEST_F(P2PTransportChannelTest, TestForceTurn) {
+  ConfigureEndpoints(NAT_PORT_RESTRICTED, NAT_SYMMETRIC,
+                     kDefaultPortAllocatorFlags |
+                         cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+                         cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     kDefaultPortAllocatorFlags |
+                         cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+                         cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+                     kDefaultStepDelay, kDefaultStepDelay,
+                     cricket::ICEPROTO_RFC5245);
+  set_force_relay(true);
+
+  SetAllocationStepDelay(0, kMinimumStepDelay);
+  SetAllocationStepDelay(1, kMinimumStepDelay);
+
+  CreateChannels(1);
+
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() &&
+                   ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() &&
+                   ep2_ch1()->writable(),
+                   1000);
+
+  EXPECT_TRUE(ep1_ch1()->best_connection() &&
+              ep2_ch1()->best_connection());
+
+  EXPECT_EQ("relay", RemoteCandidate(ep1_ch1())->type());
+  EXPECT_EQ("relay", LocalCandidate(ep1_ch1())->type());
+  EXPECT_EQ("relay", RemoteCandidate(ep2_ch1())->type());
+  EXPECT_EQ("relay", LocalCandidate(ep2_ch1())->type());
+
+  TestSendRecv(1);
+  DestroyChannels();
+}
+
+// Test what happens when we have 2 users behind the same NAT. This can lead
+// to interesting behavior because the STUN server will only give out the
+// address of the outermost NAT.
+class P2PTransportChannelSameNatTest : public P2PTransportChannelTestBase {
+ protected:
+  void ConfigureEndpoints(Config nat_type, Config config1, Config config2) {
+    ASSERT(nat_type >= NAT_FULL_CONE && nat_type <= NAT_SYMMETRIC);
+    rtc::NATSocketServer::Translator* outer_nat =
+        nat()->AddTranslator(kPublicAddrs[0], kNatAddrs[0],
+            static_cast<rtc::NATType>(nat_type - NAT_FULL_CONE));
+    ConfigureEndpoint(outer_nat, 0, config1);
+    ConfigureEndpoint(outer_nat, 1, config2);
+  }
+  void ConfigureEndpoint(rtc::NATSocketServer::Translator* nat,
+                         int endpoint, Config config) {
+    ASSERT(config <= NAT_SYMMETRIC);
+    if (config == OPEN) {
+      AddAddress(endpoint, kPrivateAddrs[endpoint]);
+      nat->AddClient(kPrivateAddrs[endpoint]);
+    } else {
+      AddAddress(endpoint, kCascadedPrivateAddrs[endpoint]);
+      nat->AddTranslator(kPrivateAddrs[endpoint], kCascadedNatAddrs[endpoint],
+          static_cast<rtc::NATType>(config - NAT_FULL_CONE))->AddClient(
+              kCascadedPrivateAddrs[endpoint]);
+    }
+  }
+};
+
+TEST_F(P2PTransportChannelSameNatTest, TestConesBehindSameCone) {
+  ConfigureEndpoints(NAT_FULL_CONE, NAT_FULL_CONE, NAT_FULL_CONE);
+  Test(kLocalUdpToStunUdp);
+}
+
+// Test what happens when we have multiple available pathways.
+// In the future we will try different RTTs and configs for the different
+// interfaces, so that we can simulate a user with Ethernet and VPN networks.
+class P2PTransportChannelMultihomedTest : public P2PTransportChannelTestBase {
+};
+
+// Test that we can establish connectivity when both peers are multihomed.
+TEST_F(P2PTransportChannelMultihomedTest, DISABLED_TestBasic) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(0, kAlternateAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  AddAddress(1, kAlternateAddrs[1]);
+  Test(kLocalUdpToLocalUdp);
+}
+
+// Test that we can quickly switch links if an interface goes down.
+TEST_F(P2PTransportChannelMultihomedTest, TestFailover) {
+  AddAddress(0, kPublicAddrs[0]);
+  // Adding alternate address will make sure |kPublicAddrs| has the higher
+  // priority than others. This is due to FakeNetwork::AddInterface method.
+  AddAddress(1, kAlternateAddrs[1]);
+  AddAddress(1, kPublicAddrs[1]);
+
+  // Use only local ports for simplicity.
+  SetAllocatorFlags(0, kOnlyLocalPorts);
+  SetAllocatorFlags(1, kOnlyLocalPorts);
+
+  // Create channels and let them go writable, as usual.
+  CreateChannels(1);
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() && ep2_ch1()->writable(),
+                   1000);
+  EXPECT_TRUE(
+      ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+      RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+
+  // Blackhole any traffic to or from the public addrs.
+  LOG(LS_INFO) << "Failing over...";
+  fw()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY,
+                kPublicAddrs[1]);
+
+  // We should detect loss of connectivity within 5 seconds or so.
+  EXPECT_TRUE_WAIT(!ep1_ch1()->writable(), 7000);
+
+  // We should switch over to use the alternate addr immediately
+  // when we lose writability.
+  EXPECT_TRUE_WAIT(
+      ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+      RemoteCandidate(ep1_ch1())->address().EqualIPs(kAlternateAddrs[1]),
+      3000);
+
+  DestroyChannels();
+}
+
+// Test that we can switch links in a coordinated fashion.
+TEST_F(P2PTransportChannelMultihomedTest, TestDrain) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  // Use only local ports for simplicity.
+  SetAllocatorFlags(0, kOnlyLocalPorts);
+  SetAllocatorFlags(1, kOnlyLocalPorts);
+
+  // Create channels and let them go writable, as usual.
+  CreateChannels(1);
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() && ep2_ch1()->writable(),
+                   1000);
+  EXPECT_TRUE(
+      ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+      RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+
+  // Remove the public interface, add the alternate interface, and allocate
+  // a new generation of candidates for the new interface (via Connect()).
+  LOG(LS_INFO) << "Draining...";
+  AddAddress(1, kAlternateAddrs[1]);
+  RemoveAddress(1, kPublicAddrs[1]);
+  ep2_ch1()->Connect();
+
+  // We should switch over to use the alternate address after
+  // an exchange of pings.
+  EXPECT_TRUE_WAIT(
+      ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+      RemoteCandidate(ep1_ch1())->address().EqualIPs(kAlternateAddrs[1]),
+      3000);
+
+  DestroyChannels();
+}
diff --git a/p2p/base/packetsocketfactory.h b/p2p/base/packetsocketfactory.h
new file mode 100644
index 0000000..1f45fec
--- /dev/null
+++ b/p2p/base/packetsocketfactory.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_P2P_BASE_PACKETSOCKETFACTORY_H_
+#define WEBRTC_P2P_BASE_PACKETSOCKETFACTORY_H_
+
+#include "webrtc/base/proxyinfo.h"
+
+namespace rtc {
+
+class AsyncPacketSocket;
+class AsyncResolverInterface;
+
+class PacketSocketFactory {
+ public:
+  enum Options {
+    OPT_SSLTCP = 0x01,  // Pseudo-TLS.
+    OPT_TLS = 0x02,
+    OPT_STUN = 0x04,
+  };
+
+  PacketSocketFactory() { }
+  virtual ~PacketSocketFactory() { }
+
+  virtual AsyncPacketSocket* CreateUdpSocket(
+      const SocketAddress& address, int min_port, int max_port) = 0;
+  virtual AsyncPacketSocket* CreateServerTcpSocket(
+      const SocketAddress& local_address, int min_port, int max_port,
+      int opts) = 0;
+
+  // TODO: |proxy_info| and |user_agent| should be set
+  // per-factory and not when socket is created.
+  virtual AsyncPacketSocket* CreateClientTcpSocket(
+      const SocketAddress& local_address, const SocketAddress& remote_address,
+      const ProxyInfo& proxy_info, const std::string& user_agent, int opts) = 0;
+
+  virtual AsyncResolverInterface* CreateAsyncResolver() = 0;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory);
+};
+
+}  // namespace rtc
+
+#endif  // WEBRTC_P2P_BASE_PACKETSOCKETFACTORY_H_
diff --git a/p2p/base/parsing.cc b/p2p/base/parsing.cc
new file mode 100644
index 0000000..04d7e79
--- /dev/null
+++ b/p2p/base/parsing.cc
@@ -0,0 +1,141 @@
+/*
+ *  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 "webrtc/p2p/base/parsing.h"
+
+#include <stdlib.h>
+#include <algorithm>
+#include "webrtc/base/stringutils.h"
+
+namespace {
+static const char kTrue[] = "true";
+static const char kOne[] = "1";
+}
+
+namespace cricket {
+
+bool BadParse(const std::string& text, ParseError* err) {
+  if (err != NULL) {
+    err->text = text;
+  }
+  return false;
+}
+
+bool BadWrite(const std::string& text, WriteError* err) {
+  if (err != NULL) {
+    err->text = text;
+  }
+  return false;
+}
+
+std::string GetXmlAttr(const buzz::XmlElement* elem,
+                       const buzz::QName& name,
+                       const std::string& def) {
+  std::string val = elem->Attr(name);
+  return val.empty() ? def : val;
+}
+
+std::string GetXmlAttr(const buzz::XmlElement* elem,
+                       const buzz::QName& name,
+                       const char* def) {
+    return GetXmlAttr(elem, name, std::string(def));
+}
+
+bool GetXmlAttr(const buzz::XmlElement* elem,
+                const buzz::QName& name, bool def) {
+  std::string val = elem->Attr(name);
+  std::transform(val.begin(), val.end(), val.begin(), tolower);
+
+  return val.empty() ? def : (val == kTrue || val == kOne);
+}
+
+int GetXmlAttr(const buzz::XmlElement* elem,
+               const buzz::QName& name, int def) {
+  std::string val = elem->Attr(name);
+  return val.empty() ? def : atoi(val.c_str());
+}
+
+const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent,
+                                    const std::string& name) {
+  for (const buzz::XmlElement* child = parent->FirstElement();
+       child != NULL;
+       child = child->NextElement()) {
+    if (child->Name().LocalPart() == name) {
+      return child;
+    }
+  }
+  return NULL;
+}
+
+bool RequireXmlChild(const buzz::XmlElement* parent,
+                     const std::string& name,
+                     const buzz::XmlElement** child,
+                     ParseError* error) {
+  *child = GetXmlChild(parent, name);
+  if (*child == NULL) {
+    return BadParse("element '" + parent->Name().Merged() +
+                    "' missing required child '" + name,
+                    error);
+  } else {
+    return true;
+  }
+}
+
+bool RequireXmlAttr(const buzz::XmlElement* elem,
+                    const buzz::QName& name,
+                    std::string* value,
+                    ParseError* error) {
+  if (!elem->HasAttr(name)) {
+    return BadParse("element '" + elem->Name().Merged() +
+                    "' missing required attribute '"
+                    + name.Merged() + "'",
+                    error);
+  } else {
+    *value = elem->Attr(name);
+    return true;
+  }
+}
+
+void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem,
+                          const buzz::QName name,
+                          const std::string& value) {
+  if (!value.empty()) {
+    elem->AddAttr(name, value);
+  }
+}
+
+void AddXmlChildren(buzz::XmlElement* parent,
+                    const std::vector<buzz::XmlElement*>& children) {
+  for (std::vector<buzz::XmlElement*>::const_iterator iter = children.begin();
+       iter != children.end();
+       iter++) {
+    parent->AddElement(*iter);
+  }
+}
+
+void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest) {
+  for (const buzz::XmlElement* child = source->FirstElement();
+       child != NULL;
+       child = child->NextElement()) {
+    dest->AddElement(new buzz::XmlElement(*child));
+  }
+}
+
+std::vector<buzz::XmlElement*> CopyOfXmlChildren(const buzz::XmlElement* elem) {
+  std::vector<buzz::XmlElement*> children;
+  for (const buzz::XmlElement* child = elem->FirstElement();
+       child != NULL;
+       child = child->NextElement()) {
+    children.push_back(new buzz::XmlElement(*child));
+  }
+  return children;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/parsing.h b/p2p/base/parsing.h
new file mode 100644
index 0000000..6b32b5d
--- /dev/null
+++ b/p2p/base/parsing.h
@@ -0,0 +1,140 @@
+/*
+ *  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.
+ */
+
+#ifndef WEBRTC_P2P_BASE_PARSING_H_
+#define WEBRTC_P2P_BASE_PARSING_H_
+
+#include <string>
+#include <vector>
+#include "webrtc/libjingle/xmllite/xmlelement.h"  // Needed to delete ParseError.extra.
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/stringencode.h"
+
+namespace cricket {
+
+typedef std::vector<buzz::XmlElement*> XmlElements;
+
+// We decided "bool Parse(in, out*, error*)" is generally the best
+// parse signature.  "out Parse(in)" doesn't allow for errors.
+// "error* Parse(in, out*)" doesn't allow flexible memory management.
+
+// The error type for parsing.
+struct ParseError {
+ public:
+  // explains the error
+  std::string text;
+  // provide details about what wasn't parsable
+  const buzz::XmlElement* extra;
+
+  ParseError() : extra(NULL) {}
+
+  ~ParseError() {
+    delete extra;
+  }
+
+  void SetText(const std::string& text) {
+    this->text = text;
+  }
+};
+
+// The error type for writing.
+struct WriteError {
+  std::string text;
+
+  void SetText(const std::string& text) {
+    this->text = text;
+  }
+};
+
+// Convenience method for returning a message when parsing fails.
+bool BadParse(const std::string& text, ParseError* err);
+
+// Convenience method for returning a message when writing fails.
+bool BadWrite(const std::string& text, WriteError* error);
+
+// helper XML functions
+std::string GetXmlAttr(const buzz::XmlElement* elem,
+                       const buzz::QName& name,
+                       const std::string& def);
+std::string GetXmlAttr(const buzz::XmlElement* elem,
+                       const buzz::QName& name,
+                       const char* def);
+// Return true if the value is "true" or "1".
+bool GetXmlAttr(const buzz::XmlElement* elem,
+                const buzz::QName& name, bool def);
+int GetXmlAttr(const buzz::XmlElement* elem,
+               const buzz::QName& name, int def);
+
+template <class T>
+bool GetXmlAttr(const buzz::XmlElement* elem,
+                const buzz::QName& name,
+                T* val_out) {
+  if (!elem->HasAttr(name)) {
+    return false;
+  }
+  std::string unparsed = elem->Attr(name);
+  return rtc::FromString(unparsed, val_out);
+}
+
+template <class T>
+bool GetXmlAttr(const buzz::XmlElement* elem,
+                const buzz::QName& name,
+                const T& def,
+                T* val_out) {
+  if (!elem->HasAttr(name)) {
+    *val_out = def;
+    return true;
+  }
+  return GetXmlAttr(elem, name, val_out);
+}
+
+template <class T>
+bool AddXmlAttr(buzz::XmlElement* elem,
+                const buzz::QName& name, const T& val) {
+  std::string buf;
+  if (!rtc::ToString(val, &buf)) {
+    return false;
+  }
+  elem->AddAttr(name, buf);
+  return true;
+}
+
+template <class T>
+bool SetXmlBody(buzz::XmlElement* elem, const T& val) {
+  std::string buf;
+  if (!rtc::ToString(val, &buf)) {
+    return false;
+  }
+  elem->SetBodyText(buf);
+  return true;
+}
+
+const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent,
+                                    const std::string& name);
+
+bool RequireXmlChild(const buzz::XmlElement* parent,
+                     const std::string& name,
+                     const buzz::XmlElement** child,
+                     ParseError* error);
+bool RequireXmlAttr(const buzz::XmlElement* elem,
+                    const buzz::QName& name,
+                    std::string* value,
+                    ParseError* error);
+void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem,
+                          const buzz::QName name,
+                          const std::string& value);
+void AddXmlChildren(buzz::XmlElement* parent,
+                    const std::vector<buzz::XmlElement*>& children);
+void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest);
+std::vector<buzz::XmlElement*> CopyOfXmlChildren(const buzz::XmlElement* elem);
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_PARSING_H_
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
new file mode 100644
index 0000000..f569d9f
--- /dev/null
+++ b/p2p/base/port.cc
@@ -0,0 +1,1430 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/port.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/base/base64.h"
+#include "webrtc/base/crc32.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/messagedigest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/stringencode.h"
+#include "webrtc/base/stringutils.h"
+
+namespace {
+
+// Determines whether we have seen at least the given maximum number of
+// pings fail to have a response.
+inline bool TooManyFailures(
+    const std::vector<uint32>& pings_since_last_response,
+    uint32 maximum_failures,
+    uint32 rtt_estimate,
+    uint32 now) {
+
+  // If we haven't sent that many pings, then we can't have failed that many.
+  if (pings_since_last_response.size() < maximum_failures)
+    return false;
+
+  // Check if the window in which we would expect a response to the ping has
+  // already elapsed.
+  return pings_since_last_response[maximum_failures - 1] + rtt_estimate < now;
+}
+
+// Determines whether we have gone too long without seeing any response.
+inline bool TooLongWithoutResponse(
+    const std::vector<uint32>& pings_since_last_response,
+    uint32 maximum_time,
+    uint32 now) {
+
+  if (pings_since_last_response.size() == 0)
+    return false;
+
+  return pings_since_last_response[0] + maximum_time < now;
+}
+
+// GICE(ICEPROTO_GOOGLE) requires different username for RTP and RTCP.
+// This function generates a different username by +1 on the last character of
+// the given username (|rtp_ufrag|).
+std::string GetRtcpUfragFromRtpUfrag(const std::string& rtp_ufrag) {
+  ASSERT(!rtp_ufrag.empty());
+  if (rtp_ufrag.empty()) {
+    return rtp_ufrag;
+  }
+  // Change the last character to the one next to it in the base64 table.
+  char new_last_char;
+  if (!rtc::Base64::GetNextBase64Char(rtp_ufrag[rtp_ufrag.size() - 1],
+                                            &new_last_char)) {
+    // Should not be here.
+    ASSERT(false);
+  }
+  std::string rtcp_ufrag = rtp_ufrag;
+  rtcp_ufrag[rtcp_ufrag.size() - 1] = new_last_char;
+  ASSERT(rtcp_ufrag != rtp_ufrag);
+  return rtcp_ufrag;
+}
+
+// We will restrict RTT estimates (when used for determining state) to be
+// within a reasonable range.
+const uint32 MINIMUM_RTT = 100;   // 0.1 seconds
+const uint32 MAXIMUM_RTT = 3000;  // 3 seconds
+
+// When we don't have any RTT data, we have to pick something reasonable.  We
+// use a large value just in case the connection is really slow.
+const uint32 DEFAULT_RTT = MAXIMUM_RTT;
+
+// Computes our estimate of the RTT given the current estimate.
+inline uint32 ConservativeRTTEstimate(uint32 rtt) {
+  return rtc::_max(MINIMUM_RTT, rtc::_min(MAXIMUM_RTT, 2 * rtt));
+}
+
+// Weighting of the old rtt value to new data.
+const int RTT_RATIO = 3;  // 3 : 1
+
+// The delay before we begin checking if this port is useless.
+const int kPortTimeoutDelay = 30 * 1000;  // 30 seconds
+
+// Used by the Connection.
+const uint32 MSG_DELETE = 1;
+}
+
+namespace cricket {
+
+// TODO(ronghuawu): Use "host", "srflx", "prflx" and "relay". But this requires
+// the signaling part be updated correspondingly as well.
+const char LOCAL_PORT_TYPE[] = "local";
+const char STUN_PORT_TYPE[] = "stun";
+const char PRFLX_PORT_TYPE[] = "prflx";
+const char RELAY_PORT_TYPE[] = "relay";
+
+const char UDP_PROTOCOL_NAME[] = "udp";
+const char TCP_PROTOCOL_NAME[] = "tcp";
+const char SSLTCP_PROTOCOL_NAME[] = "ssltcp";
+
+static const char* const PROTO_NAMES[] = { UDP_PROTOCOL_NAME,
+                                           TCP_PROTOCOL_NAME,
+                                           SSLTCP_PROTOCOL_NAME };
+
+const char* ProtoToString(ProtocolType proto) {
+  return PROTO_NAMES[proto];
+}
+
+bool StringToProto(const char* value, ProtocolType* proto) {
+  for (size_t i = 0; i <= PROTO_LAST; ++i) {
+    if (_stricmp(PROTO_NAMES[i], value) == 0) {
+      *proto = static_cast<ProtocolType>(i);
+      return true;
+    }
+  }
+  return false;
+}
+
+// RFC 6544, TCP candidate encoding rules.
+const int DISCARD_PORT = 9;
+const char TCPTYPE_ACTIVE_STR[] = "active";
+const char TCPTYPE_PASSIVE_STR[] = "passive";
+const char TCPTYPE_SIMOPEN_STR[] = "so";
+
+// Foundation:  An arbitrary string that is the same for two candidates
+//   that have the same type, base IP address, protocol (UDP, TCP,
+//   etc.), and STUN or TURN server.  If any of these are different,
+//   then the foundation will be different.  Two candidate pairs with
+//   the same foundation pairs are likely to have similar network
+//   characteristics.  Foundations are used in the frozen algorithm.
+static std::string ComputeFoundation(
+    const std::string& type,
+    const std::string& protocol,
+    const rtc::SocketAddress& base_address) {
+  std::ostringstream ost;
+  ost << type << base_address.ipaddr().ToString() << protocol;
+  return rtc::ToString<uint32>(rtc::ComputeCrc32(ost.str()));
+}
+
+Port::Port(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+           rtc::Network* network, const rtc::IPAddress& ip,
+           const std::string& username_fragment, const std::string& password)
+    : thread_(thread),
+      factory_(factory),
+      send_retransmit_count_attribute_(false),
+      network_(network),
+      ip_(ip),
+      min_port_(0),
+      max_port_(0),
+      component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
+      generation_(0),
+      ice_username_fragment_(username_fragment),
+      password_(password),
+      timeout_delay_(kPortTimeoutDelay),
+      enable_port_packets_(false),
+      ice_protocol_(ICEPROTO_HYBRID),
+      ice_role_(ICEROLE_UNKNOWN),
+      tiebreaker_(0),
+      shared_socket_(true),
+      candidate_filter_(CF_ALL) {
+  Construct();
+}
+
+Port::Port(rtc::Thread* thread, const std::string& type,
+           rtc::PacketSocketFactory* factory,
+           rtc::Network* network, const rtc::IPAddress& ip,
+           int min_port, int max_port, const std::string& username_fragment,
+           const std::string& password)
+    : thread_(thread),
+      factory_(factory),
+      type_(type),
+      send_retransmit_count_attribute_(false),
+      network_(network),
+      ip_(ip),
+      min_port_(min_port),
+      max_port_(max_port),
+      component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
+      generation_(0),
+      ice_username_fragment_(username_fragment),
+      password_(password),
+      timeout_delay_(kPortTimeoutDelay),
+      enable_port_packets_(false),
+      ice_protocol_(ICEPROTO_HYBRID),
+      ice_role_(ICEROLE_UNKNOWN),
+      tiebreaker_(0),
+      shared_socket_(false),
+      candidate_filter_(CF_ALL) {
+  ASSERT(factory_ != NULL);
+  Construct();
+}
+
+void Port::Construct() {
+  // If the username_fragment and password are empty, we should just create one.
+  if (ice_username_fragment_.empty()) {
+    ASSERT(password_.empty());
+    ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
+    password_ = rtc::CreateRandomString(ICE_PWD_LENGTH);
+  }
+  LOG_J(LS_INFO, this) << "Port created";
+}
+
+Port::~Port() {
+  // Delete all of the remaining connections.  We copy the list up front
+  // because each deletion will cause it to be modified.
+
+  std::vector<Connection*> list;
+
+  AddressMap::iterator iter = connections_.begin();
+  while (iter != connections_.end()) {
+    list.push_back(iter->second);
+    ++iter;
+  }
+
+  for (uint32 i = 0; i < list.size(); i++)
+    delete list[i];
+}
+
+Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) {
+  AddressMap::const_iterator iter = connections_.find(remote_addr);
+  if (iter != connections_.end())
+    return iter->second;
+  else
+    return NULL;
+}
+
+void Port::AddAddress(const rtc::SocketAddress& address,
+                      const rtc::SocketAddress& base_address,
+                      const rtc::SocketAddress& related_address,
+                      const std::string& protocol,
+                      const std::string& tcptype,
+                      const std::string& type,
+                      uint32 type_preference,
+                      uint32 relay_preference,
+                      bool final) {
+  if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
+    ASSERT(!tcptype.empty());
+  }
+
+  Candidate c;
+  c.set_id(rtc::CreateRandomString(8));
+  c.set_component(component_);
+  c.set_type(type);
+  c.set_protocol(protocol);
+  c.set_tcptype(tcptype);
+  c.set_address(address);
+  c.set_priority(c.GetPriority(type_preference, network_->preference(),
+                               relay_preference));
+  c.set_username(username_fragment());
+  c.set_password(password_);
+  c.set_network_name(network_->name());
+  c.set_generation(generation_);
+  c.set_related_address(related_address);
+  c.set_foundation(ComputeFoundation(type, protocol, base_address));
+  candidates_.push_back(c);
+  SignalCandidateReady(this, c);
+
+  if (final) {
+    SignalPortComplete(this);
+  }
+}
+
+void Port::AddConnection(Connection* conn) {
+  connections_[conn->remote_candidate().address()] = conn;
+  conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
+  SignalConnectionCreated(this, conn);
+}
+
+void Port::OnReadPacket(
+    const char* data, size_t size, const rtc::SocketAddress& addr,
+    ProtocolType proto) {
+  // If the user has enabled port packets, just hand this over.
+  if (enable_port_packets_) {
+    SignalReadPacket(this, data, size, addr);
+    return;
+  }
+
+  // If this is an authenticated STUN request, then signal unknown address and
+  // send back a proper binding response.
+  rtc::scoped_ptr<IceMessage> msg;
+  std::string remote_username;
+  if (!GetStunMessage(data, size, addr, msg.accept(), &remote_username)) {
+    LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address ("
+                          << addr.ToSensitiveString() << ")";
+  } else if (!msg) {
+    // STUN message handled already
+  } else if (msg->type() == STUN_BINDING_REQUEST) {
+    // Check for role conflicts.
+    if (IsStandardIce() &&
+        !MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
+      LOG(LS_INFO) << "Received conflicting role from the peer.";
+      return;
+    }
+
+    SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false);
+  } else {
+    // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we
+    // pruned a connection for this port while it had STUN requests in flight,
+    // because we then get back responses for them, which this code correctly
+    // does not handle.
+    if (msg->type() != STUN_BINDING_RESPONSE) {
+      LOG_J(LS_ERROR, this) << "Received unexpected STUN message type ("
+                            << msg->type() << ") from unknown address ("
+                            << addr.ToSensitiveString() << ")";
+    }
+  }
+}
+
+void Port::OnReadyToSend() {
+  AddressMap::iterator iter = connections_.begin();
+  for (; iter != connections_.end(); ++iter) {
+    iter->second->OnReadyToSend();
+  }
+}
+
+size_t Port::AddPrflxCandidate(const Candidate& local) {
+  candidates_.push_back(local);
+  return (candidates_.size() - 1);
+}
+
+bool Port::IsStandardIce() const {
+  return (ice_protocol_ == ICEPROTO_RFC5245);
+}
+
+bool Port::IsGoogleIce() const {
+  return (ice_protocol_ == ICEPROTO_GOOGLE);
+}
+
+bool Port::IsHybridIce() const {
+  return (ice_protocol_ == ICEPROTO_HYBRID);
+}
+
+bool Port::GetStunMessage(const char* data, size_t size,
+                          const rtc::SocketAddress& addr,
+                          IceMessage** out_msg, std::string* out_username) {
+  // NOTE: This could clearly be optimized to avoid allocating any memory.
+  //       However, at the data rates we'll be looking at on the client side,
+  //       this probably isn't worth worrying about.
+  ASSERT(out_msg != NULL);
+  ASSERT(out_username != NULL);
+  *out_msg = NULL;
+  out_username->clear();
+
+  // Don't bother parsing the packet if we can tell it's not STUN.
+  // In ICE mode, all STUN packets will have a valid fingerprint.
+  if (IsStandardIce() && !StunMessage::ValidateFingerprint(data, size)) {
+    return false;
+  }
+
+  // Parse the request message.  If the packet is not a complete and correct
+  // STUN message, then ignore it.
+  rtc::scoped_ptr<IceMessage> stun_msg(new IceMessage());
+  rtc::ByteBuffer buf(data, size);
+  if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
+    return false;
+  }
+
+  if (stun_msg->type() == STUN_BINDING_REQUEST) {
+    // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
+    // If not present, fail with a 400 Bad Request.
+    if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
+        (IsStandardIce() &&
+         !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY))) {
+      LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I "
+                            << "from " << addr.ToSensitiveString();
+      SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
+                               STUN_ERROR_REASON_BAD_REQUEST);
+      return true;
+    }
+
+    // If the username is bad or unknown, fail with a 401 Unauthorized.
+    std::string local_ufrag;
+    std::string remote_ufrag;
+    IceProtocolType remote_protocol_type;
+    if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag,
+                           &remote_protocol_type) ||
+        local_ufrag != username_fragment()) {
+      LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
+                            << local_ufrag << " from "
+                            << addr.ToSensitiveString();
+      SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
+                               STUN_ERROR_REASON_UNAUTHORIZED);
+      return true;
+    }
+
+    // Port is initialized to GOOGLE-ICE protocol type. If pings from remote
+    // are received before the signal message, protocol type may be different.
+    // Based on the STUN username, we can determine what's the remote protocol.
+    // This also enables us to send the response back using the same protocol
+    // as the request.
+    if (IsHybridIce()) {
+      SetIceProtocolType(remote_protocol_type);
+    }
+
+    // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
+    if (IsStandardIce() &&
+        !stun_msg->ValidateMessageIntegrity(data, size, password_)) {
+      LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I "
+                            << "from " << addr.ToSensitiveString();
+      SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
+                               STUN_ERROR_REASON_UNAUTHORIZED);
+      return true;
+    }
+    out_username->assign(remote_ufrag);
+  } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) ||
+             (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
+    if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
+      if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
+        LOG_J(LS_ERROR, this) << "Received STUN binding error:"
+                              << " class=" << error_code->eclass()
+                              << " number=" << error_code->number()
+                              << " reason='" << error_code->reason() << "'"
+                              << " from " << addr.ToSensitiveString();
+        // Return message to allow error-specific processing
+      } else {
+        LOG_J(LS_ERROR, this) << "Received STUN binding error without a error "
+                              << "code from " << addr.ToSensitiveString();
+        return true;
+      }
+    }
+    // NOTE: Username should not be used in verifying response messages.
+    out_username->clear();
+  } else if (stun_msg->type() == STUN_BINDING_INDICATION) {
+    LOG_J(LS_VERBOSE, this) << "Received STUN binding indication:"
+                            << " from " << addr.ToSensitiveString();
+    out_username->clear();
+    // No stun attributes will be verified, if it's stun indication message.
+    // Returning from end of the this method.
+  } else {
+    LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
+                          << stun_msg->type() << ") from "
+                          << addr.ToSensitiveString();
+    return true;
+  }
+
+  // Return the STUN message found.
+  *out_msg = stun_msg.release();
+  return true;
+}
+
+bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) {
+  int family = ip().family();
+  // We use single-stack sockets, so families must match.
+  if (addr.family() != family) {
+    return false;
+  }
+  // Link-local IPv6 ports can only connect to other link-local IPv6 ports.
+  if (family == AF_INET6 && (IPIsPrivate(ip()) != IPIsPrivate(addr.ipaddr()))) {
+    return false;
+  }
+  return true;
+}
+
+bool Port::ParseStunUsername(const StunMessage* stun_msg,
+                             std::string* local_ufrag,
+                             std::string* remote_ufrag,
+                             IceProtocolType* remote_protocol_type) const {
+  // The packet must include a username that either begins or ends with our
+  // fragment.  It should begin with our fragment if it is a request and it
+  // should end with our fragment if it is a response.
+  local_ufrag->clear();
+  remote_ufrag->clear();
+  const StunByteStringAttribute* username_attr =
+        stun_msg->GetByteString(STUN_ATTR_USERNAME);
+  if (username_attr == NULL)
+    return false;
+
+  const std::string username_attr_str = username_attr->GetString();
+  size_t colon_pos = username_attr_str.find(":");
+  // If we are in hybrid mode set the appropriate ice protocol type based on
+  // the username argument style.
+  if (IsHybridIce()) {
+    *remote_protocol_type = (colon_pos != std::string::npos) ?
+        ICEPROTO_RFC5245 : ICEPROTO_GOOGLE;
+  } else {
+    *remote_protocol_type = ice_protocol_;
+  }
+  if (*remote_protocol_type == ICEPROTO_RFC5245) {
+    if (colon_pos != std::string::npos) {  // RFRAG:LFRAG
+      *local_ufrag = username_attr_str.substr(0, colon_pos);
+      *remote_ufrag = username_attr_str.substr(
+          colon_pos + 1, username_attr_str.size());
+    } else {
+      return false;
+    }
+  } else if (*remote_protocol_type == ICEPROTO_GOOGLE) {
+    int remote_frag_len = static_cast<int>(username_attr_str.size());
+    remote_frag_len -= static_cast<int>(username_fragment().size());
+    if (remote_frag_len < 0)
+      return false;
+
+    *local_ufrag = username_attr_str.substr(0, username_fragment().size());
+    *remote_ufrag = username_attr_str.substr(
+        username_fragment().size(), username_attr_str.size());
+  }
+  return true;
+}
+
+bool Port::MaybeIceRoleConflict(
+    const rtc::SocketAddress& addr, IceMessage* stun_msg,
+    const std::string& remote_ufrag) {
+  // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes.
+  bool ret = true;
+  IceRole remote_ice_role = ICEROLE_UNKNOWN;
+  uint64 remote_tiebreaker = 0;
+  const StunUInt64Attribute* stun_attr =
+      stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
+  if (stun_attr) {
+    remote_ice_role = ICEROLE_CONTROLLING;
+    remote_tiebreaker = stun_attr->value();
+  }
+
+  // If |remote_ufrag| is same as port local username fragment and
+  // tie breaker value received in the ping message matches port
+  // tiebreaker value this must be a loopback call.
+  // We will treat this as valid scenario.
+  if (remote_ice_role == ICEROLE_CONTROLLING &&
+      username_fragment() == remote_ufrag &&
+      remote_tiebreaker == IceTiebreaker()) {
+    return true;
+  }
+
+  stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
+  if (stun_attr) {
+    remote_ice_role = ICEROLE_CONTROLLED;
+    remote_tiebreaker = stun_attr->value();
+  }
+
+  switch (ice_role_) {
+    case ICEROLE_CONTROLLING:
+      if (ICEROLE_CONTROLLING == remote_ice_role) {
+        if (remote_tiebreaker >= tiebreaker_) {
+          SignalRoleConflict(this);
+        } else {
+          // Send Role Conflict (487) error response.
+          SendBindingErrorResponse(stun_msg, addr,
+              STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
+          ret = false;
+        }
+      }
+      break;
+    case ICEROLE_CONTROLLED:
+      if (ICEROLE_CONTROLLED == remote_ice_role) {
+        if (remote_tiebreaker < tiebreaker_) {
+          SignalRoleConflict(this);
+        } else {
+          // Send Role Conflict (487) error response.
+          SendBindingErrorResponse(stun_msg, addr,
+              STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
+          ret = false;
+        }
+      }
+      break;
+    default:
+      ASSERT(false);
+  }
+  return ret;
+}
+
+void Port::CreateStunUsername(const std::string& remote_username,
+                              std::string* stun_username_attr_str) const {
+  stun_username_attr_str->clear();
+  *stun_username_attr_str = remote_username;
+  if (IsStandardIce()) {
+    // Connectivity checks from L->R will have username RFRAG:LFRAG.
+    stun_username_attr_str->append(":");
+  }
+  stun_username_attr_str->append(username_fragment());
+}
+
+void Port::SendBindingResponse(StunMessage* request,
+                               const rtc::SocketAddress& addr) {
+  ASSERT(request->type() == STUN_BINDING_REQUEST);
+
+  // Retrieve the username from the request.
+  const StunByteStringAttribute* username_attr =
+      request->GetByteString(STUN_ATTR_USERNAME);
+  ASSERT(username_attr != NULL);
+  if (username_attr == NULL) {
+    // No valid username, skip the response.
+    return;
+  }
+
+  // Fill in the response message.
+  StunMessage response;
+  response.SetType(STUN_BINDING_RESPONSE);
+  response.SetTransactionID(request->transaction_id());
+  const StunUInt32Attribute* retransmit_attr =
+      request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
+  if (retransmit_attr) {
+    // Inherit the incoming retransmit value in the response so the other side
+    // can see our view of lost pings.
+    response.AddAttribute(new StunUInt32Attribute(
+        STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
+
+    if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
+      LOG_J(LS_INFO, this)
+          << "Received a remote ping with high retransmit count: "
+          << retransmit_attr->value();
+    }
+  }
+
+  // Only GICE messages have USERNAME and MAPPED-ADDRESS in the response.
+  // ICE messages use XOR-MAPPED-ADDRESS, and add MESSAGE-INTEGRITY.
+  if (IsStandardIce()) {
+    response.AddAttribute(
+        new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
+    response.AddMessageIntegrity(password_);
+    response.AddFingerprint();
+  } else if (IsGoogleIce()) {
+    response.AddAttribute(
+        new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, addr));
+    response.AddAttribute(new StunByteStringAttribute(
+        STUN_ATTR_USERNAME, username_attr->GetString()));
+  }
+
+  // Send the response message.
+  rtc::ByteBuffer buf;
+  response.Write(&buf);
+  rtc::PacketOptions options(DefaultDscpValue());
+  if (SendTo(buf.Data(), buf.Length(), addr, options, false) < 0) {
+    LOG_J(LS_ERROR, this) << "Failed to send STUN ping response to "
+                          << addr.ToSensitiveString();
+  }
+
+  // The fact that we received a successful request means that this connection
+  // (if one exists) should now be readable.
+  Connection* conn = GetConnection(addr);
+  ASSERT(conn != NULL);
+  if (conn)
+    conn->ReceivedPing();
+}
+
+void Port::SendBindingErrorResponse(StunMessage* request,
+                                    const rtc::SocketAddress& addr,
+                                    int error_code, const std::string& reason) {
+  ASSERT(request->type() == STUN_BINDING_REQUEST);
+
+  // Fill in the response message.
+  StunMessage response;
+  response.SetType(STUN_BINDING_ERROR_RESPONSE);
+  response.SetTransactionID(request->transaction_id());
+
+  // When doing GICE, we need to write out the error code incorrectly to
+  // maintain backwards compatiblility.
+  StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
+  if (IsStandardIce()) {
+    error_attr->SetCode(error_code);
+  } else if (IsGoogleIce()) {
+    error_attr->SetClass(error_code / 256);
+    error_attr->SetNumber(error_code % 256);
+  }
+  error_attr->SetReason(reason);
+  response.AddAttribute(error_attr);
+
+  if (IsStandardIce()) {
+    // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
+    // because we don't have enough information to determine the shared secret.
+    if (error_code != STUN_ERROR_BAD_REQUEST &&
+        error_code != STUN_ERROR_UNAUTHORIZED)
+      response.AddMessageIntegrity(password_);
+    response.AddFingerprint();
+  } else if (IsGoogleIce()) {
+    // GICE responses include a username, if one exists.
+    const StunByteStringAttribute* username_attr =
+        request->GetByteString(STUN_ATTR_USERNAME);
+    if (username_attr)
+      response.AddAttribute(new StunByteStringAttribute(
+          STUN_ATTR_USERNAME, username_attr->GetString()));
+  }
+
+  // Send the response message.
+  rtc::ByteBuffer buf;
+  response.Write(&buf);
+  rtc::PacketOptions options(DefaultDscpValue());
+  SendTo(buf.Data(), buf.Length(), addr, options, false);
+  LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
+                       << " to " << addr.ToSensitiveString();
+}
+
+void Port::OnMessage(rtc::Message *pmsg) {
+  ASSERT(pmsg->message_id == MSG_CHECKTIMEOUT);
+  CheckTimeout();
+}
+
+std::string Port::ToString() const {
+  std::stringstream ss;
+  ss << "Port[" << content_name_ << ":" << component_
+     << ":" << generation_ << ":" << type_
+     << ":" << network_->ToString() << "]";
+  return ss.str();
+}
+
+void Port::EnablePortPackets() {
+  enable_port_packets_ = true;
+}
+
+void Port::OnConnectionDestroyed(Connection* conn) {
+  AddressMap::iterator iter =
+      connections_.find(conn->remote_candidate().address());
+  ASSERT(iter != connections_.end());
+  connections_.erase(iter);
+
+  // On the controlled side, ports time out, but only after all connections
+  // fail.  Note: If a new connection is added after this message is posted,
+  // but it fails and is removed before kPortTimeoutDelay, then this message
+  //  will still cause the Port to be destroyed.
+  if (ice_role_ == ICEROLE_CONTROLLED)
+    thread_->PostDelayed(timeout_delay_, this, MSG_CHECKTIMEOUT);
+}
+
+void Port::Destroy() {
+  ASSERT(connections_.empty());
+  LOG_J(LS_INFO, this) << "Port deleted";
+  SignalDestroyed(this);
+  delete this;
+}
+
+void Port::CheckTimeout() {
+  ASSERT(ice_role_ == ICEROLE_CONTROLLED);
+  // If this port has no connections, then there's no reason to keep it around.
+  // When the connections time out (both read and write), they will delete
+  // themselves, so if we have any connections, they are either readable or
+  // writable (or still connecting).
+  if (connections_.empty())
+    Destroy();
+}
+
+const std::string Port::username_fragment() const {
+  if (!IsStandardIce() &&
+      component_ == ICE_CANDIDATE_COMPONENT_RTCP) {
+    // In GICE mode, we should adjust username fragment for rtcp component.
+    return GetRtcpUfragFromRtpUfrag(ice_username_fragment_);
+  } else {
+    return ice_username_fragment_;
+  }
+}
+
+// A ConnectionRequest is a simple STUN ping used to determine writability.
+class ConnectionRequest : public StunRequest {
+ public:
+  explicit ConnectionRequest(Connection* connection)
+      : StunRequest(new IceMessage()),
+        connection_(connection) {
+  }
+
+  virtual ~ConnectionRequest() {
+  }
+
+  virtual void Prepare(StunMessage* request) {
+    request->SetType(STUN_BINDING_REQUEST);
+    std::string username;
+    connection_->port()->CreateStunUsername(
+        connection_->remote_candidate().username(), &username);
+    request->AddAttribute(
+        new StunByteStringAttribute(STUN_ATTR_USERNAME, username));
+
+    // connection_ already holds this ping, so subtract one from count.
+    if (connection_->port()->send_retransmit_count_attribute()) {
+      request->AddAttribute(new StunUInt32Attribute(
+          STUN_ATTR_RETRANSMIT_COUNT,
+          static_cast<uint32>(
+              connection_->pings_since_last_response_.size() - 1)));
+    }
+
+    // Adding ICE-specific attributes to the STUN request message.
+    if (connection_->port()->IsStandardIce()) {
+      // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
+      if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
+        request->AddAttribute(new StunUInt64Attribute(
+            STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
+        // Since we are trying aggressive nomination, sending USE-CANDIDATE
+        // attribute in every ping.
+        // If we are dealing with a ice-lite end point, nomination flag
+        // in Connection will be set to false by default. Once the connection
+        // becomes "best connection", nomination flag will be turned on.
+        if (connection_->use_candidate_attr()) {
+          request->AddAttribute(new StunByteStringAttribute(
+              STUN_ATTR_USE_CANDIDATE));
+        }
+      } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
+        request->AddAttribute(new StunUInt64Attribute(
+            STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
+      } else {
+        ASSERT(false);
+      }
+
+      // Adding PRIORITY Attribute.
+      // Changing the type preference to Peer Reflexive and local preference
+      // and component id information is unchanged from the original priority.
+      // priority = (2^24)*(type preference) +
+      //           (2^8)*(local preference) +
+      //           (2^0)*(256 - component ID)
+      uint32 prflx_priority = ICE_TYPE_PREFERENCE_PRFLX << 24 |
+          (connection_->local_candidate().priority() & 0x00FFFFFF);
+      request->AddAttribute(
+          new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
+
+      // Adding Message Integrity attribute.
+      request->AddMessageIntegrity(connection_->remote_candidate().password());
+      // Adding Fingerprint.
+      request->AddFingerprint();
+    }
+  }
+
+  virtual void OnResponse(StunMessage* response) {
+    connection_->OnConnectionRequestResponse(this, response);
+  }
+
+  virtual void OnErrorResponse(StunMessage* response) {
+    connection_->OnConnectionRequestErrorResponse(this, response);
+  }
+
+  virtual void OnTimeout() {
+    connection_->OnConnectionRequestTimeout(this);
+  }
+
+  virtual int GetNextDelay() {
+    // Each request is sent only once.  After a single delay , the request will
+    // time out.
+    timeout_ = true;
+    return CONNECTION_RESPONSE_TIMEOUT;
+  }
+
+ private:
+  Connection* connection_;
+};
+
+//
+// Connection
+//
+
+Connection::Connection(Port* port, size_t index,
+                       const Candidate& remote_candidate)
+  : port_(port), local_candidate_index_(index),
+    remote_candidate_(remote_candidate), read_state_(STATE_READ_INIT),
+    write_state_(STATE_WRITE_INIT), connected_(true), pruned_(false),
+    use_candidate_attr_(false), remote_ice_mode_(ICEMODE_FULL),
+    requests_(port->thread()), rtt_(DEFAULT_RTT), last_ping_sent_(0),
+    last_ping_received_(0), last_data_received_(0),
+    last_ping_response_received_(0), reported_(false), state_(STATE_WAITING) {
+  // All of our connections start in WAITING state.
+  // TODO(mallinath) - Start connections from STATE_FROZEN.
+  // Wire up to send stun packets
+  requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
+  LOG_J(LS_INFO, this) << "Connection created";
+}
+
+Connection::~Connection() {
+}
+
+const Candidate& Connection::local_candidate() const {
+  ASSERT(local_candidate_index_ < port_->Candidates().size());
+  return port_->Candidates()[local_candidate_index_];
+}
+
+uint64 Connection::priority() const {
+  uint64 priority = 0;
+  // RFC 5245 - 5.7.2.  Computing Pair Priority and Ordering Pairs
+  // Let G be the priority for the candidate provided by the controlling
+  // agent.  Let D be the priority for the candidate provided by the
+  // controlled agent.
+  // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
+  IceRole role = port_->GetIceRole();
+  if (role != ICEROLE_UNKNOWN) {
+    uint32 g = 0;
+    uint32 d = 0;
+    if (role == ICEROLE_CONTROLLING) {
+      g = local_candidate().priority();
+      d = remote_candidate_.priority();
+    } else {
+      g = remote_candidate_.priority();
+      d = local_candidate().priority();
+    }
+    priority = rtc::_min(g, d);
+    priority = priority << 32;
+    priority += 2 * rtc::_max(g, d) + (g > d ? 1 : 0);
+  }
+  return priority;
+}
+
+void Connection::set_read_state(ReadState value) {
+  ReadState old_value = read_state_;
+  read_state_ = value;
+  if (value != old_value) {
+    LOG_J(LS_VERBOSE, this) << "set_read_state";
+    SignalStateChange(this);
+    CheckTimeout();
+  }
+}
+
+void Connection::set_write_state(WriteState value) {
+  WriteState old_value = write_state_;
+  write_state_ = value;
+  if (value != old_value) {
+    LOG_J(LS_VERBOSE, this) << "set_write_state";
+    SignalStateChange(this);
+    CheckTimeout();
+  }
+}
+
+void Connection::set_state(State state) {
+  State old_state = state_;
+  state_ = state;
+  if (state != old_state) {
+    LOG_J(LS_VERBOSE, this) << "set_state";
+  }
+}
+
+void Connection::set_connected(bool value) {
+  bool old_value = connected_;
+  connected_ = value;
+  if (value != old_value) {
+    LOG_J(LS_VERBOSE, this) << "set_connected";
+  }
+}
+
+void Connection::set_use_candidate_attr(bool enable) {
+  use_candidate_attr_ = enable;
+}
+
+void Connection::OnSendStunPacket(const void* data, size_t size,
+                                  StunRequest* req) {
+  rtc::PacketOptions options(port_->DefaultDscpValue());
+  if (port_->SendTo(data, size, remote_candidate_.address(),
+                    options, false) < 0) {
+    LOG_J(LS_WARNING, this) << "Failed to send STUN ping " << req->id();
+  }
+}
+
+void Connection::OnReadPacket(
+  const char* data, size_t size, const rtc::PacketTime& packet_time) {
+  rtc::scoped_ptr<IceMessage> msg;
+  std::string remote_ufrag;
+  const rtc::SocketAddress& addr(remote_candidate_.address());
+  if (!port_->GetStunMessage(data, size, addr, msg.accept(), &remote_ufrag)) {
+    // The packet did not parse as a valid STUN message
+
+    // If this connection is readable, then pass along the packet.
+    if (read_state_ == STATE_READABLE) {
+      // readable means data from this address is acceptable
+      // Send it on!
+
+      last_data_received_ = rtc::Time();
+      recv_rate_tracker_.Update(size);
+      SignalReadPacket(this, data, size, packet_time);
+
+      // If timed out sending writability checks, start up again
+      if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
+        LOG(LS_WARNING) << "Received a data packet on a timed-out Connection. "
+                        << "Resetting state to STATE_WRITE_INIT.";
+        set_write_state(STATE_WRITE_INIT);
+      }
+    } else {
+      // Not readable means the remote address hasn't sent a valid
+      // binding request yet.
+
+      LOG_J(LS_WARNING, this)
+        << "Received non-STUN packet from an unreadable connection.";
+    }
+  } else if (!msg) {
+    // The packet was STUN, but failed a check and was handled internally.
+  } else {
+    // The packet is STUN and passed the Port checks.
+    // Perform our own checks to ensure this packet is valid.
+    // If this is a STUN request, then update the readable bit and respond.
+    // If this is a STUN response, then update the writable bit.
+    switch (msg->type()) {
+      case STUN_BINDING_REQUEST:
+        if (remote_ufrag == remote_candidate_.username()) {
+          // Check for role conflicts.
+          if (port_->IsStandardIce() &&
+              !port_->MaybeIceRoleConflict(addr, msg.get(), remote_ufrag)) {
+            // Received conflicting role from the peer.
+            LOG(LS_INFO) << "Received conflicting role from the peer.";
+            return;
+          }
+
+          // Incoming, validated stun request from remote peer.
+          // This call will also set the connection readable.
+          port_->SendBindingResponse(msg.get(), addr);
+
+          // If timed out sending writability checks, start up again
+          if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
+            set_write_state(STATE_WRITE_INIT);
+
+          if ((port_->IsStandardIce()) &&
+              (port_->GetIceRole() == ICEROLE_CONTROLLED)) {
+            const StunByteStringAttribute* use_candidate_attr =
+                msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
+            if (use_candidate_attr)
+              SignalUseCandidate(this);
+          }
+        } else {
+          // The packet had the right local username, but the remote username
+          // was not the right one for the remote address.
+          LOG_J(LS_ERROR, this)
+            << "Received STUN request with bad remote username "
+            << remote_ufrag;
+          port_->SendBindingErrorResponse(msg.get(), addr,
+                                          STUN_ERROR_UNAUTHORIZED,
+                                          STUN_ERROR_REASON_UNAUTHORIZED);
+
+        }
+        break;
+
+      // Response from remote peer. Does it match request sent?
+      // This doesn't just check, it makes callbacks if transaction
+      // id's match.
+      case STUN_BINDING_RESPONSE:
+      case STUN_BINDING_ERROR_RESPONSE:
+        if (port_->IsGoogleIce() ||
+            msg->ValidateMessageIntegrity(
+                data, size, remote_candidate().password())) {
+          requests_.CheckResponse(msg.get());
+        }
+        // Otherwise silently discard the response message.
+        break;
+
+      // Remote end point sent an STUN indication instead of regular
+      // binding request. In this case |last_ping_received_| will be updated.
+      // Otherwise we can mark connection to read timeout. No response will be
+      // sent in this scenario.
+      case STUN_BINDING_INDICATION:
+        if (port_->IsStandardIce() && read_state_ == STATE_READABLE) {
+          ReceivedPing();
+        } else {
+          LOG_J(LS_WARNING, this) << "Received STUN binding indication "
+                                  << "from an unreadable connection.";
+        }
+        break;
+
+      default:
+        ASSERT(false);
+        break;
+    }
+  }
+}
+
+void Connection::OnReadyToSend() {
+  if (write_state_ == STATE_WRITABLE) {
+    SignalReadyToSend(this);
+  }
+}
+
+void Connection::Prune() {
+  if (!pruned_) {
+    LOG_J(LS_VERBOSE, this) << "Connection pruned";
+    pruned_ = true;
+    requests_.Clear();
+    set_write_state(STATE_WRITE_TIMEOUT);
+  }
+}
+
+void Connection::Destroy() {
+  LOG_J(LS_VERBOSE, this) << "Connection destroyed";
+  set_read_state(STATE_READ_TIMEOUT);
+  set_write_state(STATE_WRITE_TIMEOUT);
+}
+
+void Connection::UpdateState(uint32 now) {
+  uint32 rtt = ConservativeRTTEstimate(rtt_);
+
+  std::string pings;
+  for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
+    char buf[32];
+    rtc::sprintfn(buf, sizeof(buf), "%u",
+        pings_since_last_response_[i]);
+    pings.append(buf).append(" ");
+  }
+  LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_=" <<
+      pings << ", rtt=" << rtt << ", now=" << now;
+
+  // Check the readable state.
+  //
+  // Since we don't know how many pings the other side has attempted, the best
+  // test we can do is a simple window.
+  // If other side has not sent ping after connection has become readable, use
+  // |last_data_received_| as the indication.
+  // If remote endpoint is doing RFC 5245, it's not required to send ping
+  // after connection is established. If this connection is serving a data
+  // channel, it may not be in a position to send media continuously. Do not
+  // mark connection timeout if it's in RFC5245 mode.
+  // Below check will be performed with end point if it's doing google-ice.
+  if (port_->IsGoogleIce() && (read_state_ == STATE_READABLE) &&
+      (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now) &&
+      (last_data_received_ + CONNECTION_READ_TIMEOUT <= now)) {
+    LOG_J(LS_INFO, this) << "Unreadable after "
+                         << now - last_ping_received_
+                         << " ms without a ping,"
+                         << " ms since last received response="
+                         << now - last_ping_response_received_
+                         << " ms since last received data="
+                         << now - last_data_received_
+                         << " rtt=" << rtt;
+    set_read_state(STATE_READ_TIMEOUT);
+  }
+
+  // Check the writable state.  (The order of these checks is important.)
+  //
+  // Before becoming unwritable, we allow for a fixed number of pings to fail
+  // (i.e., receive no response).  We also have to give the response time to
+  // get back, so we include a conservative estimate of this.
+  //
+  // Before timing out writability, we give a fixed amount of time.  This is to
+  // allow for changes in network conditions.
+
+  if ((write_state_ == STATE_WRITABLE) &&
+      TooManyFailures(pings_since_last_response_,
+                      CONNECTION_WRITE_CONNECT_FAILURES,
+                      rtt,
+                      now) &&
+      TooLongWithoutResponse(pings_since_last_response_,
+                             CONNECTION_WRITE_CONNECT_TIMEOUT,
+                             now)) {
+    uint32 max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
+    LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
+                         << " ping failures and "
+                         << now - pings_since_last_response_[0]
+                         << " ms without a response,"
+                         << " ms since last received ping="
+                         << now - last_ping_received_
+                         << " ms since last received data="
+                         << now - last_data_received_
+                         << " rtt=" << rtt;
+    set_write_state(STATE_WRITE_UNRELIABLE);
+  }
+
+  if ((write_state_ == STATE_WRITE_UNRELIABLE ||
+       write_state_ == STATE_WRITE_INIT) &&
+      TooLongWithoutResponse(pings_since_last_response_,
+                             CONNECTION_WRITE_TIMEOUT,
+                             now)) {
+    LOG_J(LS_INFO, this) << "Timed out after "
+                         << now - pings_since_last_response_[0]
+                         << " ms without a response, rtt=" << rtt;
+    set_write_state(STATE_WRITE_TIMEOUT);
+  }
+}
+
+void Connection::Ping(uint32 now) {
+  ASSERT(connected_);
+  last_ping_sent_ = now;
+  pings_since_last_response_.push_back(now);
+  ConnectionRequest *req = new ConnectionRequest(this);
+  LOG_J(LS_VERBOSE, this) << "Sending STUN ping " << req->id() << " at " << now;
+  requests_.Send(req);
+  state_ = STATE_INPROGRESS;
+}
+
+void Connection::ReceivedPing() {
+  last_ping_received_ = rtc::Time();
+  set_read_state(STATE_READABLE);
+}
+
+std::string Connection::ToString() const {
+  const char CONNECT_STATE_ABBREV[2] = {
+    '-',  // not connected (false)
+    'C',  // connected (true)
+  };
+  const char READ_STATE_ABBREV[3] = {
+    '-',  // STATE_READ_INIT
+    'R',  // STATE_READABLE
+    'x',  // STATE_READ_TIMEOUT
+  };
+  const char WRITE_STATE_ABBREV[4] = {
+    'W',  // STATE_WRITABLE
+    'w',  // STATE_WRITE_UNRELIABLE
+    '-',  // STATE_WRITE_INIT
+    'x',  // STATE_WRITE_TIMEOUT
+  };
+  const std::string ICESTATE[4] = {
+    "W",  // STATE_WAITING
+    "I",  // STATE_INPROGRESS
+    "S",  // STATE_SUCCEEDED
+    "F"   // STATE_FAILED
+  };
+  const Candidate& local = local_candidate();
+  const Candidate& remote = remote_candidate();
+  std::stringstream ss;
+  ss << "Conn[" << port_->content_name()
+     << ":" << local.id() << ":" << local.component()
+     << ":" << local.generation()
+     << ":" << local.type() << ":" << local.protocol()
+     << ":" << local.address().ToSensitiveString()
+     << "->" << remote.id() << ":" << remote.component()
+     << ":" << remote.priority()
+     << ":" << remote.type() << ":"
+     << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|"
+     << CONNECT_STATE_ABBREV[connected()]
+     << READ_STATE_ABBREV[read_state()]
+     << WRITE_STATE_ABBREV[write_state()]
+     << ICESTATE[state()] << "|"
+     << priority() << "|";
+  if (rtt_ < DEFAULT_RTT) {
+    ss << rtt_ << "]";
+  } else {
+    ss << "-]";
+  }
+  return ss.str();
+}
+
+std::string Connection::ToSensitiveString() const {
+  return ToString();
+}
+
+void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
+                                             StunMessage* response) {
+  // We've already validated that this is a STUN binding response with
+  // the correct local and remote username for this connection.
+  // So if we're not already, become writable. We may be bringing a pruned
+  // connection back to life, but if we don't really want it, we can always
+  // prune it again.
+  uint32 rtt = request->Elapsed();
+  set_write_state(STATE_WRITABLE);
+  set_state(STATE_SUCCEEDED);
+
+  if (remote_ice_mode_ == ICEMODE_LITE) {
+    // A ice-lite end point never initiates ping requests. This will allow
+    // us to move to STATE_READABLE.
+    ReceivedPing();
+  }
+
+  std::string pings;
+  for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
+    char buf[32];
+    rtc::sprintfn(buf, sizeof(buf), "%u",
+        pings_since_last_response_[i]);
+    pings.append(buf).append(" ");
+  }
+
+  rtc::LoggingSeverity level =
+      (pings_since_last_response_.size() > CONNECTION_WRITE_CONNECT_FAILURES) ?
+          rtc::LS_INFO : rtc::LS_VERBOSE;
+
+  LOG_JV(level, this) << "Received STUN ping response " << request->id()
+                      << ", pings_since_last_response_=" << pings
+                      << ", rtt=" << rtt;
+
+  pings_since_last_response_.clear();
+  last_ping_response_received_ = rtc::Time();
+  rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
+
+  // Peer reflexive candidate is only for RFC 5245 ICE.
+  if (port_->IsStandardIce()) {
+    MaybeAddPrflxCandidate(request, response);
+  }
+}
+
+void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
+                                                  StunMessage* response) {
+  const StunErrorCodeAttribute* error_attr = response->GetErrorCode();
+  int error_code = STUN_ERROR_GLOBAL_FAILURE;
+  if (error_attr) {
+    if (port_->IsGoogleIce()) {
+      // When doing GICE, the error code is written out incorrectly, so we need
+      // to unmunge it here.
+      error_code = error_attr->eclass() * 256 + error_attr->number();
+    } else {
+      error_code = error_attr->code();
+    }
+  }
+
+  if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
+      error_code == STUN_ERROR_SERVER_ERROR ||
+      error_code == STUN_ERROR_UNAUTHORIZED) {
+    // Recoverable error, retry
+  } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
+    // Race failure, retry
+  } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
+    HandleRoleConflictFromPeer();
+  } else {
+    // This is not a valid connection.
+    LOG_J(LS_ERROR, this) << "Received STUN error response, code="
+                          << error_code << "; killing connection";
+    set_state(STATE_FAILED);
+    set_write_state(STATE_WRITE_TIMEOUT);
+  }
+}
+
+void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
+  // Log at LS_INFO if we miss a ping on a writable connection.
+  rtc::LoggingSeverity sev = (write_state_ == STATE_WRITABLE) ?
+      rtc::LS_INFO : rtc::LS_VERBOSE;
+  LOG_JV(sev, this) << "Timing-out STUN ping " << request->id()
+                    << " after " << request->Elapsed() << " ms";
+}
+
+void Connection::CheckTimeout() {
+  // If both read and write have timed out or read has never initialized, then
+  // this connection can contribute no more to p2p socket unless at some later
+  // date readability were to come back.  However, we gave readability a long
+  // time to timeout, so at this point, it seems fair to get rid of this
+  // connection.
+  if ((read_state_ == STATE_READ_TIMEOUT ||
+       read_state_ == STATE_READ_INIT) &&
+      write_state_ == STATE_WRITE_TIMEOUT) {
+    port_->thread()->Post(this, MSG_DELETE);
+  }
+}
+
+void Connection::HandleRoleConflictFromPeer() {
+  port_->SignalRoleConflict(port_);
+}
+
+void Connection::OnMessage(rtc::Message *pmsg) {
+  ASSERT(pmsg->message_id == MSG_DELETE);
+
+  LOG_J(LS_INFO, this) << "Connection deleted";
+  SignalDestroyed(this);
+  delete this;
+}
+
+size_t Connection::recv_bytes_second() {
+  return recv_rate_tracker_.units_second();
+}
+
+size_t Connection::recv_total_bytes() {
+  return recv_rate_tracker_.total_units();
+}
+
+size_t Connection::sent_bytes_second() {
+  return send_rate_tracker_.units_second();
+}
+
+size_t Connection::sent_total_bytes() {
+  return send_rate_tracker_.total_units();
+}
+
+void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request,
+                                        StunMessage* response) {
+  // RFC 5245
+  // The agent checks the mapped address from the STUN response.  If the
+  // transport address does not match any of the local candidates that the
+  // agent knows about, the mapped address represents a new candidate -- a
+  // peer reflexive candidate.
+  const StunAddressAttribute* addr =
+      response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  if (!addr) {
+    LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
+                    << "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
+                    << "stun response message";
+    return;
+  }
+
+  bool known_addr = false;
+  for (size_t i = 0; i < port_->Candidates().size(); ++i) {
+    if (port_->Candidates()[i].address() == addr->GetAddress()) {
+      known_addr = true;
+      break;
+    }
+  }
+  if (known_addr) {
+    return;
+  }
+
+  // RFC 5245
+  // Its priority is set equal to the value of the PRIORITY attribute
+  // in the Binding request.
+  const StunUInt32Attribute* priority_attr =
+      request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
+  if (!priority_attr) {
+    LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
+                    << "No STUN_ATTR_PRIORITY found in the "
+                    << "stun response message";
+    return;
+  }
+  const uint32 priority = priority_attr->value();
+  std::string id = rtc::CreateRandomString(8);
+
+  Candidate new_local_candidate;
+  new_local_candidate.set_id(id);
+  new_local_candidate.set_component(local_candidate().component());
+  new_local_candidate.set_type(PRFLX_PORT_TYPE);
+  new_local_candidate.set_protocol(local_candidate().protocol());
+  new_local_candidate.set_address(addr->GetAddress());
+  new_local_candidate.set_priority(priority);
+  new_local_candidate.set_username(local_candidate().username());
+  new_local_candidate.set_password(local_candidate().password());
+  new_local_candidate.set_network_name(local_candidate().network_name());
+  new_local_candidate.set_related_address(local_candidate().address());
+  new_local_candidate.set_foundation(
+      ComputeFoundation(PRFLX_PORT_TYPE, local_candidate().protocol(),
+                        local_candidate().address()));
+
+  // Change the local candidate of this Connection to the new prflx candidate.
+  local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
+
+  // SignalStateChange to force a re-sort in P2PTransportChannel as this
+  // Connection's local candidate has changed.
+  SignalStateChange(this);
+}
+
+ProxyConnection::ProxyConnection(Port* port, size_t index,
+                                 const Candidate& candidate)
+  : Connection(port, index, candidate), error_(0) {
+}
+
+int ProxyConnection::Send(const void* data, size_t size,
+                          const rtc::PacketOptions& options) {
+  if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) {
+    error_ = EWOULDBLOCK;
+    return SOCKET_ERROR;
+  }
+  int sent = port_->SendTo(data, size, remote_candidate_.address(),
+                           options, true);
+  if (sent <= 0) {
+    ASSERT(sent < 0);
+    error_ = port_->GetError();
+  } else {
+    send_rate_tracker_.Update(sent);
+  }
+  return sent;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/port.h b/p2p/base/port.h
new file mode 100644
index 0000000..48b8530
--- /dev/null
+++ b/p2p/base/port.h
@@ -0,0 +1,602 @@
+/*
+ *  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_P2P_BASE_PORT_H_
+#define WEBRTC_P2P_BASE_PORT_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/packetsocketfactory.h"
+#include "webrtc/p2p/base/portinterface.h"
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/p2p/base/stunrequest.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/network.h"
+#include "webrtc/base/proxyinfo.h"
+#include "webrtc/base/ratetracker.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+class Connection;
+class ConnectionRequest;
+
+extern const char LOCAL_PORT_TYPE[];
+extern const char STUN_PORT_TYPE[];
+extern const char PRFLX_PORT_TYPE[];
+extern const char RELAY_PORT_TYPE[];
+
+extern const char UDP_PROTOCOL_NAME[];
+extern const char TCP_PROTOCOL_NAME[];
+extern const char SSLTCP_PROTOCOL_NAME[];
+
+// RFC 6544, TCP candidate encoding rules.
+extern const int DISCARD_PORT;
+extern const char TCPTYPE_ACTIVE_STR[];
+extern const char TCPTYPE_PASSIVE_STR[];
+extern const char TCPTYPE_SIMOPEN_STR[];
+
+// The length of time we wait before timing out readability on a connection.
+const uint32 CONNECTION_READ_TIMEOUT = 30 * 1000;   // 30 seconds
+
+// The length of time we wait before timing out writability on a connection.
+const uint32 CONNECTION_WRITE_TIMEOUT = 15 * 1000;  // 15 seconds
+
+// The length of time we wait before we become unwritable.
+const uint32 CONNECTION_WRITE_CONNECT_TIMEOUT = 5 * 1000;  // 5 seconds
+
+// The number of pings that must fail to respond before we become unwritable.
+const uint32 CONNECTION_WRITE_CONNECT_FAILURES = 5;
+
+// This is the length of time that we wait for a ping response to come back.
+const int CONNECTION_RESPONSE_TIMEOUT = 5 * 1000;   // 5 seconds
+
+enum RelayType {
+  RELAY_GTURN,   // Legacy google relay service.
+  RELAY_TURN     // Standard (TURN) relay service.
+};
+
+enum IcePriorityValue {
+  // The reason we are choosing Relay preference 2 is because, we can run
+  // Relay from client to server on UDP/TCP/TLS. To distinguish the transport
+  // protocol, we prefer UDP over TCP over TLS.
+  // For UDP ICE_TYPE_PREFERENCE_RELAY will be 2.
+  // For TCP ICE_TYPE_PREFERENCE_RELAY will be 1.
+  // For TLS ICE_TYPE_PREFERENCE_RELAY will be 0.
+  // Check turnport.cc for setting these values.
+  ICE_TYPE_PREFERENCE_RELAY = 2,
+  ICE_TYPE_PREFERENCE_HOST_TCP = 90,
+  ICE_TYPE_PREFERENCE_SRFLX = 100,
+  ICE_TYPE_PREFERENCE_PRFLX = 110,
+  ICE_TYPE_PREFERENCE_HOST = 126
+};
+
+const char* ProtoToString(ProtocolType proto);
+bool StringToProto(const char* value, ProtocolType* proto);
+
+struct ProtocolAddress {
+  rtc::SocketAddress address;
+  ProtocolType proto;
+  bool secure;
+
+  ProtocolAddress(const rtc::SocketAddress& a, ProtocolType p)
+      : address(a), proto(p), secure(false) { }
+  ProtocolAddress(const rtc::SocketAddress& a, ProtocolType p, bool sec)
+      : address(a), proto(p), secure(sec) { }
+};
+
+typedef std::set<rtc::SocketAddress> ServerAddresses;
+
+// Represents a local communication mechanism that can be used to create
+// connections to similar mechanisms of the other client.  Subclasses of this
+// one add support for specific mechanisms like local UDP ports.
+class Port : public PortInterface, public rtc::MessageHandler,
+             public sigslot::has_slots<> {
+ public:
+  Port(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+       rtc::Network* network, const rtc::IPAddress& ip,
+       const std::string& username_fragment, const std::string& password);
+  Port(rtc::Thread* thread, const std::string& type,
+       rtc::PacketSocketFactory* factory,
+       rtc::Network* network, const rtc::IPAddress& ip,
+       int min_port, int max_port, const std::string& username_fragment,
+       const std::string& password);
+  virtual ~Port();
+
+  virtual const std::string& Type() const { return type_; }
+  virtual rtc::Network* Network() const { return network_; }
+
+  // This method will set the flag which enables standard ICE/STUN procedures
+  // in STUN connectivity checks. Currently this method does
+  // 1. Add / Verify MI attribute in STUN binding requests.
+  // 2. Username attribute in STUN binding request will be RFRAF:LFRAG,
+  // as opposed to RFRAGLFRAG.
+  virtual void SetIceProtocolType(IceProtocolType protocol) {
+    ice_protocol_ = protocol;
+  }
+  virtual IceProtocolType IceProtocol() const { return ice_protocol_; }
+
+  // Methods to set/get ICE role and tiebreaker values.
+  IceRole GetIceRole() const { return ice_role_; }
+  void SetIceRole(IceRole role) { ice_role_ = role; }
+
+  void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
+  uint64 IceTiebreaker() const { return tiebreaker_; }
+
+  virtual bool SharedSocket() const { return shared_socket_; }
+  void ResetSharedSocket() { shared_socket_ = false; }
+
+  // The thread on which this port performs its I/O.
+  rtc::Thread* thread() { return thread_; }
+
+  // The factory used to create the sockets of this port.
+  rtc::PacketSocketFactory* socket_factory() const { return factory_; }
+  void set_socket_factory(rtc::PacketSocketFactory* factory) {
+    factory_ = factory;
+  }
+
+  // For debugging purposes.
+  const std::string& content_name() const { return content_name_; }
+  void set_content_name(const std::string& content_name) {
+    content_name_ = content_name;
+  }
+
+  int component() const { return component_; }
+  void set_component(int component) { component_ = component; }
+
+  bool send_retransmit_count_attribute() const {
+    return send_retransmit_count_attribute_;
+  }
+  void set_send_retransmit_count_attribute(bool enable) {
+    send_retransmit_count_attribute_ = enable;
+  }
+
+  // Identifies the generation that this port was created in.
+  uint32 generation() { return generation_; }
+  void set_generation(uint32 generation) { generation_ = generation; }
+
+  // ICE requires a single username/password per content/media line. So the
+  // |ice_username_fragment_| of the ports that belongs to the same content will
+  // be the same. However this causes a small complication with our relay
+  // server, which expects different username for RTP and RTCP.
+  //
+  // To resolve this problem, we implemented the username_fragment(),
+  // which returns a different username (calculated from
+  // |ice_username_fragment_|) for RTCP in the case of ICEPROTO_GOOGLE. And the
+  // username_fragment() simply returns |ice_username_fragment_| when running
+  // in ICEPROTO_RFC5245.
+  //
+  // As a result the ICEPROTO_GOOGLE will use different usernames for RTP and
+  // RTCP. And the ICEPROTO_RFC5245 will use same username for both RTP and
+  // RTCP.
+  const std::string username_fragment() const;
+  const std::string& password() const { return password_; }
+
+  // Fired when candidates are discovered by the port. When all candidates
+  // are discovered that belong to port SignalAddressReady is fired.
+  sigslot::signal2<Port*, const Candidate&> SignalCandidateReady;
+
+  // Provides all of the above information in one handy object.
+  virtual const std::vector<Candidate>& Candidates() const {
+    return candidates_;
+  }
+
+  // SignalPortComplete is sent when port completes the task of candidates
+  // allocation.
+  sigslot::signal1<Port*> SignalPortComplete;
+  // This signal sent when port fails to allocate candidates and this port
+  // can't be used in establishing the connections. When port is in shared mode
+  // and port fails to allocate one of the candidates, port shouldn't send
+  // this signal as other candidates might be usefull in establishing the
+  // connection.
+  sigslot::signal1<Port*> SignalPortError;
+
+  // Returns a map containing all of the connections of this port, keyed by the
+  // remote address.
+  typedef std::map<rtc::SocketAddress, Connection*> AddressMap;
+  const AddressMap& connections() { return connections_; }
+
+  // Returns the connection to the given address or NULL if none exists.
+  virtual Connection* GetConnection(
+      const rtc::SocketAddress& remote_addr);
+
+  // Called each time a connection is created.
+  sigslot::signal2<Port*, Connection*> SignalConnectionCreated;
+
+  // In a shared socket mode each port which shares the socket will decide
+  // to accept the packet based on the |remote_addr|. Currently only UDP
+  // port implemented this method.
+  // TODO(mallinath) - Make it pure virtual.
+  virtual bool HandleIncomingPacket(
+      rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+      const rtc::SocketAddress& remote_addr,
+      const rtc::PacketTime& packet_time) {
+    ASSERT(false);
+    return false;
+  }
+
+  // Sends a response message (normal or error) to the given request.  One of
+  // these methods should be called as a response to SignalUnknownAddress.
+  // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse.
+  virtual void SendBindingResponse(StunMessage* request,
+                                   const rtc::SocketAddress& addr);
+  virtual void SendBindingErrorResponse(
+      StunMessage* request, const rtc::SocketAddress& addr,
+      int error_code, const std::string& reason);
+
+  void set_proxy(const std::string& user_agent,
+                 const rtc::ProxyInfo& proxy) {
+    user_agent_ = user_agent;
+    proxy_ = proxy;
+  }
+  const std::string& user_agent() { return user_agent_; }
+  const rtc::ProxyInfo& proxy() { return proxy_; }
+
+  virtual void EnablePortPackets();
+
+  // Called if the port has no connections and is no longer useful.
+  void Destroy();
+
+  virtual void OnMessage(rtc::Message *pmsg);
+
+  // Debugging description of this port
+  virtual std::string ToString() const;
+  rtc::IPAddress& ip() { return ip_; }
+  int min_port() { return min_port_; }
+  int max_port() { return max_port_; }
+
+  // Timeout shortening function to speed up unit tests.
+  void set_timeout_delay(int delay) { timeout_delay_ = delay; }
+
+  // This method will return local and remote username fragements from the
+  // stun username attribute if present.
+  bool ParseStunUsername(const StunMessage* stun_msg,
+                         std::string* local_username,
+                         std::string* remote_username,
+                         IceProtocolType* remote_protocol_type) const;
+  void CreateStunUsername(const std::string& remote_username,
+                          std::string* stun_username_attr_str) const;
+
+  bool MaybeIceRoleConflict(const rtc::SocketAddress& addr,
+                            IceMessage* stun_msg,
+                            const std::string& remote_ufrag);
+
+  // Called when the socket is currently able to send.
+  void OnReadyToSend();
+
+  // Called when the Connection discovers a local peer reflexive candidate.
+  // Returns the index of the new local candidate.
+  size_t AddPrflxCandidate(const Candidate& local);
+
+  // Returns if RFC 5245 ICE protocol is used.
+  bool IsStandardIce() const;
+
+  // Returns if Google ICE protocol is used.
+  bool IsGoogleIce() const;
+
+  // Returns if Hybrid ICE protocol is used.
+  bool IsHybridIce() const;
+
+  void set_candidate_filter(uint32 candidate_filter) {
+    candidate_filter_ = candidate_filter;
+  }
+
+ protected:
+  enum {
+    MSG_CHECKTIMEOUT = 0,
+    MSG_FIRST_AVAILABLE
+  };
+
+  void set_type(const std::string& type) { type_ = type; }
+
+  void AddAddress(const rtc::SocketAddress& address,
+                  const rtc::SocketAddress& base_address,
+                  const rtc::SocketAddress& related_address,
+                  const std::string& protocol, const std::string& tcptype,
+                  const std::string& type, uint32 type_preference,
+                  uint32 relay_preference, bool final);
+
+  // Adds the given connection to the list.  (Deleting removes them.)
+  void AddConnection(Connection* conn);
+
+  // Called when a packet is received from an unknown address that is not
+  // currently a connection.  If this is an authenticated STUN binding request,
+  // then we will signal the client.
+  void OnReadPacket(const char* data, size_t size,
+                    const rtc::SocketAddress& addr,
+                    ProtocolType proto);
+
+  // If the given data comprises a complete and correct STUN message then the
+  // return value is true, otherwise false. If the message username corresponds
+  // with this port's username fragment, msg will contain the parsed STUN
+  // message.  Otherwise, the function may send a STUN response internally.
+  // remote_username contains the remote fragment of the STUN username.
+  bool GetStunMessage(const char* data, size_t size,
+                      const rtc::SocketAddress& addr,
+                      IceMessage** out_msg, std::string* out_username);
+
+  // Checks if the address in addr is compatible with the port's ip.
+  bool IsCompatibleAddress(const rtc::SocketAddress& addr);
+
+  // Returns default DSCP value.
+  rtc::DiffServCodePoint DefaultDscpValue() const {
+    // No change from what MediaChannel set.
+    return rtc::DSCP_NO_CHANGE;
+  }
+
+  uint32 candidate_filter() { return candidate_filter_; }
+
+ private:
+  void Construct();
+  // Called when one of our connections deletes itself.
+  void OnConnectionDestroyed(Connection* conn);
+
+  // Checks if this port is useless, and hence, should be destroyed.
+  void CheckTimeout();
+
+  rtc::Thread* thread_;
+  rtc::PacketSocketFactory* factory_;
+  std::string type_;
+  bool send_retransmit_count_attribute_;
+  rtc::Network* network_;
+  rtc::IPAddress ip_;
+  int min_port_;
+  int max_port_;
+  std::string content_name_;
+  int component_;
+  uint32 generation_;
+  // In order to establish a connection to this Port (so that real data can be
+  // sent through), the other side must send us a STUN binding request that is
+  // authenticated with this username_fragment and password.
+  // PortAllocatorSession will provide these username_fragment and password.
+  //
+  // Note: we should always use username_fragment() instead of using
+  // |ice_username_fragment_| directly. For the details see the comment on
+  // username_fragment().
+  std::string ice_username_fragment_;
+  std::string password_;
+  std::vector<Candidate> candidates_;
+  AddressMap connections_;
+  int timeout_delay_;
+  bool enable_port_packets_;
+  IceProtocolType ice_protocol_;
+  IceRole ice_role_;
+  uint64 tiebreaker_;
+  bool shared_socket_;
+  // Information to use when going through a proxy.
+  std::string user_agent_;
+  rtc::ProxyInfo proxy_;
+
+  // Candidate filter is pushed down to Port such that each Port could
+  // make its own decision on how to create candidates. For example,
+  // when IceTransportsType is set to relay, both RelayPort and
+  // TurnPort will hide raddr to avoid local address leakage.
+  uint32 candidate_filter_;
+
+  friend class Connection;
+};
+
+// Represents a communication link between a port on the local client and a
+// port on the remote client.
+class Connection : public rtc::MessageHandler,
+    public sigslot::has_slots<> {
+ public:
+  // States are from RFC 5245. http://tools.ietf.org/html/rfc5245#section-5.7.4
+  enum State {
+    STATE_WAITING = 0,  // Check has not been performed, Waiting pair on CL.
+    STATE_INPROGRESS,   // Check has been sent, transaction is in progress.
+    STATE_SUCCEEDED,    // Check already done, produced a successful result.
+    STATE_FAILED        // Check for this connection failed.
+  };
+
+  virtual ~Connection();
+
+  // The local port where this connection sends and receives packets.
+  Port* port() { return port_; }
+  const Port* port() const { return port_; }
+
+  // Returns the description of the local port
+  virtual const Candidate& local_candidate() const;
+
+  // Returns the description of the remote port to which we communicate.
+  const Candidate& remote_candidate() const { return remote_candidate_; }
+
+  // Returns the pair priority.
+  uint64 priority() const;
+
+  enum ReadState {
+    STATE_READ_INIT    = 0,  // we have yet to receive a ping
+    STATE_READABLE     = 1,  // we have received pings recently
+    STATE_READ_TIMEOUT = 2,  // we haven't received pings in a while
+  };
+
+  ReadState read_state() const { return read_state_; }
+  bool readable() const { return read_state_ == STATE_READABLE; }
+
+  enum WriteState {
+    STATE_WRITABLE          = 0,  // we have received ping responses recently
+    STATE_WRITE_UNRELIABLE  = 1,  // we have had a few ping failures
+    STATE_WRITE_INIT        = 2,  // we have yet to receive a ping response
+    STATE_WRITE_TIMEOUT     = 3,  // we have had a large number of ping failures
+  };
+
+  WriteState write_state() const { return write_state_; }
+  bool writable() const { return write_state_ == STATE_WRITABLE; }
+
+  // Determines whether the connection has finished connecting.  This can only
+  // be false for TCP connections.
+  bool connected() const { return connected_; }
+
+  // Estimate of the round-trip time over this connection.
+  uint32 rtt() const { return rtt_; }
+
+  size_t sent_total_bytes();
+  size_t sent_bytes_second();
+  size_t recv_total_bytes();
+  size_t recv_bytes_second();
+  sigslot::signal1<Connection*> SignalStateChange;
+
+  // Sent when the connection has decided that it is no longer of value.  It
+  // will delete itself immediately after this call.
+  sigslot::signal1<Connection*> SignalDestroyed;
+
+  // The connection can send and receive packets asynchronously.  This matches
+  // the interface of AsyncPacketSocket, which may use UDP or TCP under the
+  // covers.
+  virtual int Send(const void* data, size_t size,
+                   const rtc::PacketOptions& options) = 0;
+
+  // Error if Send() returns < 0
+  virtual int GetError() = 0;
+
+  sigslot::signal4<Connection*, const char*, size_t,
+                   const rtc::PacketTime&> SignalReadPacket;
+
+  sigslot::signal1<Connection*> SignalReadyToSend;
+
+  // Called when a packet is received on this connection.
+  void OnReadPacket(const char* data, size_t size,
+                    const rtc::PacketTime& packet_time);
+
+  // Called when the socket is currently able to send.
+  void OnReadyToSend();
+
+  // Called when a connection is determined to be no longer useful to us.  We
+  // still keep it around in case the other side wants to use it.  But we can
+  // safely stop pinging on it and we can allow it to time out if the other
+  // side stops using it as well.
+  bool pruned() const { return pruned_; }
+  void Prune();
+
+  bool use_candidate_attr() const { return use_candidate_attr_; }
+  void set_use_candidate_attr(bool enable);
+
+  void set_remote_ice_mode(IceMode mode) {
+    remote_ice_mode_ = mode;
+  }
+
+  // Makes the connection go away.
+  void Destroy();
+
+  // Checks that the state of this connection is up-to-date.  The argument is
+  // the current time, which is compared against various timeouts.
+  void UpdateState(uint32 now);
+
+  // Called when this connection should try checking writability again.
+  uint32 last_ping_sent() const { return last_ping_sent_; }
+  void Ping(uint32 now);
+
+  // Called whenever a valid ping is received on this connection.  This is
+  // public because the connection intercepts the first ping for us.
+  uint32 last_ping_received() const { return last_ping_received_; }
+  void ReceivedPing();
+
+  // Debugging description of this connection
+  std::string ToString() const;
+  std::string ToSensitiveString() const;
+
+  bool reported() const { return reported_; }
+  void set_reported(bool reported) { reported_ = reported;}
+
+  // This flag will be set if this connection is the chosen one for media
+  // transmission. This connection will send STUN ping with USE-CANDIDATE
+  // attribute.
+  sigslot::signal1<Connection*> SignalUseCandidate;
+  // Invoked when Connection receives STUN error response with 487 code.
+  void HandleRoleConflictFromPeer();
+
+  State state() const { return state_; }
+
+  IceMode remote_ice_mode() const { return remote_ice_mode_; }
+
+ protected:
+  // Constructs a new connection to the given remote port.
+  Connection(Port* port, size_t index, const Candidate& candidate);
+
+  // Called back when StunRequestManager has a stun packet to send
+  void OnSendStunPacket(const void* data, size_t size, StunRequest* req);
+
+  // Callbacks from ConnectionRequest
+  void OnConnectionRequestResponse(ConnectionRequest* req,
+                                   StunMessage* response);
+  void OnConnectionRequestErrorResponse(ConnectionRequest* req,
+                                        StunMessage* response);
+  void OnConnectionRequestTimeout(ConnectionRequest* req);
+
+  // Changes the state and signals if necessary.
+  void set_read_state(ReadState value);
+  void set_write_state(WriteState value);
+  void set_state(State state);
+  void set_connected(bool value);
+
+  // Checks if this connection is useless, and hence, should be destroyed.
+  void CheckTimeout();
+
+  void OnMessage(rtc::Message *pmsg);
+
+  Port* port_;
+  size_t local_candidate_index_;
+  Candidate remote_candidate_;
+  ReadState read_state_;
+  WriteState write_state_;
+  bool connected_;
+  bool pruned_;
+  // By default |use_candidate_attr_| flag will be true,
+  // as we will be using agrressive nomination.
+  // But when peer is ice-lite, this flag "must" be initialized to false and
+  // turn on when connection becomes "best connection".
+  bool use_candidate_attr_;
+  IceMode remote_ice_mode_;
+  StunRequestManager requests_;
+  uint32 rtt_;
+  uint32 last_ping_sent_;      // last time we sent a ping to the other side
+  uint32 last_ping_received_;  // last time we received a ping from the other
+                               // side
+  uint32 last_data_received_;
+  uint32 last_ping_response_received_;
+  std::vector<uint32> pings_since_last_response_;
+
+  rtc::RateTracker recv_rate_tracker_;
+  rtc::RateTracker send_rate_tracker_;
+
+ private:
+  void MaybeAddPrflxCandidate(ConnectionRequest* request,
+                              StunMessage* response);
+
+  bool reported_;
+  State state_;
+
+  friend class Port;
+  friend class ConnectionRequest;
+};
+
+// ProxyConnection defers all the interesting work to the port
+class ProxyConnection : public Connection {
+ public:
+  ProxyConnection(Port* port, size_t index, const Candidate& candidate);
+
+  virtual int Send(const void* data, size_t size,
+                   const rtc::PacketOptions& options);
+  virtual int GetError() { return error_; }
+
+ private:
+  int error_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_PORT_H_
diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc
new file mode 100644
index 0000000..8805709
--- /dev/null
+++ b/p2p/base/port_unittest.cc
@@ -0,0 +1,2494 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/portproxy.h"
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/p2p/base/stunport.h"
+#include "webrtc/p2p/base/tcpport.h"
+#include "webrtc/p2p/base/testrelayserver.h"
+#include "webrtc/p2p/base/teststunserver.h"
+#include "webrtc/p2p/base/testturnserver.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/turnport.h"
+#include "webrtc/base/crc32.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/natserver.h"
+#include "webrtc/base/natsocketfactory.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/stringutils.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+using rtc::AsyncPacketSocket;
+using rtc::ByteBuffer;
+using rtc::NATType;
+using rtc::NAT_OPEN_CONE;
+using rtc::NAT_ADDR_RESTRICTED;
+using rtc::NAT_PORT_RESTRICTED;
+using rtc::NAT_SYMMETRIC;
+using rtc::PacketSocketFactory;
+using rtc::scoped_ptr;
+using rtc::Socket;
+using rtc::SocketAddress;
+using namespace cricket;
+
+static const int kTimeout = 1000;
+static const SocketAddress kLocalAddr1("192.168.1.2", 0);
+static const SocketAddress kLocalAddr2("192.168.1.3", 0);
+static const SocketAddress kNatAddr1("77.77.77.77", rtc::NAT_SERVER_PORT);
+static const SocketAddress kNatAddr2("88.88.88.88", rtc::NAT_SERVER_PORT);
+static const SocketAddress kStunAddr("99.99.99.1", STUN_SERVER_PORT);
+static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000);
+static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001);
+static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002);
+static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003);
+static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004);
+static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005);
+static const SocketAddress kTurnUdpIntAddr("99.99.99.4", STUN_SERVER_PORT);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
+static const RelayCredentials kRelayCredentials("test", "test");
+
+// TODO: Update these when RFC5245 is completely supported.
+// Magic value of 30 is from RFC3484, for IPv4 addresses.
+static const uint32 kDefaultPrflxPriority = ICE_TYPE_PREFERENCE_PRFLX << 24 |
+             30 << 8 | (256 - ICE_CANDIDATE_COMPONENT_DEFAULT);
+static const int STUN_ERROR_BAD_REQUEST_AS_GICE =
+    STUN_ERROR_BAD_REQUEST / 256 * 100 + STUN_ERROR_BAD_REQUEST % 256;
+static const int STUN_ERROR_UNAUTHORIZED_AS_GICE =
+    STUN_ERROR_UNAUTHORIZED / 256 * 100 + STUN_ERROR_UNAUTHORIZED % 256;
+static const int STUN_ERROR_SERVER_ERROR_AS_GICE =
+    STUN_ERROR_SERVER_ERROR / 256 * 100 + STUN_ERROR_SERVER_ERROR % 256;
+
+static const int kTiebreaker1 = 11111;
+static const int kTiebreaker2 = 22222;
+
+static Candidate GetCandidate(Port* port) {
+  assert(port->Candidates().size() == 1);
+  return port->Candidates()[0];
+}
+
+static SocketAddress GetAddress(Port* port) {
+  return GetCandidate(port).address();
+}
+
+static IceMessage* CopyStunMessage(const IceMessage* src) {
+  IceMessage* dst = new IceMessage();
+  ByteBuffer buf;
+  src->Write(&buf);
+  dst->Read(&buf);
+  return dst;
+}
+
+static bool WriteStunMessage(const StunMessage* msg, ByteBuffer* buf) {
+  buf->Resize(0);  // clear out any existing buffer contents
+  return msg->Write(buf);
+}
+
+// Stub port class for testing STUN generation and processing.
+class TestPort : public Port {
+ public:
+  TestPort(rtc::Thread* thread, const std::string& type,
+           rtc::PacketSocketFactory* factory, rtc::Network* network,
+           const rtc::IPAddress& ip, int min_port, int max_port,
+           const std::string& username_fragment, const std::string& password)
+      : Port(thread, type, factory, network, ip,
+             min_port, max_port, username_fragment, password) {
+  }
+  ~TestPort() {}
+
+  // Expose GetStunMessage so that we can test it.
+  using cricket::Port::GetStunMessage;
+
+  // The last StunMessage that was sent on this Port.
+  // TODO: Make these const; requires changes to SendXXXXResponse.
+  ByteBuffer* last_stun_buf() { return last_stun_buf_.get(); }
+  IceMessage* last_stun_msg() { return last_stun_msg_.get(); }
+  int last_stun_error_code() {
+    int code = 0;
+    if (last_stun_msg_) {
+      const StunErrorCodeAttribute* error_attr = last_stun_msg_->GetErrorCode();
+      if (error_attr) {
+        code = error_attr->code();
+      }
+    }
+    return code;
+  }
+
+  virtual void PrepareAddress() {
+    rtc::SocketAddress addr(ip(), min_port());
+    AddAddress(addr, addr, rtc::SocketAddress(), "udp", "", Type(),
+               ICE_TYPE_PREFERENCE_HOST, 0, true);
+  }
+
+  // Exposed for testing candidate building.
+  void AddCandidateAddress(const rtc::SocketAddress& addr) {
+    AddAddress(addr, addr, rtc::SocketAddress(), "udp", "", Type(),
+               type_preference_, 0, false);
+  }
+  void AddCandidateAddress(const rtc::SocketAddress& addr,
+                           const rtc::SocketAddress& base_address,
+                           const std::string& type,
+                           int type_preference,
+                           bool final) {
+    AddAddress(addr, base_address, rtc::SocketAddress(), "udp", "", type,
+               type_preference, 0, final);
+  }
+
+  virtual Connection* CreateConnection(const Candidate& remote_candidate,
+                                       CandidateOrigin origin) {
+    Connection* conn = new ProxyConnection(this, 0, remote_candidate);
+    AddConnection(conn);
+    // Set use-candidate attribute flag as this will add USE-CANDIDATE attribute
+    // in STUN binding requests.
+    conn->set_use_candidate_attr(true);
+    return conn;
+  }
+  virtual int SendTo(
+      const void* data, size_t size, const rtc::SocketAddress& addr,
+      const rtc::PacketOptions& options, bool payload) {
+    if (!payload) {
+      IceMessage* msg = new IceMessage;
+      ByteBuffer* buf = new ByteBuffer(static_cast<const char*>(data), size);
+      ByteBuffer::ReadPosition pos(buf->GetReadPosition());
+      if (!msg->Read(buf)) {
+        delete msg;
+        delete buf;
+        return -1;
+      }
+      buf->SetReadPosition(pos);
+      last_stun_buf_.reset(buf);
+      last_stun_msg_.reset(msg);
+    }
+    return static_cast<int>(size);
+  }
+  virtual int SetOption(rtc::Socket::Option opt, int value) {
+    return 0;
+  }
+  virtual int GetOption(rtc::Socket::Option opt, int* value) {
+    return -1;
+  }
+  virtual int GetError() {
+    return 0;
+  }
+  void Reset() {
+    last_stun_buf_.reset();
+    last_stun_msg_.reset();
+  }
+  void set_type_preference(int type_preference) {
+    type_preference_ = type_preference;
+  }
+
+ private:
+  rtc::scoped_ptr<ByteBuffer> last_stun_buf_;
+  rtc::scoped_ptr<IceMessage> last_stun_msg_;
+  int type_preference_;
+};
+
+class TestChannel : public sigslot::has_slots<> {
+ public:
+  // Takes ownership of |p1| (but not |p2|).
+  TestChannel(Port* p1, Port* p2)
+      : ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0),
+	conn_(NULL), remote_request_(), nominated_(false) {
+    src_->SignalPortComplete.connect(
+        this, &TestChannel::OnPortComplete);
+    src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress);
+    src_->SignalDestroyed.connect(this, &TestChannel::OnSrcPortDestroyed);
+  }
+
+  int complete_count() { return complete_count_; }
+  Connection* conn() { return conn_; }
+  const SocketAddress& remote_address() { return remote_address_; }
+  const std::string remote_fragment() { return remote_frag_; }
+
+  void Start() {
+    src_->PrepareAddress();
+  }
+  void CreateConnection() {
+    conn_ = src_->CreateConnection(GetCandidate(dst_), Port::ORIGIN_MESSAGE);
+    IceMode remote_ice_mode =
+        (ice_mode_ == ICEMODE_FULL) ? ICEMODE_LITE : ICEMODE_FULL;
+    conn_->set_remote_ice_mode(remote_ice_mode);
+    conn_->set_use_candidate_attr(remote_ice_mode == ICEMODE_FULL);
+    conn_->SignalStateChange.connect(
+        this, &TestChannel::OnConnectionStateChange);
+  }
+  void OnConnectionStateChange(Connection* conn) {
+    if (conn->write_state() == Connection::STATE_WRITABLE) {
+      conn->set_use_candidate_attr(true);
+      nominated_ = true;
+    }
+  }
+  void AcceptConnection() {
+    ASSERT_TRUE(remote_request_.get() != NULL);
+    Candidate c = GetCandidate(dst_);
+    c.set_address(remote_address_);
+    conn_ = src_->CreateConnection(c, Port::ORIGIN_MESSAGE);
+    src_->SendBindingResponse(remote_request_.get(), remote_address_);
+    remote_request_.reset();
+  }
+  void Ping() {
+    Ping(0);
+  }
+  void Ping(uint32 now) {
+    conn_->Ping(now);
+  }
+  void Stop() {
+    conn_->SignalDestroyed.connect(this, &TestChannel::OnDestroyed);
+    conn_->Destroy();
+  }
+
+  void OnPortComplete(Port* port) {
+    complete_count_++;
+  }
+  void SetIceMode(IceMode ice_mode) {
+    ice_mode_ = ice_mode;
+  }
+
+  void OnUnknownAddress(PortInterface* port, const SocketAddress& addr,
+                        ProtocolType proto,
+                        IceMessage* msg, const std::string& rf,
+                        bool /*port_muxed*/) {
+    ASSERT_EQ(src_.get(), port);
+    if (!remote_address_.IsNil()) {
+      ASSERT_EQ(remote_address_, addr);
+    }
+    // MI and PRIORITY attribute should be present in ping requests when port
+    // is in ICEPROTO_RFC5245 mode.
+    const cricket::StunUInt32Attribute* priority_attr =
+        msg->GetUInt32(STUN_ATTR_PRIORITY);
+    const cricket::StunByteStringAttribute* mi_attr =
+        msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
+    const cricket::StunUInt32Attribute* fingerprint_attr =
+        msg->GetUInt32(STUN_ATTR_FINGERPRINT);
+    if (src_->IceProtocol() == cricket::ICEPROTO_RFC5245) {
+      EXPECT_TRUE(priority_attr != NULL);
+      EXPECT_TRUE(mi_attr != NULL);
+      EXPECT_TRUE(fingerprint_attr != NULL);
+    } else {
+      EXPECT_TRUE(priority_attr == NULL);
+      EXPECT_TRUE(mi_attr == NULL);
+      EXPECT_TRUE(fingerprint_attr == NULL);
+    }
+    remote_address_ = addr;
+    remote_request_.reset(CopyStunMessage(msg));
+    remote_frag_ = rf;
+  }
+
+  void OnDestroyed(Connection* conn) {
+    ASSERT_EQ(conn_, conn);
+    conn_ = NULL;
+  }
+
+  void OnSrcPortDestroyed(PortInterface* port) {
+    Port* destroyed_src = src_.release();
+    ASSERT_EQ(destroyed_src, port);
+  }
+
+  bool nominated() const { return nominated_; }
+
+ private:
+  IceMode ice_mode_;
+  rtc::scoped_ptr<Port> src_;
+  Port* dst_;
+
+  int complete_count_;
+  Connection* conn_;
+  SocketAddress remote_address_;
+  rtc::scoped_ptr<StunMessage> remote_request_;
+  std::string remote_frag_;
+  bool nominated_;
+};
+
+class PortTest : public testing::Test, public sigslot::has_slots<> {
+ public:
+  PortTest()
+      : main_(rtc::Thread::Current()),
+        pss_(new rtc::PhysicalSocketServer),
+        ss_(new rtc::VirtualSocketServer(pss_.get())),
+        ss_scope_(ss_.get()),
+        network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32),
+        socket_factory_(rtc::Thread::Current()),
+        nat_factory1_(ss_.get(), kNatAddr1),
+        nat_factory2_(ss_.get(), kNatAddr2),
+        nat_socket_factory1_(&nat_factory1_),
+        nat_socket_factory2_(&nat_factory2_),
+        stun_server_(TestStunServer::Create(main_, kStunAddr)),
+        turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr),
+        relay_server_(main_, kRelayUdpIntAddr, kRelayUdpExtAddr,
+                      kRelayTcpIntAddr, kRelayTcpExtAddr,
+                      kRelaySslTcpIntAddr, kRelaySslTcpExtAddr),
+        username_(rtc::CreateRandomString(ICE_UFRAG_LENGTH)),
+        password_(rtc::CreateRandomString(ICE_PWD_LENGTH)),
+        ice_protocol_(cricket::ICEPROTO_GOOGLE),
+        role_conflict_(false),
+        destroyed_(false) {
+    network_.AddIP(rtc::IPAddress(INADDR_ANY));
+  }
+
+ protected:
+  void TestLocalToLocal() {
+    Port* port1 = CreateUdpPort(kLocalAddr1);
+    Port* port2 = CreateUdpPort(kLocalAddr2);
+    TestConnectivity("udp", port1, "udp", port2, true, true, true, true);
+  }
+  void TestLocalToStun(NATType ntype) {
+    Port* port1 = CreateUdpPort(kLocalAddr1);
+    nat_server2_.reset(CreateNatServer(kNatAddr2, ntype));
+    Port* port2 = CreateStunPort(kLocalAddr2, &nat_socket_factory2_);
+    TestConnectivity("udp", port1, StunName(ntype), port2,
+                     ntype == NAT_OPEN_CONE, true,
+                     ntype != NAT_SYMMETRIC, true);
+  }
+  void TestLocalToRelay(RelayType rtype, ProtocolType proto) {
+    Port* port1 = CreateUdpPort(kLocalAddr1);
+    Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_UDP);
+    TestConnectivity("udp", port1, RelayName(rtype, proto), port2,
+                     rtype == RELAY_GTURN, true, true, true);
+  }
+  void TestStunToLocal(NATType ntype) {
+    nat_server1_.reset(CreateNatServer(kNatAddr1, ntype));
+    Port* port1 = CreateStunPort(kLocalAddr1, &nat_socket_factory1_);
+    Port* port2 = CreateUdpPort(kLocalAddr2);
+    TestConnectivity(StunName(ntype), port1, "udp", port2,
+                     true, ntype != NAT_SYMMETRIC, true, true);
+  }
+  void TestStunToStun(NATType ntype1, NATType ntype2) {
+    nat_server1_.reset(CreateNatServer(kNatAddr1, ntype1));
+    Port* port1 = CreateStunPort(kLocalAddr1, &nat_socket_factory1_);
+    nat_server2_.reset(CreateNatServer(kNatAddr2, ntype2));
+    Port* port2 = CreateStunPort(kLocalAddr2, &nat_socket_factory2_);
+    TestConnectivity(StunName(ntype1), port1, StunName(ntype2), port2,
+                     ntype2 == NAT_OPEN_CONE,
+                     ntype1 != NAT_SYMMETRIC, ntype2 != NAT_SYMMETRIC,
+                     ntype1 + ntype2 < (NAT_PORT_RESTRICTED + NAT_SYMMETRIC));
+  }
+  void TestStunToRelay(NATType ntype, RelayType rtype, ProtocolType proto) {
+    nat_server1_.reset(CreateNatServer(kNatAddr1, ntype));
+    Port* port1 = CreateStunPort(kLocalAddr1, &nat_socket_factory1_);
+    Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_UDP);
+    TestConnectivity(StunName(ntype), port1, RelayName(rtype, proto), port2,
+                     rtype == RELAY_GTURN, ntype != NAT_SYMMETRIC, true, true);
+  }
+  void TestTcpToTcp() {
+    Port* port1 = CreateTcpPort(kLocalAddr1);
+    Port* port2 = CreateTcpPort(kLocalAddr2);
+    TestConnectivity("tcp", port1, "tcp", port2, true, false, true, true);
+  }
+  void TestTcpToRelay(RelayType rtype, ProtocolType proto) {
+    Port* port1 = CreateTcpPort(kLocalAddr1);
+    Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_TCP);
+    TestConnectivity("tcp", port1, RelayName(rtype, proto), port2,
+                     rtype == RELAY_GTURN, false, true, true);
+  }
+  void TestSslTcpToRelay(RelayType rtype, ProtocolType proto) {
+    Port* port1 = CreateTcpPort(kLocalAddr1);
+    Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_SSLTCP);
+    TestConnectivity("ssltcp", port1, RelayName(rtype, proto), port2,
+                     rtype == RELAY_GTURN, false, true, true);
+  }
+
+  // helpers for above functions
+  UDPPort* CreateUdpPort(const SocketAddress& addr) {
+    return CreateUdpPort(addr, &socket_factory_);
+  }
+  UDPPort* CreateUdpPort(const SocketAddress& addr,
+                         PacketSocketFactory* socket_factory) {
+    UDPPort* port = UDPPort::Create(main_, socket_factory, &network_,
+                                    addr.ipaddr(), 0, 0, username_, password_);
+    port->SetIceProtocolType(ice_protocol_);
+    return port;
+  }
+  TCPPort* CreateTcpPort(const SocketAddress& addr) {
+    TCPPort* port = CreateTcpPort(addr, &socket_factory_);
+    port->SetIceProtocolType(ice_protocol_);
+    return port;
+  }
+  TCPPort* CreateTcpPort(const SocketAddress& addr,
+                        PacketSocketFactory* socket_factory) {
+    TCPPort* port = TCPPort::Create(main_, socket_factory, &network_,
+                                    addr.ipaddr(), 0, 0, username_, password_,
+                                    true);
+    port->SetIceProtocolType(ice_protocol_);
+    return port;
+  }
+  StunPort* CreateStunPort(const SocketAddress& addr,
+                           rtc::PacketSocketFactory* factory) {
+    ServerAddresses stun_servers;
+    stun_servers.insert(kStunAddr);
+    StunPort* port = StunPort::Create(main_, factory, &network_,
+                                      addr.ipaddr(), 0, 0,
+                                      username_, password_, stun_servers);
+    port->SetIceProtocolType(ice_protocol_);
+    return port;
+  }
+  Port* CreateRelayPort(const SocketAddress& addr, RelayType rtype,
+                        ProtocolType int_proto, ProtocolType ext_proto) {
+    if (rtype == RELAY_TURN) {
+      return CreateTurnPort(addr, &socket_factory_, int_proto, ext_proto);
+    } else {
+      return CreateGturnPort(addr, int_proto, ext_proto);
+    }
+  }
+  TurnPort* CreateTurnPort(const SocketAddress& addr,
+                           PacketSocketFactory* socket_factory,
+                           ProtocolType int_proto, ProtocolType ext_proto) {
+    return CreateTurnPort(addr, socket_factory,
+                          int_proto, ext_proto, kTurnUdpIntAddr);
+  }
+  TurnPort* CreateTurnPort(const SocketAddress& addr,
+                           PacketSocketFactory* socket_factory,
+                           ProtocolType int_proto, ProtocolType ext_proto,
+                           const rtc::SocketAddress& server_addr) {
+    TurnPort* port = TurnPort::Create(main_, socket_factory, &network_,
+                                      addr.ipaddr(), 0, 0,
+                                      username_, password_, ProtocolAddress(
+                                          server_addr, PROTO_UDP),
+                                      kRelayCredentials, 0);
+    port->SetIceProtocolType(ice_protocol_);
+    return port;
+  }
+  RelayPort* CreateGturnPort(const SocketAddress& addr,
+                             ProtocolType int_proto, ProtocolType ext_proto) {
+    RelayPort* port = CreateGturnPort(addr);
+    SocketAddress addrs[] =
+        { kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr };
+    port->AddServerAddress(ProtocolAddress(addrs[int_proto], int_proto));
+    return port;
+  }
+  RelayPort* CreateGturnPort(const SocketAddress& addr) {
+    RelayPort* port = RelayPort::Create(main_, &socket_factory_, &network_,
+                                        addr.ipaddr(), 0, 0,
+                                        username_, password_);
+    // TODO: Add an external address for ext_proto, so that the
+    // other side can connect to this port using a non-UDP protocol.
+    port->SetIceProtocolType(ice_protocol_);
+    return port;
+  }
+  rtc::NATServer* CreateNatServer(const SocketAddress& addr,
+                                        rtc::NATType type) {
+    return new rtc::NATServer(type, ss_.get(), addr, ss_.get(), addr);
+  }
+  static const char* StunName(NATType type) {
+    switch (type) {
+      case NAT_OPEN_CONE:       return "stun(open cone)";
+      case NAT_ADDR_RESTRICTED: return "stun(addr restricted)";
+      case NAT_PORT_RESTRICTED: return "stun(port restricted)";
+      case NAT_SYMMETRIC:       return "stun(symmetric)";
+      default:                  return "stun(?)";
+    }
+  }
+  static const char* RelayName(RelayType type, ProtocolType proto) {
+    if (type == RELAY_TURN) {
+      switch (proto) {
+        case PROTO_UDP:           return "turn(udp)";
+        case PROTO_TCP:           return "turn(tcp)";
+        case PROTO_SSLTCP:        return "turn(ssltcp)";
+        default:                  return "turn(?)";
+      }
+    } else {
+      switch (proto) {
+        case PROTO_UDP:           return "gturn(udp)";
+        case PROTO_TCP:           return "gturn(tcp)";
+        case PROTO_SSLTCP:        return "gturn(ssltcp)";
+        default:                  return "gturn(?)";
+      }
+    }
+  }
+
+  void TestCrossFamilyPorts(int type);
+
+  // This does all the work and then deletes |port1| and |port2|.
+  void TestConnectivity(const char* name1, Port* port1,
+                        const char* name2, Port* port2,
+                        bool accept, bool same_addr1,
+                        bool same_addr2, bool possible);
+
+  // This connects and disconnects the provided channels in the same sequence as
+  // TestConnectivity with all options set to |true|.  It does not delete either
+  // channel.
+  void ConnectAndDisconnectChannels(TestChannel* ch1, TestChannel* ch2);
+
+  void SetIceProtocolType(cricket::IceProtocolType protocol) {
+    ice_protocol_ = protocol;
+  }
+
+  IceMessage* CreateStunMessage(int type) {
+    IceMessage* msg = new IceMessage();
+    msg->SetType(type);
+    msg->SetTransactionID("TESTTESTTEST");
+    return msg;
+  }
+  IceMessage* CreateStunMessageWithUsername(int type,
+                                            const std::string& username) {
+    IceMessage* msg = CreateStunMessage(type);
+    msg->AddAttribute(
+        new StunByteStringAttribute(STUN_ATTR_USERNAME, username));
+    return msg;
+  }
+  TestPort* CreateTestPort(const rtc::SocketAddress& addr,
+                           const std::string& username,
+                           const std::string& password) {
+    TestPort* port =  new TestPort(main_, "test", &socket_factory_, &network_,
+                                   addr.ipaddr(), 0, 0, username, password);
+    port->SignalRoleConflict.connect(this, &PortTest::OnRoleConflict);
+    return port;
+  }
+  TestPort* CreateTestPort(const rtc::SocketAddress& addr,
+                           const std::string& username,
+                           const std::string& password,
+                           cricket::IceProtocolType type,
+                           cricket::IceRole role,
+                           int tiebreaker) {
+    TestPort* port = CreateTestPort(addr, username, password);
+    port->SetIceProtocolType(type);
+    port->SetIceRole(role);
+    port->SetIceTiebreaker(tiebreaker);
+    return port;
+  }
+
+  void OnRoleConflict(PortInterface* port) {
+    role_conflict_ = true;
+  }
+  bool role_conflict() const { return role_conflict_; }
+
+  void ConnectToSignalDestroyed(PortInterface* port) {
+    port->SignalDestroyed.connect(this, &PortTest::OnDestroyed);
+  }
+
+  void OnDestroyed(PortInterface* port) {
+    destroyed_ = true;
+  }
+  bool destroyed() const { return destroyed_; }
+
+  rtc::BasicPacketSocketFactory* nat_socket_factory1() {
+    return &nat_socket_factory1_;
+  }
+
+ private:
+  rtc::Thread* main_;
+  rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> ss_;
+  rtc::SocketServerScope ss_scope_;
+  rtc::Network network_;
+  rtc::BasicPacketSocketFactory socket_factory_;
+  rtc::scoped_ptr<rtc::NATServer> nat_server1_;
+  rtc::scoped_ptr<rtc::NATServer> nat_server2_;
+  rtc::NATSocketFactory nat_factory1_;
+  rtc::NATSocketFactory nat_factory2_;
+  rtc::BasicPacketSocketFactory nat_socket_factory1_;
+  rtc::BasicPacketSocketFactory nat_socket_factory2_;
+  scoped_ptr<TestStunServer> stun_server_;
+  TestTurnServer turn_server_;
+  TestRelayServer relay_server_;
+  std::string username_;
+  std::string password_;
+  cricket::IceProtocolType ice_protocol_;
+  bool role_conflict_;
+  bool destroyed_;
+};
+
+void PortTest::TestConnectivity(const char* name1, Port* port1,
+                                const char* name2, Port* port2,
+                                bool accept, bool same_addr1,
+                                bool same_addr2, bool possible) {
+  LOG(LS_INFO) << "Test: " << name1 << " to " << name2 << ": ";
+  port1->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
+  port2->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
+
+  // Set up channels and ensure both ports will be deleted.
+  TestChannel ch1(port1, port2);
+  TestChannel ch2(port2, port1);
+  EXPECT_EQ(0, ch1.complete_count());
+  EXPECT_EQ(0, ch2.complete_count());
+
+  // Acquire addresses.
+  ch1.Start();
+  ch2.Start();
+  ASSERT_EQ_WAIT(1, ch1.complete_count(), kTimeout);
+  ASSERT_EQ_WAIT(1, ch2.complete_count(), kTimeout);
+
+  // Send a ping from src to dst. This may or may not make it.
+  ch1.CreateConnection();
+  ASSERT_TRUE(ch1.conn() != NULL);
+  EXPECT_TRUE_WAIT(ch1.conn()->connected(), kTimeout);  // for TCP connect
+  ch1.Ping();
+  WAIT(!ch2.remote_address().IsNil(), kTimeout);
+
+  if (accept) {
+    // We are able to send a ping from src to dst. This is the case when
+    // sending to UDP ports and cone NATs.
+    EXPECT_TRUE(ch1.remote_address().IsNil());
+    EXPECT_EQ(ch2.remote_fragment(), port1->username_fragment());
+
+    // Ensure the ping came from the same address used for src.
+    // This is the case unless the source NAT was symmetric.
+    if (same_addr1) EXPECT_EQ(ch2.remote_address(), GetAddress(port1));
+    EXPECT_TRUE(same_addr2);
+
+    // Send a ping from dst to src.
+    ch2.AcceptConnection();
+    ASSERT_TRUE(ch2.conn() != NULL);
+    ch2.Ping();
+    EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch2.conn()->write_state(),
+                   kTimeout);
+  } else {
+    // We can't send a ping from src to dst, so flip it around. This will happen
+    // when the destination NAT is addr/port restricted or symmetric.
+    EXPECT_TRUE(ch1.remote_address().IsNil());
+    EXPECT_TRUE(ch2.remote_address().IsNil());
+
+    // Send a ping from dst to src. Again, this may or may not make it.
+    ch2.CreateConnection();
+    ASSERT_TRUE(ch2.conn() != NULL);
+    ch2.Ping();
+    WAIT(ch2.conn()->write_state() == Connection::STATE_WRITABLE, kTimeout);
+
+    if (same_addr1 && same_addr2) {
+      // The new ping got back to the source.
+      EXPECT_EQ(Connection::STATE_READABLE, ch1.conn()->read_state());
+      EXPECT_EQ(Connection::STATE_WRITABLE, ch2.conn()->write_state());
+
+      // First connection may not be writable if the first ping did not get
+      // through.  So we will have to do another.
+      if (ch1.conn()->write_state() == Connection::STATE_WRITE_INIT) {
+        ch1.Ping();
+        EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(),
+                       kTimeout);
+      }
+    } else if (!same_addr1 && possible) {
+      // The new ping went to the candidate address, but that address was bad.
+      // This will happen when the source NAT is symmetric.
+      EXPECT_TRUE(ch1.remote_address().IsNil());
+      EXPECT_TRUE(ch2.remote_address().IsNil());
+
+      // However, since we have now sent a ping to the source IP, we should be
+      // able to get a ping from it. This gives us the real source address.
+      ch1.Ping();
+      EXPECT_TRUE_WAIT(!ch2.remote_address().IsNil(), kTimeout);
+      EXPECT_EQ(Connection::STATE_READ_INIT, ch2.conn()->read_state());
+      EXPECT_TRUE(ch1.remote_address().IsNil());
+
+      // Pick up the actual address and establish the connection.
+      ch2.AcceptConnection();
+      ASSERT_TRUE(ch2.conn() != NULL);
+      ch2.Ping();
+      EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch2.conn()->write_state(),
+                     kTimeout);
+    } else if (!same_addr2 && possible) {
+      // The new ping came in, but from an unexpected address. This will happen
+      // when the destination NAT is symmetric.
+      EXPECT_FALSE(ch1.remote_address().IsNil());
+      EXPECT_EQ(Connection::STATE_READ_INIT, ch1.conn()->read_state());
+
+      // Update our address and complete the connection.
+      ch1.AcceptConnection();
+      ch1.Ping();
+      EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(),
+                     kTimeout);
+    } else {  // (!possible)
+      // There should be s no way for the pings to reach each other. Check it.
+      EXPECT_TRUE(ch1.remote_address().IsNil());
+      EXPECT_TRUE(ch2.remote_address().IsNil());
+      ch1.Ping();
+      WAIT(!ch2.remote_address().IsNil(), kTimeout);
+      EXPECT_TRUE(ch1.remote_address().IsNil());
+      EXPECT_TRUE(ch2.remote_address().IsNil());
+    }
+  }
+
+  // Everything should be good, unless we know the situation is impossible.
+  ASSERT_TRUE(ch1.conn() != NULL);
+  ASSERT_TRUE(ch2.conn() != NULL);
+  if (possible) {
+    EXPECT_EQ(Connection::STATE_READABLE, ch1.conn()->read_state());
+    EXPECT_EQ(Connection::STATE_WRITABLE, ch1.conn()->write_state());
+    EXPECT_EQ(Connection::STATE_READABLE, ch2.conn()->read_state());
+    EXPECT_EQ(Connection::STATE_WRITABLE, ch2.conn()->write_state());
+  } else {
+    EXPECT_NE(Connection::STATE_READABLE, ch1.conn()->read_state());
+    EXPECT_NE(Connection::STATE_WRITABLE, ch1.conn()->write_state());
+    EXPECT_NE(Connection::STATE_READABLE, ch2.conn()->read_state());
+    EXPECT_NE(Connection::STATE_WRITABLE, ch2.conn()->write_state());
+  }
+
+  // Tear down and ensure that goes smoothly.
+  ch1.Stop();
+  ch2.Stop();
+  EXPECT_TRUE_WAIT(ch1.conn() == NULL, kTimeout);
+  EXPECT_TRUE_WAIT(ch2.conn() == NULL, kTimeout);
+}
+
+void PortTest::ConnectAndDisconnectChannels(TestChannel* ch1,
+                                            TestChannel* ch2) {
+  // Acquire addresses.
+  ch1->Start();
+  ch2->Start();
+
+  // Send a ping from src to dst.
+  ch1->CreateConnection();
+  EXPECT_TRUE_WAIT(ch1->conn()->connected(), kTimeout);  // for TCP connect
+  ch1->Ping();
+  WAIT(!ch2->remote_address().IsNil(), kTimeout);
+
+  // Send a ping from dst to src.
+  ch2->AcceptConnection();
+  ch2->Ping();
+  EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch2->conn()->write_state(),
+                 kTimeout);
+
+  // Destroy the connections.
+  ch1->Stop();
+  ch2->Stop();
+}
+
+class FakePacketSocketFactory : public rtc::PacketSocketFactory {
+ public:
+  FakePacketSocketFactory()
+      : next_udp_socket_(NULL),
+        next_server_tcp_socket_(NULL),
+        next_client_tcp_socket_(NULL) {
+  }
+  virtual ~FakePacketSocketFactory() { }
+
+  virtual AsyncPacketSocket* CreateUdpSocket(
+      const SocketAddress& address, int min_port, int max_port) {
+    EXPECT_TRUE(next_udp_socket_ != NULL);
+    AsyncPacketSocket* result = next_udp_socket_;
+    next_udp_socket_ = NULL;
+    return result;
+  }
+
+  virtual AsyncPacketSocket* CreateServerTcpSocket(
+      const SocketAddress& local_address, int min_port, int max_port,
+      int opts) {
+    EXPECT_TRUE(next_server_tcp_socket_ != NULL);
+    AsyncPacketSocket* result = next_server_tcp_socket_;
+    next_server_tcp_socket_ = NULL;
+    return result;
+  }
+
+  // TODO: |proxy_info| and |user_agent| should be set
+  // per-factory and not when socket is created.
+  virtual AsyncPacketSocket* CreateClientTcpSocket(
+      const SocketAddress& local_address, const SocketAddress& remote_address,
+      const rtc::ProxyInfo& proxy_info,
+      const std::string& user_agent, int opts) {
+    EXPECT_TRUE(next_client_tcp_socket_ != NULL);
+    AsyncPacketSocket* result = next_client_tcp_socket_;
+    next_client_tcp_socket_ = NULL;
+    return result;
+  }
+
+  void set_next_udp_socket(AsyncPacketSocket* next_udp_socket) {
+    next_udp_socket_ = next_udp_socket;
+  }
+  void set_next_server_tcp_socket(AsyncPacketSocket* next_server_tcp_socket) {
+    next_server_tcp_socket_ = next_server_tcp_socket;
+  }
+  void set_next_client_tcp_socket(AsyncPacketSocket* next_client_tcp_socket) {
+    next_client_tcp_socket_ = next_client_tcp_socket;
+  }
+  rtc::AsyncResolverInterface* CreateAsyncResolver() {
+    return NULL;
+  }
+
+ private:
+  AsyncPacketSocket* next_udp_socket_;
+  AsyncPacketSocket* next_server_tcp_socket_;
+  AsyncPacketSocket* next_client_tcp_socket_;
+};
+
+class FakeAsyncPacketSocket : public AsyncPacketSocket {
+ public:
+  // Returns current local address. Address may be set to NULL if the
+  // socket is not bound yet (GetState() returns STATE_BINDING).
+  virtual SocketAddress GetLocalAddress() const {
+    return SocketAddress();
+  }
+
+  // Returns remote address. Returns zeroes if this is not a client TCP socket.
+  virtual SocketAddress GetRemoteAddress() const {
+    return SocketAddress();
+  }
+
+  // Send a packet.
+  virtual int Send(const void *pv, size_t cb,
+                   const rtc::PacketOptions& options) {
+    return static_cast<int>(cb);
+  }
+  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
+                     const rtc::PacketOptions& options) {
+    return static_cast<int>(cb);
+  }
+  virtual int Close() {
+    return 0;
+  }
+
+  virtual State GetState() const { return state_; }
+  virtual int GetOption(Socket::Option opt, int* value) { return 0; }
+  virtual int SetOption(Socket::Option opt, int value) { return 0; }
+  virtual int GetError() const { return 0; }
+  virtual void SetError(int error) { }
+
+  void set_state(State state) { state_ = state; }
+
+ private:
+  State state_;
+};
+
+// Local -> XXXX
+TEST_F(PortTest, TestLocalToLocal) {
+  TestLocalToLocal();
+}
+
+TEST_F(PortTest, TestLocalToConeNat) {
+  TestLocalToStun(NAT_OPEN_CONE);
+}
+
+TEST_F(PortTest, TestLocalToARNat) {
+  TestLocalToStun(NAT_ADDR_RESTRICTED);
+}
+
+TEST_F(PortTest, TestLocalToPRNat) {
+  TestLocalToStun(NAT_PORT_RESTRICTED);
+}
+
+TEST_F(PortTest, TestLocalToSymNat) {
+  TestLocalToStun(NAT_SYMMETRIC);
+}
+
+// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3316.
+TEST_F(PortTest, DISABLED_TestLocalToTurn) {
+  TestLocalToRelay(RELAY_TURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestLocalToGturn) {
+  TestLocalToRelay(RELAY_GTURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestLocalToTcpGturn) {
+  TestLocalToRelay(RELAY_GTURN, PROTO_TCP);
+}
+
+TEST_F(PortTest, TestLocalToSslTcpGturn) {
+  TestLocalToRelay(RELAY_GTURN, PROTO_SSLTCP);
+}
+
+// Cone NAT -> XXXX
+TEST_F(PortTest, TestConeNatToLocal) {
+  TestStunToLocal(NAT_OPEN_CONE);
+}
+
+TEST_F(PortTest, TestConeNatToConeNat) {
+  TestStunToStun(NAT_OPEN_CONE, NAT_OPEN_CONE);
+}
+
+TEST_F(PortTest, TestConeNatToARNat) {
+  TestStunToStun(NAT_OPEN_CONE, NAT_ADDR_RESTRICTED);
+}
+
+TEST_F(PortTest, TestConeNatToPRNat) {
+  TestStunToStun(NAT_OPEN_CONE, NAT_PORT_RESTRICTED);
+}
+
+TEST_F(PortTest, TestConeNatToSymNat) {
+  TestStunToStun(NAT_OPEN_CONE, NAT_SYMMETRIC);
+}
+
+TEST_F(PortTest, TestConeNatToTurn) {
+  TestStunToRelay(NAT_OPEN_CONE, RELAY_TURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestConeNatToGturn) {
+  TestStunToRelay(NAT_OPEN_CONE, RELAY_GTURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestConeNatToTcpGturn) {
+  TestStunToRelay(NAT_OPEN_CONE, RELAY_GTURN, PROTO_TCP);
+}
+
+// Address-restricted NAT -> XXXX
+TEST_F(PortTest, TestARNatToLocal) {
+  TestStunToLocal(NAT_ADDR_RESTRICTED);
+}
+
+TEST_F(PortTest, TestARNatToConeNat) {
+  TestStunToStun(NAT_ADDR_RESTRICTED, NAT_OPEN_CONE);
+}
+
+TEST_F(PortTest, TestARNatToARNat) {
+  TestStunToStun(NAT_ADDR_RESTRICTED, NAT_ADDR_RESTRICTED);
+}
+
+TEST_F(PortTest, TestARNatToPRNat) {
+  TestStunToStun(NAT_ADDR_RESTRICTED, NAT_PORT_RESTRICTED);
+}
+
+TEST_F(PortTest, TestARNatToSymNat) {
+  TestStunToStun(NAT_ADDR_RESTRICTED, NAT_SYMMETRIC);
+}
+
+TEST_F(PortTest, TestARNatToTurn) {
+  TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_TURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestARNatToGturn) {
+  TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_GTURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestARNATNatToTcpGturn) {
+  TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_GTURN, PROTO_TCP);
+}
+
+// Port-restricted NAT -> XXXX
+TEST_F(PortTest, TestPRNatToLocal) {
+  TestStunToLocal(NAT_PORT_RESTRICTED);
+}
+
+TEST_F(PortTest, TestPRNatToConeNat) {
+  TestStunToStun(NAT_PORT_RESTRICTED, NAT_OPEN_CONE);
+}
+
+TEST_F(PortTest, TestPRNatToARNat) {
+  TestStunToStun(NAT_PORT_RESTRICTED, NAT_ADDR_RESTRICTED);
+}
+
+TEST_F(PortTest, TestPRNatToPRNat) {
+  TestStunToStun(NAT_PORT_RESTRICTED, NAT_PORT_RESTRICTED);
+}
+
+TEST_F(PortTest, TestPRNatToSymNat) {
+  // Will "fail"
+  TestStunToStun(NAT_PORT_RESTRICTED, NAT_SYMMETRIC);
+}
+
+TEST_F(PortTest, TestPRNatToTurn) {
+  TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_TURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestPRNatToGturn) {
+  TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_GTURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestPRNatToTcpGturn) {
+  TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_GTURN, PROTO_TCP);
+}
+
+// Symmetric NAT -> XXXX
+TEST_F(PortTest, TestSymNatToLocal) {
+  TestStunToLocal(NAT_SYMMETRIC);
+}
+
+TEST_F(PortTest, TestSymNatToConeNat) {
+  TestStunToStun(NAT_SYMMETRIC, NAT_OPEN_CONE);
+}
+
+TEST_F(PortTest, TestSymNatToARNat) {
+  TestStunToStun(NAT_SYMMETRIC, NAT_ADDR_RESTRICTED);
+}
+
+TEST_F(PortTest, TestSymNatToPRNat) {
+  // Will "fail"
+  TestStunToStun(NAT_SYMMETRIC, NAT_PORT_RESTRICTED);
+}
+
+TEST_F(PortTest, TestSymNatToSymNat) {
+  // Will "fail"
+  TestStunToStun(NAT_SYMMETRIC, NAT_SYMMETRIC);
+}
+
+TEST_F(PortTest, TestSymNatToTurn) {
+  TestStunToRelay(NAT_SYMMETRIC, RELAY_TURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestSymNatToGturn) {
+  TestStunToRelay(NAT_SYMMETRIC, RELAY_GTURN, PROTO_UDP);
+}
+
+TEST_F(PortTest, TestSymNatToTcpGturn) {
+  TestStunToRelay(NAT_SYMMETRIC, RELAY_GTURN, PROTO_TCP);
+}
+
+// Outbound TCP -> XXXX
+TEST_F(PortTest, TestTcpToTcp) {
+  TestTcpToTcp();
+}
+
+/* TODO: Enable these once testrelayserver can accept external TCP.
+TEST_F(PortTest, TestTcpToTcpRelay) {
+  TestTcpToRelay(PROTO_TCP);
+}
+
+TEST_F(PortTest, TestTcpToSslTcpRelay) {
+  TestTcpToRelay(PROTO_SSLTCP);
+}
+*/
+
+// Outbound SSLTCP -> XXXX
+/* TODO: Enable these once testrelayserver can accept external SSL.
+TEST_F(PortTest, TestSslTcpToTcpRelay) {
+  TestSslTcpToRelay(PROTO_TCP);
+}
+
+TEST_F(PortTest, TestSslTcpToSslTcpRelay) {
+  TestSslTcpToRelay(PROTO_SSLTCP);
+}
+*/
+
+// This test case verifies standard ICE features in STUN messages. Currently it
+// verifies Message Integrity attribute in STUN messages and username in STUN
+// binding request will have colon (":") between remote and local username.
+TEST_F(PortTest, TestLocalToLocalAsIce) {
+  SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+  UDPPort* port1 = CreateUdpPort(kLocalAddr1);
+  port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  port1->SetIceTiebreaker(kTiebreaker1);
+  ASSERT_EQ(cricket::ICEPROTO_RFC5245, port1->IceProtocol());
+  UDPPort* port2 = CreateUdpPort(kLocalAddr2);
+  port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  port2->SetIceTiebreaker(kTiebreaker2);
+  ASSERT_EQ(cricket::ICEPROTO_RFC5245, port2->IceProtocol());
+  // Same parameters as TestLocalToLocal above.
+  TestConnectivity("udp", port1, "udp", port2, true, true, true, true);
+}
+
+// This test is trying to validate a successful and failure scenario in a
+// loopback test when protocol is RFC5245. For success IceTiebreaker, username
+// should remain equal to the request generated by the port and role of port
+// must be in controlling.
+TEST_F(PortTest, TestLoopbackCallAsIce) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
+  lport->SetIceProtocolType(ICEPROTO_RFC5245);
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  lport->SetIceTiebreaker(kTiebreaker1);
+  lport->PrepareAddress();
+  ASSERT_FALSE(lport->Candidates().empty());
+  Connection* conn = lport->CreateConnection(lport->Candidates()[0],
+                                             Port::ORIGIN_MESSAGE);
+  conn->Ping(0);
+
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = lport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg->type());
+  conn->OnReadPacket(lport->last_stun_buf()->Data(),
+                     lport->last_stun_buf()->Length(),
+                     rtc::PacketTime());
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  msg = lport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type());
+
+  // If the tiebreaker value is different from port, we expect a error
+  // response.
+  lport->Reset();
+  lport->AddCandidateAddress(kLocalAddr2);
+  // Creating a different connection as |conn| is in STATE_READABLE.
+  Connection* conn1 = lport->CreateConnection(lport->Candidates()[1],
+                                              Port::ORIGIN_MESSAGE);
+  conn1->Ping(0);
+
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  msg = lport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg->type());
+  rtc::scoped_ptr<IceMessage> modified_req(
+      CreateStunMessage(STUN_BINDING_REQUEST));
+  const StunByteStringAttribute* username_attr = msg->GetByteString(
+      STUN_ATTR_USERNAME);
+  modified_req->AddAttribute(new StunByteStringAttribute(
+      STUN_ATTR_USERNAME, username_attr->GetString()));
+  // To make sure we receive error response, adding tiebreaker less than
+  // what's present in request.
+  modified_req->AddAttribute(new StunUInt64Attribute(
+      STUN_ATTR_ICE_CONTROLLING, kTiebreaker1 - 1));
+  modified_req->AddMessageIntegrity("lpass");
+  modified_req->AddFingerprint();
+
+  lport->Reset();
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  WriteStunMessage(modified_req.get(), buf.get());
+  conn1->OnReadPacket(buf->Data(), buf->Length(), rtc::PacketTime());
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  msg = lport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, msg->type());
+}
+
+// This test verifies role conflict signal is received when there is
+// conflict in the role. In this case both ports are in controlling and
+// |rport| has higher tiebreaker value than |lport|. Since |lport| has lower
+// value of tiebreaker, when it receives ping request from |rport| it will
+// send role conflict signal.
+TEST_F(PortTest, TestIceRoleConflict) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
+  lport->SetIceProtocolType(ICEPROTO_RFC5245);
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  lport->SetIceTiebreaker(kTiebreaker1);
+  rtc::scoped_ptr<TestPort> rport(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  rport->SetIceProtocolType(ICEPROTO_RFC5245);
+  rport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  rport->SetIceTiebreaker(kTiebreaker2);
+
+  lport->PrepareAddress();
+  rport->PrepareAddress();
+  ASSERT_FALSE(lport->Candidates().empty());
+  ASSERT_FALSE(rport->Candidates().empty());
+  Connection* lconn = lport->CreateConnection(rport->Candidates()[0],
+                                              Port::ORIGIN_MESSAGE);
+  Connection* rconn = rport->CreateConnection(lport->Candidates()[0],
+                                              Port::ORIGIN_MESSAGE);
+  rconn->Ping(0);
+
+  ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = rport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg->type());
+  // Send rport binding request to lport.
+  lconn->OnReadPacket(rport->last_stun_buf()->Data(),
+                      rport->last_stun_buf()->Length(),
+                      rtc::PacketTime());
+
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  EXPECT_EQ(STUN_BINDING_RESPONSE, lport->last_stun_msg()->type());
+  EXPECT_TRUE(role_conflict());
+}
+
+TEST_F(PortTest, TestTcpNoDelay) {
+  TCPPort* port1 = CreateTcpPort(kLocalAddr1);
+  int option_value = -1;
+  int success = port1->GetOption(rtc::Socket::OPT_NODELAY,
+                                 &option_value);
+  ASSERT_EQ(0, success);  // GetOption() should complete successfully w/ 0
+  ASSERT_EQ(1, option_value);
+  delete port1;
+}
+
+TEST_F(PortTest, TestDelayedBindingUdp) {
+  FakeAsyncPacketSocket *socket = new FakeAsyncPacketSocket();
+  FakePacketSocketFactory socket_factory;
+
+  socket_factory.set_next_udp_socket(socket);
+  scoped_ptr<UDPPort> port(
+      CreateUdpPort(kLocalAddr1, &socket_factory));
+
+  socket->set_state(AsyncPacketSocket::STATE_BINDING);
+  port->PrepareAddress();
+
+  EXPECT_EQ(0U, port->Candidates().size());
+  socket->SignalAddressReady(socket, kLocalAddr2);
+
+  EXPECT_EQ(1U, port->Candidates().size());
+}
+
+TEST_F(PortTest, TestDelayedBindingTcp) {
+  FakeAsyncPacketSocket *socket = new FakeAsyncPacketSocket();
+  FakePacketSocketFactory socket_factory;
+
+  socket_factory.set_next_server_tcp_socket(socket);
+  scoped_ptr<TCPPort> port(
+      CreateTcpPort(kLocalAddr1, &socket_factory));
+
+  socket->set_state(AsyncPacketSocket::STATE_BINDING);
+  port->PrepareAddress();
+
+  EXPECT_EQ(0U, port->Candidates().size());
+  socket->SignalAddressReady(socket, kLocalAddr2);
+
+  EXPECT_EQ(1U, port->Candidates().size());
+}
+
+void PortTest::TestCrossFamilyPorts(int type) {
+  FakePacketSocketFactory factory;
+  scoped_ptr<Port> ports[4];
+  SocketAddress addresses[4] = {SocketAddress("192.168.1.3", 0),
+                                SocketAddress("192.168.1.4", 0),
+                                SocketAddress("2001:db8::1", 0),
+                                SocketAddress("2001:db8::2", 0)};
+  for (int i = 0; i < 4; i++) {
+    FakeAsyncPacketSocket *socket = new FakeAsyncPacketSocket();
+    if (type == SOCK_DGRAM) {
+      factory.set_next_udp_socket(socket);
+      ports[i].reset(CreateUdpPort(addresses[i], &factory));
+    } else if (type == SOCK_STREAM) {
+      factory.set_next_server_tcp_socket(socket);
+      ports[i].reset(CreateTcpPort(addresses[i], &factory));
+    }
+    socket->set_state(AsyncPacketSocket::STATE_BINDING);
+    socket->SignalAddressReady(socket, addresses[i]);
+    ports[i]->PrepareAddress();
+  }
+
+  // IPv4 Port, connects to IPv6 candidate and then to IPv4 candidate.
+  if (type == SOCK_STREAM) {
+    FakeAsyncPacketSocket* clientsocket = new FakeAsyncPacketSocket();
+    factory.set_next_client_tcp_socket(clientsocket);
+  }
+  Connection* c = ports[0]->CreateConnection(GetCandidate(ports[2].get()),
+                                             Port::ORIGIN_MESSAGE);
+  EXPECT_TRUE(NULL == c);
+  EXPECT_EQ(0U, ports[0]->connections().size());
+  c = ports[0]->CreateConnection(GetCandidate(ports[1].get()),
+                                 Port::ORIGIN_MESSAGE);
+  EXPECT_FALSE(NULL == c);
+  EXPECT_EQ(1U, ports[0]->connections().size());
+
+  // IPv6 Port, connects to IPv4 candidate and to IPv6 candidate.
+  if (type == SOCK_STREAM) {
+    FakeAsyncPacketSocket* clientsocket = new FakeAsyncPacketSocket();
+    factory.set_next_client_tcp_socket(clientsocket);
+  }
+  c = ports[2]->CreateConnection(GetCandidate(ports[0].get()),
+                                 Port::ORIGIN_MESSAGE);
+  EXPECT_TRUE(NULL == c);
+  EXPECT_EQ(0U, ports[2]->connections().size());
+  c = ports[2]->CreateConnection(GetCandidate(ports[3].get()),
+                                 Port::ORIGIN_MESSAGE);
+  EXPECT_FALSE(NULL == c);
+  EXPECT_EQ(1U, ports[2]->connections().size());
+}
+
+TEST_F(PortTest, TestSkipCrossFamilyTcp) {
+  TestCrossFamilyPorts(SOCK_STREAM);
+}
+
+TEST_F(PortTest, TestSkipCrossFamilyUdp) {
+  TestCrossFamilyPorts(SOCK_DGRAM);
+}
+
+// This test verifies DSCP value set through SetOption interface can be
+// get through DefaultDscpValue.
+TEST_F(PortTest, TestDefaultDscpValue) {
+  int dscp;
+  rtc::scoped_ptr<UDPPort> udpport(CreateUdpPort(kLocalAddr1));
+  EXPECT_EQ(0, udpport->SetOption(rtc::Socket::OPT_DSCP,
+                                  rtc::DSCP_CS6));
+  EXPECT_EQ(0, udpport->GetOption(rtc::Socket::OPT_DSCP, &dscp));
+  rtc::scoped_ptr<TCPPort> tcpport(CreateTcpPort(kLocalAddr1));
+  EXPECT_EQ(0, tcpport->SetOption(rtc::Socket::OPT_DSCP,
+                                 rtc::DSCP_AF31));
+  EXPECT_EQ(0, tcpport->GetOption(rtc::Socket::OPT_DSCP, &dscp));
+  EXPECT_EQ(rtc::DSCP_AF31, dscp);
+  rtc::scoped_ptr<StunPort> stunport(
+      CreateStunPort(kLocalAddr1, nat_socket_factory1()));
+  EXPECT_EQ(0, stunport->SetOption(rtc::Socket::OPT_DSCP,
+                                  rtc::DSCP_AF41));
+  EXPECT_EQ(0, stunport->GetOption(rtc::Socket::OPT_DSCP, &dscp));
+  EXPECT_EQ(rtc::DSCP_AF41, dscp);
+  rtc::scoped_ptr<TurnPort> turnport1(CreateTurnPort(
+      kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+  // Socket is created in PrepareAddress.
+  turnport1->PrepareAddress();
+  EXPECT_EQ(0, turnport1->SetOption(rtc::Socket::OPT_DSCP,
+                                  rtc::DSCP_CS7));
+  EXPECT_EQ(0, turnport1->GetOption(rtc::Socket::OPT_DSCP, &dscp));
+  EXPECT_EQ(rtc::DSCP_CS7, dscp);
+  // This will verify correct value returned without the socket.
+  rtc::scoped_ptr<TurnPort> turnport2(CreateTurnPort(
+      kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+  EXPECT_EQ(0, turnport2->SetOption(rtc::Socket::OPT_DSCP,
+                                  rtc::DSCP_CS6));
+  EXPECT_EQ(0, turnport2->GetOption(rtc::Socket::OPT_DSCP, &dscp));
+  EXPECT_EQ(rtc::DSCP_CS6, dscp);
+}
+
+// Test sending STUN messages in GICE format.
+TEST_F(PortTest, TestSendStunMessageAsGice) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
+  rtc::scoped_ptr<TestPort> rport(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  lport->SetIceProtocolType(ICEPROTO_GOOGLE);
+  rport->SetIceProtocolType(ICEPROTO_GOOGLE);
+
+  // Send a fake ping from lport to rport.
+  lport->PrepareAddress();
+  rport->PrepareAddress();
+  ASSERT_FALSE(rport->Candidates().empty());
+  Connection* conn = lport->CreateConnection(rport->Candidates()[0],
+      Port::ORIGIN_MESSAGE);
+  rport->CreateConnection(lport->Candidates()[0], Port::ORIGIN_MESSAGE);
+  conn->Ping(0);
+
+  // Check that it's a proper BINDING-REQUEST.
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = lport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg->type());
+  EXPECT_FALSE(msg->IsLegacy());
+  const StunByteStringAttribute* username_attr = msg->GetByteString(
+      STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username_attr != NULL);
+  EXPECT_EQ("rfraglfrag", username_attr->GetString());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_FINGERPRINT) == NULL);
+
+  // Save a copy of the BINDING-REQUEST for use below.
+  rtc::scoped_ptr<IceMessage> request(CopyStunMessage(msg));
+
+  // Respond with a BINDING-RESPONSE.
+  rport->SendBindingResponse(request.get(), lport->Candidates()[0].address());
+  msg = rport->last_stun_msg();
+  ASSERT_TRUE(msg != NULL);
+  EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type());
+  EXPECT_FALSE(msg->IsLegacy());
+  username_attr = msg->GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username_attr != NULL);  // GICE has a username in the response.
+  EXPECT_EQ("rfraglfrag", username_attr->GetString());
+  const StunAddressAttribute* addr_attr = msg->GetAddress(
+      STUN_ATTR_MAPPED_ADDRESS);
+  ASSERT_TRUE(addr_attr != NULL);
+  EXPECT_EQ(lport->Candidates()[0].address(), addr_attr->GetAddress());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_XOR_MAPPED_ADDRESS) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_FINGERPRINT) == NULL);
+
+  // Respond with a BINDING-ERROR-RESPONSE. This wouldn't happen in real life,
+  // but we can do it here.
+  rport->SendBindingErrorResponse(request.get(),
+                                  rport->Candidates()[0].address(),
+                                  STUN_ERROR_SERVER_ERROR,
+                                  STUN_ERROR_REASON_SERVER_ERROR);
+  msg = rport->last_stun_msg();
+  ASSERT_TRUE(msg != NULL);
+  EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, msg->type());
+  EXPECT_FALSE(msg->IsLegacy());
+  username_attr = msg->GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username_attr != NULL);  // GICE has a username in the response.
+  EXPECT_EQ("rfraglfrag", username_attr->GetString());
+  const StunErrorCodeAttribute* error_attr = msg->GetErrorCode();
+  ASSERT_TRUE(error_attr != NULL);
+  // The GICE wire format for error codes is incorrect.
+  EXPECT_EQ(STUN_ERROR_SERVER_ERROR_AS_GICE, error_attr->code());
+  EXPECT_EQ(STUN_ERROR_SERVER_ERROR / 256, error_attr->eclass());
+  EXPECT_EQ(STUN_ERROR_SERVER_ERROR % 256, error_attr->number());
+  EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR), error_attr->reason());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_FINGERPRINT) == NULL);
+}
+
+// Test sending STUN messages in ICE format.
+TEST_F(PortTest, TestSendStunMessageAsIce) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
+  rtc::scoped_ptr<TestPort> rport(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  lport->SetIceProtocolType(ICEPROTO_RFC5245);
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  lport->SetIceTiebreaker(kTiebreaker1);
+  rport->SetIceProtocolType(ICEPROTO_RFC5245);
+  rport->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  rport->SetIceTiebreaker(kTiebreaker2);
+
+  // Send a fake ping from lport to rport.
+  lport->PrepareAddress();
+  rport->PrepareAddress();
+  ASSERT_FALSE(rport->Candidates().empty());
+  Connection* lconn = lport->CreateConnection(
+      rport->Candidates()[0], Port::ORIGIN_MESSAGE);
+  Connection* rconn = rport->CreateConnection(
+      lport->Candidates()[0], Port::ORIGIN_MESSAGE);
+  lconn->Ping(0);
+
+  // Check that it's a proper BINDING-REQUEST.
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = lport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg->type());
+  EXPECT_FALSE(msg->IsLegacy());
+  const StunByteStringAttribute* username_attr =
+      msg->GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username_attr != NULL);
+  const StunUInt32Attribute* priority_attr = msg->GetUInt32(STUN_ATTR_PRIORITY);
+  ASSERT_TRUE(priority_attr != NULL);
+  EXPECT_EQ(kDefaultPrflxPriority, priority_attr->value());
+  EXPECT_EQ("rfrag:lfrag", username_attr->GetString());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+      lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length(),
+      "rpass"));
+  const StunUInt64Attribute* ice_controlling_attr =
+      msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
+  ASSERT_TRUE(ice_controlling_attr != NULL);
+  EXPECT_EQ(lport->IceTiebreaker(), ice_controlling_attr->value());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_ICE_CONTROLLED) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) != NULL);
+  EXPECT_TRUE(msg->GetUInt32(STUN_ATTR_FINGERPRINT) != NULL);
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(
+      lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length()));
+
+  // Request should not include ping count.
+  ASSERT_TRUE(msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT) == NULL);
+
+  // Save a copy of the BINDING-REQUEST for use below.
+  rtc::scoped_ptr<IceMessage> request(CopyStunMessage(msg));
+
+  // Respond with a BINDING-RESPONSE.
+  rport->SendBindingResponse(request.get(), lport->Candidates()[0].address());
+  msg = rport->last_stun_msg();
+  ASSERT_TRUE(msg != NULL);
+  EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type());
+
+
+  EXPECT_FALSE(msg->IsLegacy());
+  const StunAddressAttribute* addr_attr = msg->GetAddress(
+      STUN_ATTR_XOR_MAPPED_ADDRESS);
+  ASSERT_TRUE(addr_attr != NULL);
+  EXPECT_EQ(lport->Candidates()[0].address(), addr_attr->GetAddress());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+      rport->last_stun_buf()->Data(), rport->last_stun_buf()->Length(),
+      "rpass"));
+  EXPECT_TRUE(msg->GetUInt32(STUN_ATTR_FINGERPRINT) != NULL);
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(
+      lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length()));
+  // No USERNAME or PRIORITY in ICE responses.
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USERNAME) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MAPPED_ADDRESS) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_ICE_CONTROLLING) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_ICE_CONTROLLED) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) == NULL);
+
+  // Response should not include ping count.
+  ASSERT_TRUE(msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT) == NULL);
+
+  // Respond with a BINDING-ERROR-RESPONSE. This wouldn't happen in real life,
+  // but we can do it here.
+  rport->SendBindingErrorResponse(request.get(),
+                                  lport->Candidates()[0].address(),
+                                  STUN_ERROR_SERVER_ERROR,
+                                  STUN_ERROR_REASON_SERVER_ERROR);
+  msg = rport->last_stun_msg();
+  ASSERT_TRUE(msg != NULL);
+  EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, msg->type());
+  EXPECT_FALSE(msg->IsLegacy());
+  const StunErrorCodeAttribute* error_attr = msg->GetErrorCode();
+  ASSERT_TRUE(error_attr != NULL);
+  EXPECT_EQ(STUN_ERROR_SERVER_ERROR, error_attr->code());
+  EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR), error_attr->reason());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+      rport->last_stun_buf()->Data(), rport->last_stun_buf()->Length(),
+      "rpass"));
+  EXPECT_TRUE(msg->GetUInt32(STUN_ATTR_FINGERPRINT) != NULL);
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(
+      lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length()));
+  // No USERNAME with ICE.
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USERNAME) == NULL);
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL);
+
+  // Testing STUN binding requests from rport --> lport, having ICE_CONTROLLED
+  // and (incremented) RETRANSMIT_COUNT attributes.
+  rport->Reset();
+  rport->set_send_retransmit_count_attribute(true);
+  rconn->Ping(0);
+  rconn->Ping(0);
+  rconn->Ping(0);
+  ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000);
+  msg = rport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg->type());
+  const StunUInt64Attribute* ice_controlled_attr =
+      msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
+  ASSERT_TRUE(ice_controlled_attr != NULL);
+  EXPECT_EQ(rport->IceTiebreaker(), ice_controlled_attr->value());
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) == NULL);
+
+  // Request should include ping count.
+  const StunUInt32Attribute* retransmit_attr =
+      msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
+  ASSERT_TRUE(retransmit_attr != NULL);
+  EXPECT_EQ(2U, retransmit_attr->value());
+
+  // Respond with a BINDING-RESPONSE.
+  request.reset(CopyStunMessage(msg));
+  lport->SendBindingResponse(request.get(), rport->Candidates()[0].address());
+  msg = lport->last_stun_msg();
+
+  // Response should include same ping count.
+  retransmit_attr = msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
+  ASSERT_TRUE(retransmit_attr != NULL);
+  EXPECT_EQ(2U, retransmit_attr->value());
+}
+
+TEST_F(PortTest, TestUseCandidateAttribute) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
+  rtc::scoped_ptr<TestPort> rport(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  lport->SetIceProtocolType(ICEPROTO_RFC5245);
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  lport->SetIceTiebreaker(kTiebreaker1);
+  rport->SetIceProtocolType(ICEPROTO_RFC5245);
+  rport->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  rport->SetIceTiebreaker(kTiebreaker2);
+
+  // Send a fake ping from lport to rport.
+  lport->PrepareAddress();
+  rport->PrepareAddress();
+  ASSERT_FALSE(rport->Candidates().empty());
+  Connection* lconn = lport->CreateConnection(
+      rport->Candidates()[0], Port::ORIGIN_MESSAGE);
+  lconn->Ping(0);
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = lport->last_stun_msg();
+  const StunUInt64Attribute* ice_controlling_attr =
+      msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
+  ASSERT_TRUE(ice_controlling_attr != NULL);
+  const StunByteStringAttribute* use_candidate_attr = msg->GetByteString(
+      STUN_ATTR_USE_CANDIDATE);
+  ASSERT_TRUE(use_candidate_attr != NULL);
+}
+
+// Test handling STUN messages in GICE format.
+TEST_F(PortTest, TestHandleStunMessageAsGice) {
+  // Our port will act as the "remote" port.
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_GOOGLE);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST from local to remote with valid GICE username and no M-I.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfraglfrag"));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);  // Succeeds, since this is GICE.
+  EXPECT_EQ("lfrag", username);
+
+  // Add M-I; should be ignored and rest of message parsed normally.
+  in_msg->AddMessageIntegrity("password");
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("lfrag", username);
+
+  // BINDING-RESPONSE with username, as done in GICE. Should succeed.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_RESPONSE,
+                                             "rfraglfrag"));
+  in_msg->AddAttribute(
+      new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, kLocalAddr2));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("", username);
+
+  // BINDING-RESPONSE without username. Should be tolerated as well.
+  in_msg.reset(CreateStunMessage(STUN_BINDING_RESPONSE));
+  in_msg->AddAttribute(
+      new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, kLocalAddr2));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("", username);
+
+  // BINDING-ERROR-RESPONSE with username and error code.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_ERROR_RESPONSE,
+                                             "rfraglfrag"));
+  in_msg->AddAttribute(new StunErrorCodeAttribute(STUN_ATTR_ERROR_CODE,
+      STUN_ERROR_SERVER_ERROR_AS_GICE, STUN_ERROR_REASON_SERVER_ERROR));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  ASSERT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("", username);
+  ASSERT_TRUE(out_msg->GetErrorCode() != NULL);
+  // GetStunMessage doesn't unmunge the GICE error code (happens downstream).
+  EXPECT_EQ(STUN_ERROR_SERVER_ERROR_AS_GICE, out_msg->GetErrorCode()->code());
+  EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR),
+      out_msg->GetErrorCode()->reason());
+}
+
+// Test handling STUN messages in ICE format.
+TEST_F(PortTest, TestHandleStunMessageAsIce) {
+  // Our port will act as the "remote" port.
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_RFC5245);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST from local to remote with valid ICE username,
+  // MESSAGE-INTEGRITY, and FINGERPRINT.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfrag:lfrag"));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("lfrag", username);
+
+  // BINDING-RESPONSE without username, with MESSAGE-INTEGRITY and FINGERPRINT.
+  in_msg.reset(CreateStunMessage(STUN_BINDING_RESPONSE));
+  in_msg->AddAttribute(
+      new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, kLocalAddr2));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("", username);
+
+  // BINDING-ERROR-RESPONSE without username, with error, M-I, and FINGERPRINT.
+  in_msg.reset(CreateStunMessage(STUN_BINDING_ERROR_RESPONSE));
+  in_msg->AddAttribute(new StunErrorCodeAttribute(STUN_ATTR_ERROR_CODE,
+      STUN_ERROR_SERVER_ERROR, STUN_ERROR_REASON_SERVER_ERROR));
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("", username);
+  ASSERT_TRUE(out_msg->GetErrorCode() != NULL);
+  EXPECT_EQ(STUN_ERROR_SERVER_ERROR, out_msg->GetErrorCode()->code());
+  EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR),
+      out_msg->GetErrorCode()->reason());
+}
+
+// This test verifies port can handle ICE messages in Hybrid mode and switches
+// ICEPROTO_RFC5245 mode after successfully handling the message.
+TEST_F(PortTest, TestHandleStunMessageAsIceInHybridMode) {
+  // Our port will act as the "remote" port.
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_HYBRID);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST from local to remote with valid ICE username,
+  // MESSAGE-INTEGRITY, and FINGERPRINT.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfrag:lfrag"));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ("lfrag", username);
+  EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol());
+}
+
+// This test verifies port can handle GICE messages in Hybrid mode and switches
+// ICEPROTO_GOOGLE mode after successfully handling the message.
+TEST_F(PortTest, TestHandleStunMessageAsGiceInHybridMode) {
+  // Our port will act as the "remote" port.
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_HYBRID);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST from local to remote with valid GICE username and no M-I.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfraglfrag"));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);  // Succeeds, since this is GICE.
+  EXPECT_EQ("lfrag", username);
+  EXPECT_EQ(ICEPROTO_GOOGLE, port->IceProtocol());
+}
+
+// Verify port is not switched out of RFC5245 mode if GICE message is received
+// in that mode.
+TEST_F(PortTest, TestHandleStunMessageAsGiceInIceMode) {
+  // Our port will act as the "remote" port.
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_RFC5245);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST from local to remote with valid GICE username and no M-I.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfraglfrag"));
+  WriteStunMessage(in_msg.get(), buf.get());
+  // Should fail as there is no MI and fingerprint.
+  EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol());
+}
+
+
+// Tests handling of GICE binding requests with missing or incorrect usernames.
+TEST_F(PortTest, TestHandleStunMessageAsGiceBadUsername) {
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_GOOGLE);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST with no username.
+  in_msg.reset(CreateStunMessage(STUN_BINDING_REQUEST));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_BAD_REQUEST_AS_GICE, port->last_stun_error_code());
+
+  // BINDING-REQUEST with empty username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, ""));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code());
+
+  // BINDING-REQUEST with too-short username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, "lfra"));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code());
+
+  // BINDING-REQUEST with reversed username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "lfragrfrag"));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code());
+
+  // BINDING-REQUEST with garbage username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "abcdefgh"));
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code());
+}
+
+// Tests handling of ICE binding requests with missing or incorrect usernames.
+TEST_F(PortTest, TestHandleStunMessageAsIceBadUsername) {
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_RFC5245);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST with no username.
+  in_msg.reset(CreateStunMessage(STUN_BINDING_REQUEST));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_BAD_REQUEST, port->last_stun_error_code());
+
+  // BINDING-REQUEST with empty username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, ""));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code());
+
+  // BINDING-REQUEST with too-short username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, "rfra"));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code());
+
+  // BINDING-REQUEST with reversed username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                            "lfrag:rfrag"));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code());
+
+  // BINDING-REQUEST with garbage username.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "abcd:efgh"));
+  in_msg->AddMessageIntegrity("rpass");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code());
+}
+
+// Test handling STUN messages (as ICE) with missing or malformed M-I.
+TEST_F(PortTest, TestHandleStunMessageAsIceBadMessageIntegrity) {
+  // Our port will act as the "remote" port.
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_RFC5245);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST from local to remote with valid ICE username and
+  // FINGERPRINT, but no MESSAGE-INTEGRITY.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfrag:lfrag"));
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_BAD_REQUEST, port->last_stun_error_code());
+
+  // BINDING-REQUEST from local to remote with valid ICE username and
+  // FINGERPRINT, but invalid MESSAGE-INTEGRITY.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfrag:lfrag"));
+  in_msg->AddMessageIntegrity("invalid");
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                   out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() == NULL);
+  EXPECT_EQ("", username);
+  EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code());
+
+  // TODO: BINDING-RESPONSES and BINDING-ERROR-RESPONSES are checked
+  // by the Connection, not the Port, since they require the remote username.
+  // Change this test to pass in data via Connection::OnReadPacket instead.
+}
+
+// Test handling STUN messages (as ICE) with missing or malformed FINGERPRINT.
+TEST_F(PortTest, TestHandleStunMessageAsIceBadFingerprint) {
+  // Our port will act as the "remote" port.
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  port->SetIceProtocolType(ICEPROTO_RFC5245);
+
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  // BINDING-REQUEST from local to remote with valid ICE username and
+  // MESSAGE-INTEGRITY, but no FINGERPRINT; GetStunMessage should fail.
+  in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+                                             "rfrag:lfrag"));
+  in_msg->AddMessageIntegrity("rpass");
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_EQ(0, port->last_stun_error_code());
+
+  // Now, add a fingerprint, but munge the message so it's not valid.
+  in_msg->AddFingerprint();
+  in_msg->SetTransactionID("TESTTESTBADD");
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_EQ(0, port->last_stun_error_code());
+
+  // Valid BINDING-RESPONSE, except no FINGERPRINT.
+  in_msg.reset(CreateStunMessage(STUN_BINDING_RESPONSE));
+  in_msg->AddAttribute(
+      new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, kLocalAddr2));
+  in_msg->AddMessageIntegrity("rpass");
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_EQ(0, port->last_stun_error_code());
+
+  // Now, add a fingerprint, but munge the message so it's not valid.
+  in_msg->AddFingerprint();
+  in_msg->SetTransactionID("TESTTESTBADD");
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_EQ(0, port->last_stun_error_code());
+
+  // Valid BINDING-ERROR-RESPONSE, except no FINGERPRINT.
+  in_msg.reset(CreateStunMessage(STUN_BINDING_ERROR_RESPONSE));
+  in_msg->AddAttribute(new StunErrorCodeAttribute(STUN_ATTR_ERROR_CODE,
+      STUN_ERROR_SERVER_ERROR, STUN_ERROR_REASON_SERVER_ERROR));
+  in_msg->AddMessageIntegrity("rpass");
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_EQ(0, port->last_stun_error_code());
+
+  // Now, add a fingerprint, but munge the message so it's not valid.
+  in_msg->AddFingerprint();
+  in_msg->SetTransactionID("TESTTESTBADD");
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_EQ(0, port->last_stun_error_code());
+}
+
+// Test handling of STUN binding indication messages (as ICE). STUN binding
+// indications are allowed only to the connection which is in read mode.
+TEST_F(PortTest, TestHandleStunBindingIndication) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr2, "lfrag", "lpass"));
+  lport->SetIceProtocolType(ICEPROTO_RFC5245);
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  lport->SetIceTiebreaker(kTiebreaker1);
+
+  // Verifying encoding and decoding STUN indication message.
+  rtc::scoped_ptr<IceMessage> in_msg, out_msg;
+  rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+  rtc::SocketAddress addr(kLocalAddr1);
+  std::string username;
+
+  in_msg.reset(CreateStunMessage(STUN_BINDING_INDICATION));
+  in_msg->AddFingerprint();
+  WriteStunMessage(in_msg.get(), buf.get());
+  EXPECT_TRUE(lport->GetStunMessage(buf->Data(), buf->Length(), addr,
+                                    out_msg.accept(), &username));
+  EXPECT_TRUE(out_msg.get() != NULL);
+  EXPECT_EQ(out_msg->type(), STUN_BINDING_INDICATION);
+  EXPECT_EQ("", username);
+
+  // Verify connection can handle STUN indication and updates
+  // last_ping_received.
+  rtc::scoped_ptr<TestPort> rport(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  rport->SetIceProtocolType(ICEPROTO_RFC5245);
+  rport->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  rport->SetIceTiebreaker(kTiebreaker2);
+
+  lport->PrepareAddress();
+  rport->PrepareAddress();
+  ASSERT_FALSE(lport->Candidates().empty());
+  ASSERT_FALSE(rport->Candidates().empty());
+
+  Connection* lconn = lport->CreateConnection(rport->Candidates()[0],
+                                              Port::ORIGIN_MESSAGE);
+  Connection* rconn = rport->CreateConnection(lport->Candidates()[0],
+                                              Port::ORIGIN_MESSAGE);
+  rconn->Ping(0);
+
+  ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = rport->last_stun_msg();
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg->type());
+  // Send rport binding request to lport.
+  lconn->OnReadPacket(rport->last_stun_buf()->Data(),
+                      rport->last_stun_buf()->Length(),
+                      rtc::PacketTime());
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  EXPECT_EQ(STUN_BINDING_RESPONSE, lport->last_stun_msg()->type());
+  uint32 last_ping_received1 = lconn->last_ping_received();
+
+  // Adding a delay of 100ms.
+  rtc::Thread::Current()->ProcessMessages(100);
+  // Pinging lconn using stun indication message.
+  lconn->OnReadPacket(buf->Data(), buf->Length(), rtc::PacketTime());
+  uint32 last_ping_received2 = lconn->last_ping_received();
+  EXPECT_GT(last_ping_received2, last_ping_received1);
+}
+
+TEST_F(PortTest, TestComputeCandidatePriority) {
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr1, "name", "pass"));
+  port->set_type_preference(90);
+  port->set_component(177);
+  port->AddCandidateAddress(SocketAddress("192.168.1.4", 1234));
+  port->AddCandidateAddress(SocketAddress("2001:db8::1234", 1234));
+  port->AddCandidateAddress(SocketAddress("fc12:3456::1234", 1234));
+  port->AddCandidateAddress(SocketAddress("::ffff:192.168.1.4", 1234));
+  port->AddCandidateAddress(SocketAddress("::192.168.1.4", 1234));
+  port->AddCandidateAddress(SocketAddress("2002::1234:5678", 1234));
+  port->AddCandidateAddress(SocketAddress("2001::1234:5678", 1234));
+  port->AddCandidateAddress(SocketAddress("fecf::1234:5678", 1234));
+  port->AddCandidateAddress(SocketAddress("3ffe::1234:5678", 1234));
+  // These should all be:
+  // (90 << 24) | ([rfc3484 pref value] << 8) | (256 - 177)
+  uint32 expected_priority_v4 = 1509957199U;
+  uint32 expected_priority_v6 = 1509959759U;
+  uint32 expected_priority_ula = 1509962319U;
+  uint32 expected_priority_v4mapped = expected_priority_v4;
+  uint32 expected_priority_v4compat = 1509949775U;
+  uint32 expected_priority_6to4 = 1509954639U;
+  uint32 expected_priority_teredo = 1509952079U;
+  uint32 expected_priority_sitelocal = 1509949775U;
+  uint32 expected_priority_6bone = 1509949775U;
+  ASSERT_EQ(expected_priority_v4, port->Candidates()[0].priority());
+  ASSERT_EQ(expected_priority_v6, port->Candidates()[1].priority());
+  ASSERT_EQ(expected_priority_ula, port->Candidates()[2].priority());
+  ASSERT_EQ(expected_priority_v4mapped, port->Candidates()[3].priority());
+  ASSERT_EQ(expected_priority_v4compat, port->Candidates()[4].priority());
+  ASSERT_EQ(expected_priority_6to4, port->Candidates()[5].priority());
+  ASSERT_EQ(expected_priority_teredo, port->Candidates()[6].priority());
+  ASSERT_EQ(expected_priority_sitelocal, port->Candidates()[7].priority());
+  ASSERT_EQ(expected_priority_6bone, port->Candidates()[8].priority());
+}
+
+TEST_F(PortTest, TestPortProxyProperties) {
+  rtc::scoped_ptr<TestPort> port(
+      CreateTestPort(kLocalAddr1, "name", "pass"));
+  port->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  port->SetIceTiebreaker(kTiebreaker1);
+
+  // Create a proxy port.
+  rtc::scoped_ptr<PortProxy> proxy(new PortProxy());
+  proxy->set_impl(port.get());
+  EXPECT_EQ(port->Type(), proxy->Type());
+  EXPECT_EQ(port->Network(), proxy->Network());
+  EXPECT_EQ(port->GetIceRole(), proxy->GetIceRole());
+  EXPECT_EQ(port->IceTiebreaker(), proxy->IceTiebreaker());
+}
+
+// In the case of shared socket, one port may be shared by local and stun.
+// Test that candidates with different types will have different foundation.
+TEST_F(PortTest, TestFoundation) {
+  rtc::scoped_ptr<TestPort> testport(
+      CreateTestPort(kLocalAddr1, "name", "pass"));
+  testport->AddCandidateAddress(kLocalAddr1, kLocalAddr1,
+                                LOCAL_PORT_TYPE,
+                                cricket::ICE_TYPE_PREFERENCE_HOST, false);
+  testport->AddCandidateAddress(kLocalAddr2, kLocalAddr1,
+                                STUN_PORT_TYPE,
+                                cricket::ICE_TYPE_PREFERENCE_SRFLX, true);
+  EXPECT_NE(testport->Candidates()[0].foundation(),
+            testport->Candidates()[1].foundation());
+}
+
+// This test verifies the foundation of different types of ICE candidates.
+TEST_F(PortTest, TestCandidateFoundation) {
+  rtc::scoped_ptr<rtc::NATServer> nat_server(
+      CreateNatServer(kNatAddr1, NAT_OPEN_CONE));
+  rtc::scoped_ptr<UDPPort> udpport1(CreateUdpPort(kLocalAddr1));
+  udpport1->PrepareAddress();
+  rtc::scoped_ptr<UDPPort> udpport2(CreateUdpPort(kLocalAddr1));
+  udpport2->PrepareAddress();
+  EXPECT_EQ(udpport1->Candidates()[0].foundation(),
+            udpport2->Candidates()[0].foundation());
+  rtc::scoped_ptr<TCPPort> tcpport1(CreateTcpPort(kLocalAddr1));
+  tcpport1->PrepareAddress();
+  rtc::scoped_ptr<TCPPort> tcpport2(CreateTcpPort(kLocalAddr1));
+  tcpport2->PrepareAddress();
+  EXPECT_EQ(tcpport1->Candidates()[0].foundation(),
+            tcpport2->Candidates()[0].foundation());
+  rtc::scoped_ptr<Port> stunport(
+      CreateStunPort(kLocalAddr1, nat_socket_factory1()));
+  stunport->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, stunport->Candidates().size(), kTimeout);
+  EXPECT_NE(tcpport1->Candidates()[0].foundation(),
+            stunport->Candidates()[0].foundation());
+  EXPECT_NE(tcpport2->Candidates()[0].foundation(),
+            stunport->Candidates()[0].foundation());
+  EXPECT_NE(udpport1->Candidates()[0].foundation(),
+            stunport->Candidates()[0].foundation());
+  EXPECT_NE(udpport2->Candidates()[0].foundation(),
+            stunport->Candidates()[0].foundation());
+  // Verify GTURN candidate foundation.
+  rtc::scoped_ptr<RelayPort> relayport(
+      CreateGturnPort(kLocalAddr1));
+  relayport->AddServerAddress(
+      cricket::ProtocolAddress(kRelayUdpIntAddr, cricket::PROTO_UDP));
+  relayport->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, relayport->Candidates().size(), kTimeout);
+  EXPECT_NE(udpport1->Candidates()[0].foundation(),
+            relayport->Candidates()[0].foundation());
+  EXPECT_NE(udpport2->Candidates()[0].foundation(),
+            relayport->Candidates()[0].foundation());
+  // Verifying TURN candidate foundation.
+  rtc::scoped_ptr<Port> turnport1(CreateTurnPort(
+      kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+  turnport1->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, turnport1->Candidates().size(), kTimeout);
+  EXPECT_NE(udpport1->Candidates()[0].foundation(),
+            turnport1->Candidates()[0].foundation());
+  EXPECT_NE(udpport2->Candidates()[0].foundation(),
+            turnport1->Candidates()[0].foundation());
+  EXPECT_NE(stunport->Candidates()[0].foundation(),
+            turnport1->Candidates()[0].foundation());
+  rtc::scoped_ptr<Port> turnport2(CreateTurnPort(
+      kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+  turnport2->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, turnport2->Candidates().size(), kTimeout);
+  EXPECT_EQ(turnport1->Candidates()[0].foundation(),
+            turnport2->Candidates()[0].foundation());
+
+  // Running a second turn server, to get different base IP address.
+  SocketAddress kTurnUdpIntAddr2("99.99.98.4", STUN_SERVER_PORT);
+  SocketAddress kTurnUdpExtAddr2("99.99.98.5", 0);
+  TestTurnServer turn_server2(
+      rtc::Thread::Current(), kTurnUdpIntAddr2, kTurnUdpExtAddr2);
+  rtc::scoped_ptr<Port> turnport3(CreateTurnPort(
+      kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP,
+      kTurnUdpIntAddr2));
+  turnport3->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, turnport3->Candidates().size(), kTimeout);
+  EXPECT_NE(turnport3->Candidates()[0].foundation(),
+            turnport2->Candidates()[0].foundation());
+}
+
+// This test verifies the related addresses of different types of
+// ICE candiates.
+TEST_F(PortTest, TestCandidateRelatedAddress) {
+  rtc::scoped_ptr<rtc::NATServer> nat_server(
+      CreateNatServer(kNatAddr1, NAT_OPEN_CONE));
+  rtc::scoped_ptr<UDPPort> udpport(CreateUdpPort(kLocalAddr1));
+  udpport->PrepareAddress();
+  // For UDPPort, related address will be empty.
+  EXPECT_TRUE(udpport->Candidates()[0].related_address().IsNil());
+  // Testing related address for stun candidates.
+  // For stun candidate related address must be equal to the base
+  // socket address.
+  rtc::scoped_ptr<StunPort> stunport(
+      CreateStunPort(kLocalAddr1, nat_socket_factory1()));
+  stunport->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, stunport->Candidates().size(), kTimeout);
+  // Check STUN candidate address.
+  EXPECT_EQ(stunport->Candidates()[0].address().ipaddr(),
+            kNatAddr1.ipaddr());
+  // Check STUN candidate related address.
+  EXPECT_EQ(stunport->Candidates()[0].related_address(),
+            stunport->GetLocalAddress());
+  // Verifying the related address for the GTURN candidates.
+  // NOTE: In case of GTURN related address will be equal to the mapped
+  // address, but address(mapped) will not be XOR.
+  rtc::scoped_ptr<RelayPort> relayport(
+      CreateGturnPort(kLocalAddr1));
+  relayport->AddServerAddress(
+      cricket::ProtocolAddress(kRelayUdpIntAddr, cricket::PROTO_UDP));
+  relayport->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, relayport->Candidates().size(), kTimeout);
+  // For Gturn related address is set to "0.0.0.0:0"
+  EXPECT_EQ(rtc::SocketAddress(),
+            relayport->Candidates()[0].related_address());
+  // Verifying the related address for TURN candidate.
+  // For TURN related address must be equal to the mapped address.
+  rtc::scoped_ptr<Port> turnport(CreateTurnPort(
+      kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+  turnport->PrepareAddress();
+  ASSERT_EQ_WAIT(1U, turnport->Candidates().size(), kTimeout);
+  EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
+            turnport->Candidates()[0].address().ipaddr());
+  EXPECT_EQ(kNatAddr1.ipaddr(),
+            turnport->Candidates()[0].related_address().ipaddr());
+}
+
+// Test priority value overflow handling when preference is set to 3.
+TEST_F(PortTest, TestCandidatePreference) {
+  cricket::Candidate cand1;
+  cand1.set_preference(3);
+  cricket::Candidate cand2;
+  cand2.set_preference(1);
+  EXPECT_TRUE(cand1.preference() > cand2.preference());
+}
+
+// Test the Connection priority is calculated correctly.
+TEST_F(PortTest, TestConnectionPriority) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
+  lport->set_type_preference(cricket::ICE_TYPE_PREFERENCE_HOST);
+  rtc::scoped_ptr<TestPort> rport(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  rport->set_type_preference(cricket::ICE_TYPE_PREFERENCE_RELAY);
+  lport->set_component(123);
+  lport->AddCandidateAddress(SocketAddress("192.168.1.4", 1234));
+  rport->set_component(23);
+  rport->AddCandidateAddress(SocketAddress("10.1.1.100", 1234));
+
+  EXPECT_EQ(0x7E001E85U, lport->Candidates()[0].priority());
+  EXPECT_EQ(0x2001EE9U, rport->Candidates()[0].priority());
+
+  // RFC 5245
+  // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  rport->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  Connection* lconn = lport->CreateConnection(
+      rport->Candidates()[0], Port::ORIGIN_MESSAGE);
+#if defined(WEBRTC_WIN)
+  EXPECT_EQ(0x2001EE9FC003D0BU, lconn->priority());
+#else
+  EXPECT_EQ(0x2001EE9FC003D0BLLU, lconn->priority());
+#endif
+
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  rport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  Connection* rconn = rport->CreateConnection(
+      lport->Candidates()[0], Port::ORIGIN_MESSAGE);
+#if defined(WEBRTC_WIN)
+  EXPECT_EQ(0x2001EE9FC003D0AU, rconn->priority());
+#else
+  EXPECT_EQ(0x2001EE9FC003D0ALLU, rconn->priority());
+#endif
+}
+
+TEST_F(PortTest, TestWritableState) {
+  UDPPort* port1 = CreateUdpPort(kLocalAddr1);
+  UDPPort* port2 = CreateUdpPort(kLocalAddr2);
+
+  // Set up channels.
+  TestChannel ch1(port1, port2);
+  TestChannel ch2(port2, port1);
+
+  // Acquire addresses.
+  ch1.Start();
+  ch2.Start();
+  ASSERT_EQ_WAIT(1, ch1.complete_count(), kTimeout);
+  ASSERT_EQ_WAIT(1, ch2.complete_count(), kTimeout);
+
+  // Send a ping from src to dst.
+  ch1.CreateConnection();
+  ASSERT_TRUE(ch1.conn() != NULL);
+  EXPECT_EQ(Connection::STATE_WRITE_INIT, ch1.conn()->write_state());
+  EXPECT_TRUE_WAIT(ch1.conn()->connected(), kTimeout);  // for TCP connect
+  ch1.Ping();
+  WAIT(!ch2.remote_address().IsNil(), kTimeout);
+
+  // Data should be unsendable until the connection is accepted.
+  char data[] = "abcd";
+  int data_size = ARRAY_SIZE(data);
+  rtc::PacketOptions options;
+  EXPECT_EQ(SOCKET_ERROR, ch1.conn()->Send(data, data_size, options));
+
+  // Accept the connection to return the binding response, transition to
+  // writable, and allow data to be sent.
+  ch2.AcceptConnection();
+  EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(),
+                 kTimeout);
+  EXPECT_EQ(data_size, ch1.conn()->Send(data, data_size, options));
+
+  // Ask the connection to update state as if enough time has passed to lose
+  // full writability and 5 pings went unresponded to. We'll accomplish the
+  // latter by sending pings but not pumping messages.
+  for (uint32 i = 1; i <= CONNECTION_WRITE_CONNECT_FAILURES; ++i) {
+    ch1.Ping(i);
+  }
+  uint32 unreliable_timeout_delay = CONNECTION_WRITE_CONNECT_TIMEOUT + 500u;
+  ch1.conn()->UpdateState(unreliable_timeout_delay);
+  EXPECT_EQ(Connection::STATE_WRITE_UNRELIABLE, ch1.conn()->write_state());
+
+  // Data should be able to be sent in this state.
+  EXPECT_EQ(data_size, ch1.conn()->Send(data, data_size, options));
+
+  // And now allow the other side to process the pings and send binding
+  // responses.
+  EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(),
+                 kTimeout);
+
+  // Wait long enough for a full timeout (past however long we've already
+  // waited).
+  for (uint32 i = 1; i <= CONNECTION_WRITE_CONNECT_FAILURES; ++i) {
+    ch1.Ping(unreliable_timeout_delay + i);
+  }
+  ch1.conn()->UpdateState(unreliable_timeout_delay + CONNECTION_WRITE_TIMEOUT +
+                          500u);
+  EXPECT_EQ(Connection::STATE_WRITE_TIMEOUT, ch1.conn()->write_state());
+
+  // Now that the connection has completely timed out, data send should fail.
+  EXPECT_EQ(SOCKET_ERROR, ch1.conn()->Send(data, data_size, options));
+
+  ch1.Stop();
+  ch2.Stop();
+}
+
+TEST_F(PortTest, TestTimeoutForNeverWritable) {
+  UDPPort* port1 = CreateUdpPort(kLocalAddr1);
+  UDPPort* port2 = CreateUdpPort(kLocalAddr2);
+
+  // Set up channels.
+  TestChannel ch1(port1, port2);
+  TestChannel ch2(port2, port1);
+
+  // Acquire addresses.
+  ch1.Start();
+  ch2.Start();
+
+  ch1.CreateConnection();
+  ASSERT_TRUE(ch1.conn() != NULL);
+  EXPECT_EQ(Connection::STATE_WRITE_INIT, ch1.conn()->write_state());
+
+  // Attempt to go directly to write timeout.
+  for (uint32 i = 1; i <= CONNECTION_WRITE_CONNECT_FAILURES; ++i) {
+    ch1.Ping(i);
+  }
+  ch1.conn()->UpdateState(CONNECTION_WRITE_TIMEOUT + 500u);
+  EXPECT_EQ(Connection::STATE_WRITE_TIMEOUT, ch1.conn()->write_state());
+}
+
+// This test verifies the connection setup between ICEMODE_FULL
+// and ICEMODE_LITE.
+// In this test |ch1| behaves like FULL mode client and we have created
+// port which responds to the ping message just like LITE client.
+TEST_F(PortTest, TestIceLiteConnectivity) {
+  TestPort* ice_full_port = CreateTestPort(
+      kLocalAddr1, "lfrag", "lpass", cricket::ICEPROTO_RFC5245,
+      cricket::ICEROLE_CONTROLLING, kTiebreaker1);
+
+  rtc::scoped_ptr<TestPort> ice_lite_port(CreateTestPort(
+      kLocalAddr2, "rfrag", "rpass", cricket::ICEPROTO_RFC5245,
+      cricket::ICEROLE_CONTROLLED, kTiebreaker2));
+  // Setup TestChannel. This behaves like FULL mode client.
+  TestChannel ch1(ice_full_port, ice_lite_port.get());
+  ch1.SetIceMode(ICEMODE_FULL);
+
+  // Start gathering candidates.
+  ch1.Start();
+  ice_lite_port->PrepareAddress();
+
+  ASSERT_EQ_WAIT(1, ch1.complete_count(), kTimeout);
+  ASSERT_FALSE(ice_lite_port->Candidates().empty());
+
+  ch1.CreateConnection();
+  ASSERT_TRUE(ch1.conn() != NULL);
+  EXPECT_EQ(Connection::STATE_WRITE_INIT, ch1.conn()->write_state());
+
+  // Send ping from full mode client.
+  // This ping must not have USE_CANDIDATE_ATTR.
+  ch1.Ping();
+
+  // Verify stun ping is without USE_CANDIDATE_ATTR. Getting message directly
+  // from port.
+  ASSERT_TRUE_WAIT(ice_full_port->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = ice_full_port->last_stun_msg();
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) == NULL);
+
+  // Respond with a BINDING-RESPONSE from litemode client.
+  // NOTE: Ideally we should't create connection at this stage from lite
+  // port, as it should be done only after receiving ping with USE_CANDIDATE.
+  // But we need a connection to send a response message.
+  ice_lite_port->CreateConnection(
+      ice_full_port->Candidates()[0], cricket::Port::ORIGIN_MESSAGE);
+  rtc::scoped_ptr<IceMessage> request(CopyStunMessage(msg));
+  ice_lite_port->SendBindingResponse(
+      request.get(), ice_full_port->Candidates()[0].address());
+
+  // Feeding the respone message from litemode to the full mode connection.
+  ch1.conn()->OnReadPacket(ice_lite_port->last_stun_buf()->Data(),
+                           ice_lite_port->last_stun_buf()->Length(),
+                           rtc::PacketTime());
+  // Verifying full mode connection becomes writable from the response.
+  EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(),
+                 kTimeout);
+  EXPECT_TRUE_WAIT(ch1.nominated(), kTimeout);
+
+  // Clear existing stun messsages. Otherwise we will process old stun
+  // message right after we send ping.
+  ice_full_port->Reset();
+  // Send ping. This must have USE_CANDIDATE_ATTR.
+  ch1.Ping();
+  ASSERT_TRUE_WAIT(ice_full_port->last_stun_msg() != NULL, 1000);
+  msg = ice_full_port->last_stun_msg();
+  EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) != NULL);
+  ch1.Stop();
+}
+
+// This test case verifies that the CONTROLLING port does not time out.
+TEST_F(PortTest, TestControllingNoTimeout) {
+  SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+  UDPPort* port1 = CreateUdpPort(kLocalAddr1);
+  ConnectToSignalDestroyed(port1);
+  port1->set_timeout_delay(10);  // milliseconds
+  port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  port1->SetIceTiebreaker(kTiebreaker1);
+
+  UDPPort* port2 = CreateUdpPort(kLocalAddr2);
+  port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  port2->SetIceTiebreaker(kTiebreaker2);
+
+  // Set up channels and ensure both ports will be deleted.
+  TestChannel ch1(port1, port2);
+  TestChannel ch2(port2, port1);
+
+  // Simulate a connection that succeeds, and then is destroyed.
+  ConnectAndDisconnectChannels(&ch1, &ch2);
+
+  // After the connection is destroyed, the port should not be destroyed.
+  rtc::Thread::Current()->ProcessMessages(kTimeout);
+  EXPECT_FALSE(destroyed());
+}
+
+// This test case verifies that the CONTROLLED port does time out, but only
+// after connectivity is lost.
+TEST_F(PortTest, TestControlledTimeout) {
+  SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+  UDPPort* port1 = CreateUdpPort(kLocalAddr1);
+  port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  port1->SetIceTiebreaker(kTiebreaker1);
+
+  UDPPort* port2 = CreateUdpPort(kLocalAddr2);
+  ConnectToSignalDestroyed(port2);
+  port2->set_timeout_delay(10);  // milliseconds
+  port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  port2->SetIceTiebreaker(kTiebreaker2);
+
+  // The connection must not be destroyed before a connection is attempted.
+  EXPECT_FALSE(destroyed());
+
+  port1->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
+  port2->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
+
+  // Set up channels and ensure both ports will be deleted.
+  TestChannel ch1(port1, port2);
+  TestChannel ch2(port2, port1);
+
+  // Simulate a connection that succeeds, and then is destroyed.
+  ConnectAndDisconnectChannels(&ch1, &ch2);
+
+  // The controlled port should be destroyed after 10 milliseconds.
+  EXPECT_TRUE_WAIT(destroyed(), kTimeout);
+}
diff --git a/p2p/base/portallocator.cc b/p2p/base/portallocator.cc
new file mode 100644
index 0000000..8613347
--- /dev/null
+++ b/p2p/base/portallocator.cc
@@ -0,0 +1,92 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/portallocator.h"
+
+#include "webrtc/p2p/base/portallocatorsessionproxy.h"
+
+namespace cricket {
+
+PortAllocatorSession::PortAllocatorSession(const std::string& content_name,
+                                           int component,
+                                           const std::string& ice_ufrag,
+                                           const std::string& ice_pwd,
+                                           uint32 flags)
+    : content_name_(content_name),
+      component_(component),
+      flags_(flags),
+      generation_(0),
+      // If PORTALLOCATOR_ENABLE_SHARED_UFRAG flag is not enabled, ignore the
+      // incoming ufrag and pwd, which will cause each Port to generate one
+      // by itself.
+      username_(flags_ & PORTALLOCATOR_ENABLE_SHARED_UFRAG ? ice_ufrag : ""),
+      password_(flags_ & PORTALLOCATOR_ENABLE_SHARED_UFRAG ? ice_pwd : "") {
+}
+
+PortAllocator::~PortAllocator() {
+  for (SessionMuxerMap::iterator iter = muxers_.begin();
+       iter != muxers_.end(); ++iter) {
+    delete iter->second;
+  }
+}
+
+PortAllocatorSession* PortAllocator::CreateSession(
+    const std::string& sid,
+    const std::string& content_name,
+    int component,
+    const std::string& ice_ufrag,
+    const std::string& ice_pwd) {
+  if (flags_ & PORTALLOCATOR_ENABLE_BUNDLE) {
+    // If we just use |sid| as key in identifying PortAllocatorSessionMuxer,
+    // ICE restart will not result in different candidates, as |sid| will
+    // be same. To yield different candiates we are using combination of
+    // |ice_ufrag| and |ice_pwd|.
+    // Ideally |ice_ufrag| and |ice_pwd| should change together, but
+    // there can be instances where only ice_pwd will be changed.
+    std::string key_str = ice_ufrag + ":" + ice_pwd;
+    PortAllocatorSessionMuxer* muxer = GetSessionMuxer(key_str);
+    if (!muxer) {
+      PortAllocatorSession* session_impl = CreateSessionInternal(
+          content_name, component, ice_ufrag, ice_pwd);
+      // Create PortAllocatorSessionMuxer object for |session_impl|.
+      muxer = new PortAllocatorSessionMuxer(session_impl);
+      muxer->SignalDestroyed.connect(
+          this, &PortAllocator::OnSessionMuxerDestroyed);
+      // Add PortAllocatorSession to the map.
+      muxers_[key_str] = muxer;
+    }
+    PortAllocatorSessionProxy* proxy =
+        new PortAllocatorSessionProxy(content_name, component, flags_);
+    muxer->RegisterSessionProxy(proxy);
+    return proxy;
+  }
+  return CreateSessionInternal(content_name, component, ice_ufrag, ice_pwd);
+}
+
+PortAllocatorSessionMuxer* PortAllocator::GetSessionMuxer(
+    const std::string& key) const {
+  SessionMuxerMap::const_iterator iter = muxers_.find(key);
+  if (iter != muxers_.end())
+    return iter->second;
+  return NULL;
+}
+
+void PortAllocator::OnSessionMuxerDestroyed(
+    PortAllocatorSessionMuxer* session) {
+  SessionMuxerMap::iterator iter;
+  for (iter = muxers_.begin(); iter != muxers_.end(); ++iter) {
+    if (iter->second == session)
+      break;
+  }
+  if (iter != muxers_.end())
+    muxers_.erase(iter);
+}
+
+}  // namespace cricket
diff --git a/p2p/base/portallocator.h b/p2p/base/portallocator.h
new file mode 100644
index 0000000..65aab44
--- /dev/null
+++ b/p2p/base/portallocator.h
@@ -0,0 +1,192 @@
+/*
+ *  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_P2P_BASE_PORTALLOCATOR_H_
+#define WEBRTC_P2P_BASE_PORTALLOCATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/portinterface.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/proxyinfo.h"
+#include "webrtc/base/sigslot.h"
+
+namespace cricket {
+
+// PortAllocator is responsible for allocating Port types for a given
+// P2PSocket. It also handles port freeing.
+//
+// Clients can override this class to control port allocation, including
+// what kinds of ports are allocated.
+
+enum {
+  PORTALLOCATOR_DISABLE_UDP = 0x01,
+  PORTALLOCATOR_DISABLE_STUN = 0x02,
+  PORTALLOCATOR_DISABLE_RELAY = 0x04,
+  PORTALLOCATOR_DISABLE_TCP = 0x08,
+  PORTALLOCATOR_ENABLE_SHAKER = 0x10,
+  PORTALLOCATOR_ENABLE_BUNDLE = 0x20,
+  PORTALLOCATOR_ENABLE_IPV6 = 0x40,
+  PORTALLOCATOR_ENABLE_SHARED_UFRAG = 0x80,
+  PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100,
+  PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200,
+};
+
+const uint32 kDefaultPortAllocatorFlags = 0;
+
+const uint32 kDefaultStepDelay = 1000;  // 1 sec step delay.
+// As per RFC 5245 Appendix B.1, STUN transactions need to be paced at certain
+// internal. Less than 20ms is not acceptable. We choose 50ms as our default.
+const uint32 kMinimumStepDelay = 50;
+
+// CF = CANDIDATE FILTER
+enum {
+  CF_NONE = 0x0,
+  CF_HOST = 0x1,
+  CF_REFLEXIVE = 0x2,
+  CF_RELAY = 0x4,
+  CF_ALL = 0x7,
+};
+
+class PortAllocatorSessionMuxer;
+
+class PortAllocatorSession : public sigslot::has_slots<> {
+ public:
+  // Content name passed in mostly for logging and debugging.
+  // TODO(mallinath) - Change username and password to ice_ufrag and ice_pwd.
+  PortAllocatorSession(const std::string& content_name,
+                       int component,
+                       const std::string& username,
+                       const std::string& password,
+                       uint32 flags);
+
+  // Subclasses should clean up any ports created.
+  virtual ~PortAllocatorSession() {}
+
+  uint32 flags() const { return flags_; }
+  void set_flags(uint32 flags) { flags_ = flags; }
+  std::string content_name() const { return content_name_; }
+  int component() const { return component_; }
+
+  // Starts gathering STUN and Relay configurations.
+  virtual void StartGettingPorts() = 0;
+  virtual void StopGettingPorts() = 0;
+  virtual bool IsGettingPorts() = 0;
+
+  sigslot::signal2<PortAllocatorSession*, PortInterface*> SignalPortReady;
+  sigslot::signal2<PortAllocatorSession*,
+                   const std::vector<Candidate>&> SignalCandidatesReady;
+  sigslot::signal1<PortAllocatorSession*> SignalCandidatesAllocationDone;
+
+  virtual uint32 generation() { return generation_; }
+  virtual void set_generation(uint32 generation) { generation_ = generation; }
+  sigslot::signal1<PortAllocatorSession*> SignalDestroyed;
+
+ protected:
+  const std::string& username() const { return username_; }
+  const std::string& password() const { return password_; }
+
+  std::string content_name_;
+  int component_;
+
+ private:
+  uint32 flags_;
+  uint32 generation_;
+  std::string username_;
+  std::string password_;
+};
+
+class PortAllocator : public sigslot::has_slots<> {
+ public:
+  PortAllocator() :
+      flags_(kDefaultPortAllocatorFlags),
+      min_port_(0),
+      max_port_(0),
+      step_delay_(kDefaultStepDelay),
+      allow_tcp_listen_(true),
+      candidate_filter_(CF_ALL) {
+    // This will allow us to have old behavior on non webrtc clients.
+  }
+  virtual ~PortAllocator();
+
+  PortAllocatorSession* CreateSession(
+      const std::string& sid,
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd);
+
+  PortAllocatorSessionMuxer* GetSessionMuxer(const std::string& key) const;
+  void OnSessionMuxerDestroyed(PortAllocatorSessionMuxer* session);
+
+  uint32 flags() const { return flags_; }
+  void set_flags(uint32 flags) { flags_ = flags; }
+
+  const std::string& user_agent() const { return agent_; }
+  const rtc::ProxyInfo& proxy() const { return proxy_; }
+  void set_proxy(const std::string& agent, const rtc::ProxyInfo& proxy) {
+    agent_ = agent;
+    proxy_ = proxy;
+  }
+
+  // Gets/Sets the port range to use when choosing client ports.
+  int min_port() const { return min_port_; }
+  int max_port() const { return max_port_; }
+  bool SetPortRange(int min_port, int max_port) {
+    if (min_port > max_port) {
+      return false;
+    }
+
+    min_port_ = min_port;
+    max_port_ = max_port;
+    return true;
+  }
+
+  uint32 step_delay() const { return step_delay_; }
+  void set_step_delay(uint32 delay) {
+    step_delay_ = delay;
+  }
+
+  bool allow_tcp_listen() const { return allow_tcp_listen_; }
+  void set_allow_tcp_listen(bool allow_tcp_listen) {
+    allow_tcp_listen_ = allow_tcp_listen;
+  }
+
+  uint32 candidate_filter() { return candidate_filter_; }
+  bool set_candidate_filter(uint32 filter) {
+    // TODO(mallinath) - Do transition check?
+    candidate_filter_ = filter;
+    return true;
+  }
+
+ protected:
+  virtual PortAllocatorSession* CreateSessionInternal(
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd) = 0;
+
+  typedef std::map<std::string, PortAllocatorSessionMuxer*> SessionMuxerMap;
+
+  uint32 flags_;
+  std::string agent_;
+  rtc::ProxyInfo proxy_;
+  int min_port_;
+  int max_port_;
+  uint32 step_delay_;
+  SessionMuxerMap muxers_;
+  bool allow_tcp_listen_;
+  uint32 candidate_filter_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_PORTALLOCATOR_H_
diff --git a/p2p/base/portallocatorsessionproxy.cc b/p2p/base/portallocatorsessionproxy.cc
new file mode 100644
index 0000000..f5ce9a4
--- /dev/null
+++ b/p2p/base/portallocatorsessionproxy.cc
@@ -0,0 +1,222 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/portallocatorsessionproxy.h"
+
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/portproxy.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+enum {
+  MSG_SEND_ALLOCATION_DONE = 1,
+  MSG_SEND_ALLOCATED_PORTS,
+};
+
+typedef rtc::TypedMessageData<PortAllocatorSessionProxy*> ProxyObjData;
+
+PortAllocatorSessionMuxer::PortAllocatorSessionMuxer(
+    PortAllocatorSession* session)
+    : worker_thread_(rtc::Thread::Current()),
+      session_(session),
+      candidate_done_signal_received_(false) {
+  session_->SignalPortReady.connect(
+      this, &PortAllocatorSessionMuxer::OnPortReady);
+  session_->SignalCandidatesAllocationDone.connect(
+      this, &PortAllocatorSessionMuxer::OnCandidatesAllocationDone);
+}
+
+PortAllocatorSessionMuxer::~PortAllocatorSessionMuxer() {
+  for (size_t i = 0; i < session_proxies_.size(); ++i)
+    delete session_proxies_[i];
+
+  SignalDestroyed(this);
+}
+
+void PortAllocatorSessionMuxer::RegisterSessionProxy(
+    PortAllocatorSessionProxy* session_proxy) {
+  session_proxies_.push_back(session_proxy);
+  session_proxy->SignalDestroyed.connect(
+      this, &PortAllocatorSessionMuxer::OnSessionProxyDestroyed);
+  session_proxy->set_impl(session_.get());
+
+  // Populate new proxy session with the information available in the actual
+  // implementation.
+  if (!ports_.empty()) {
+    worker_thread_->Post(
+        this, MSG_SEND_ALLOCATED_PORTS, new ProxyObjData(session_proxy));
+  }
+
+  if (candidate_done_signal_received_) {
+    worker_thread_->Post(
+        this, MSG_SEND_ALLOCATION_DONE, new ProxyObjData(session_proxy));
+  }
+}
+
+void PortAllocatorSessionMuxer::OnCandidatesAllocationDone(
+    PortAllocatorSession* session) {
+  candidate_done_signal_received_ = true;
+}
+
+void PortAllocatorSessionMuxer::OnPortReady(PortAllocatorSession* session,
+                                            PortInterface* port) {
+  ASSERT(session == session_.get());
+  ports_.push_back(port);
+  port->SignalDestroyed.connect(
+      this, &PortAllocatorSessionMuxer::OnPortDestroyed);
+}
+
+void PortAllocatorSessionMuxer::OnPortDestroyed(PortInterface* port) {
+  std::vector<PortInterface*>::iterator it =
+      std::find(ports_.begin(), ports_.end(), port);
+  if (it != ports_.end())
+    ports_.erase(it);
+}
+
+void PortAllocatorSessionMuxer::OnSessionProxyDestroyed(
+    PortAllocatorSession* proxy) {
+
+  std::vector<PortAllocatorSessionProxy*>::iterator it =
+      std::find(session_proxies_.begin(), session_proxies_.end(), proxy);
+  if (it != session_proxies_.end()) {
+    session_proxies_.erase(it);
+  }
+
+  if (session_proxies_.empty()) {
+    // Destroy PortAllocatorSession and its associated muxer object if all
+    // proxies belonging to this session are already destroyed.
+    delete this;
+  }
+}
+
+void PortAllocatorSessionMuxer::OnMessage(rtc::Message *pmsg) {
+  ProxyObjData* proxy = static_cast<ProxyObjData*>(pmsg->pdata);
+  switch (pmsg->message_id) {
+    case MSG_SEND_ALLOCATION_DONE:
+      SendAllocationDone_w(proxy->data());
+      delete proxy;
+      break;
+    case MSG_SEND_ALLOCATED_PORTS:
+      SendAllocatedPorts_w(proxy->data());
+      delete proxy;
+      break;
+    default:
+      ASSERT(false);
+      break;
+  }
+}
+
+void PortAllocatorSessionMuxer::SendAllocationDone_w(
+    PortAllocatorSessionProxy* proxy) {
+  std::vector<PortAllocatorSessionProxy*>::iterator iter =
+      std::find(session_proxies_.begin(), session_proxies_.end(), proxy);
+  if (iter != session_proxies_.end()) {
+    proxy->OnCandidatesAllocationDone(session_.get());
+  }
+}
+
+void PortAllocatorSessionMuxer::SendAllocatedPorts_w(
+    PortAllocatorSessionProxy* proxy) {
+  std::vector<PortAllocatorSessionProxy*>::iterator iter =
+      std::find(session_proxies_.begin(), session_proxies_.end(), proxy);
+  if (iter != session_proxies_.end()) {
+    for (size_t i = 0; i < ports_.size(); ++i) {
+      PortInterface* port = ports_[i];
+      proxy->OnPortReady(session_.get(), port);
+      // If port already has candidates, send this to the clients of proxy
+      // session. This can happen if proxy is created later than the actual
+      // implementation.
+      if (!port->Candidates().empty()) {
+        proxy->OnCandidatesReady(session_.get(), port->Candidates());
+      }
+    }
+  }
+}
+
+PortAllocatorSessionProxy::~PortAllocatorSessionProxy() {
+  std::map<PortInterface*, PortProxy*>::iterator it;
+  for (it = proxy_ports_.begin(); it != proxy_ports_.end(); it++)
+    delete it->second;
+
+  SignalDestroyed(this);
+}
+
+void PortAllocatorSessionProxy::set_impl(
+    PortAllocatorSession* session) {
+  impl_ = session;
+
+  impl_->SignalCandidatesReady.connect(
+      this, &PortAllocatorSessionProxy::OnCandidatesReady);
+  impl_->SignalPortReady.connect(
+      this, &PortAllocatorSessionProxy::OnPortReady);
+  impl_->SignalCandidatesAllocationDone.connect(
+      this, &PortAllocatorSessionProxy::OnCandidatesAllocationDone);
+}
+
+void PortAllocatorSessionProxy::StartGettingPorts() {
+  ASSERT(impl_ != NULL);
+  // Since all proxies share a common PortAllocatorSession, this check will
+  // prohibit sending multiple STUN ping messages to the stun server, which
+  // is a problem on Chrome. GetInitialPorts() and StartGetAllPorts() called
+  // from the worker thread and are called together from TransportChannel,
+  // checking for IsGettingAllPorts() for GetInitialPorts() will not be a
+  // problem.
+  if (!impl_->IsGettingPorts()) {
+    impl_->StartGettingPorts();
+  }
+}
+
+void PortAllocatorSessionProxy::StopGettingPorts() {
+  ASSERT(impl_ != NULL);
+  if (impl_->IsGettingPorts()) {
+    impl_->StopGettingPorts();
+  }
+}
+
+bool PortAllocatorSessionProxy::IsGettingPorts() {
+  ASSERT(impl_ != NULL);
+  return impl_->IsGettingPorts();
+}
+
+void PortAllocatorSessionProxy::OnPortReady(PortAllocatorSession* session,
+                                            PortInterface* port) {
+  ASSERT(session == impl_);
+
+  PortProxy* proxy_port = new PortProxy();
+  proxy_port->set_impl(port);
+  proxy_ports_[port] = proxy_port;
+  SignalPortReady(this, proxy_port);
+}
+
+void PortAllocatorSessionProxy::OnCandidatesReady(
+    PortAllocatorSession* session,
+    const std::vector<Candidate>& candidates) {
+  ASSERT(session == impl_);
+
+  // Since all proxy sessions share a common PortAllocatorSession,
+  // all Candidates will have name associated with the common PAS.
+  // Change Candidate name with the PortAllocatorSessionProxy name.
+  std::vector<Candidate> our_candidates;
+  for (size_t i = 0; i < candidates.size(); ++i) {
+    Candidate new_local_candidate = candidates[i];
+    new_local_candidate.set_component(component_);
+    our_candidates.push_back(new_local_candidate);
+  }
+  SignalCandidatesReady(this, our_candidates);
+}
+
+void PortAllocatorSessionProxy::OnCandidatesAllocationDone(
+    PortAllocatorSession* session) {
+  ASSERT(session == impl_);
+  SignalCandidatesAllocationDone(this);
+}
+
+}  // namespace cricket
diff --git a/p2p/base/portallocatorsessionproxy.h b/p2p/base/portallocatorsessionproxy.h
new file mode 100644
index 0000000..94ae19d
--- /dev/null
+++ b/p2p/base/portallocatorsessionproxy.h
@@ -0,0 +1,106 @@
+/*
+ *  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_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_
+#define WEBRTC_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_
+
+#include <string>
+
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/portallocator.h"
+
+namespace cricket {
+class PortAllocator;
+class PortAllocatorSessionProxy;
+class PortProxy;
+
+// This class maintains the list of cricket::Port* objects. Ports will be
+// deleted upon receiving SignalDestroyed signal. This class is used when
+// PORTALLOCATOR_ENABLE_BUNDLE flag is set.
+
+class PortAllocatorSessionMuxer : public rtc::MessageHandler,
+                                  public sigslot::has_slots<> {
+ public:
+  explicit PortAllocatorSessionMuxer(PortAllocatorSession* session);
+  virtual ~PortAllocatorSessionMuxer();
+
+  void RegisterSessionProxy(PortAllocatorSessionProxy* session_proxy);
+
+  void OnPortReady(PortAllocatorSession* session, PortInterface* port);
+  void OnPortDestroyed(PortInterface* port);
+  void OnCandidatesAllocationDone(PortAllocatorSession* session);
+
+  const std::vector<PortInterface*>& ports() { return ports_; }
+
+  sigslot::signal1<PortAllocatorSessionMuxer*> SignalDestroyed;
+
+ private:
+  virtual void OnMessage(rtc::Message *pmsg);
+  void OnSessionProxyDestroyed(PortAllocatorSession* proxy);
+  void SendAllocationDone_w(PortAllocatorSessionProxy* proxy);
+  void SendAllocatedPorts_w(PortAllocatorSessionProxy* proxy);
+
+  // Port will be deleted when SignalDestroyed received, otherwise delete
+  // happens when PortAllocatorSession dtor is called.
+  rtc::Thread* worker_thread_;
+  std::vector<PortInterface*> ports_;
+  rtc::scoped_ptr<PortAllocatorSession> session_;
+  std::vector<PortAllocatorSessionProxy*> session_proxies_;
+  bool candidate_done_signal_received_;
+};
+
+class PortAllocatorSessionProxy : public PortAllocatorSession {
+ public:
+  PortAllocatorSessionProxy(const std::string& content_name,
+                            int component,
+                            uint32 flags)
+        // Use empty string as the ufrag and pwd because the proxy always uses
+        // the ufrag and pwd from the underlying implementation.
+      : PortAllocatorSession(content_name, component, "", "", flags),
+        impl_(NULL) {
+  }
+
+  virtual ~PortAllocatorSessionProxy();
+
+  PortAllocatorSession* impl() { return impl_; }
+  void set_impl(PortAllocatorSession* session);
+
+  // Forwards call to the actual PortAllocatorSession.
+  virtual void StartGettingPorts();
+  virtual void StopGettingPorts();
+  virtual bool IsGettingPorts();
+
+  virtual void set_generation(uint32 generation) {
+    ASSERT(impl_ != NULL);
+    impl_->set_generation(generation);
+  }
+
+  virtual uint32 generation() {
+    ASSERT(impl_ != NULL);
+    return impl_->generation();
+  }
+
+ private:
+  void OnPortReady(PortAllocatorSession* session, PortInterface* port);
+  void OnCandidatesReady(PortAllocatorSession* session,
+                         const std::vector<Candidate>& candidates);
+  void OnPortDestroyed(PortInterface* port);
+  void OnCandidatesAllocationDone(PortAllocatorSession* session);
+
+  // This is the actual PortAllocatorSession, owned by PortAllocator.
+  PortAllocatorSession* impl_;
+  std::map<PortInterface*, PortProxy*> proxy_ports_;
+
+  friend class PortAllocatorSessionMuxer;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_
diff --git a/p2p/base/portallocatorsessionproxy_unittest.cc b/p2p/base/portallocatorsessionproxy_unittest.cc
new file mode 100644
index 0000000..61a9e98
--- /dev/null
+++ b/p2p/base/portallocatorsessionproxy_unittest.cc
@@ -0,0 +1,146 @@
+/*
+ *  Copyright 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 <vector>
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/portallocatorsessionproxy.h"
+#include "webrtc/p2p/client/basicportallocator.h"
+#include "webrtc/p2p/client/fakeportallocator.h"
+#include "webrtc/base/fakenetwork.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/thread.h"
+
+using cricket::Candidate;
+using cricket::PortAllocatorSession;
+using cricket::PortAllocatorSessionMuxer;
+using cricket::PortAllocatorSessionProxy;
+
+// Based on ICE_UFRAG_LENGTH
+static const char kIceUfrag0[] = "TESTICEUFRAG0000";
+// Based on ICE_PWD_LENGTH
+static const char kIcePwd0[] = "TESTICEPWD00000000000000";
+
+class TestSessionChannel : public sigslot::has_slots<> {
+ public:
+  explicit TestSessionChannel(PortAllocatorSessionProxy* proxy)
+      : proxy_session_(proxy),
+        candidates_count_(0),
+        allocation_complete_(false),
+        ports_count_(0) {
+    proxy_session_->SignalCandidatesAllocationDone.connect(
+        this, &TestSessionChannel::OnCandidatesAllocationDone);
+    proxy_session_->SignalCandidatesReady.connect(
+        this, &TestSessionChannel::OnCandidatesReady);
+    proxy_session_->SignalPortReady.connect(
+        this, &TestSessionChannel::OnPortReady);
+  }
+  virtual ~TestSessionChannel() {
+    delete proxy_session_;
+  }
+  void OnCandidatesReady(PortAllocatorSession* session,
+                         const std::vector<Candidate>& candidates) {
+    EXPECT_EQ(proxy_session_, session);
+    candidates_count_ += static_cast<int>(candidates.size());
+  }
+  void OnCandidatesAllocationDone(PortAllocatorSession* session) {
+    EXPECT_EQ(proxy_session_, session);
+    allocation_complete_ = true;
+  }
+  void OnPortReady(PortAllocatorSession* session,
+                   cricket::PortInterface* port) {
+    EXPECT_EQ(proxy_session_, session);
+    ++ports_count_;
+  }
+  int candidates_count() { return candidates_count_; }
+  bool allocation_complete() { return allocation_complete_; }
+  int ports_count() { return ports_count_; }
+
+  void StartGettingPorts() {
+    proxy_session_->StartGettingPorts();
+  }
+
+  void StopGettingPorts() {
+    proxy_session_->StopGettingPorts();
+  }
+
+  bool IsGettingPorts() {
+    return proxy_session_->IsGettingPorts();
+  }
+
+ private:
+  PortAllocatorSessionProxy* proxy_session_;
+  int candidates_count_;
+  bool allocation_complete_;
+  int ports_count_;
+};
+
+class PortAllocatorSessionProxyTest : public testing::Test {
+ public:
+  PortAllocatorSessionProxyTest()
+      : socket_factory_(rtc::Thread::Current()),
+        allocator_(rtc::Thread::Current(), NULL),
+        session_(new cricket::FakePortAllocatorSession(
+                     rtc::Thread::Current(), &socket_factory_,
+                     "test content", 1,
+                     kIceUfrag0, kIcePwd0)),
+        session_muxer_(new PortAllocatorSessionMuxer(session_)) {
+  }
+  virtual ~PortAllocatorSessionProxyTest() {}
+  void RegisterSessionProxy(PortAllocatorSessionProxy* proxy) {
+    session_muxer_->RegisterSessionProxy(proxy);
+  }
+
+  TestSessionChannel* CreateChannel() {
+    PortAllocatorSessionProxy* proxy =
+        new PortAllocatorSessionProxy("test content", 1, 0);
+    TestSessionChannel* channel = new TestSessionChannel(proxy);
+    session_muxer_->RegisterSessionProxy(proxy);
+    channel->StartGettingPorts();
+    return channel;
+  }
+
+ protected:
+  rtc::BasicPacketSocketFactory socket_factory_;
+  cricket::FakePortAllocator allocator_;
+  cricket::FakePortAllocatorSession* session_;
+  // Muxer object will be delete itself after all registered session proxies
+  // are deleted.
+  PortAllocatorSessionMuxer* session_muxer_;
+};
+
+TEST_F(PortAllocatorSessionProxyTest, TestBasic) {
+  TestSessionChannel* channel = CreateChannel();
+  EXPECT_EQ_WAIT(1, channel->candidates_count(), 1000);
+  EXPECT_EQ(1, channel->ports_count());
+  EXPECT_TRUE(channel->allocation_complete());
+  delete channel;
+}
+
+TEST_F(PortAllocatorSessionProxyTest, TestLateBinding) {
+  TestSessionChannel* channel1 = CreateChannel();
+  EXPECT_EQ_WAIT(1, channel1->candidates_count(), 1000);
+  EXPECT_EQ(1, channel1->ports_count());
+  EXPECT_TRUE(channel1->allocation_complete());
+  EXPECT_EQ(1, session_->port_config_count());
+  // Creating another PortAllocatorSessionProxy and it also should receive
+  // already happened events.
+  PortAllocatorSessionProxy* proxy =
+      new PortAllocatorSessionProxy("test content", 2, 0);
+  TestSessionChannel* channel2 = new TestSessionChannel(proxy);
+  session_muxer_->RegisterSessionProxy(proxy);
+  EXPECT_TRUE(channel2->IsGettingPorts());
+  EXPECT_EQ_WAIT(1, channel2->candidates_count(), 1000);
+  EXPECT_EQ(1, channel2->ports_count());
+  EXPECT_TRUE_WAIT(channel2->allocation_complete(), 1000);
+  EXPECT_EQ(1, session_->port_config_count());
+  delete channel1;
+  delete channel2;
+}
diff --git a/p2p/base/portinterface.h b/p2p/base/portinterface.h
new file mode 100644
index 0000000..ee6835e
--- /dev/null
+++ b/p2p/base/portinterface.h
@@ -0,0 +1,126 @@
+/*
+ *  Copyright 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_P2P_BASE_PORTINTERFACE_H_
+#define WEBRTC_P2P_BASE_PORTINTERFACE_H_
+
+#include <string>
+
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace rtc {
+class Network;
+struct PacketOptions;
+}
+
+namespace cricket {
+class Connection;
+class IceMessage;
+class StunMessage;
+
+enum ProtocolType {
+  PROTO_UDP,
+  PROTO_TCP,
+  PROTO_SSLTCP,
+  PROTO_LAST = PROTO_SSLTCP
+};
+
+// Defines the interface for a port, which represents a local communication
+// mechanism that can be used to create connections to similar mechanisms of
+// the other client. Various types of ports will implement this interface.
+class PortInterface {
+ public:
+  virtual ~PortInterface() {}
+
+  virtual const std::string& Type() const = 0;
+  virtual rtc::Network* Network() const = 0;
+
+  virtual void SetIceProtocolType(IceProtocolType protocol) = 0;
+  virtual IceProtocolType IceProtocol() const = 0;
+
+  // Methods to set/get ICE role and tiebreaker values.
+  virtual void SetIceRole(IceRole role) = 0;
+  virtual IceRole GetIceRole() const = 0;
+
+  virtual void SetIceTiebreaker(uint64 tiebreaker) = 0;
+  virtual uint64 IceTiebreaker() const = 0;
+
+  virtual bool SharedSocket() const = 0;
+
+  // PrepareAddress will attempt to get an address for this port that other
+  // clients can send to.  It may take some time before the address is ready.
+  // Once it is ready, we will send SignalAddressReady.  If errors are
+  // preventing the port from getting an address, it may send
+  // SignalAddressError.
+  virtual void PrepareAddress() = 0;
+
+  // Returns the connection to the given address or NULL if none exists.
+  virtual Connection* GetConnection(
+      const rtc::SocketAddress& remote_addr) = 0;
+
+  // Creates a new connection to the given address.
+  enum CandidateOrigin { ORIGIN_THIS_PORT, ORIGIN_OTHER_PORT, ORIGIN_MESSAGE };
+  virtual Connection* CreateConnection(
+      const Candidate& remote_candidate, CandidateOrigin origin) = 0;
+
+  // Functions on the underlying socket(s).
+  virtual int SetOption(rtc::Socket::Option opt, int value) = 0;
+  virtual int GetOption(rtc::Socket::Option opt, int* value) = 0;
+  virtual int GetError() = 0;
+
+  virtual const std::vector<Candidate>& Candidates() const = 0;
+
+  // Sends the given packet to the given address, provided that the address is
+  // that of a connection or an address that has sent to us already.
+  virtual int SendTo(const void* data, size_t size,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options, bool payload) = 0;
+
+  // Indicates that we received a successful STUN binding request from an
+  // address that doesn't correspond to any current connection.  To turn this
+  // into a real connection, call CreateConnection.
+  sigslot::signal6<PortInterface*, const rtc::SocketAddress&,
+                   ProtocolType, IceMessage*, const std::string&,
+                   bool> SignalUnknownAddress;
+
+  // Sends a response message (normal or error) to the given request.  One of
+  // these methods should be called as a response to SignalUnknownAddress.
+  // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse.
+  virtual void SendBindingResponse(StunMessage* request,
+                                   const rtc::SocketAddress& addr) = 0;
+  virtual void SendBindingErrorResponse(
+      StunMessage* request, const rtc::SocketAddress& addr,
+      int error_code, const std::string& reason) = 0;
+
+  // Signaled when this port decides to delete itself because it no longer has
+  // any usefulness.
+  sigslot::signal1<PortInterface*> SignalDestroyed;
+
+  // Signaled when Port discovers ice role conflict with the peer.
+  sigslot::signal1<PortInterface*> SignalRoleConflict;
+
+  // Normally, packets arrive through a connection (or they result signaling of
+  // unknown address).  Calling this method turns off delivery of packets
+  // through their respective connection and instead delivers every packet
+  // through this port.
+  virtual void EnablePortPackets() = 0;
+  sigslot::signal4<PortInterface*, const char*, size_t,
+                   const rtc::SocketAddress&> SignalReadPacket;
+
+  virtual std::string ToString() const = 0;
+
+ protected:
+  PortInterface() {}
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_PORTINTERFACE_H_
diff --git a/p2p/base/portproxy.cc b/p2p/base/portproxy.cc
new file mode 100644
index 0000000..e28af27
--- /dev/null
+++ b/p2p/base/portproxy.cc
@@ -0,0 +1,163 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/portproxy.h"
+
+namespace cricket {
+
+void PortProxy::set_impl(PortInterface* port) {
+  impl_ = port;
+  impl_->SignalUnknownAddress.connect(
+      this, &PortProxy::OnUnknownAddress);
+  impl_->SignalDestroyed.connect(this, &PortProxy::OnPortDestroyed);
+  impl_->SignalRoleConflict.connect(this, &PortProxy::OnRoleConflict);
+}
+
+const std::string& PortProxy::Type() const {
+  ASSERT(impl_ != NULL);
+  return impl_->Type();
+}
+
+rtc::Network* PortProxy::Network() const {
+  ASSERT(impl_ != NULL);
+  return impl_->Network();
+}
+
+void PortProxy::SetIceProtocolType(IceProtocolType protocol) {
+  ASSERT(impl_ != NULL);
+  impl_->SetIceProtocolType(protocol);
+}
+
+IceProtocolType PortProxy::IceProtocol() const {
+  ASSERT(impl_ != NULL);
+  return impl_->IceProtocol();
+}
+
+// Methods to set/get ICE role and tiebreaker values.
+void PortProxy::SetIceRole(IceRole role) {
+  ASSERT(impl_ != NULL);
+  impl_->SetIceRole(role);
+}
+
+IceRole PortProxy::GetIceRole() const {
+  ASSERT(impl_ != NULL);
+  return impl_->GetIceRole();
+}
+
+void PortProxy::SetIceTiebreaker(uint64 tiebreaker) {
+  ASSERT(impl_ != NULL);
+  impl_->SetIceTiebreaker(tiebreaker);
+}
+
+uint64 PortProxy::IceTiebreaker() const {
+  ASSERT(impl_ != NULL);
+  return impl_->IceTiebreaker();
+}
+
+bool PortProxy::SharedSocket() const {
+  ASSERT(impl_ != NULL);
+  return impl_->SharedSocket();
+}
+
+void PortProxy::PrepareAddress() {
+  ASSERT(impl_ != NULL);
+  impl_->PrepareAddress();
+}
+
+Connection* PortProxy::CreateConnection(const Candidate& remote_candidate,
+                                        CandidateOrigin origin) {
+  ASSERT(impl_ != NULL);
+  return impl_->CreateConnection(remote_candidate, origin);
+}
+
+int PortProxy::SendTo(const void* data,
+                      size_t size,
+                      const rtc::SocketAddress& addr,
+                      const rtc::PacketOptions& options,
+                      bool payload) {
+  ASSERT(impl_ != NULL);
+  return impl_->SendTo(data, size, addr, options, payload);
+}
+
+int PortProxy::SetOption(rtc::Socket::Option opt,
+                         int value) {
+  ASSERT(impl_ != NULL);
+  return impl_->SetOption(opt, value);
+}
+
+int PortProxy::GetOption(rtc::Socket::Option opt,
+                         int* value) {
+  ASSERT(impl_ != NULL);
+  return impl_->GetOption(opt, value);
+}
+
+int PortProxy::GetError() {
+  ASSERT(impl_ != NULL);
+  return impl_->GetError();
+}
+
+const std::vector<Candidate>& PortProxy::Candidates() const {
+  ASSERT(impl_ != NULL);
+  return impl_->Candidates();
+}
+
+void PortProxy::SendBindingResponse(
+    StunMessage* request, const rtc::SocketAddress& addr) {
+  ASSERT(impl_ != NULL);
+  impl_->SendBindingResponse(request, addr);
+}
+
+Connection* PortProxy::GetConnection(
+    const rtc::SocketAddress& remote_addr) {
+  ASSERT(impl_ != NULL);
+  return impl_->GetConnection(remote_addr);
+}
+
+void PortProxy::SendBindingErrorResponse(
+    StunMessage* request, const rtc::SocketAddress& addr,
+    int error_code, const std::string& reason) {
+  ASSERT(impl_ != NULL);
+  impl_->SendBindingErrorResponse(request, addr, error_code, reason);
+}
+
+void PortProxy::EnablePortPackets() {
+  ASSERT(impl_ != NULL);
+  impl_->EnablePortPackets();
+}
+
+std::string PortProxy::ToString() const {
+  ASSERT(impl_ != NULL);
+  return impl_->ToString();
+}
+
+void PortProxy::OnUnknownAddress(
+    PortInterface *port,
+    const rtc::SocketAddress &addr,
+    ProtocolType proto,
+    IceMessage *stun_msg,
+    const std::string &remote_username,
+    bool port_muxed) {
+  ASSERT(port == impl_);
+  ASSERT(!port_muxed);
+  SignalUnknownAddress(this, addr, proto, stun_msg, remote_username, true);
+}
+
+void PortProxy::OnRoleConflict(PortInterface* port) {
+  ASSERT(port == impl_);
+  SignalRoleConflict(this);
+}
+
+void PortProxy::OnPortDestroyed(PortInterface* port) {
+  ASSERT(port == impl_);
+  // |port| will be destroyed in PortAllocatorSessionMuxer.
+  SignalDestroyed(this);
+}
+
+}  // namespace cricket
diff --git a/p2p/base/portproxy.h b/p2p/base/portproxy.h
new file mode 100644
index 0000000..79507fe
--- /dev/null
+++ b/p2p/base/portproxy.h
@@ -0,0 +1,87 @@
+/*
+ *  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_P2P_BASE_PORTPROXY_H_
+#define WEBRTC_P2P_BASE_PORTPROXY_H_
+
+#include "webrtc/p2p/base/portinterface.h"
+#include "webrtc/base/sigslot.h"
+
+namespace rtc {
+class Network;
+}
+
+namespace cricket {
+
+class PortProxy : public PortInterface, public sigslot::has_slots<> {
+ public:
+  PortProxy() {}
+  virtual ~PortProxy() {}
+
+  PortInterface* impl() { return impl_; }
+  void set_impl(PortInterface* port);
+
+  virtual const std::string& Type() const;
+  virtual rtc::Network* Network() const;
+
+  virtual void SetIceProtocolType(IceProtocolType protocol);
+  virtual IceProtocolType IceProtocol() const;
+
+  // Methods to set/get ICE role and tiebreaker values.
+  virtual void SetIceRole(IceRole role);
+  virtual IceRole GetIceRole() const;
+
+  virtual void SetIceTiebreaker(uint64 tiebreaker);
+  virtual uint64 IceTiebreaker() const;
+
+  virtual bool SharedSocket() const;
+
+  // Forwards call to the actual Port.
+  virtual void PrepareAddress();
+  virtual Connection* CreateConnection(const Candidate& remote_candidate,
+                                       CandidateOrigin origin);
+  virtual Connection* GetConnection(
+      const rtc::SocketAddress& remote_addr);
+
+  virtual int SendTo(const void* data, size_t size,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options,
+                     bool payload);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetOption(rtc::Socket::Option opt, int* value);
+  virtual int GetError();
+
+  virtual const std::vector<Candidate>& Candidates() const;
+
+  virtual void SendBindingResponse(StunMessage* request,
+                                   const rtc::SocketAddress& addr);
+  virtual void SendBindingErrorResponse(
+        StunMessage* request, const rtc::SocketAddress& addr,
+        int error_code, const std::string& reason);
+
+  virtual void EnablePortPackets();
+  virtual std::string ToString() const;
+
+ private:
+  void OnUnknownAddress(PortInterface *port,
+                        const rtc::SocketAddress &addr,
+                        ProtocolType proto,
+                        IceMessage *stun_msg,
+                        const std::string &remote_username,
+                        bool port_muxed);
+  void OnRoleConflict(PortInterface* port);
+  void OnPortDestroyed(PortInterface* port);
+
+  PortInterface* impl_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_PORTPROXY_H_
diff --git a/p2p/base/pseudotcp.cc b/p2p/base/pseudotcp.cc
new file mode 100644
index 0000000..0dfe7d8
--- /dev/null
+++ b/p2p/base/pseudotcp.cc
@@ -0,0 +1,1274 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/pseudotcp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <set>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/bytebuffer.h"
+#include "webrtc/base/byteorder.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socket.h"
+#include "webrtc/base/stringutils.h"
+#include "webrtc/base/timeutils.h"
+
+// The following logging is for detailed (packet-level) analysis only.
+#define _DBG_NONE     0
+#define _DBG_NORMAL   1
+#define _DBG_VERBOSE  2
+#define _DEBUGMSG _DBG_NONE
+
+namespace cricket {
+
+//////////////////////////////////////////////////////////////////////
+// Network Constants
+//////////////////////////////////////////////////////////////////////
+
+// Standard MTUs
+const uint16 PACKET_MAXIMUMS[] = {
+  65535,    // Theoretical maximum, Hyperchannel
+  32000,    // Nothing
+  17914,    // 16Mb IBM Token Ring
+  8166,   // IEEE 802.4
+  //4464,   // IEEE 802.5 (4Mb max)
+  4352,   // FDDI
+  //2048,   // Wideband Network
+  2002,   // IEEE 802.5 (4Mb recommended)
+  //1536,   // Expermental Ethernet Networks
+  //1500,   // Ethernet, Point-to-Point (default)
+  1492,   // IEEE 802.3
+  1006,   // SLIP, ARPANET
+  //576,    // X.25 Networks
+  //544,    // DEC IP Portal
+  //512,    // NETBIOS
+  508,    // IEEE 802/Source-Rt Bridge, ARCNET
+  296,    // Point-to-Point (low delay)
+  //68,     // Official minimum
+  0,      // End of list marker
+};
+
+const uint32 MAX_PACKET = 65535;
+// Note: we removed lowest level because packet overhead was larger!
+const uint32 MIN_PACKET = 296;
+
+const uint32 IP_HEADER_SIZE = 20; // (+ up to 40 bytes of options?)
+const uint32 UDP_HEADER_SIZE = 8;
+// TODO: Make JINGLE_HEADER_SIZE transparent to this code?
+const uint32 JINGLE_HEADER_SIZE = 64; // when relay framing is in use
+
+// Default size for receive and send buffer.
+const uint32 DEFAULT_RCV_BUF_SIZE = 60 * 1024;
+const uint32 DEFAULT_SND_BUF_SIZE = 90 * 1024;
+
+//////////////////////////////////////////////////////////////////////
+// Global Constants and Functions
+//////////////////////////////////////////////////////////////////////
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |                      Conversation Number                      |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                        Sequence Number                        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |                     Acknowledgment Number                     |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |               |   |U|A|P|R|S|F|                               |
+// 12 |    Control    |   |R|C|S|S|Y|I|            Window             |
+//    |               |   |G|K|H|T|N|N|                               |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |                       Timestamp sending                       |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 |                      Timestamp receiving                      |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 24 |                             data                              |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//////////////////////////////////////////////////////////////////////
+
+#define PSEUDO_KEEPALIVE 0
+
+const uint32 HEADER_SIZE = 24;
+const uint32 PACKET_OVERHEAD = HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE + JINGLE_HEADER_SIZE;
+
+const uint32 MIN_RTO   =   250; // 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a second")
+const uint32 DEF_RTO   =  3000; // 3 seconds (RFC1122, Sec 4.2.3.1)
+const uint32 MAX_RTO   = 60000; // 60 seconds
+const uint32 DEF_ACK_DELAY = 100; // 100 milliseconds
+
+const uint8 FLAG_CTL = 0x02;
+const uint8 FLAG_RST = 0x04;
+
+const uint8 CTL_CONNECT = 0;
+
+// TCP options.
+const uint8 TCP_OPT_EOL = 0;  // End of list.
+const uint8 TCP_OPT_NOOP = 1;  // No-op.
+const uint8 TCP_OPT_MSS = 2;  // Maximum segment size.
+const uint8 TCP_OPT_WND_SCALE = 3;  // Window scale factor.
+
+const long DEFAULT_TIMEOUT = 4000; // If there are no pending clocks, wake up every 4 seconds
+const long CLOSED_TIMEOUT = 60 * 1000; // If the connection is closed, once per minute
+
+#if PSEUDO_KEEPALIVE
+// !?! Rethink these times
+const uint32 IDLE_PING = 20 * 1000; // 20 seconds (note: WinXP SP2 firewall udp timeout is 90 seconds)
+const uint32 IDLE_TIMEOUT = 90 * 1000; // 90 seconds;
+#endif // PSEUDO_KEEPALIVE
+
+//////////////////////////////////////////////////////////////////////
+// Helper Functions
+//////////////////////////////////////////////////////////////////////
+
+inline void long_to_bytes(uint32 val, void* buf) {
+  *static_cast<uint32*>(buf) = rtc::HostToNetwork32(val);
+}
+
+inline void short_to_bytes(uint16 val, void* buf) {
+  *static_cast<uint16*>(buf) = rtc::HostToNetwork16(val);
+}
+
+inline uint32 bytes_to_long(const void* buf) {
+  return rtc::NetworkToHost32(*static_cast<const uint32*>(buf));
+}
+
+inline uint16 bytes_to_short(const void* buf) {
+  return rtc::NetworkToHost16(*static_cast<const uint16*>(buf));
+}
+
+uint32 bound(uint32 lower, uint32 middle, uint32 upper) {
+  return rtc::_min(rtc::_max(lower, middle), upper);
+}
+
+//////////////////////////////////////////////////////////////////////
+// Debugging Statistics
+//////////////////////////////////////////////////////////////////////
+
+#if 0  // Not used yet
+
+enum Stat {
+  S_SENT_PACKET,   // All packet sends
+  S_RESENT_PACKET, // All packet sends that are retransmits
+  S_RECV_PACKET,   // All packet receives
+  S_RECV_NEW,      // All packet receives that are too new
+  S_RECV_OLD,      // All packet receives that are too old
+  S_NUM_STATS
+};
+
+const char* const STAT_NAMES[S_NUM_STATS] = {
+  "snt",
+  "snt-r",
+  "rcv"
+  "rcv-n",
+  "rcv-o"
+};
+
+int g_stats[S_NUM_STATS];
+inline void Incr(Stat s) { ++g_stats[s]; }
+void ReportStats() {
+  char buffer[256];
+  size_t len = 0;
+  for (int i = 0; i < S_NUM_STATS; ++i) {
+    len += rtc::sprintfn(buffer, ARRAY_SIZE(buffer), "%s%s:%d",
+                               (i == 0) ? "" : ",", STAT_NAMES[i], g_stats[i]);
+    g_stats[i] = 0;
+  }
+  LOG(LS_INFO) << "Stats[" << buffer << "]";
+}
+
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// PseudoTcp
+//////////////////////////////////////////////////////////////////////
+
+uint32 PseudoTcp::Now() {
+#if 0  // Use this to synchronize timers with logging timestamps (easier debug)
+  return rtc::TimeSince(StartTime());
+#else
+  return rtc::Time();
+#endif
+}
+
+PseudoTcp::PseudoTcp(IPseudoTcpNotify* notify, uint32 conv)
+    : m_notify(notify),
+      m_shutdown(SD_NONE),
+      m_error(0),
+      m_rbuf_len(DEFAULT_RCV_BUF_SIZE),
+      m_rbuf(m_rbuf_len),
+      m_sbuf_len(DEFAULT_SND_BUF_SIZE),
+      m_sbuf(m_sbuf_len) {
+
+  // Sanity check on buffer sizes (needed for OnTcpWriteable notification logic)
+  ASSERT(m_rbuf_len + MIN_PACKET < m_sbuf_len);
+
+  uint32 now = Now();
+
+  m_state = TCP_LISTEN;
+  m_conv = conv;
+  m_rcv_wnd = m_rbuf_len;
+  m_rwnd_scale = m_swnd_scale = 0;
+  m_snd_nxt = 0;
+  m_snd_wnd = 1;
+  m_snd_una = m_rcv_nxt = 0;
+  m_bReadEnable = true;
+  m_bWriteEnable = false;
+  m_t_ack = 0;
+
+  m_msslevel = 0;
+  m_largest = 0;
+  ASSERT(MIN_PACKET > PACKET_OVERHEAD);
+  m_mss = MIN_PACKET - PACKET_OVERHEAD;
+  m_mtu_advise = MAX_PACKET;
+
+  m_rto_base = 0;
+
+  m_cwnd = 2 * m_mss;
+  m_ssthresh = m_rbuf_len;
+  m_lastrecv = m_lastsend = m_lasttraffic = now;
+  m_bOutgoing = false;
+
+  m_dup_acks = 0;
+  m_recover = 0;
+
+  m_ts_recent = m_ts_lastack = 0;
+
+  m_rx_rto = DEF_RTO;
+  m_rx_srtt = m_rx_rttvar = 0;
+
+  m_use_nagling = true;
+  m_ack_delay = DEF_ACK_DELAY;
+  m_support_wnd_scale = true;
+}
+
+PseudoTcp::~PseudoTcp() {
+}
+
+int PseudoTcp::Connect() {
+  if (m_state != TCP_LISTEN) {
+    m_error = EINVAL;
+    return -1;
+  }
+
+  m_state = TCP_SYN_SENT;
+  LOG(LS_INFO) << "State: TCP_SYN_SENT";
+
+  queueConnectMessage();
+  attemptSend();
+
+  return 0;
+}
+
+void PseudoTcp::NotifyMTU(uint16 mtu) {
+  m_mtu_advise = mtu;
+  if (m_state == TCP_ESTABLISHED) {
+    adjustMTU();
+  }
+}
+
+void PseudoTcp::NotifyClock(uint32 now) {
+  if (m_state == TCP_CLOSED)
+    return;
+
+    // Check if it's time to retransmit a segment
+  if (m_rto_base && (rtc::TimeDiff(m_rto_base + m_rx_rto, now) <= 0)) {
+    if (m_slist.empty()) {
+      ASSERT(false);
+    } else {
+      // Note: (m_slist.front().xmit == 0)) {
+      // retransmit segments
+#if _DEBUGMSG >= _DBG_NORMAL
+      LOG(LS_INFO) << "timeout retransmit (rto: " << m_rx_rto
+                   << ") (rto_base: " << m_rto_base
+                   << ") (now: " << now
+                   << ") (dup_acks: " << static_cast<unsigned>(m_dup_acks)
+                   << ")";
+#endif // _DEBUGMSG
+      if (!transmit(m_slist.begin(), now)) {
+        closedown(ECONNABORTED);
+        return;
+      }
+
+      uint32 nInFlight = m_snd_nxt - m_snd_una;
+      m_ssthresh = rtc::_max(nInFlight / 2, 2 * m_mss);
+      //LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << "  nInFlight: " << nInFlight << "  m_mss: " << m_mss;
+      m_cwnd = m_mss;
+
+      // Back off retransmit timer.  Note: the limit is lower when connecting.
+      uint32 rto_limit = (m_state < TCP_ESTABLISHED) ? DEF_RTO : MAX_RTO;
+      m_rx_rto = rtc::_min(rto_limit, m_rx_rto * 2);
+      m_rto_base = now;
+    }
+  }
+
+  // Check if it's time to probe closed windows
+  if ((m_snd_wnd == 0)
+        && (rtc::TimeDiff(m_lastsend + m_rx_rto, now) <= 0)) {
+    if (rtc::TimeDiff(now, m_lastrecv) >= 15000) {
+      closedown(ECONNABORTED);
+      return;
+    }
+
+    // probe the window
+    packet(m_snd_nxt - 1, 0, 0, 0);
+    m_lastsend = now;
+
+    // back off retransmit timer
+    m_rx_rto = rtc::_min(MAX_RTO, m_rx_rto * 2);
+  }
+
+  // Check if it's time to send delayed acks
+  if (m_t_ack && (rtc::TimeDiff(m_t_ack + m_ack_delay, now) <= 0)) {
+    packet(m_snd_nxt, 0, 0, 0);
+  }
+
+#if PSEUDO_KEEPALIVE
+  // Check for idle timeout
+  if ((m_state == TCP_ESTABLISHED) && (TimeDiff(m_lastrecv + IDLE_TIMEOUT, now) <= 0)) {
+    closedown(ECONNABORTED);
+    return;
+  }
+
+  // Check for ping timeout (to keep udp mapping open)
+  if ((m_state == TCP_ESTABLISHED) && (TimeDiff(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3/2 : IDLE_PING), now) <= 0)) {
+    packet(m_snd_nxt, 0, 0, 0);
+  }
+#endif // PSEUDO_KEEPALIVE
+}
+
+bool PseudoTcp::NotifyPacket(const char* buffer, size_t len) {
+  if (len > MAX_PACKET) {
+    LOG_F(WARNING) << "packet too large";
+    return false;
+  }
+  return parse(reinterpret_cast<const uint8 *>(buffer), uint32(len));
+}
+
+bool PseudoTcp::GetNextClock(uint32 now, long& timeout) {
+  return clock_check(now, timeout);
+}
+
+void PseudoTcp::GetOption(Option opt, int* value) {
+  if (opt == OPT_NODELAY) {
+    *value = m_use_nagling ? 0 : 1;
+  } else if (opt == OPT_ACKDELAY) {
+    *value = m_ack_delay;
+  } else if (opt == OPT_SNDBUF) {
+    *value = m_sbuf_len;
+  } else if (opt == OPT_RCVBUF) {
+    *value = m_rbuf_len;
+  } else {
+    ASSERT(false);
+  }
+}
+void PseudoTcp::SetOption(Option opt, int value) {
+  if (opt == OPT_NODELAY) {
+    m_use_nagling = value == 0;
+  } else if (opt == OPT_ACKDELAY) {
+    m_ack_delay = value;
+  } else if (opt == OPT_SNDBUF) {
+    ASSERT(m_state == TCP_LISTEN);
+    resizeSendBuffer(value);
+  } else if (opt == OPT_RCVBUF) {
+    ASSERT(m_state == TCP_LISTEN);
+    resizeReceiveBuffer(value);
+  } else {
+    ASSERT(false);
+  }
+}
+
+uint32 PseudoTcp::GetCongestionWindow() const {
+  return m_cwnd;
+}
+
+uint32 PseudoTcp::GetBytesInFlight() const {
+  return m_snd_nxt - m_snd_una;
+}
+
+uint32 PseudoTcp::GetBytesBufferedNotSent() const {
+  size_t buffered_bytes = 0;
+  m_sbuf.GetBuffered(&buffered_bytes);
+  return static_cast<uint32>(m_snd_una + buffered_bytes - m_snd_nxt);
+}
+
+uint32 PseudoTcp::GetRoundTripTimeEstimateMs() const {
+  return m_rx_srtt;
+}
+
+//
+// IPStream Implementation
+//
+
+int PseudoTcp::Recv(char* buffer, size_t len) {
+  if (m_state != TCP_ESTABLISHED) {
+    m_error = ENOTCONN;
+    return SOCKET_ERROR;
+  }
+
+  size_t read = 0;
+  rtc::StreamResult result = m_rbuf.Read(buffer, len, &read, NULL);
+
+  // If there's no data in |m_rbuf|.
+  if (result == rtc::SR_BLOCK) {
+    m_bReadEnable = true;
+    m_error = EWOULDBLOCK;
+    return SOCKET_ERROR;
+  }
+  ASSERT(result == rtc::SR_SUCCESS);
+
+  size_t available_space = 0;
+  m_rbuf.GetWriteRemaining(&available_space);
+
+  if (uint32(available_space) - m_rcv_wnd >=
+      rtc::_min<uint32>(m_rbuf_len / 2, m_mss)) {
+    // TODO(jbeda): !?! Not sure about this was closed business
+    bool bWasClosed = (m_rcv_wnd == 0);
+    m_rcv_wnd = static_cast<uint32>(available_space);
+
+    if (bWasClosed) {
+      attemptSend(sfImmediateAck);
+    }
+  }
+
+  return static_cast<int>(read);
+}
+
+int PseudoTcp::Send(const char* buffer, size_t len) {
+  if (m_state != TCP_ESTABLISHED) {
+    m_error = ENOTCONN;
+    return SOCKET_ERROR;
+  }
+
+  size_t available_space = 0;
+  m_sbuf.GetWriteRemaining(&available_space);
+
+  if (!available_space) {
+    m_bWriteEnable = true;
+    m_error = EWOULDBLOCK;
+    return SOCKET_ERROR;
+  }
+
+  int written = queue(buffer, uint32(len), false);
+  attemptSend();
+  return written;
+}
+
+void PseudoTcp::Close(bool force) {
+  LOG_F(LS_VERBOSE) << "(" << (force ? "true" : "false") << ")";
+  m_shutdown = force ? SD_FORCEFUL : SD_GRACEFUL;
+}
+
+int PseudoTcp::GetError() {
+  return m_error;
+}
+
+//
+// Internal Implementation
+//
+
+uint32 PseudoTcp::queue(const char* data, uint32 len, bool bCtrl) {
+  size_t available_space = 0;
+  m_sbuf.GetWriteRemaining(&available_space);
+
+  if (len > static_cast<uint32>(available_space)) {
+    ASSERT(!bCtrl);
+    len = static_cast<uint32>(available_space);
+  }
+
+  // We can concatenate data if the last segment is the same type
+  // (control v. regular data), and has not been transmitted yet
+  if (!m_slist.empty() && (m_slist.back().bCtrl == bCtrl) &&
+      (m_slist.back().xmit == 0)) {
+    m_slist.back().len += len;
+  } else {
+    size_t snd_buffered = 0;
+    m_sbuf.GetBuffered(&snd_buffered);
+    SSegment sseg(static_cast<uint32>(m_snd_una + snd_buffered), len, bCtrl);
+    m_slist.push_back(sseg);
+  }
+
+  size_t written = 0;
+  m_sbuf.Write(data, len, &written, NULL);
+  return static_cast<uint32>(written);
+}
+
+IPseudoTcpNotify::WriteResult PseudoTcp::packet(uint32 seq, uint8 flags,
+                                                uint32 offset, uint32 len) {
+  ASSERT(HEADER_SIZE + len <= MAX_PACKET);
+
+  uint32 now = Now();
+
+  rtc::scoped_ptr<uint8[]> buffer(new uint8[MAX_PACKET]);
+  long_to_bytes(m_conv, buffer.get());
+  long_to_bytes(seq, buffer.get() + 4);
+  long_to_bytes(m_rcv_nxt, buffer.get() + 8);
+  buffer[12] = 0;
+  buffer[13] = flags;
+  short_to_bytes(
+      static_cast<uint16>(m_rcv_wnd >> m_rwnd_scale), buffer.get() + 14);
+
+  // Timestamp computations
+  long_to_bytes(now, buffer.get() + 16);
+  long_to_bytes(m_ts_recent, buffer.get() + 20);
+  m_ts_lastack = m_rcv_nxt;
+
+  if (len) {
+    size_t bytes_read = 0;
+    rtc::StreamResult result = m_sbuf.ReadOffset(
+        buffer.get() + HEADER_SIZE, len, offset, &bytes_read);
+    RTC_UNUSED(result);
+    ASSERT(result == rtc::SR_SUCCESS);
+    ASSERT(static_cast<uint32>(bytes_read) == len);
+  }
+
+#if _DEBUGMSG >= _DBG_VERBOSE
+  LOG(LS_INFO) << "<-- <CONV=" << m_conv
+               << "><FLG=" << static_cast<unsigned>(flags)
+               << "><SEQ=" << seq << ":" << seq + len
+               << "><ACK=" << m_rcv_nxt
+               << "><WND=" << m_rcv_wnd
+               << "><TS="  << (now % 10000)
+               << "><TSR=" << (m_ts_recent % 10000)
+               << "><LEN=" << len << ">";
+#endif // _DEBUGMSG
+
+  IPseudoTcpNotify::WriteResult wres = m_notify->TcpWritePacket(
+      this, reinterpret_cast<char *>(buffer.get()), len + HEADER_SIZE);
+  // Note: When len is 0, this is an ACK packet.  We don't read the return value for those,
+  // and thus we won't retry.  So go ahead and treat the packet as a success (basically simulate
+  // as if it were dropped), which will prevent our timers from being messed up.
+  if ((wres != IPseudoTcpNotify::WR_SUCCESS) && (0 != len))
+    return wres;
+
+  m_t_ack = 0;
+  if (len > 0) {
+    m_lastsend = now;
+  }
+  m_lasttraffic = now;
+  m_bOutgoing = true;
+
+  return IPseudoTcpNotify::WR_SUCCESS;
+}
+
+bool PseudoTcp::parse(const uint8* buffer, uint32 size) {
+  if (size < 12)
+    return false;
+
+  Segment seg;
+  seg.conv = bytes_to_long(buffer);
+  seg.seq = bytes_to_long(buffer + 4);
+  seg.ack = bytes_to_long(buffer + 8);
+  seg.flags = buffer[13];
+  seg.wnd = bytes_to_short(buffer + 14);
+
+  seg.tsval = bytes_to_long(buffer + 16);
+  seg.tsecr = bytes_to_long(buffer + 20);
+
+  seg.data = reinterpret_cast<const char *>(buffer) + HEADER_SIZE;
+  seg.len = size - HEADER_SIZE;
+
+#if _DEBUGMSG >= _DBG_VERBOSE
+  LOG(LS_INFO) << "--> <CONV=" << seg.conv
+               << "><FLG=" << static_cast<unsigned>(seg.flags)
+               << "><SEQ=" << seg.seq << ":" << seg.seq + seg.len
+               << "><ACK=" << seg.ack
+               << "><WND=" << seg.wnd
+               << "><TS="  << (seg.tsval % 10000)
+               << "><TSR=" << (seg.tsecr % 10000)
+               << "><LEN=" << seg.len << ">";
+#endif // _DEBUGMSG
+
+  return process(seg);
+}
+
+bool PseudoTcp::clock_check(uint32 now, long& nTimeout) {
+  if (m_shutdown == SD_FORCEFUL)
+    return false;
+
+  size_t snd_buffered = 0;
+  m_sbuf.GetBuffered(&snd_buffered);
+  if ((m_shutdown == SD_GRACEFUL)
+      && ((m_state != TCP_ESTABLISHED)
+          || ((snd_buffered == 0) && (m_t_ack == 0)))) {
+    return false;
+  }
+
+  if (m_state == TCP_CLOSED) {
+    nTimeout = CLOSED_TIMEOUT;
+    return true;
+  }
+
+  nTimeout = DEFAULT_TIMEOUT;
+
+  if (m_t_ack) {
+    nTimeout = rtc::_min<int32>(nTimeout,
+      rtc::TimeDiff(m_t_ack + m_ack_delay, now));
+  }
+  if (m_rto_base) {
+    nTimeout = rtc::_min<int32>(nTimeout,
+      rtc::TimeDiff(m_rto_base + m_rx_rto, now));
+  }
+  if (m_snd_wnd == 0) {
+    nTimeout = rtc::_min<int32>(nTimeout, rtc::TimeDiff(m_lastsend + m_rx_rto, now));
+  }
+#if PSEUDO_KEEPALIVE
+  if (m_state == TCP_ESTABLISHED) {
+    nTimeout = rtc::_min<int32>(nTimeout,
+      rtc::TimeDiff(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3/2 : IDLE_PING), now));
+  }
+#endif // PSEUDO_KEEPALIVE
+  return true;
+}
+
+bool PseudoTcp::process(Segment& seg) {
+  // If this is the wrong conversation, send a reset!?! (with the correct conversation?)
+  if (seg.conv != m_conv) {
+    //if ((seg.flags & FLAG_RST) == 0) {
+    //  packet(tcb, seg.ack, 0, FLAG_RST, 0, 0);
+    //}
+    LOG_F(LS_ERROR) << "wrong conversation";
+    return false;
+  }
+
+  uint32 now = Now();
+  m_lasttraffic = m_lastrecv = now;
+  m_bOutgoing = false;
+
+  if (m_state == TCP_CLOSED) {
+    // !?! send reset?
+    LOG_F(LS_ERROR) << "closed";
+    return false;
+  }
+
+  // Check if this is a reset segment
+  if (seg.flags & FLAG_RST) {
+    closedown(ECONNRESET);
+    return false;
+  }
+
+  // Check for control data
+  bool bConnect = false;
+  if (seg.flags & FLAG_CTL) {
+    if (seg.len == 0) {
+      LOG_F(LS_ERROR) << "Missing control code";
+      return false;
+    } else if (seg.data[0] == CTL_CONNECT) {
+      bConnect = true;
+
+      // TCP options are in the remainder of the payload after CTL_CONNECT.
+      parseOptions(&seg.data[1], seg.len - 1);
+
+      if (m_state == TCP_LISTEN) {
+        m_state = TCP_SYN_RECEIVED;
+        LOG(LS_INFO) << "State: TCP_SYN_RECEIVED";
+        //m_notify->associate(addr);
+        queueConnectMessage();
+      } else if (m_state == TCP_SYN_SENT) {
+        m_state = TCP_ESTABLISHED;
+        LOG(LS_INFO) << "State: TCP_ESTABLISHED";
+        adjustMTU();
+        if (m_notify) {
+          m_notify->OnTcpOpen(this);
+        }
+        //notify(evOpen);
+      }
+    } else {
+      LOG_F(LS_WARNING) << "Unknown control code: " << seg.data[0];
+      return false;
+    }
+  }
+
+  // Update timestamp
+  if ((seg.seq <= m_ts_lastack) && (m_ts_lastack < seg.seq + seg.len)) {
+    m_ts_recent = seg.tsval;
+  }
+
+  // Check if this is a valuable ack
+  if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) {
+    // Calculate round-trip time
+    if (seg.tsecr) {
+      int32 rtt = rtc::TimeDiff(now, seg.tsecr);
+      if (rtt >= 0) {
+        if (m_rx_srtt == 0) {
+          m_rx_srtt = rtt;
+          m_rx_rttvar = rtt / 2;
+        } else {
+          uint32 unsigned_rtt = static_cast<uint32>(rtt);
+          uint32 abs_err = unsigned_rtt > m_rx_srtt ? unsigned_rtt - m_rx_srtt
+                                                    : m_rx_srtt - unsigned_rtt;
+          m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4;
+          m_rx_srtt = (7 * m_rx_srtt + rtt) / 8;
+        }
+        m_rx_rto = bound(MIN_RTO, m_rx_srtt +
+            rtc::_max<uint32>(1, 4 * m_rx_rttvar), MAX_RTO);
+#if _DEBUGMSG >= _DBG_VERBOSE
+        LOG(LS_INFO) << "rtt: " << rtt
+                     << "  srtt: " << m_rx_srtt
+                     << "  rto: " << m_rx_rto;
+#endif // _DEBUGMSG
+      } else {
+        ASSERT(false);
+      }
+    }
+
+    m_snd_wnd = static_cast<uint32>(seg.wnd) << m_swnd_scale;
+
+    uint32 nAcked = seg.ack - m_snd_una;
+    m_snd_una = seg.ack;
+
+    m_rto_base = (m_snd_una == m_snd_nxt) ? 0 : now;
+
+    m_sbuf.ConsumeReadData(nAcked);
+
+    for (uint32 nFree = nAcked; nFree > 0; ) {
+      ASSERT(!m_slist.empty());
+      if (nFree < m_slist.front().len) {
+        m_slist.front().len -= nFree;
+        nFree = 0;
+      } else {
+        if (m_slist.front().len > m_largest) {
+          m_largest = m_slist.front().len;
+        }
+        nFree -= m_slist.front().len;
+        m_slist.pop_front();
+      }
+    }
+
+    if (m_dup_acks >= 3) {
+      if (m_snd_una >= m_recover) { // NewReno
+        uint32 nInFlight = m_snd_nxt - m_snd_una;
+        m_cwnd = rtc::_min(m_ssthresh, nInFlight + m_mss); // (Fast Retransmit)
+#if _DEBUGMSG >= _DBG_NORMAL
+        LOG(LS_INFO) << "exit recovery";
+#endif // _DEBUGMSG
+        m_dup_acks = 0;
+      } else {
+#if _DEBUGMSG >= _DBG_NORMAL
+        LOG(LS_INFO) << "recovery retransmit";
+#endif // _DEBUGMSG
+        if (!transmit(m_slist.begin(), now)) {
+          closedown(ECONNABORTED);
+          return false;
+        }
+        m_cwnd += m_mss - rtc::_min(nAcked, m_cwnd);
+      }
+    } else {
+      m_dup_acks = 0;
+      // Slow start, congestion avoidance
+      if (m_cwnd < m_ssthresh) {
+        m_cwnd += m_mss;
+      } else {
+        m_cwnd += rtc::_max<uint32>(1, m_mss * m_mss / m_cwnd);
+      }
+    }
+  } else if (seg.ack == m_snd_una) {
+    // !?! Note, tcp says don't do this... but otherwise how does a closed window become open?
+    m_snd_wnd = static_cast<uint32>(seg.wnd) << m_swnd_scale;
+
+    // Check duplicate acks
+    if (seg.len > 0) {
+      // it's a dup ack, but with a data payload, so don't modify m_dup_acks
+    } else if (m_snd_una != m_snd_nxt) {
+      m_dup_acks += 1;
+      if (m_dup_acks == 3) { // (Fast Retransmit)
+#if _DEBUGMSG >= _DBG_NORMAL
+        LOG(LS_INFO) << "enter recovery";
+        LOG(LS_INFO) << "recovery retransmit";
+#endif // _DEBUGMSG
+        if (!transmit(m_slist.begin(), now)) {
+          closedown(ECONNABORTED);
+          return false;
+        }
+        m_recover = m_snd_nxt;
+        uint32 nInFlight = m_snd_nxt - m_snd_una;
+        m_ssthresh = rtc::_max(nInFlight / 2, 2 * m_mss);
+        //LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << "  nInFlight: " << nInFlight << "  m_mss: " << m_mss;
+        m_cwnd = m_ssthresh + 3 * m_mss;
+      } else if (m_dup_acks > 3) {
+        m_cwnd += m_mss;
+      }
+    } else {
+      m_dup_acks = 0;
+    }
+  }
+
+  // !?! A bit hacky
+  if ((m_state == TCP_SYN_RECEIVED) && !bConnect) {
+    m_state = TCP_ESTABLISHED;
+    LOG(LS_INFO) << "State: TCP_ESTABLISHED";
+    adjustMTU();
+    if (m_notify) {
+      m_notify->OnTcpOpen(this);
+    }
+    //notify(evOpen);
+  }
+
+  // If we make room in the send queue, notify the user
+  // The goal it to make sure we always have at least enough data to fill the
+  // window.  We'd like to notify the app when we are halfway to that point.
+  const uint32 kIdealRefillSize = (m_sbuf_len + m_rbuf_len) / 2;
+  size_t snd_buffered = 0;
+  m_sbuf.GetBuffered(&snd_buffered);
+  if (m_bWriteEnable && static_cast<uint32>(snd_buffered) < kIdealRefillSize) {
+    m_bWriteEnable = false;
+    if (m_notify) {
+      m_notify->OnTcpWriteable(this);
+    }
+    //notify(evWrite);
+  }
+
+  // Conditions were acks must be sent:
+  // 1) Segment is too old (they missed an ACK) (immediately)
+  // 2) Segment is too new (we missed a segment) (immediately)
+  // 3) Segment has data (so we need to ACK!) (delayed)
+  // ... so the only time we don't need to ACK, is an empty segment that points to rcv_nxt!
+
+  SendFlags sflags = sfNone;
+  if (seg.seq != m_rcv_nxt) {
+    sflags = sfImmediateAck; // (Fast Recovery)
+  } else if (seg.len != 0) {
+    if (m_ack_delay == 0) {
+      sflags = sfImmediateAck;
+    } else {
+      sflags = sfDelayedAck;
+    }
+  }
+#if _DEBUGMSG >= _DBG_NORMAL
+  if (sflags == sfImmediateAck) {
+    if (seg.seq > m_rcv_nxt) {
+      LOG_F(LS_INFO) << "too new";
+    } else if (seg.seq + seg.len <= m_rcv_nxt) {
+      LOG_F(LS_INFO) << "too old";
+    }
+  }
+#endif // _DEBUGMSG
+
+  // Adjust the incoming segment to fit our receive buffer
+  if (seg.seq < m_rcv_nxt) {
+    uint32 nAdjust = m_rcv_nxt - seg.seq;
+    if (nAdjust < seg.len) {
+      seg.seq += nAdjust;
+      seg.data += nAdjust;
+      seg.len -= nAdjust;
+    } else {
+      seg.len = 0;
+    }
+  }
+
+  size_t available_space = 0;
+  m_rbuf.GetWriteRemaining(&available_space);
+
+  if ((seg.seq + seg.len - m_rcv_nxt) > static_cast<uint32>(available_space)) {
+    uint32 nAdjust = seg.seq + seg.len - m_rcv_nxt - static_cast<uint32>(available_space);
+    if (nAdjust < seg.len) {
+      seg.len -= nAdjust;
+    } else {
+      seg.len = 0;
+    }
+  }
+
+  bool bIgnoreData = (seg.flags & FLAG_CTL) || (m_shutdown != SD_NONE);
+  bool bNewData = false;
+
+  if (seg.len > 0) {
+    if (bIgnoreData) {
+      if (seg.seq == m_rcv_nxt) {
+        m_rcv_nxt += seg.len;
+      }
+    } else {
+      uint32 nOffset = seg.seq - m_rcv_nxt;
+
+      rtc::StreamResult result = m_rbuf.WriteOffset(seg.data, seg.len,
+                                                          nOffset, NULL);
+      ASSERT(result == rtc::SR_SUCCESS);
+      RTC_UNUSED(result);
+
+      if (seg.seq == m_rcv_nxt) {
+        m_rbuf.ConsumeWriteBuffer(seg.len);
+        m_rcv_nxt += seg.len;
+        m_rcv_wnd -= seg.len;
+        bNewData = true;
+
+        RList::iterator it = m_rlist.begin();
+        while ((it != m_rlist.end()) && (it->seq <= m_rcv_nxt)) {
+          if (it->seq + it->len > m_rcv_nxt) {
+            sflags = sfImmediateAck; // (Fast Recovery)
+            uint32 nAdjust = (it->seq + it->len) - m_rcv_nxt;
+#if _DEBUGMSG >= _DBG_NORMAL
+            LOG(LS_INFO) << "Recovered " << nAdjust << " bytes (" << m_rcv_nxt << " -> " << m_rcv_nxt + nAdjust << ")";
+#endif // _DEBUGMSG
+            m_rbuf.ConsumeWriteBuffer(nAdjust);
+            m_rcv_nxt += nAdjust;
+            m_rcv_wnd -= nAdjust;
+          }
+          it = m_rlist.erase(it);
+        }
+      } else {
+#if _DEBUGMSG >= _DBG_NORMAL
+        LOG(LS_INFO) << "Saving " << seg.len << " bytes (" << seg.seq << " -> " << seg.seq + seg.len << ")";
+#endif // _DEBUGMSG
+        RSegment rseg;
+        rseg.seq = seg.seq;
+        rseg.len = seg.len;
+        RList::iterator it = m_rlist.begin();
+        while ((it != m_rlist.end()) && (it->seq < rseg.seq)) {
+          ++it;
+        }
+        m_rlist.insert(it, rseg);
+      }
+    }
+  }
+
+  attemptSend(sflags);
+
+  // If we have new data, notify the user
+  if (bNewData && m_bReadEnable) {
+    m_bReadEnable = false;
+    if (m_notify) {
+      m_notify->OnTcpReadable(this);
+    }
+    //notify(evRead);
+  }
+
+  return true;
+}
+
+bool PseudoTcp::transmit(const SList::iterator& seg, uint32 now) {
+  if (seg->xmit >= ((m_state == TCP_ESTABLISHED) ? 15 : 30)) {
+    LOG_F(LS_VERBOSE) << "too many retransmits";
+    return false;
+  }
+
+  uint32 nTransmit = rtc::_min(seg->len, m_mss);
+
+  while (true) {
+    uint32 seq = seg->seq;
+    uint8 flags = (seg->bCtrl ? FLAG_CTL : 0);
+    IPseudoTcpNotify::WriteResult wres = packet(seq,
+                                                flags,
+                                                seg->seq - m_snd_una,
+                                                nTransmit);
+
+    if (wres == IPseudoTcpNotify::WR_SUCCESS)
+      break;
+
+    if (wres == IPseudoTcpNotify::WR_FAIL) {
+      LOG_F(LS_VERBOSE) << "packet failed";
+      return false;
+    }
+
+    ASSERT(wres == IPseudoTcpNotify::WR_TOO_LARGE);
+
+    while (true) {
+      if (PACKET_MAXIMUMS[m_msslevel + 1] == 0) {
+        LOG_F(LS_VERBOSE) << "MTU too small";
+        return false;
+      }
+      // !?! We need to break up all outstanding and pending packets and then retransmit!?!
+
+      m_mss = PACKET_MAXIMUMS[++m_msslevel] - PACKET_OVERHEAD;
+      m_cwnd = 2 * m_mss; // I added this... haven't researched actual formula
+      if (m_mss < nTransmit) {
+        nTransmit = m_mss;
+        break;
+      }
+    }
+#if _DEBUGMSG >= _DBG_NORMAL
+    LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes";
+#endif // _DEBUGMSG
+  }
+
+  if (nTransmit < seg->len) {
+    LOG_F(LS_VERBOSE) << "mss reduced to " << m_mss;
+
+    SSegment subseg(seg->seq + nTransmit, seg->len - nTransmit, seg->bCtrl);
+    //subseg.tstamp = seg->tstamp;
+    subseg.xmit = seg->xmit;
+    seg->len = nTransmit;
+
+    SList::iterator next = seg;
+    m_slist.insert(++next, subseg);
+  }
+
+  if (seg->xmit == 0) {
+    m_snd_nxt += seg->len;
+  }
+  seg->xmit += 1;
+  //seg->tstamp = now;
+  if (m_rto_base == 0) {
+    m_rto_base = now;
+  }
+
+  return true;
+}
+
+void PseudoTcp::attemptSend(SendFlags sflags) {
+  uint32 now = Now();
+
+  if (rtc::TimeDiff(now, m_lastsend) > static_cast<long>(m_rx_rto)) {
+    m_cwnd = m_mss;
+  }
+
+#if _DEBUGMSG
+  bool bFirst = true;
+  RTC_UNUSED(bFirst);
+#endif // _DEBUGMSG
+
+  while (true) {
+    uint32 cwnd = m_cwnd;
+    if ((m_dup_acks == 1) || (m_dup_acks == 2)) { // Limited Transmit
+      cwnd += m_dup_acks * m_mss;
+    }
+    uint32 nWindow = rtc::_min(m_snd_wnd, cwnd);
+    uint32 nInFlight = m_snd_nxt - m_snd_una;
+    uint32 nUseable = (nInFlight < nWindow) ? (nWindow - nInFlight) : 0;
+
+    size_t snd_buffered = 0;
+    m_sbuf.GetBuffered(&snd_buffered);
+    uint32 nAvailable =
+        rtc::_min(static_cast<uint32>(snd_buffered) - nInFlight, m_mss);
+
+    if (nAvailable > nUseable) {
+      if (nUseable * 4 < nWindow) {
+        // RFC 813 - avoid SWS
+        nAvailable = 0;
+      } else {
+        nAvailable = nUseable;
+      }
+    }
+
+#if _DEBUGMSG >= _DBG_VERBOSE
+    if (bFirst) {
+      size_t available_space = 0;
+      m_sbuf.GetWriteRemaining(&available_space);
+
+      bFirst = false;
+      LOG(LS_INFO) << "[cwnd: " << m_cwnd
+                   << "  nWindow: " << nWindow
+                   << "  nInFlight: " << nInFlight
+                   << "  nAvailable: " << nAvailable
+                   << "  nQueued: " << snd_buffered
+                   << "  nEmpty: " << available_space
+                   << "  ssthresh: " << m_ssthresh << "]";
+    }
+#endif // _DEBUGMSG
+
+    if (nAvailable == 0) {
+      if (sflags == sfNone)
+        return;
+
+      // If this is an immediate ack, or the second delayed ack
+      if ((sflags == sfImmediateAck) || m_t_ack) {
+        packet(m_snd_nxt, 0, 0, 0);
+      } else {
+        m_t_ack = Now();
+      }
+      return;
+    }
+
+    // Nagle's algorithm.
+    // If there is data already in-flight, and we haven't a full segment of
+    // data ready to send then hold off until we get more to send, or the
+    // in-flight data is acknowledged.
+    if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss))  {
+      return;
+    }
+
+    // Find the next segment to transmit
+    SList::iterator it = m_slist.begin();
+    while (it->xmit > 0) {
+      ++it;
+      ASSERT(it != m_slist.end());
+    }
+    SList::iterator seg = it;
+
+    // If the segment is too large, break it into two
+    if (seg->len > nAvailable) {
+      SSegment subseg(seg->seq + nAvailable, seg->len - nAvailable, seg->bCtrl);
+      seg->len = nAvailable;
+      m_slist.insert(++it, subseg);
+    }
+
+    if (!transmit(seg, now)) {
+      LOG_F(LS_VERBOSE) << "transmit failed";
+      // TODO: consider closing socket
+      return;
+    }
+
+    sflags = sfNone;
+  }
+}
+
+void
+PseudoTcp::closedown(uint32 err) {
+  LOG(LS_INFO) << "State: TCP_CLOSED";
+  m_state = TCP_CLOSED;
+  if (m_notify) {
+    m_notify->OnTcpClosed(this, err);
+  }
+  //notify(evClose, err);
+}
+
+void
+PseudoTcp::adjustMTU() {
+  // Determine our current mss level, so that we can adjust appropriately later
+  for (m_msslevel = 0; PACKET_MAXIMUMS[m_msslevel + 1] > 0; ++m_msslevel) {
+    if (static_cast<uint16>(PACKET_MAXIMUMS[m_msslevel]) <= m_mtu_advise) {
+      break;
+    }
+  }
+  m_mss = m_mtu_advise - PACKET_OVERHEAD;
+  // !?! Should we reset m_largest here?
+#if _DEBUGMSG >= _DBG_NORMAL
+  LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes";
+#endif // _DEBUGMSG
+  // Enforce minimums on ssthresh and cwnd
+  m_ssthresh = rtc::_max(m_ssthresh, 2 * m_mss);
+  m_cwnd = rtc::_max(m_cwnd, m_mss);
+}
+
+bool
+PseudoTcp::isReceiveBufferFull() const {
+  size_t available_space = 0;
+  m_rbuf.GetWriteRemaining(&available_space);
+  return !available_space;
+}
+
+void
+PseudoTcp::disableWindowScale() {
+  m_support_wnd_scale = false;
+}
+
+void
+PseudoTcp::queueConnectMessage() {
+  rtc::ByteBuffer buf(rtc::ByteBuffer::ORDER_NETWORK);
+
+  buf.WriteUInt8(CTL_CONNECT);
+  if (m_support_wnd_scale) {
+    buf.WriteUInt8(TCP_OPT_WND_SCALE);
+    buf.WriteUInt8(1);
+    buf.WriteUInt8(m_rwnd_scale);
+  }
+  m_snd_wnd = static_cast<uint32>(buf.Length());
+  queue(buf.Data(), static_cast<uint32>(buf.Length()), true);
+}
+
+void
+PseudoTcp::parseOptions(const char* data, uint32 len) {
+  std::set<uint8> options_specified;
+
+  // See http://www.freesoft.org/CIE/Course/Section4/8.htm for
+  // parsing the options list.
+  rtc::ByteBuffer buf(data, len);
+  while (buf.Length()) {
+    uint8 kind = TCP_OPT_EOL;
+    buf.ReadUInt8(&kind);
+
+    if (kind == TCP_OPT_EOL) {
+      // End of option list.
+      break;
+    } else if (kind == TCP_OPT_NOOP) {
+      // No op.
+      continue;
+    }
+
+    // Length of this option.
+    ASSERT(len != 0);
+    RTC_UNUSED(len);
+    uint8 opt_len = 0;
+    buf.ReadUInt8(&opt_len);
+
+    // Content of this option.
+    if (opt_len <= buf.Length()) {
+      applyOption(kind, buf.Data(), opt_len);
+      buf.Consume(opt_len);
+    } else {
+      LOG(LS_ERROR) << "Invalid option length received.";
+      return;
+    }
+    options_specified.insert(kind);
+  }
+
+  if (options_specified.find(TCP_OPT_WND_SCALE) == options_specified.end()) {
+    LOG(LS_WARNING) << "Peer doesn't support window scaling";
+
+    if (m_rwnd_scale > 0) {
+      // Peer doesn't support TCP options and window scaling.
+      // Revert receive buffer size to default value.
+      resizeReceiveBuffer(DEFAULT_RCV_BUF_SIZE);
+      m_swnd_scale = 0;
+    }
+  }
+}
+
+void
+PseudoTcp::applyOption(char kind, const char* data, uint32 len) {
+  if (kind == TCP_OPT_MSS) {
+    LOG(LS_WARNING) << "Peer specified MSS option which is not supported.";
+    // TODO: Implement.
+  } else if (kind == TCP_OPT_WND_SCALE) {
+    // Window scale factor.
+    // http://www.ietf.org/rfc/rfc1323.txt
+    if (len != 1) {
+      LOG_F(WARNING) << "Invalid window scale option received.";
+      return;
+    }
+    applyWindowScaleOption(data[0]);
+  }
+}
+
+void
+PseudoTcp::applyWindowScaleOption(uint8 scale_factor) {
+  m_swnd_scale = scale_factor;
+}
+
+void
+PseudoTcp::resizeSendBuffer(uint32 new_size) {
+  m_sbuf_len = new_size;
+  m_sbuf.SetCapacity(new_size);
+}
+
+void
+PseudoTcp::resizeReceiveBuffer(uint32 new_size) {
+  uint8 scale_factor = 0;
+
+  // Determine the scale factor such that the scaled window size can fit
+  // in a 16-bit unsigned integer.
+  while (new_size > 0xFFFF) {
+    ++scale_factor;
+    new_size >>= 1;
+  }
+
+  // Determine the proper size of the buffer.
+  new_size <<= scale_factor;
+  bool result = m_rbuf.SetCapacity(new_size);
+
+  // Make sure the new buffer is large enough to contain data in the old
+  // buffer. This should always be true because this method is called either
+  // before connection is established or when peers are exchanging connect
+  // messages.
+  ASSERT(result);
+  RTC_UNUSED(result);
+  m_rbuf_len = new_size;
+  m_rwnd_scale = scale_factor;
+  m_ssthresh = new_size;
+
+  size_t available_space = 0;
+  m_rbuf.GetWriteRemaining(&available_space);
+  m_rcv_wnd = static_cast<uint32>(available_space);
+}
+
+}  // namespace cricket
diff --git a/p2p/base/pseudotcp.h b/p2p/base/pseudotcp.h
new file mode 100644
index 0000000..b2cfcb7
--- /dev/null
+++ b/p2p/base/pseudotcp.h
@@ -0,0 +1,241 @@
+/*
+ *  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_P2P_BASE_PSEUDOTCP_H_
+#define WEBRTC_P2P_BASE_PSEUDOTCP_H_
+
+#include <list>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/stream.h"
+
+namespace cricket {
+
+//////////////////////////////////////////////////////////////////////
+// IPseudoTcpNotify
+//////////////////////////////////////////////////////////////////////
+
+class PseudoTcp;
+
+class IPseudoTcpNotify {
+ public:
+  // Notification of tcp events
+  virtual void OnTcpOpen(PseudoTcp* tcp) = 0;
+  virtual void OnTcpReadable(PseudoTcp* tcp) = 0;
+  virtual void OnTcpWriteable(PseudoTcp* tcp) = 0;
+  virtual void OnTcpClosed(PseudoTcp* tcp, uint32 error) = 0;
+
+  // Write the packet onto the network
+  enum WriteResult { WR_SUCCESS, WR_TOO_LARGE, WR_FAIL };
+  virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
+                                     const char* buffer, size_t len) = 0;
+
+ protected:
+  virtual ~IPseudoTcpNotify() {}
+};
+
+//////////////////////////////////////////////////////////////////////
+// PseudoTcp
+//////////////////////////////////////////////////////////////////////
+
+class PseudoTcp {
+ public:
+  static uint32 Now();
+
+  PseudoTcp(IPseudoTcpNotify* notify, uint32 conv);
+  virtual ~PseudoTcp();
+
+  int Connect();
+  int Recv(char* buffer, size_t len);
+  int Send(const char* buffer, size_t len);
+  void Close(bool force);
+  int GetError();
+
+  enum TcpState {
+    TCP_LISTEN, TCP_SYN_SENT, TCP_SYN_RECEIVED, TCP_ESTABLISHED, TCP_CLOSED
+  };
+  TcpState State() const { return m_state; }
+
+  // Call this when the PMTU changes.
+  void NotifyMTU(uint16 mtu);
+
+  // Call this based on timeout value returned from GetNextClock.
+  // It's ok to call this too frequently.
+  void NotifyClock(uint32 now);
+
+  // Call this whenever a packet arrives.
+  // Returns true if the packet was processed successfully.
+  bool NotifyPacket(const char * buffer, size_t len);
+
+  // Call this to determine the next time NotifyClock should be called.
+  // Returns false if the socket is ready to be destroyed.
+  bool GetNextClock(uint32 now, long& timeout);
+
+  // Call these to get/set option values to tailor this PseudoTcp
+  // instance's behaviour for the kind of data it will carry.
+  // If an unrecognized option is set or got, an assertion will fire.
+  //
+  // Setting options for OPT_RCVBUF or OPT_SNDBUF after Connect() is called
+  // will result in an assertion.
+  enum Option {
+    OPT_NODELAY,      // Whether to enable Nagle's algorithm (0 == off)
+    OPT_ACKDELAY,     // The Delayed ACK timeout (0 == off).
+    OPT_RCVBUF,       // Set the receive buffer size, in bytes.
+    OPT_SNDBUF,       // Set the send buffer size, in bytes.
+  };
+  void GetOption(Option opt, int* value);
+  void SetOption(Option opt, int value);
+
+  // Returns current congestion window in bytes.
+  uint32 GetCongestionWindow() const;
+
+  // Returns amount of data in bytes that has been sent, but haven't
+  // been acknowledged.
+  uint32 GetBytesInFlight() const;
+
+  // Returns number of bytes that were written in buffer and haven't
+  // been sent.
+  uint32 GetBytesBufferedNotSent() const;
+
+  // Returns current round-trip time estimate in milliseconds.
+  uint32 GetRoundTripTimeEstimateMs() const;
+
+ protected:
+  enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck };
+
+  struct Segment {
+    uint32 conv, seq, ack;
+    uint8 flags;
+    uint16 wnd;
+    const char * data;
+    uint32 len;
+    uint32 tsval, tsecr;
+  };
+
+  struct SSegment {
+    SSegment(uint32 s, uint32 l, bool c)
+        : seq(s), len(l), /*tstamp(0),*/ xmit(0), bCtrl(c) {
+    }
+    uint32 seq, len;
+    //uint32 tstamp;
+    uint8 xmit;
+    bool bCtrl;
+  };
+  typedef std::list<SSegment> SList;
+
+  struct RSegment {
+    uint32 seq, len;
+  };
+
+  uint32 queue(const char* data, uint32 len, bool bCtrl);
+
+  // Creates a packet and submits it to the network. This method can either
+  // send payload or just an ACK packet.
+  //
+  // |seq| is the sequence number of this packet.
+  // |flags| is the flags for sending this packet.
+  // |offset| is the offset to read from |m_sbuf|.
+  // |len| is the number of bytes to read from |m_sbuf| as payload. If this
+  // value is 0 then this is an ACK packet, otherwise this packet has payload.
+  IPseudoTcpNotify::WriteResult packet(uint32 seq, uint8 flags,
+                                       uint32 offset, uint32 len);
+  bool parse(const uint8* buffer, uint32 size);
+
+  void attemptSend(SendFlags sflags = sfNone);
+
+  void closedown(uint32 err = 0);
+
+  bool clock_check(uint32 now, long& nTimeout);
+
+  bool process(Segment& seg);
+  bool transmit(const SList::iterator& seg, uint32 now);
+
+  void adjustMTU();
+
+ protected:
+  // This method is used in test only to query receive buffer state.
+  bool isReceiveBufferFull() const;
+
+  // This method is only used in tests, to disable window scaling
+  // support for testing backward compatibility.
+  void disableWindowScale();
+
+ private:
+  // Queue the connect message with TCP options.
+  void queueConnectMessage();
+
+  // Parse TCP options in the header.
+  void parseOptions(const char* data, uint32 len);
+
+  // Apply a TCP option that has been read from the header.
+  void applyOption(char kind, const char* data, uint32 len);
+
+  // Apply window scale option.
+  void applyWindowScaleOption(uint8 scale_factor);
+
+  // Resize the send buffer with |new_size| in bytes.
+  void resizeSendBuffer(uint32 new_size);
+
+  // Resize the receive buffer with |new_size| in bytes. This call adjusts
+  // window scale factor |m_swnd_scale| accordingly.
+  void resizeReceiveBuffer(uint32 new_size);
+
+  IPseudoTcpNotify* m_notify;
+  enum Shutdown { SD_NONE, SD_GRACEFUL, SD_FORCEFUL } m_shutdown;
+  int m_error;
+
+  // TCB data
+  TcpState m_state;
+  uint32 m_conv;
+  bool m_bReadEnable, m_bWriteEnable, m_bOutgoing;
+  uint32 m_lasttraffic;
+
+  // Incoming data
+  typedef std::list<RSegment> RList;
+  RList m_rlist;
+  uint32 m_rbuf_len, m_rcv_nxt, m_rcv_wnd, m_lastrecv;
+  uint8 m_rwnd_scale;  // Window scale factor.
+  rtc::FifoBuffer m_rbuf;
+
+  // Outgoing data
+  SList m_slist;
+  uint32 m_sbuf_len, m_snd_nxt, m_snd_wnd, m_lastsend, m_snd_una;
+  uint8 m_swnd_scale;  // Window scale factor.
+  rtc::FifoBuffer m_sbuf;
+
+  // Maximum segment size, estimated protocol level, largest segment sent
+  uint32 m_mss, m_msslevel, m_largest, m_mtu_advise;
+  // Retransmit timer
+  uint32 m_rto_base;
+
+  // Timestamp tracking
+  uint32 m_ts_recent, m_ts_lastack;
+
+  // Round-trip calculation
+  uint32 m_rx_rttvar, m_rx_srtt, m_rx_rto;
+
+  // Congestion avoidance, Fast retransmit/recovery, Delayed ACKs
+  uint32 m_ssthresh, m_cwnd;
+  uint8 m_dup_acks;
+  uint32 m_recover;
+  uint32 m_t_ack;
+
+  // Configuration options
+  bool m_use_nagling;
+  uint32 m_ack_delay;
+
+  // This is used by unit tests to test backward compatibility of
+  // PseudoTcp implementations that don't support window scaling.
+  bool m_support_wnd_scale;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_PSEUDOTCP_H_
diff --git a/p2p/base/pseudotcp_unittest.cc b/p2p/base/pseudotcp_unittest.cc
new file mode 100644
index 0000000..f5ea7ac
--- /dev/null
+++ b/p2p/base/pseudotcp_unittest.cc
@@ -0,0 +1,841 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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 <vector>
+
+#include "webrtc/p2p/base/pseudotcp.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/messagehandler.h"
+#include "webrtc/base/stream.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/timeutils.h"
+
+using cricket::PseudoTcp;
+
+static const int kConnectTimeoutMs = 10000;  // ~3 * default RTO of 3000ms
+static const int kTransferTimeoutMs = 15000;
+static const int kBlockSize = 4096;
+
+class PseudoTcpForTest : public cricket::PseudoTcp {
+ public:
+  PseudoTcpForTest(cricket::IPseudoTcpNotify* notify, uint32 conv)
+      : PseudoTcp(notify, conv) {
+  }
+
+  bool isReceiveBufferFull() const {
+    return PseudoTcp::isReceiveBufferFull();
+  }
+
+  void disableWindowScale() {
+    PseudoTcp::disableWindowScale();
+  }
+};
+
+class PseudoTcpTestBase : public testing::Test,
+                      public rtc::MessageHandler,
+                      public cricket::IPseudoTcpNotify {
+ public:
+  PseudoTcpTestBase()
+      : local_(this, 1),
+        remote_(this, 1),
+        have_connected_(false),
+        have_disconnected_(false),
+        local_mtu_(65535),
+        remote_mtu_(65535),
+        delay_(0),
+        loss_(0) {
+    // Set use of the test RNG to get predictable loss patterns.
+    rtc::SetRandomTestMode(true);
+  }
+  ~PseudoTcpTestBase() {
+    // Put it back for the next test.
+    rtc::SetRandomTestMode(false);
+  }
+  void SetLocalMtu(int mtu) {
+    local_.NotifyMTU(mtu);
+    local_mtu_ = mtu;
+  }
+  void SetRemoteMtu(int mtu) {
+    remote_.NotifyMTU(mtu);
+    remote_mtu_ = mtu;
+  }
+  void SetDelay(int delay) {
+    delay_ = delay;
+  }
+  void SetLoss(int percent) {
+    loss_ = percent;
+  }
+  void SetOptNagling(bool enable_nagles) {
+    local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
+    remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
+  }
+  void SetOptAckDelay(int ack_delay) {
+    local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
+    remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
+  }
+  void SetOptSndBuf(int size) {
+    local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
+    remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
+  }
+  void SetRemoteOptRcvBuf(int size) {
+    remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
+  }
+  void SetLocalOptRcvBuf(int size) {
+    local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
+  }
+  void DisableRemoteWindowScale() {
+    remote_.disableWindowScale();
+  }
+  void DisableLocalWindowScale() {
+    local_.disableWindowScale();
+  }
+
+ protected:
+  int Connect() {
+    int ret = local_.Connect();
+    if (ret == 0) {
+      UpdateLocalClock();
+    }
+    return ret;
+  }
+  void Close() {
+    local_.Close(false);
+    UpdateLocalClock();
+  }
+
+  enum { MSG_LPACKET, MSG_RPACKET, MSG_LCLOCK, MSG_RCLOCK, MSG_IOCOMPLETE,
+         MSG_WRITE};
+  virtual void OnTcpOpen(PseudoTcp* tcp) {
+    // Consider ourselves connected when the local side gets OnTcpOpen.
+    // OnTcpWriteable isn't fired at open, so we trigger it now.
+    LOG(LS_VERBOSE) << "Opened";
+    if (tcp == &local_) {
+      have_connected_ = true;
+      OnTcpWriteable(tcp);
+    }
+  }
+  // Test derived from the base should override
+  //   virtual void OnTcpReadable(PseudoTcp* tcp)
+  // and
+  //   virtual void OnTcpWritable(PseudoTcp* tcp)
+  virtual void OnTcpClosed(PseudoTcp* tcp, uint32 error) {
+    // Consider ourselves closed when the remote side gets OnTcpClosed.
+    // TODO: OnTcpClosed is only ever notified in case of error in
+    // the current implementation.  Solicited close is not (yet) supported.
+    LOG(LS_VERBOSE) << "Closed";
+    EXPECT_EQ(0U, error);
+    if (tcp == &remote_) {
+      have_disconnected_ = true;
+    }
+  }
+  virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
+                                     const char* buffer, size_t len) {
+    // Randomly drop the desired percentage of packets.
+    // Also drop packets that are larger than the configured MTU.
+    if (rtc::CreateRandomId() % 100 < static_cast<uint32>(loss_)) {
+      LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
+    } else if (len > static_cast<size_t>(
+        rtc::_min(local_mtu_, remote_mtu_))) {
+      LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size=" << len;
+    } else {
+      int id = (tcp == &local_) ? MSG_RPACKET : MSG_LPACKET;
+      std::string packet(buffer, len);
+      rtc::Thread::Current()->PostDelayed(delay_, this, id,
+          rtc::WrapMessageData(packet));
+    }
+    return WR_SUCCESS;
+  }
+
+  void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); }
+  void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); }
+  void UpdateClock(PseudoTcp* tcp, uint32 message) {
+    long interval = 0;  // NOLINT
+    tcp->GetNextClock(PseudoTcp::Now(), interval);
+    interval = rtc::_max<int>(interval, 0L);  // sometimes interval is < 0
+    rtc::Thread::Current()->Clear(this, message);
+    rtc::Thread::Current()->PostDelayed(interval, this, message);
+  }
+
+  virtual void OnMessage(rtc::Message* message) {
+    switch (message->message_id) {
+      case MSG_LPACKET: {
+        const std::string& s(
+            rtc::UseMessageData<std::string>(message->pdata));
+        local_.NotifyPacket(s.c_str(), s.size());
+        UpdateLocalClock();
+        break;
+      }
+      case MSG_RPACKET: {
+        const std::string& s(
+            rtc::UseMessageData<std::string>(message->pdata));
+        remote_.NotifyPacket(s.c_str(), s.size());
+        UpdateRemoteClock();
+        break;
+      }
+      case MSG_LCLOCK:
+        local_.NotifyClock(PseudoTcp::Now());
+        UpdateLocalClock();
+        break;
+      case MSG_RCLOCK:
+        remote_.NotifyClock(PseudoTcp::Now());
+        UpdateRemoteClock();
+        break;
+      default:
+        break;
+    }
+    delete message->pdata;
+  }
+
+  PseudoTcpForTest local_;
+  PseudoTcpForTest remote_;
+  rtc::MemoryStream send_stream_;
+  rtc::MemoryStream recv_stream_;
+  bool have_connected_;
+  bool have_disconnected_;
+  int local_mtu_;
+  int remote_mtu_;
+  int delay_;
+  int loss_;
+};
+
+class PseudoTcpTest : public PseudoTcpTestBase {
+ public:
+  void TestTransfer(int size) {
+    uint32 start, elapsed;
+    size_t received;
+    // Create some dummy data to send.
+    send_stream_.ReserveSize(size);
+    for (int i = 0; i < size; ++i) {
+      char ch = static_cast<char>(i);
+      send_stream_.Write(&ch, 1, NULL, NULL);
+    }
+    send_stream_.Rewind();
+    // Prepare the receive stream.
+    recv_stream_.ReserveSize(size);
+    // Connect and wait until connected.
+    start = rtc::Time();
+    EXPECT_EQ(0, Connect());
+    EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
+    // Sending will start from OnTcpWriteable and complete when all data has
+    // been received.
+    EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
+    elapsed = rtc::TimeSince(start);
+    recv_stream_.GetSize(&received);
+    // Ensure we closed down OK and we got the right data.
+    // TODO: Ensure the errors are cleared properly.
+    //EXPECT_EQ(0, local_.GetError());
+    //EXPECT_EQ(0, remote_.GetError());
+    EXPECT_EQ(static_cast<size_t>(size), received);
+    EXPECT_EQ(0, memcmp(send_stream_.GetBuffer(),
+                        recv_stream_.GetBuffer(), size));
+    LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed
+                 << " ms (" << size * 8 / elapsed << " Kbps)";
+  }
+
+ private:
+  // IPseudoTcpNotify interface
+
+  virtual void OnTcpReadable(PseudoTcp* tcp) {
+    // Stream bytes to the recv stream as they arrive.
+    if (tcp == &remote_) {
+      ReadData();
+
+      // TODO: OnTcpClosed() is currently only notified on error -
+      // there is no on-the-wire equivalent of TCP FIN.
+      // So we fake the notification when all the data has been read.
+      size_t received, required;
+      recv_stream_.GetPosition(&received);
+      send_stream_.GetSize(&required);
+      if (received == required)
+        OnTcpClosed(&remote_, 0);
+    }
+  }
+  virtual void OnTcpWriteable(PseudoTcp* tcp) {
+    // Write bytes from the send stream when we can.
+    // Shut down when we've sent everything.
+    if (tcp == &local_) {
+      LOG(LS_VERBOSE) << "Flow Control Lifted";
+      bool done;
+      WriteData(&done);
+      if (done) {
+        Close();
+      }
+    }
+  }
+
+  void ReadData() {
+    char block[kBlockSize];
+    size_t position;
+    int rcvd;
+    do {
+      rcvd = remote_.Recv(block, sizeof(block));
+      if (rcvd != -1) {
+        recv_stream_.Write(block, rcvd, NULL, NULL);
+        recv_stream_.GetPosition(&position);
+        LOG(LS_VERBOSE) << "Received: " << position;
+      }
+    } while (rcvd > 0);
+  }
+  void WriteData(bool* done) {
+    size_t position, tosend;
+    int sent;
+    char block[kBlockSize];
+    do {
+      send_stream_.GetPosition(&position);
+      if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
+          rtc::SR_EOS) {
+        sent = local_.Send(block, tosend);
+        UpdateLocalClock();
+        if (sent != -1) {
+          send_stream_.SetPosition(position + sent);
+          LOG(LS_VERBOSE) << "Sent: " << position + sent;
+        } else {
+          send_stream_.SetPosition(position);
+          LOG(LS_VERBOSE) << "Flow Controlled";
+        }
+      } else {
+        sent = static_cast<int>(tosend = 0);
+      }
+    } while (sent > 0);
+    *done = (tosend == 0);
+  }
+
+ private:
+  rtc::MemoryStream send_stream_;
+  rtc::MemoryStream recv_stream_;
+};
+
+
+class PseudoTcpTestPingPong : public PseudoTcpTestBase {
+ public:
+  PseudoTcpTestPingPong()
+      : iterations_remaining_(0),
+	sender_(NULL),
+	receiver_(NULL),
+	bytes_per_send_(0) {
+  }
+  void SetBytesPerSend(int bytes) {
+    bytes_per_send_ = bytes;
+  }
+  void TestPingPong(int size, int iterations) {
+    uint32 start, elapsed;
+    iterations_remaining_ = iterations;
+    receiver_ = &remote_;
+    sender_ = &local_;
+    // Create some dummy data to send.
+    send_stream_.ReserveSize(size);
+    for (int i = 0; i < size; ++i) {
+      char ch = static_cast<char>(i);
+      send_stream_.Write(&ch, 1, NULL, NULL);
+    }
+    send_stream_.Rewind();
+    // Prepare the receive stream.
+    recv_stream_.ReserveSize(size);
+    // Connect and wait until connected.
+    start = rtc::Time();
+    EXPECT_EQ(0, Connect());
+    EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
+    // Sending will start from OnTcpWriteable and stop when the required
+    // number of iterations have completed.
+    EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
+    elapsed = rtc::TimeSince(start);
+    LOG(LS_INFO) << "Performed " << iterations << " pings in "
+                 << elapsed << " ms";
+  }
+
+ private:
+  // IPseudoTcpNotify interface
+
+  virtual void OnTcpReadable(PseudoTcp* tcp) {
+    if (tcp != receiver_) {
+      LOG_F(LS_ERROR) << "unexpected OnTcpReadable";
+      return;
+    }
+    // Stream bytes to the recv stream as they arrive.
+    ReadData();
+    // If we've received the desired amount of data, rewind things
+    // and send it back the other way!
+    size_t position, desired;
+    recv_stream_.GetPosition(&position);
+    send_stream_.GetSize(&desired);
+    if (position == desired) {
+      if (receiver_ == &local_ && --iterations_remaining_ == 0) {
+        Close();
+        // TODO: Fake OnTcpClosed() on the receiver for now.
+        OnTcpClosed(&remote_, 0);
+        return;
+      }
+      PseudoTcp* tmp = receiver_;
+      receiver_ = sender_;
+      sender_ = tmp;
+      recv_stream_.Rewind();
+      send_stream_.Rewind();
+      OnTcpWriteable(sender_);
+    }
+  }
+  virtual void OnTcpWriteable(PseudoTcp* tcp) {
+    if (tcp != sender_)
+      return;
+    // Write bytes from the send stream when we can.
+    // Shut down when we've sent everything.
+    LOG(LS_VERBOSE) << "Flow Control Lifted";
+    WriteData();
+  }
+
+  void ReadData() {
+    char block[kBlockSize];
+    size_t position;
+    int rcvd;
+    do {
+      rcvd = receiver_->Recv(block, sizeof(block));
+      if (rcvd != -1) {
+        recv_stream_.Write(block, rcvd, NULL, NULL);
+        recv_stream_.GetPosition(&position);
+        LOG(LS_VERBOSE) << "Received: " << position;
+      }
+    } while (rcvd > 0);
+  }
+  void WriteData() {
+    size_t position, tosend;
+    int sent;
+    char block[kBlockSize];
+    do {
+      send_stream_.GetPosition(&position);
+      tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block);
+      if (send_stream_.Read(block, tosend, &tosend, NULL) !=
+          rtc::SR_EOS) {
+        sent = sender_->Send(block, tosend);
+        UpdateLocalClock();
+        if (sent != -1) {
+          send_stream_.SetPosition(position + sent);
+          LOG(LS_VERBOSE) << "Sent: " << position + sent;
+        } else {
+          send_stream_.SetPosition(position);
+          LOG(LS_VERBOSE) << "Flow Controlled";
+        }
+      } else {
+        sent = static_cast<int>(tosend = 0);
+      }
+    } while (sent > 0);
+  }
+
+ private:
+  int iterations_remaining_;
+  PseudoTcp* sender_;
+  PseudoTcp* receiver_;
+  int bytes_per_send_;
+};
+
+// Fill the receiver window until it is full, drain it and then
+// fill it with the same amount. This is to test that receiver window
+// contracts and enlarges correctly.
+class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase {
+ public:
+  // Not all the data are transfered, |size| just need to be big enough
+  // to fill up the receiver window twice.
+  void TestTransfer(int size) {
+    // Create some dummy data to send.
+    send_stream_.ReserveSize(size);
+    for (int i = 0; i < size; ++i) {
+      char ch = static_cast<char>(i);
+      send_stream_.Write(&ch, 1, NULL, NULL);
+    }
+    send_stream_.Rewind();
+
+    // Prepare the receive stream.
+    recv_stream_.ReserveSize(size);
+
+    // Connect and wait until connected.
+    EXPECT_EQ(0, Connect());
+    EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs);
+
+    rtc::Thread::Current()->Post(this, MSG_WRITE);
+    EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs);
+
+    ASSERT_EQ(2u, send_position_.size());
+    ASSERT_EQ(2u, recv_position_.size());
+
+    const size_t estimated_recv_window = EstimateReceiveWindowSize();
+
+    // The difference in consecutive send positions should equal the
+    // receive window size or match very closely. This verifies that receive
+    // window is open after receiver drained all the data.
+    const size_t send_position_diff = send_position_[1] - send_position_[0];
+    EXPECT_GE(1024u, estimated_recv_window - send_position_diff);
+
+    // Receiver drained the receive window twice.
+    EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]);
+  }
+
+  virtual void OnMessage(rtc::Message* message) {
+    int message_id = message->message_id;
+    PseudoTcpTestBase::OnMessage(message);
+
+    switch (message_id) {
+      case MSG_WRITE: {
+        WriteData();
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  uint32 EstimateReceiveWindowSize() const {
+    return static_cast<uint32>(recv_position_[0]);
+  }
+
+  uint32 EstimateSendWindowSize() const {
+    return static_cast<uint32>(send_position_[0] - recv_position_[0]);
+  }
+
+ private:
+  // IPseudoTcpNotify interface
+  virtual void OnTcpReadable(PseudoTcp* tcp) {
+  }
+
+  virtual void OnTcpWriteable(PseudoTcp* tcp) {
+  }
+
+  void ReadUntilIOPending() {
+    char block[kBlockSize];
+    size_t position;
+    int rcvd;
+
+    do {
+      rcvd = remote_.Recv(block, sizeof(block));
+      if (rcvd != -1) {
+        recv_stream_.Write(block, rcvd, NULL, NULL);
+        recv_stream_.GetPosition(&position);
+        LOG(LS_VERBOSE) << "Received: " << position;
+      }
+    } while (rcvd > 0);
+
+    recv_stream_.GetPosition(&position);
+    recv_position_.push_back(position);
+
+    // Disconnect if we have done two transfers.
+    if (recv_position_.size() == 2u) {
+      Close();
+      OnTcpClosed(&remote_, 0);
+    } else {
+      WriteData();
+    }
+  }
+
+  void WriteData() {
+    size_t position, tosend;
+    int sent;
+    char block[kBlockSize];
+    do {
+      send_stream_.GetPosition(&position);
+      if (send_stream_.Read(block, sizeof(block), &tosend, NULL) !=
+          rtc::SR_EOS) {
+        sent = local_.Send(block, tosend);
+        UpdateLocalClock();
+        if (sent != -1) {
+          send_stream_.SetPosition(position + sent);
+          LOG(LS_VERBOSE) << "Sent: " << position + sent;
+        } else {
+          send_stream_.SetPosition(position);
+          LOG(LS_VERBOSE) << "Flow Controlled";
+        }
+      } else {
+        sent = static_cast<int>(tosend = 0);
+      }
+    } while (sent > 0);
+    // At this point, we've filled up the available space in the send queue.
+
+    int message_queue_size =
+        static_cast<int>(rtc::Thread::Current()->size());
+    // The message queue will always have at least 2 messages, an RCLOCK and
+    // an LCLOCK, since they are added back on the delay queue at the same time
+    // they are pulled off and therefore are never really removed.
+    if (message_queue_size > 2) {
+      // If there are non-clock messages remaining, attempt to continue sending
+      // after giving those messages time to process, which should free up the
+      // send buffer.
+      rtc::Thread::Current()->PostDelayed(10, this, MSG_WRITE);
+    } else {
+      if (!remote_.isReceiveBufferFull()) {
+        LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, "
+                      << "the receive buffer is not, and there are no "
+                      << "remaining messages to process.";
+      }
+      send_stream_.GetPosition(&position);
+      send_position_.push_back(position);
+
+      // Drain the receiver buffer.
+      ReadUntilIOPending();
+    }
+  }
+
+ private:
+  rtc::MemoryStream send_stream_;
+  rtc::MemoryStream recv_stream_;
+
+  std::vector<size_t> send_position_;
+  std::vector<size_t> recv_position_;
+};
+
+// Basic end-to-end data transfer tests
+
+// Test the normal case of sending data from one side to the other.
+TEST_F(PseudoTcpTest, TestSend) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  TestTransfer(1000000);
+}
+
+// Test sending data with a 50 ms RTT. Transmission should take longer due
+// to a slower ramp-up in send rate.
+TEST_F(PseudoTcpTest, TestSendWithDelay) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetDelay(50);
+  TestTransfer(1000000);
+}
+
+// Test sending data with packet loss. Transmission should take much longer due
+// to send back-off when loss occurs.
+TEST_F(PseudoTcpTest, TestSendWithLoss) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetLoss(10);
+  TestTransfer(100000);  // less data so test runs faster
+}
+
+// Test sending data with a 50 ms RTT and 10% packet loss. Transmission should
+// take much longer due to send back-off and slower detection of loss.
+TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetDelay(50);
+  SetLoss(10);
+  TestTransfer(100000);  // less data so test runs faster
+}
+
+// Test sending data with 10% packet loss and Nagling disabled.  Transmission
+// should take about the same time as with Nagling enabled.
+TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetLoss(10);
+  SetOptNagling(false);
+  TestTransfer(100000);  // less data so test runs faster
+}
+
+// Test sending data with 10% packet loss and Delayed ACK disabled.
+// Transmission should be slightly faster than with it enabled.
+TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetLoss(10);
+  SetOptAckDelay(0);
+  TestTransfer(100000);
+}
+
+// Test sending data with 50ms delay and Nagling disabled.
+TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetDelay(50);
+  SetOptNagling(false);
+  TestTransfer(100000);  // less data so test runs faster
+}
+
+// Test sending data with 50ms delay and Delayed ACK disabled.
+TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetDelay(50);
+  SetOptAckDelay(0);
+  TestTransfer(100000);  // less data so test runs faster
+}
+
+// Test a large receive buffer with a sender that doesn't support scaling.
+TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetLocalOptRcvBuf(100000);
+  DisableRemoteWindowScale();
+  TestTransfer(1000000);
+}
+
+// Test a large sender-side receive buffer with a receiver that doesn't support
+// scaling.
+TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetRemoteOptRcvBuf(100000);
+  DisableLocalWindowScale();
+  TestTransfer(1000000);
+}
+
+// Test when both sides use window scaling.
+TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetRemoteOptRcvBuf(100000);
+  SetLocalOptRcvBuf(100000);
+  TestTransfer(1000000);
+}
+
+// Test using a large window scale value.
+TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetRemoteOptRcvBuf(100000);
+  SetLocalOptRcvBuf(100000);
+  SetOptSndBuf(150000);
+  TestTransfer(1000000);
+}
+
+TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetRemoteOptRcvBuf(1000000);
+  SetLocalOptRcvBuf(1000000);
+  TestTransfer(10000000);
+}
+
+// Test using a small receive buffer.
+TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetRemoteOptRcvBuf(10000);
+  SetLocalOptRcvBuf(10000);
+  TestTransfer(1000000);
+}
+
+// Test using a very small receive buffer.
+TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetRemoteOptRcvBuf(100);
+  SetLocalOptRcvBuf(100);
+  TestTransfer(100000);
+}
+
+// Ping-pong (request/response) tests
+
+// Test sending <= 1x MTU of data in each ping/pong.  Should take <10ms.
+TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  TestPingPong(100, 100);
+}
+
+// Test sending 2x-3x MTU of data in each ping/pong.  Should take <10ms.
+TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  TestPingPong(400, 100);
+}
+
+// Test sending 1x-2x MTU of data in each ping/pong.
+// Should take ~1s, due to interaction between Nagling and Delayed ACK.
+TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  TestPingPong(2000, 5);
+}
+
+// Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off.
+// Should take <10ms.
+TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetOptAckDelay(0);
+  TestPingPong(2000, 100);
+}
+
+// Test sending 1x-2x MTU of data in each ping/pong with Nagling off.
+// Should take <10ms.
+TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetOptNagling(false);
+  TestPingPong(2000, 5);
+}
+
+// Test sending a ping as pair of short (non-full) segments.
+// Should take ~1s, due to Delayed ACK interaction with Nagling.
+TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetOptAckDelay(5000);
+  SetBytesPerSend(50); // i.e. two Send calls per payload
+  TestPingPong(100, 5);
+}
+
+// Test sending ping as a pair of short (non-full) segments, with Nagling off.
+// Should take <10ms.
+TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetOptNagling(false);
+  SetBytesPerSend(50); // i.e. two Send calls per payload
+  TestPingPong(100, 5);
+}
+
+// Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK.
+// Should take ~1s.
+TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetBytesPerSend(50); // i.e. two Send calls per payload
+  SetOptAckDelay(0);
+  TestPingPong(100, 5);
+}
+
+// Test that receive window expands and contract correctly.
+TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetOptNagling(false);
+  SetOptAckDelay(0);
+  TestTransfer(1024 * 1000);
+}
+
+// Test setting send window size to a very small value.
+TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetOptNagling(false);
+  SetOptAckDelay(0);
+  SetOptSndBuf(900);
+  TestTransfer(1024 * 1000);
+  EXPECT_EQ(900u, EstimateSendWindowSize());
+}
+
+// Test setting receive window size to a value other than default.
+TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1500);
+  SetOptNagling(false);
+  SetOptAckDelay(0);
+  SetRemoteOptRcvBuf(100000);
+  SetLocalOptRcvBuf(100000);
+  TestTransfer(1024 * 1000);
+  EXPECT_EQ(100000u, EstimateReceiveWindowSize());
+}
+
+/* Test sending data with mismatched MTUs. We should detect this and reduce
+// our packet size accordingly.
+// TODO: This doesn't actually work right now. The current code
+// doesn't detect if the MTU is set too high on either side.
+TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
+  SetLocalMtu(1500);
+  SetRemoteMtu(1280);
+  TestTransfer(1000000);
+}
+*/
diff --git a/p2p/base/rawtransport.cc b/p2p/base/rawtransport.cc
new file mode 100644
index 0000000..374ed98
--- /dev/null
+++ b/p2p/base/rawtransport.cc
@@ -0,0 +1,115 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+#include <vector>
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/rawtransport.h"
+#include "webrtc/p2p/base/rawtransportchannel.h"
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/common.h"
+
+#if defined(FEATURE_ENABLE_PSTN)
+namespace cricket {
+
+RawTransport::RawTransport(rtc::Thread* signaling_thread,
+                           rtc::Thread* worker_thread,
+                           const std::string& content_name,
+                           PortAllocator* allocator)
+    : Transport(signaling_thread, worker_thread,
+                content_name, NS_GINGLE_RAW, allocator) {
+}
+
+RawTransport::~RawTransport() {
+  DestroyAllChannels();
+}
+
+bool RawTransport::ParseCandidates(SignalingProtocol protocol,
+                                   const buzz::XmlElement* elem,
+                                   const CandidateTranslator* translator,
+                                   Candidates* candidates,
+                                   ParseError* error) {
+  for (const buzz::XmlElement* cand_elem = elem->FirstElement();
+       cand_elem != NULL;
+       cand_elem = cand_elem->NextElement()) {
+    if (cand_elem->Name() == QN_GINGLE_RAW_CHANNEL) {
+      if (!cand_elem->HasAttr(buzz::QN_NAME)) {
+        return BadParse("no channel name given", error);
+      }
+      if (type() != cand_elem->Attr(buzz::QN_NAME)) {
+        return BadParse("channel named does not exist", error);
+      }
+      rtc::SocketAddress addr;
+      if (!ParseRawAddress(cand_elem, &addr, error))
+        return false;
+
+      Candidate candidate;
+      candidate.set_component(1);
+      candidate.set_address(addr);
+      candidates->push_back(candidate);
+    }
+  }
+  return true;
+}
+
+bool RawTransport::WriteCandidates(SignalingProtocol protocol,
+                                   const Candidates& candidates,
+                                   const CandidateTranslator* translator,
+                                   XmlElements* candidate_elems,
+                                   WriteError* error) {
+  for (std::vector<Candidate>::const_iterator
+       cand = candidates.begin();
+       cand != candidates.end();
+       ++cand) {
+    ASSERT(cand->component() == 1);
+    ASSERT(cand->protocol() == "udp");
+    rtc::SocketAddress addr = cand->address();
+
+    buzz::XmlElement* elem = new buzz::XmlElement(QN_GINGLE_RAW_CHANNEL);
+    elem->SetAttr(buzz::QN_NAME, type());
+    elem->SetAttr(QN_ADDRESS, addr.ipaddr().ToString());
+    elem->SetAttr(QN_PORT, addr.PortAsString());
+    candidate_elems->push_back(elem);
+  }
+  return true;
+}
+
+bool RawTransport::ParseRawAddress(const buzz::XmlElement* elem,
+                                   rtc::SocketAddress* addr,
+                                   ParseError* error) {
+  // Make sure the required attributes exist
+  if (!elem->HasAttr(QN_ADDRESS) ||
+      !elem->HasAttr(QN_PORT)) {
+    return BadParse("channel missing required attribute", error);
+  }
+
+  // Parse the address.
+  if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, addr, error))
+    return false;
+
+  return true;
+}
+
+TransportChannelImpl* RawTransport::CreateTransportChannel(int component) {
+  return new RawTransportChannel(content_name(), component, this,
+                                 worker_thread(),
+                                 port_allocator());
+}
+
+void RawTransport::DestroyTransportChannel(TransportChannelImpl* channel) {
+  delete channel;
+}
+
+}  // namespace cricket
+#endif  // defined(FEATURE_ENABLE_PSTN)
diff --git a/p2p/base/rawtransport.h b/p2p/base/rawtransport.h
new file mode 100644
index 0000000..dbe8f98
--- /dev/null
+++ b/p2p/base/rawtransport.h
@@ -0,0 +1,64 @@
+/*
+ *  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_P2P_BASE_RAWTRANSPORT_H_
+#define WEBRTC_P2P_BASE_RAWTRANSPORT_H_
+
+#include <string>
+#include "webrtc/p2p/base/transport.h"
+
+#if defined(FEATURE_ENABLE_PSTN)
+namespace cricket {
+
+// Implements a transport that only sends raw packets, no STUN.  As a result,
+// it cannot do pings to determine connectivity, so it only uses a single port
+// that it thinks will work.
+class RawTransport : public Transport, public TransportParser {
+ public:
+  RawTransport(rtc::Thread* signaling_thread,
+               rtc::Thread* worker_thread,
+               const std::string& content_name,
+               PortAllocator* allocator);
+  virtual ~RawTransport();
+
+  virtual bool ParseCandidates(SignalingProtocol protocol,
+                               const buzz::XmlElement* elem,
+                               const CandidateTranslator* translator,
+                               Candidates* candidates,
+                               ParseError* error);
+  virtual bool WriteCandidates(SignalingProtocol protocol,
+                               const Candidates& candidates,
+                               const CandidateTranslator* translator,
+                               XmlElements* candidate_elems,
+                               WriteError* error);
+
+ protected:
+  // Creates and destroys raw channels.
+  virtual TransportChannelImpl* CreateTransportChannel(int component);
+  virtual void DestroyTransportChannel(TransportChannelImpl* channel);
+
+ private:
+  // Parses the given element, which should describe the address to use for a
+  // given channel.  This will return false and signal an error if the address
+  // or channel name is bad.
+  bool ParseRawAddress(const buzz::XmlElement* elem,
+                       rtc::SocketAddress* addr,
+                       ParseError* error);
+
+  friend class RawTransportChannel;  // For ParseAddress.
+
+  DISALLOW_EVIL_CONSTRUCTORS(RawTransport);
+};
+
+}  // namespace cricket
+
+#endif  // defined(FEATURE_ENABLE_PSTN)
+
+#endif  // WEBRTC_P2P_BASE_RAWTRANSPORT_H_
diff --git a/p2p/base/rawtransportchannel.cc b/p2p/base/rawtransportchannel.cc
new file mode 100644
index 0000000..5779c6e
--- /dev/null
+++ b/p2p/base/rawtransportchannel.cc
@@ -0,0 +1,260 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/rawtransportchannel.h"
+
+#include <string>
+#include <vector>
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/portinterface.h"
+#include "webrtc/p2p/base/rawtransport.h"
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/p2p/base/stunport.h"
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/common.h"
+
+#if defined(FEATURE_ENABLE_PSTN)
+
+namespace {
+
+const uint32 MSG_DESTROY_RTC_UNUSED_PORTS = 1;
+
+}  // namespace
+
+namespace cricket {
+
+RawTransportChannel::RawTransportChannel(const std::string& content_name,
+                                         int component,
+                                         RawTransport* transport,
+                                         rtc::Thread *worker_thread,
+                                         PortAllocator *allocator)
+  : TransportChannelImpl(content_name, component),
+    raw_transport_(transport),
+    allocator_(allocator),
+    allocator_session_(NULL),
+    stun_port_(NULL),
+    relay_port_(NULL),
+    port_(NULL),
+    use_relay_(false) {
+  if (worker_thread == NULL)
+    worker_thread_ = raw_transport_->worker_thread();
+  else
+    worker_thread_ = worker_thread;
+}
+
+RawTransportChannel::~RawTransportChannel() {
+  delete allocator_session_;
+}
+
+int RawTransportChannel::SendPacket(const char *data, size_t size,
+                                    const rtc::PacketOptions& options,
+                                    int flags) {
+  if (port_ == NULL)
+    return -1;
+  if (remote_address_.IsNil())
+    return -1;
+  if (flags != 0)
+    return -1;
+  return port_->SendTo(data, size, remote_address_, options, true);
+}
+
+int RawTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
+  // TODO: allow these to be set before we have a port
+  if (port_ == NULL)
+    return -1;
+  return port_->SetOption(opt, value);
+}
+
+int RawTransportChannel::GetError() {
+  return (port_ != NULL) ? port_->GetError() : 0;
+}
+
+void RawTransportChannel::Connect() {
+  // Create an allocator that only returns stun and relay ports.
+  // Use empty string for ufrag and pwd here. There won't be any STUN or relay
+  // interactions when using RawTC.
+  // TODO: Change raw to only use local udp ports.
+  allocator_session_ = allocator_->CreateSession(
+      SessionId(), content_name(), component(), "", "");
+
+  uint32 flags = PORTALLOCATOR_DISABLE_UDP | PORTALLOCATOR_DISABLE_TCP;
+
+#if !defined(FEATURE_ENABLE_STUN_CLASSIFICATION)
+  flags |= PORTALLOCATOR_DISABLE_RELAY;
+#endif
+  allocator_session_->set_flags(flags);
+  allocator_session_->SignalPortReady.connect(
+      this, &RawTransportChannel::OnPortReady);
+  allocator_session_->SignalCandidatesReady.connect(
+      this, &RawTransportChannel::OnCandidatesReady);
+
+  // The initial ports will include stun.
+  allocator_session_->StartGettingPorts();
+}
+
+void RawTransportChannel::Reset() {
+  set_readable(false);
+  set_writable(false);
+
+  delete allocator_session_;
+
+  allocator_session_ = NULL;
+  stun_port_ = NULL;
+  relay_port_ = NULL;
+  port_ = NULL;
+  remote_address_ = rtc::SocketAddress();
+}
+
+void RawTransportChannel::OnCandidate(const Candidate& candidate) {
+  remote_address_ = candidate.address();
+  ASSERT(!remote_address_.IsNil());
+  set_readable(true);
+
+  // We can write once we have a port and a remote address.
+  if (port_ != NULL)
+    SetWritable();
+}
+
+void RawTransportChannel::OnRemoteAddress(
+    const rtc::SocketAddress& remote_address) {
+  remote_address_ = remote_address;
+  set_readable(true);
+
+  if (port_ != NULL)
+    SetWritable();
+}
+
+// Note about stun classification
+// Code to classify our NAT type and use the relay port if we are behind an
+// asymmetric NAT is under a FEATURE_ENABLE_STUN_CLASSIFICATION #define.
+// To turn this one we will have to enable a second stun address and make sure
+// that the relay server works for raw UDP.
+//
+// Another option is to classify the NAT type early and not offer the raw
+// transport type at all if we can't support it.
+
+void RawTransportChannel::OnPortReady(
+    PortAllocatorSession* session, PortInterface* port) {
+  ASSERT(session == allocator_session_);
+
+  if (port->Type() == STUN_PORT_TYPE) {
+    stun_port_ = static_cast<StunPort*>(port);
+  } else if (port->Type() == RELAY_PORT_TYPE) {
+    relay_port_ = static_cast<RelayPort*>(port);
+  } else {
+    ASSERT(false);
+  }
+}
+
+void RawTransportChannel::OnCandidatesReady(
+    PortAllocatorSession *session, const std::vector<Candidate>& candidates) {
+  ASSERT(session == allocator_session_);
+  ASSERT(candidates.size() >= 1);
+
+  // The most recent candidate is the one we haven't seen yet.
+  Candidate c = candidates[candidates.size() - 1];
+
+  if (c.type() == STUN_PORT_TYPE) {
+    ASSERT(stun_port_ != NULL);
+
+#if defined(FEATURE_ENABLE_STUN_CLASSIFICATION)
+    // We need to wait until we have two addresses.
+    if (stun_port_->candidates().size() < 2)
+      return;
+
+    // This is the second address.  If these addresses are the same, then we
+    // are not behind a symmetric NAT.  Hence, a stun port should be sufficient.
+    if (stun_port_->candidates()[0].address() ==
+        stun_port_->candidates()[1].address()) {
+      SetPort(stun_port_);
+      return;
+    }
+
+    // We will need to use relay.
+    use_relay_ = true;
+
+    // If we already have a relay address, we're good.  Otherwise, we will need
+    // to wait until one arrives.
+    if (relay_port_->candidates().size() > 0)
+      SetPort(relay_port_);
+#else  // defined(FEATURE_ENABLE_STUN_CLASSIFICATION)
+    // Always use the stun port.  We don't classify right now so just assume it
+    // will work fine.
+    SetPort(stun_port_);
+#endif
+  } else if (c.type() == RELAY_PORT_TYPE) {
+    if (use_relay_)
+      SetPort(relay_port_);
+  } else {
+    ASSERT(false);
+  }
+}
+
+void RawTransportChannel::SetPort(PortInterface* port) {
+  ASSERT(port_ == NULL);
+  port_ = port;
+
+  // We don't need any ports other than the one we picked.
+  allocator_session_->StopGettingPorts();
+  worker_thread_->Post(
+      this, MSG_DESTROY_RTC_UNUSED_PORTS, NULL);
+
+  // Send a message to the other client containing our address.
+
+  ASSERT(port_->Candidates().size() >= 1);
+  ASSERT(port_->Candidates()[0].protocol() == "udp");
+  SignalCandidateReady(this, port_->Candidates()[0]);
+
+  // Read all packets from this port.
+  port_->EnablePortPackets();
+  port_->SignalReadPacket.connect(this, &RawTransportChannel::OnReadPacket);
+
+  // We can write once we have a port and a remote address.
+  if (!remote_address_.IsAny())
+    SetWritable();
+}
+
+void RawTransportChannel::SetWritable() {
+  ASSERT(port_ != NULL);
+  ASSERT(!remote_address_.IsAny());
+
+  set_writable(true);
+
+  Candidate remote_candidate;
+  remote_candidate.set_address(remote_address_);
+  SignalRouteChange(this, remote_candidate);
+}
+
+void RawTransportChannel::OnReadPacket(
+    PortInterface* port, const char* data, size_t size,
+    const rtc::SocketAddress& addr) {
+  ASSERT(port_ == port);
+  SignalReadPacket(this, data, size, rtc::CreatePacketTime(0), 0);
+}
+
+void RawTransportChannel::OnMessage(rtc::Message* msg) {
+  ASSERT(msg->message_id == MSG_DESTROY_RTC_UNUSED_PORTS);
+  ASSERT(port_ != NULL);
+  if (port_ != stun_port_) {
+    stun_port_->Destroy();
+    stun_port_ = NULL;
+  }
+  if (port_ != relay_port_ && relay_port_ != NULL) {
+    relay_port_->Destroy();
+    relay_port_ = NULL;
+  }
+}
+
+}  // namespace cricket
+#endif  // defined(FEATURE_ENABLE_PSTN)
diff --git a/p2p/base/rawtransportchannel.h b/p2p/base/rawtransportchannel.h
new file mode 100644
index 0000000..3041cad
--- /dev/null
+++ b/p2p/base/rawtransportchannel.h
@@ -0,0 +1,189 @@
+/*
+ *  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_P2P_BASE_RAWTRANSPORTCHANNEL_H_
+#define WEBRTC_P2P_BASE_RAWTRANSPORTCHANNEL_H_
+
+#include <string>
+#include <vector>
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/rawtransport.h"
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/base/messagequeue.h"
+
+#if defined(FEATURE_ENABLE_PSTN)
+
+namespace rtc {
+class Thread;
+}
+
+namespace cricket {
+
+class Connection;
+class PortAllocator;
+class PortAllocatorSession;
+class PortInterface;
+class RelayPort;
+class StunPort;
+
+// Implements a channel that just sends bare packets once we have received the
+// address of the other side.  We pick a single address to send them based on
+// a simple investigation of NAT type.
+class RawTransportChannel : public TransportChannelImpl,
+    public rtc::MessageHandler {
+ public:
+  RawTransportChannel(const std::string& content_name,
+                      int component,
+                      RawTransport* transport,
+                      rtc::Thread *worker_thread,
+                      PortAllocator *allocator);
+  virtual ~RawTransportChannel();
+
+  // Implementation of normal channel packet sending.
+  virtual int SendPacket(const char *data, size_t len,
+                         const rtc::PacketOptions& options, int flags);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetError();
+
+  // Implements TransportChannelImpl.
+  virtual Transport* GetTransport() { return raw_transport_; }
+  virtual void SetIceCredentials(const std::string& ice_ufrag,
+                                 const std::string& ice_pwd) {}
+  virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
+                                       const std::string& ice_pwd) {}
+
+  // Creates an allocator session to start figuring out which type of
+  // port we should send to the other client.  This will send
+  // SignalAvailableCandidate once we have decided.
+  virtual void Connect();
+
+  // Resets state back to unconnected.
+  virtual void Reset();
+
+  // We don't actually worry about signaling since we can't send new candidates.
+  virtual void OnSignalingReady() {}
+
+  // Handles a message setting the remote address.  We are writable once we
+  // have this since we now know where to send.
+  virtual void OnCandidate(const Candidate& candidate);
+
+  void OnRemoteAddress(const rtc::SocketAddress& remote_address);
+
+  // Below ICE specific virtual methods not implemented.
+  virtual IceRole GetIceRole() const { return ICEROLE_UNKNOWN; }
+  virtual void SetIceRole(IceRole role) {}
+  virtual void SetIceTiebreaker(uint64 tiebreaker) {}
+
+  virtual bool GetIceProtocolType(IceProtocolType* type) const { return false; }
+  virtual void SetIceProtocolType(IceProtocolType type) {}
+
+  virtual void SetIceUfrag(const std::string& ice_ufrag) {}
+  virtual void SetIcePwd(const std::string& ice_pwd) {}
+  virtual void SetRemoteIceMode(IceMode mode) {}
+  virtual size_t GetConnectionCount() const { return 1; }
+
+  virtual bool GetStats(ConnectionInfos* infos) {
+    return false;
+  }
+
+  // DTLS methods.
+  virtual bool IsDtlsActive() const { return false; }
+
+  // Default implementation.
+  virtual bool GetSslRole(rtc::SSLRole* role) const {
+    return false;
+  }
+
+  virtual bool SetSslRole(rtc::SSLRole role) {
+    return false;
+  }
+
+  // Set up the ciphers to use for DTLS-SRTP.
+  virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) {
+    return false;
+  }
+
+  // Find out which DTLS-SRTP cipher was negotiated
+  virtual bool GetSrtpCipher(std::string* cipher) {
+    return false;
+  }
+
+  // Returns false because the channel is not DTLS.
+  virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const {
+    return false;
+  }
+
+  virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const {
+    return false;
+  }
+
+  // Allows key material to be extracted for external encryption.
+  virtual bool ExportKeyingMaterial(
+      const std::string& label,
+      const uint8* context,
+      size_t context_len,
+      bool use_context,
+      uint8* result,
+      size_t result_len) {
+    return false;
+  }
+
+  virtual bool SetLocalIdentity(rtc::SSLIdentity* identity) {
+    return false;
+  }
+
+  // Set DTLS Remote fingerprint. Must be after local identity set.
+  virtual bool SetRemoteFingerprint(
+    const std::string& digest_alg,
+    const uint8* digest,
+    size_t digest_len) {
+    return false;
+  }
+
+ private:
+  RawTransport* raw_transport_;
+  rtc::Thread *worker_thread_;
+  PortAllocator* allocator_;
+  PortAllocatorSession* allocator_session_;
+  StunPort* stun_port_;
+  RelayPort* relay_port_;
+  PortInterface* port_;
+  bool use_relay_;
+  rtc::SocketAddress remote_address_;
+
+  // Called when the allocator creates another port.
+  void OnPortReady(PortAllocatorSession* session, PortInterface* port);
+
+  // Called when one of the ports we are using has determined its address.
+  void OnCandidatesReady(PortAllocatorSession *session,
+                         const std::vector<Candidate>& candidates);
+
+  // Called once we have chosen the port to use for communication with the
+  // other client.  This will send its address and prepare the port for use.
+  void SetPort(PortInterface* port);
+
+  // Called once we have a port and a remote address.  This will set mark the
+  // channel as writable and signal the route to the client.
+  void SetWritable();
+
+  // Called when we receive a packet from the other client.
+  void OnReadPacket(PortInterface* port, const char* data, size_t size,
+                    const rtc::SocketAddress& addr);
+
+  // Handles a message to destroy unused ports.
+  virtual void OnMessage(rtc::Message *msg);
+
+  DISALLOW_EVIL_CONSTRUCTORS(RawTransportChannel);
+};
+
+}  // namespace cricket
+
+#endif  // defined(FEATURE_ENABLE_PSTN)
+#endif  // WEBRTC_P2P_BASE_RAWTRANSPORTCHANNEL_H_
diff --git a/p2p/base/relayport.cc b/p2p/base/relayport.cc
new file mode 100644
index 0000000..4c40b3d
--- /dev/null
+++ b/p2p/base/relayport.cc
@@ -0,0 +1,818 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+
+namespace cricket {
+
+static const uint32 kMessageConnectTimeout = 1;
+static const int kKeepAliveDelay           = 10 * 60 * 1000;
+static const int kRetryTimeout             = 50 * 1000;  // ICE says 50 secs
+// How long to wait for a socket to connect to remote host in milliseconds
+// before trying another connection.
+static const int kSoftConnectTimeoutMs     = 3 * 1000;
+
+// Handles a connection to one address/port/protocol combination for a
+// particular RelayEntry.
+class RelayConnection : public sigslot::has_slots<> {
+ public:
+  RelayConnection(const ProtocolAddress* protocol_address,
+                  rtc::AsyncPacketSocket* socket,
+                  rtc::Thread* thread);
+  ~RelayConnection();
+  rtc::AsyncPacketSocket* socket() const { return socket_; }
+
+  const ProtocolAddress* protocol_address() {
+    return protocol_address_;
+  }
+
+  rtc::SocketAddress GetAddress() const {
+    return protocol_address_->address;
+  }
+
+  ProtocolType GetProtocol() const {
+    return protocol_address_->proto;
+  }
+
+  int SetSocketOption(rtc::Socket::Option opt, int value);
+
+  // Validates a response to a STUN allocate request.
+  bool CheckResponse(StunMessage* msg);
+
+  // Sends data to the relay server.
+  int Send(const void* pv, size_t cb, const rtc::PacketOptions& options);
+
+  // Sends a STUN allocate request message to the relay server.
+  void SendAllocateRequest(RelayEntry* entry, int delay);
+
+  // Return the latest error generated by the socket.
+  int GetError() { return socket_->GetError(); }
+
+  // Called on behalf of a StunRequest to write data to the socket.  This is
+  // already STUN intended for the server, so no wrapping is necessary.
+  void OnSendPacket(const void* data, size_t size, StunRequest* req);
+
+ private:
+  rtc::AsyncPacketSocket* socket_;
+  const ProtocolAddress* protocol_address_;
+  StunRequestManager *request_manager_;
+};
+
+// Manages a number of connections to the relayserver, one for each
+// available protocol. We aim to use each connection for only a
+// specific destination address so that we can avoid wrapping every
+// packet in a STUN send / data indication.
+class RelayEntry : public rtc::MessageHandler,
+                   public sigslot::has_slots<> {
+ public:
+  RelayEntry(RelayPort* port, const rtc::SocketAddress& ext_addr);
+  ~RelayEntry();
+
+  RelayPort* port() { return port_; }
+
+  const rtc::SocketAddress& address() const { return ext_addr_; }
+  void set_address(const rtc::SocketAddress& addr) { ext_addr_ = addr; }
+
+  bool connected() const { return connected_; }
+  bool locked() const { return locked_; }
+
+  // Returns the last error on the socket of this entry.
+  int GetError();
+
+  // Returns the most preferred connection of the given
+  // ones. Connections are rated based on protocol in the order of:
+  // UDP, TCP and SSLTCP, where UDP is the most preferred protocol
+  static RelayConnection* GetBestConnection(RelayConnection* conn1,
+                                            RelayConnection* conn2);
+
+  // Sends the STUN requests to the server to initiate this connection.
+  void Connect();
+
+  // Called when this entry becomes connected.  The address given is the one
+  // exposed to the outside world on the relay server.
+  void OnConnect(const rtc::SocketAddress& mapped_addr,
+                 RelayConnection* socket);
+
+  // Sends a packet to the given destination address using the socket of this
+  // entry.  This will wrap the packet in STUN if necessary.
+  int SendTo(const void* data, size_t size,
+             const rtc::SocketAddress& addr,
+             const rtc::PacketOptions& options);
+
+  // Schedules a keep-alive allocate request.
+  void ScheduleKeepAlive();
+
+  void SetServerIndex(size_t sindex) { server_index_ = sindex; }
+
+  // Sets this option on the socket of each connection.
+  int SetSocketOption(rtc::Socket::Option opt, int value);
+
+  size_t ServerIndex() const { return server_index_; }
+
+  // Try a different server address
+  void HandleConnectFailure(rtc::AsyncPacketSocket* socket);
+
+  // Implementation of the MessageHandler Interface.
+  virtual void OnMessage(rtc::Message *pmsg);
+
+ private:
+  RelayPort* port_;
+  rtc::SocketAddress ext_addr_;
+  size_t server_index_;
+  bool connected_;
+  bool locked_;
+  RelayConnection* current_connection_;
+
+  // Called when a TCP connection is established or fails
+  void OnSocketConnect(rtc::AsyncPacketSocket* socket);
+  void OnSocketClose(rtc::AsyncPacketSocket* socket, int error);
+
+  // Called when a packet is received on this socket.
+  void OnReadPacket(
+    rtc::AsyncPacketSocket* socket,
+    const char* data, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time);
+  // Called when the socket is currently able to send.
+  void OnReadyToSend(rtc::AsyncPacketSocket* socket);
+
+  // Sends the given data on the socket to the server with no wrapping.  This
+  // returns the number of bytes written or -1 if an error occurred.
+  int SendPacket(const void* data, size_t size,
+                 const rtc::PacketOptions& options);
+};
+
+// Handles an allocate request for a particular RelayEntry.
+class AllocateRequest : public StunRequest {
+ public:
+  AllocateRequest(RelayEntry* entry, RelayConnection* connection);
+  virtual ~AllocateRequest() {}
+
+  virtual void Prepare(StunMessage* request);
+
+  virtual int GetNextDelay();
+
+  virtual void OnResponse(StunMessage* response);
+  virtual void OnErrorResponse(StunMessage* response);
+  virtual void OnTimeout();
+
+ private:
+  RelayEntry* entry_;
+  RelayConnection* connection_;
+  uint32 start_time_;
+};
+
+RelayPort::RelayPort(
+    rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+    rtc::Network* network, const rtc::IPAddress& ip,
+    int min_port, int max_port, const std::string& username,
+    const std::string& password)
+    : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port,
+           username, password),
+      ready_(false),
+      error_(0) {
+  entries_.push_back(
+      new RelayEntry(this, rtc::SocketAddress()));
+  // TODO: set local preference value for TCP based candidates.
+}
+
+RelayPort::~RelayPort() {
+  for (size_t i = 0; i < entries_.size(); ++i)
+    delete entries_[i];
+  thread()->Clear(this);
+}
+
+void RelayPort::AddServerAddress(const ProtocolAddress& addr) {
+  // Since HTTP proxies usually only allow 443,
+  // let's up the priority on PROTO_SSLTCP
+  if (addr.proto == PROTO_SSLTCP &&
+      (proxy().type == rtc::PROXY_HTTPS ||
+       proxy().type == rtc::PROXY_UNKNOWN)) {
+    server_addr_.push_front(addr);
+  } else {
+    server_addr_.push_back(addr);
+  }
+}
+
+void RelayPort::AddExternalAddress(const ProtocolAddress& addr) {
+  std::string proto_name = ProtoToString(addr.proto);
+  for (std::vector<ProtocolAddress>::iterator it = external_addr_.begin();
+       it != external_addr_.end(); ++it) {
+    if ((it->address == addr.address) && (it->proto == addr.proto)) {
+      LOG(INFO) << "Redundant relay address: " << proto_name
+                << " @ " << addr.address.ToSensitiveString();
+      return;
+    }
+  }
+  external_addr_.push_back(addr);
+}
+
+void RelayPort::SetReady() {
+  if (!ready_) {
+    std::vector<ProtocolAddress>::iterator iter;
+    for (iter = external_addr_.begin();
+         iter != external_addr_.end(); ++iter) {
+      std::string proto_name = ProtoToString(iter->proto);
+      // In case of Gturn, related address is set to null socket address.
+      // This is due to as mapped address stun attribute is used for allocated
+      // address.
+      AddAddress(iter->address, iter->address, rtc::SocketAddress(),
+                 proto_name, "", RELAY_PORT_TYPE,
+                 ICE_TYPE_PREFERENCE_RELAY, 0, false);
+    }
+    ready_ = true;
+    SignalPortComplete(this);
+  }
+}
+
+const ProtocolAddress * RelayPort::ServerAddress(size_t index) const {
+  if (index < server_addr_.size())
+    return &server_addr_[index];
+  return NULL;
+}
+
+bool RelayPort::HasMagicCookie(const char* data, size_t size) {
+  if (size < 24 + sizeof(TURN_MAGIC_COOKIE_VALUE)) {
+    return false;
+  } else {
+    return memcmp(data + 24,
+                  TURN_MAGIC_COOKIE_VALUE,
+                  sizeof(TURN_MAGIC_COOKIE_VALUE)) == 0;
+  }
+}
+
+void RelayPort::PrepareAddress() {
+  // We initiate a connect on the first entry.  If this completes, it will fill
+  // in the server address as the address of this port.
+  ASSERT(entries_.size() == 1);
+  entries_[0]->Connect();
+  ready_ = false;
+}
+
+Connection* RelayPort::CreateConnection(const Candidate& address,
+                                        CandidateOrigin origin) {
+  // We only create conns to non-udp sockets if they are incoming on this port
+  if ((address.protocol() != UDP_PROTOCOL_NAME) &&
+      (origin != ORIGIN_THIS_PORT)) {
+    return 0;
+  }
+
+  // We don't support loopback on relays
+  if (address.type() == Type()) {
+    return 0;
+  }
+
+  if (!IsCompatibleAddress(address.address())) {
+    return 0;
+  }
+
+  size_t index = 0;
+  for (size_t i = 0; i < Candidates().size(); ++i) {
+    const Candidate& local = Candidates()[i];
+    if (local.protocol() == address.protocol()) {
+      index = i;
+      break;
+    }
+  }
+
+  Connection * conn = new ProxyConnection(this, index, address);
+  AddConnection(conn);
+  return conn;
+}
+
+int RelayPort::SendTo(const void* data, size_t size,
+                      const rtc::SocketAddress& addr,
+                      const rtc::PacketOptions& options,
+                      bool payload) {
+  // Try to find an entry for this specific address.  Note that the first entry
+  // created was not given an address initially, so it can be set to the first
+  // address that comes along.
+  RelayEntry* entry = 0;
+
+  for (size_t i = 0; i < entries_.size(); ++i) {
+    if (entries_[i]->address().IsNil() && payload) {
+      entry = entries_[i];
+      entry->set_address(addr);
+      break;
+    } else if (entries_[i]->address() == addr) {
+      entry = entries_[i];
+      break;
+    }
+  }
+
+  // If we did not find one, then we make a new one.  This will not be useable
+  // until it becomes connected, however.
+  if (!entry && payload) {
+    entry = new RelayEntry(this, addr);
+    if (!entries_.empty()) {
+      entry->SetServerIndex(entries_[0]->ServerIndex());
+    }
+    entry->Connect();
+    entries_.push_back(entry);
+  }
+
+  // If the entry is connected, then we can send on it (though wrapping may
+  // still be necessary).  Otherwise, we can't yet use this connection, so we
+  // default to the first one.
+  if (!entry || !entry->connected()) {
+    ASSERT(!entries_.empty());
+    entry = entries_[0];
+    if (!entry->connected()) {
+      error_ = EWOULDBLOCK;
+      return SOCKET_ERROR;
+    }
+  }
+
+  // Send the actual contents to the server using the usual mechanism.
+  int sent = entry->SendTo(data, size, addr, options);
+  if (sent <= 0) {
+    ASSERT(sent < 0);
+    error_ = entry->GetError();
+    return SOCKET_ERROR;
+  }
+  // The caller of the function is expecting the number of user data bytes,
+  // rather than the size of the packet.
+  return static_cast<int>(size);
+}
+
+int RelayPort::SetOption(rtc::Socket::Option opt, int value) {
+  int result = 0;
+  for (size_t i = 0; i < entries_.size(); ++i) {
+    if (entries_[i]->SetSocketOption(opt, value) < 0) {
+      result = -1;
+      error_ = entries_[i]->GetError();
+    }
+  }
+  options_.push_back(OptionValue(opt, value));
+  return result;
+}
+
+int RelayPort::GetOption(rtc::Socket::Option opt, int* value) {
+  std::vector<OptionValue>::iterator it;
+  for (it = options_.begin(); it < options_.end(); ++it) {
+    if (it->first == opt) {
+      *value = it->second;
+      return 0;
+    }
+  }
+  return SOCKET_ERROR;
+}
+
+int RelayPort::GetError() {
+  return error_;
+}
+
+void RelayPort::OnReadPacket(
+    const char* data, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    ProtocolType proto,
+    const rtc::PacketTime& packet_time) {
+  if (Connection* conn = GetConnection(remote_addr)) {
+    conn->OnReadPacket(data, size, packet_time);
+  } else {
+    Port::OnReadPacket(data, size, remote_addr, proto);
+  }
+}
+
+RelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
+                                 rtc::AsyncPacketSocket* socket,
+                                 rtc::Thread* thread)
+    : socket_(socket),
+      protocol_address_(protocol_address) {
+  request_manager_ = new StunRequestManager(thread);
+  request_manager_->SignalSendPacket.connect(this,
+                                             &RelayConnection::OnSendPacket);
+}
+
+RelayConnection::~RelayConnection() {
+  delete request_manager_;
+  delete socket_;
+}
+
+int RelayConnection::SetSocketOption(rtc::Socket::Option opt,
+                                     int value) {
+  if (socket_) {
+    return socket_->SetOption(opt, value);
+  }
+  return 0;
+}
+
+bool RelayConnection::CheckResponse(StunMessage* msg) {
+  return request_manager_->CheckResponse(msg);
+}
+
+void RelayConnection::OnSendPacket(const void* data, size_t size,
+                                   StunRequest* req) {
+  // TODO(mallinath) Find a way to get DSCP value from Port.
+  rtc::PacketOptions options;  // Default dscp set to NO_CHANGE.
+  int sent = socket_->SendTo(data, size, GetAddress(), options);
+  if (sent <= 0) {
+    LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() <<
+        strerror(socket_->GetError());
+    ASSERT(sent < 0);
+  }
+}
+
+int RelayConnection::Send(const void* pv, size_t cb,
+                          const rtc::PacketOptions& options) {
+  return socket_->SendTo(pv, cb, GetAddress(), options);
+}
+
+void RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) {
+  request_manager_->SendDelayed(new AllocateRequest(entry, this), delay);
+}
+
+RelayEntry::RelayEntry(RelayPort* port,
+                       const rtc::SocketAddress& ext_addr)
+    : port_(port), ext_addr_(ext_addr),
+      server_index_(0), connected_(false), locked_(false),
+      current_connection_(NULL) {
+}
+
+RelayEntry::~RelayEntry() {
+  // Remove all RelayConnections and dispose sockets.
+  delete current_connection_;
+  current_connection_ = NULL;
+}
+
+void RelayEntry::Connect() {
+  // If we're already connected, return.
+  if (connected_)
+    return;
+
+  // If we've exhausted all options, bail out.
+  const ProtocolAddress* ra = port()->ServerAddress(server_index_);
+  if (!ra) {
+    LOG(LS_WARNING) << "No more relay addresses left to try";
+    return;
+  }
+
+  // Remove any previous connection.
+  if (current_connection_) {
+    port()->thread()->Dispose(current_connection_);
+    current_connection_ = NULL;
+  }
+
+  // Try to set up our new socket.
+  LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) <<
+      " @ " << ra->address.ToSensitiveString();
+
+  rtc::AsyncPacketSocket* socket = NULL;
+
+  if (ra->proto == PROTO_UDP) {
+    // UDP sockets are simple.
+    socket = port_->socket_factory()->CreateUdpSocket(
+        rtc::SocketAddress(port_->ip(), 0),
+        port_->min_port(), port_->max_port());
+  } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
+    int opts = (ra->proto == PROTO_SSLTCP) ?
+     rtc::PacketSocketFactory::OPT_SSLTCP : 0;
+    socket = port_->socket_factory()->CreateClientTcpSocket(
+        rtc::SocketAddress(port_->ip(), 0), ra->address,
+        port_->proxy(), port_->user_agent(), opts);
+  } else {
+    LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")";
+  }
+
+  if (!socket) {
+    LOG(LS_WARNING) << "Socket creation failed";
+  }
+
+  // If we failed to get a socket, move on to the next protocol.
+  if (!socket) {
+    port()->thread()->Post(this, kMessageConnectTimeout);
+    return;
+  }
+
+  // Otherwise, create the new connection and configure any socket options.
+  socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
+  socket->SignalReadyToSend.connect(this, &RelayEntry::OnReadyToSend);
+  current_connection_ = new RelayConnection(ra, socket, port()->thread());
+  for (size_t i = 0; i < port_->options().size(); ++i) {
+    current_connection_->SetSocketOption(port_->options()[i].first,
+                                         port_->options()[i].second);
+  }
+
+  // If we're trying UDP, start binding requests.
+  // If we're trying TCP, wait for connection with a fixed timeout.
+  if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
+    socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
+    socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
+    port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this,
+                                  kMessageConnectTimeout);
+  } else {
+    current_connection_->SendAllocateRequest(this, 0);
+  }
+}
+
+int RelayEntry::GetError() {
+  if (current_connection_ != NULL) {
+    return current_connection_->GetError();
+  }
+  return 0;
+}
+
+RelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1,
+                                               RelayConnection* conn2) {
+  return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2;
+}
+
+void RelayEntry::OnConnect(const rtc::SocketAddress& mapped_addr,
+                           RelayConnection* connection) {
+  // We are connected, notify our parent.
+  ProtocolType proto = PROTO_UDP;
+  LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto)
+            << " @ " << mapped_addr.ToSensitiveString();
+  connected_ = true;
+
+  port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
+  port_->SetReady();
+}
+
+int RelayEntry::SendTo(const void* data, size_t size,
+                       const rtc::SocketAddress& addr,
+                       const rtc::PacketOptions& options) {
+  // If this connection is locked to the address given, then we can send the
+  // packet with no wrapper.
+  if (locked_ && (ext_addr_ == addr))
+    return SendPacket(data, size, options);
+
+  // Otherwise, we must wrap the given data in a STUN SEND request so that we
+  // can communicate the destination address to the server.
+  //
+  // Note that we do not use a StunRequest here.  This is because there is
+  // likely no reason to resend this packet. If it is late, we just drop it.
+  // The next send to this address will try again.
+
+  RelayMessage request;
+  request.SetType(STUN_SEND_REQUEST);
+
+  StunByteStringAttribute* magic_cookie_attr =
+      StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+  magic_cookie_attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE,
+                               sizeof(TURN_MAGIC_COOKIE_VALUE));
+  VERIFY(request.AddAttribute(magic_cookie_attr));
+
+  StunByteStringAttribute* username_attr =
+      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+  username_attr->CopyBytes(port_->username_fragment().c_str(),
+                           port_->username_fragment().size());
+  VERIFY(request.AddAttribute(username_attr));
+
+  StunAddressAttribute* addr_attr =
+      StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+  addr_attr->SetIP(addr.ipaddr());
+  addr_attr->SetPort(addr.port());
+  VERIFY(request.AddAttribute(addr_attr));
+
+  // Attempt to lock
+  if (ext_addr_ == addr) {
+    StunUInt32Attribute* options_attr =
+      StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS);
+    options_attr->SetValue(0x1);
+    VERIFY(request.AddAttribute(options_attr));
+  }
+
+  StunByteStringAttribute* data_attr =
+      StunAttribute::CreateByteString(STUN_ATTR_DATA);
+  data_attr->CopyBytes(data, size);
+  VERIFY(request.AddAttribute(data_attr));
+
+  // TODO: compute the HMAC.
+
+  rtc::ByteBuffer buf;
+  request.Write(&buf);
+
+  return SendPacket(buf.Data(), buf.Length(), options);
+}
+
+void RelayEntry::ScheduleKeepAlive() {
+  if (current_connection_) {
+    current_connection_->SendAllocateRequest(this, kKeepAliveDelay);
+  }
+}
+
+int RelayEntry::SetSocketOption(rtc::Socket::Option opt, int value) {
+  // Set the option on all available sockets.
+  int socket_error = 0;
+  if (current_connection_) {
+    socket_error = current_connection_->SetSocketOption(opt, value);
+  }
+  return socket_error;
+}
+
+void RelayEntry::HandleConnectFailure(
+    rtc::AsyncPacketSocket* socket) {
+  // Make sure it's the current connection that has failed, it might
+  // be an old socked that has not yet been disposed.
+  if (!socket ||
+      (current_connection_ && socket == current_connection_->socket())) {
+    if (current_connection_)
+      port()->SignalConnectFailure(current_connection_->protocol_address());
+
+    // Try to connect to the next server address.
+    server_index_ += 1;
+    Connect();
+  }
+}
+
+void RelayEntry::OnMessage(rtc::Message *pmsg) {
+  ASSERT(pmsg->message_id == kMessageConnectTimeout);
+  if (current_connection_) {
+    const ProtocolAddress* ra = current_connection_->protocol_address();
+    LOG(LS_WARNING) << "Relay " << ra->proto << " connection to " <<
+        ra->address << " timed out";
+
+    // Currently we connect to each server address in sequence. If we
+    // have more addresses to try, treat this is an error and move on to
+    // the next address, otherwise give this connection more time and
+    // await the real timeout.
+    //
+    // TODO: Connect to servers in parallel to speed up connect time
+    // and to avoid giving up too early.
+    port_->SignalSoftTimeout(ra);
+    HandleConnectFailure(current_connection_->socket());
+  } else {
+    HandleConnectFailure(NULL);
+  }
+}
+
+void RelayEntry::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
+  LOG(INFO) << "relay tcp connected to " <<
+      socket->GetRemoteAddress().ToSensitiveString();
+  if (current_connection_ != NULL) {
+    current_connection_->SendAllocateRequest(this, 0);
+  }
+}
+
+void RelayEntry::OnSocketClose(rtc::AsyncPacketSocket* socket,
+                               int error) {
+  PLOG(LERROR, error) << "Relay connection failed: socket closed";
+  HandleConnectFailure(socket);
+}
+
+void RelayEntry::OnReadPacket(
+    rtc::AsyncPacketSocket* socket,
+    const char* data, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time) {
+  // ASSERT(remote_addr == port_->server_addr());
+  // TODO: are we worried about this?
+
+  if (current_connection_ == NULL || socket != current_connection_->socket()) {
+    // This packet comes from an unknown address.
+    LOG(WARNING) << "Dropping packet: unknown address";
+    return;
+  }
+
+  // If the magic cookie is not present, then this is an unwrapped packet sent
+  // by the server,  The actual remote address is the one we recorded.
+  if (!port_->HasMagicCookie(data, size)) {
+    if (locked_) {
+      port_->OnReadPacket(data, size, ext_addr_, PROTO_UDP, packet_time);
+    } else {
+      LOG(WARNING) << "Dropping packet: entry not locked";
+    }
+    return;
+  }
+
+  rtc::ByteBuffer buf(data, size);
+  RelayMessage msg;
+  if (!msg.Read(&buf)) {
+    LOG(INFO) << "Incoming packet was not STUN";
+    return;
+  }
+
+  // The incoming packet should be a STUN ALLOCATE response, SEND response, or
+  // DATA indication.
+  if (current_connection_->CheckResponse(&msg)) {
+    return;
+  } else if (msg.type() == STUN_SEND_RESPONSE) {
+    if (const StunUInt32Attribute* options_attr =
+        msg.GetUInt32(STUN_ATTR_OPTIONS)) {
+      if (options_attr->value() & 0x1) {
+        locked_ = true;
+      }
+    }
+    return;
+  } else if (msg.type() != STUN_DATA_INDICATION) {
+    LOG(INFO) << "Received BAD stun type from server: " << msg.type();
+    return;
+  }
+
+  // This must be a data indication.
+
+  const StunAddressAttribute* addr_attr =
+      msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
+  if (!addr_attr) {
+    LOG(INFO) << "Data indication has no source address";
+    return;
+  } else if (addr_attr->family() != 1) {
+    LOG(INFO) << "Source address has bad family";
+    return;
+  }
+
+  rtc::SocketAddress remote_addr2(addr_attr->ipaddr(), addr_attr->port());
+
+  const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
+  if (!data_attr) {
+    LOG(INFO) << "Data indication has no data";
+    return;
+  }
+
+  // Process the actual data and remote address in the normal manner.
+  port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2,
+                      PROTO_UDP, packet_time);
+}
+
+void RelayEntry::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
+  if (connected()) {
+    port_->OnReadyToSend();
+  }
+}
+
+int RelayEntry::SendPacket(const void* data, size_t size,
+                           const rtc::PacketOptions& options) {
+  int sent = 0;
+  if (current_connection_) {
+    // We are connected, no need to send packets anywere else than to
+    // the current connection.
+    sent = current_connection_->Send(data, size, options);
+  }
+  return sent;
+}
+
+AllocateRequest::AllocateRequest(RelayEntry* entry,
+                                 RelayConnection* connection)
+    : StunRequest(new RelayMessage()),
+      entry_(entry),
+      connection_(connection) {
+  start_time_ = rtc::Time();
+}
+
+void AllocateRequest::Prepare(StunMessage* request) {
+  request->SetType(STUN_ALLOCATE_REQUEST);
+
+  StunByteStringAttribute* username_attr =
+      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+  username_attr->CopyBytes(
+      entry_->port()->username_fragment().c_str(),
+      entry_->port()->username_fragment().size());
+  VERIFY(request->AddAttribute(username_attr));
+}
+
+int AllocateRequest::GetNextDelay() {
+  int delay = 100 * rtc::_max(1 << count_, 2);
+  count_ += 1;
+  if (count_ == 5)
+    timeout_ = true;
+  return delay;
+}
+
+void AllocateRequest::OnResponse(StunMessage* response) {
+  const StunAddressAttribute* addr_attr =
+      response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  if (!addr_attr) {
+    LOG(INFO) << "Allocate response missing mapped address.";
+  } else if (addr_attr->family() != 1) {
+    LOG(INFO) << "Mapped address has bad family";
+  } else {
+    rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
+    entry_->OnConnect(addr, connection_);
+  }
+
+  // We will do a keep-alive regardless of whether this request suceeds.
+  // This should have almost no impact on network usage.
+  entry_->ScheduleKeepAlive();
+}
+
+void AllocateRequest::OnErrorResponse(StunMessage* response) {
+  const StunErrorCodeAttribute* attr = response->GetErrorCode();
+  if (!attr) {
+    LOG(INFO) << "Bad allocate response error code";
+  } else {
+    LOG(INFO) << "Allocate error response:"
+              << " code=" << attr->code()
+              << " reason='" << attr->reason() << "'";
+  }
+
+  if (rtc::TimeSince(start_time_) <= kRetryTimeout)
+    entry_->ScheduleKeepAlive();
+}
+
+void AllocateRequest::OnTimeout() {
+  LOG(INFO) << "Allocate request timed out";
+  entry_->HandleConnectFailure(connection_->socket());
+}
+
+}  // namespace cricket
diff --git a/p2p/base/relayport.h b/p2p/base/relayport.h
new file mode 100644
index 0000000..3d9538d
--- /dev/null
+++ b/p2p/base/relayport.h
@@ -0,0 +1,101 @@
+/*
+ *  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_P2P_BASE_RELAYPORT_H_
+#define WEBRTC_P2P_BASE_RELAYPORT_H_
+
+#include <deque>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/stunrequest.h"
+
+namespace cricket {
+
+class RelayEntry;
+class RelayConnection;
+
+// Communicates using an allocated port on the relay server. For each
+// remote candidate that we try to send data to a RelayEntry instance
+// is created. The RelayEntry will try to reach the remote destination
+// by connecting to all available server addresses in a pre defined
+// order with a small delay in between. When a connection is
+// successful all other connection attemts are aborted.
+class RelayPort : public Port {
+ public:
+  typedef std::pair<rtc::Socket::Option, int> OptionValue;
+
+  // RelayPort doesn't yet do anything fancy in the ctor.
+  static RelayPort* Create(
+      rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+      rtc::Network* network, const rtc::IPAddress& ip,
+      int min_port, int max_port, const std::string& username,
+      const std::string& password) {
+    return new RelayPort(thread, factory, network, ip, min_port, max_port,
+                         username, password);
+  }
+  virtual ~RelayPort();
+
+  void AddServerAddress(const ProtocolAddress& addr);
+  void AddExternalAddress(const ProtocolAddress& addr);
+
+  const std::vector<OptionValue>& options() const { return options_; }
+  bool HasMagicCookie(const char* data, size_t size);
+
+  virtual void PrepareAddress();
+  virtual Connection* CreateConnection(const Candidate& address,
+                                       CandidateOrigin origin);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetOption(rtc::Socket::Option opt, int* value);
+  virtual int GetError();
+
+  const ProtocolAddress * ServerAddress(size_t index) const;
+  bool IsReady() { return ready_; }
+
+  // Used for testing.
+  sigslot::signal1<const ProtocolAddress*> SignalConnectFailure;
+  sigslot::signal1<const ProtocolAddress*> SignalSoftTimeout;
+
+ protected:
+  RelayPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+            rtc::Network*, const rtc::IPAddress& ip,
+            int min_port, int max_port, const std::string& username,
+            const std::string& password);
+  bool Init();
+
+  void SetReady();
+
+  virtual int SendTo(const void* data, size_t size,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options,
+                     bool payload);
+
+  // Dispatches the given packet to the port or connection as appropriate.
+  void OnReadPacket(const char* data, size_t size,
+                    const rtc::SocketAddress& remote_addr,
+                    ProtocolType proto,
+                    const rtc::PacketTime& packet_time);
+
+ private:
+  friend class RelayEntry;
+
+  std::deque<ProtocolAddress> server_addr_;
+  std::vector<ProtocolAddress> external_addr_;
+  bool ready_;
+  std::vector<RelayEntry*> entries_;
+  std::vector<OptionValue> options_;
+  int error_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_RELAYPORT_H_
diff --git a/p2p/base/relayport_unittest.cc b/p2p/base/relayport_unittest.cc
new file mode 100644
index 0000000..d644d67
--- /dev/null
+++ b/p2p/base/relayport_unittest.cc
@@ -0,0 +1,272 @@
+/*
+ *  Copyright 2009 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/p2p/base/relayserver.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketadapters.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+using rtc::SocketAddress;
+
+static const SocketAddress kLocalAddress = SocketAddress("192.168.1.2", 0);
+static const SocketAddress kRelayUdpAddr = SocketAddress("99.99.99.1", 5000);
+static const SocketAddress kRelayTcpAddr = SocketAddress("99.99.99.2", 5001);
+static const SocketAddress kRelaySslAddr = SocketAddress("99.99.99.3", 443);
+static const SocketAddress kRelayExtAddr = SocketAddress("99.99.99.3", 5002);
+
+static const int kTimeoutMs = 1000;
+static const int kMaxTimeoutMs = 5000;
+
+// Tests connecting a RelayPort to a fake relay server
+// (cricket::RelayServer) using all currently available protocols. The
+// network layer is faked out by using a VirtualSocketServer for
+// creating sockets. The test will monitor the current state of the
+// RelayPort and created sockets by listening for signals such as,
+// SignalConnectFailure, SignalConnectTimeout, SignalSocketClosed and
+// SignalReadPacket.
+class RelayPortTest : public testing::Test,
+                      public sigslot::has_slots<> {
+ public:
+  RelayPortTest()
+      : main_(rtc::Thread::Current()),
+        physical_socket_server_(new rtc::PhysicalSocketServer),
+        virtual_socket_server_(new rtc::VirtualSocketServer(
+            physical_socket_server_.get())),
+        ss_scope_(virtual_socket_server_.get()),
+        network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32),
+        socket_factory_(rtc::Thread::Current()),
+        username_(rtc::CreateRandomString(16)),
+        password_(rtc::CreateRandomString(16)),
+        relay_port_(cricket::RelayPort::Create(main_, &socket_factory_,
+                                               &network_,
+                                               kLocalAddress.ipaddr(),
+                                               0, 0, username_, password_)),
+        relay_server_(new cricket::RelayServer(main_)) {
+  }
+
+  void OnReadPacket(rtc::AsyncPacketSocket* socket,
+                    const char* data, size_t size,
+                    const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time) {
+    received_packet_count_[socket]++;
+  }
+
+  void OnConnectFailure(const cricket::ProtocolAddress* addr) {
+    failed_connections_.push_back(*addr);
+  }
+
+  void OnSoftTimeout(const cricket::ProtocolAddress* addr) {
+    soft_timedout_connections_.push_back(*addr);
+  }
+
+ protected:
+  virtual void SetUp() {
+    // The relay server needs an external socket to work properly.
+    rtc::AsyncUDPSocket* ext_socket =
+        CreateAsyncUdpSocket(kRelayExtAddr);
+    relay_server_->AddExternalSocket(ext_socket);
+
+    // Listen for failures.
+    relay_port_->SignalConnectFailure.
+        connect(this, &RelayPortTest::OnConnectFailure);
+
+    // Listen for soft timeouts.
+    relay_port_->SignalSoftTimeout.
+        connect(this, &RelayPortTest::OnSoftTimeout);
+  }
+
+  // Udp has the highest 'goodness' value of the three different
+  // protocols used for connecting to the relay server. As soon as
+  // PrepareAddress is called, the RelayPort will start trying to
+  // connect to the given UDP address. As soon as a response to the
+  // sent STUN allocate request message has been received, the
+  // RelayPort will consider the connection to be complete and will
+  // abort any other connection attempts.
+  void TestConnectUdp() {
+    // Add a UDP socket to the relay server.
+    rtc::AsyncUDPSocket* internal_udp_socket =
+        CreateAsyncUdpSocket(kRelayUdpAddr);
+    rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr);
+
+    relay_server_->AddInternalSocket(internal_udp_socket);
+    relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP);
+
+    // Now add our relay addresses to the relay port and let it start.
+    relay_port_->AddServerAddress(
+        cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP));
+    relay_port_->AddServerAddress(
+        cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP));
+    relay_port_->PrepareAddress();
+
+    // Should be connected.
+    EXPECT_TRUE_WAIT(relay_port_->IsReady(), kTimeoutMs);
+
+    // Make sure that we are happy with UDP, ie. not continuing with
+    // TCP, SSLTCP, etc.
+    WAIT(relay_server_->HasConnection(kRelayTcpAddr), kTimeoutMs);
+
+    // Should have only one connection.
+    EXPECT_EQ(1, relay_server_->GetConnectionCount());
+
+    // Should be the UDP address.
+    EXPECT_TRUE(relay_server_->HasConnection(kRelayUdpAddr));
+  }
+
+  // TCP has the second best 'goodness' value, and as soon as UDP
+  // connection has failed, the RelayPort will attempt to connect via
+  // TCP. Here we add a fake UDP address together with a real TCP
+  // address to simulate an UDP failure. As soon as UDP has failed the
+  // RelayPort will try the TCP adress and succed.
+  void TestConnectTcp() {
+    // Create a fake UDP address for relay port to simulate a failure.
+    cricket::ProtocolAddress fake_protocol_address =
+        cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP);
+
+    // Create a server socket for the RelayServer.
+    rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr);
+    relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP);
+
+    // Add server addresses to the relay port and let it start.
+    relay_port_->AddServerAddress(
+        cricket::ProtocolAddress(fake_protocol_address));
+    relay_port_->AddServerAddress(
+        cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP));
+    relay_port_->PrepareAddress();
+
+    EXPECT_FALSE(relay_port_->IsReady());
+
+    // Should have timed out in 200 + 200 + 400 + 800 + 1600 ms.
+    EXPECT_TRUE_WAIT(HasFailed(&fake_protocol_address), 3600);
+
+    // Wait until relayport is ready.
+    EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs);
+
+    // Should have only one connection.
+    EXPECT_EQ(1, relay_server_->GetConnectionCount());
+
+    // Should be the TCP address.
+    EXPECT_TRUE(relay_server_->HasConnection(kRelayTcpAddr));
+  }
+
+  void TestConnectSslTcp() {
+    // Create a fake TCP address for relay port to simulate a failure.
+    // We skip UDP here since transition from UDP to TCP has been
+    // tested above.
+    cricket::ProtocolAddress fake_protocol_address =
+        cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP);
+
+    // Create a ssl server socket for the RelayServer.
+    rtc::AsyncSocket* ssl_server_socket =
+        CreateServerSocket(kRelaySslAddr);
+    relay_server_->AddInternalServerSocket(ssl_server_socket,
+                                           cricket::PROTO_SSLTCP);
+
+    // Create a tcp server socket that listens on the fake address so
+    // the relay port can attempt to connect to it.
+    rtc::scoped_ptr<rtc::AsyncSocket> tcp_server_socket(
+        CreateServerSocket(kRelayTcpAddr));
+
+    // Add server addresses to the relay port and let it start.
+    relay_port_->AddServerAddress(fake_protocol_address);
+    relay_port_->AddServerAddress(
+        cricket::ProtocolAddress(kRelaySslAddr, cricket::PROTO_SSLTCP));
+    relay_port_->PrepareAddress();
+    EXPECT_FALSE(relay_port_->IsReady());
+
+    // Should have timed out in 3000 ms(relayport.cc, kSoftConnectTimeoutMs).
+    EXPECT_TRUE_WAIT_MARGIN(HasTimedOut(&fake_protocol_address), 3000, 100);
+
+    // Wait until relayport is ready.
+    EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs);
+
+    // Should have only one connection.
+    EXPECT_EQ(1, relay_server_->GetConnectionCount());
+
+    // Should be the SSLTCP address.
+    EXPECT_TRUE(relay_server_->HasConnection(kRelaySslAddr));
+  }
+
+ private:
+  rtc::AsyncUDPSocket* CreateAsyncUdpSocket(const SocketAddress addr) {
+    rtc::AsyncSocket* socket =
+        virtual_socket_server_->CreateAsyncSocket(SOCK_DGRAM);
+    rtc::AsyncUDPSocket* packet_socket =
+        rtc::AsyncUDPSocket::Create(socket, addr);
+    EXPECT_TRUE(packet_socket != NULL);
+    packet_socket->SignalReadPacket.connect(this, &RelayPortTest::OnReadPacket);
+    return packet_socket;
+  }
+
+  rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) {
+    rtc::AsyncSocket* socket =
+        virtual_socket_server_->CreateAsyncSocket(SOCK_STREAM);
+    EXPECT_GE(socket->Bind(addr), 0);
+    EXPECT_GE(socket->Listen(5), 0);
+    return socket;
+  }
+
+  bool HasFailed(cricket::ProtocolAddress* addr) {
+    for (size_t i = 0; i < failed_connections_.size(); i++) {
+      if (failed_connections_[i].address == addr->address &&
+          failed_connections_[i].proto == addr->proto) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool HasTimedOut(cricket::ProtocolAddress* addr) {
+    for (size_t i = 0; i < soft_timedout_connections_.size(); i++) {
+      if (soft_timedout_connections_[i].address == addr->address &&
+          soft_timedout_connections_[i].proto == addr->proto) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  typedef std::map<rtc::AsyncPacketSocket*, int> PacketMap;
+
+  rtc::Thread* main_;
+  rtc::scoped_ptr<rtc::PhysicalSocketServer>
+      physical_socket_server_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> virtual_socket_server_;
+  rtc::SocketServerScope ss_scope_;
+  rtc::Network network_;
+  rtc::BasicPacketSocketFactory socket_factory_;
+  std::string username_;
+  std::string password_;
+  rtc::scoped_ptr<cricket::RelayPort> relay_port_;
+  rtc::scoped_ptr<cricket::RelayServer> relay_server_;
+  std::vector<cricket::ProtocolAddress> failed_connections_;
+  std::vector<cricket::ProtocolAddress> soft_timedout_connections_;
+  PacketMap received_packet_count_;
+};
+
+TEST_F(RelayPortTest, ConnectUdp) {
+  TestConnectUdp();
+}
+
+TEST_F(RelayPortTest, ConnectTcp) {
+  TestConnectTcp();
+}
+
+TEST_F(RelayPortTest, ConnectSslTcp) {
+  TestConnectSslTcp();
+}
diff --git a/p2p/base/relayserver.cc b/p2p/base/relayserver.cc
new file mode 100644
index 0000000..e37a168
--- /dev/null
+++ b/p2p/base/relayserver.cc
@@ -0,0 +1,746 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/relayserver.h"
+
+#ifdef WEBRTC_POSIX
+#include <errno.h>
+#endif  // WEBRTC_POSIX
+
+#include <algorithm>
+
+#include "webrtc/base/asynctcpsocket.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/socketadapters.h"
+
+namespace cricket {
+
+// By default, we require a ping every 90 seconds.
+const int MAX_LIFETIME = 15 * 60 * 1000;
+
+// The number of bytes in each of the usernames we use.
+const uint32 USERNAME_LENGTH = 16;
+
+// Calls SendTo on the given socket and logs any bad results.
+void Send(rtc::AsyncPacketSocket* socket, const char* bytes, size_t size,
+          const rtc::SocketAddress& addr) {
+  rtc::PacketOptions options;
+  int result = socket->SendTo(bytes, size, addr, options);
+  if (result < static_cast<int>(size)) {
+    LOG(LS_ERROR) << "SendTo wrote only " << result << " of " << size
+                  << " bytes";
+  } else if (result < 0) {
+    LOG_ERR(LS_ERROR) << "SendTo";
+  }
+}
+
+// Sends the given STUN message on the given socket.
+void SendStun(const StunMessage& msg,
+              rtc::AsyncPacketSocket* socket,
+              const rtc::SocketAddress& addr) {
+  rtc::ByteBuffer buf;
+  msg.Write(&buf);
+  Send(socket, buf.Data(), buf.Length(), addr);
+}
+
+// Constructs a STUN error response and sends it on the given socket.
+void SendStunError(const StunMessage& msg, rtc::AsyncPacketSocket* socket,
+                   const rtc::SocketAddress& remote_addr, int error_code,
+                   const char* error_desc, const std::string& magic_cookie) {
+  RelayMessage err_msg;
+  err_msg.SetType(GetStunErrorResponseType(msg.type()));
+  err_msg.SetTransactionID(msg.transaction_id());
+
+  StunByteStringAttribute* magic_cookie_attr =
+      StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+  if (magic_cookie.size() == 0) {
+    magic_cookie_attr->CopyBytes(cricket::TURN_MAGIC_COOKIE_VALUE,
+                                 sizeof(cricket::TURN_MAGIC_COOKIE_VALUE));
+  } else {
+    magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size());
+  }
+  err_msg.AddAttribute(magic_cookie_attr);
+
+  StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
+  err_code->SetClass(error_code / 100);
+  err_code->SetNumber(error_code % 100);
+  err_code->SetReason(error_desc);
+  err_msg.AddAttribute(err_code);
+
+  SendStun(err_msg, socket, remote_addr);
+}
+
+RelayServer::RelayServer(rtc::Thread* thread)
+  : thread_(thread), log_bindings_(true) {
+}
+
+RelayServer::~RelayServer() {
+  // Deleting the binding will cause it to be removed from the map.
+  while (!bindings_.empty())
+    delete bindings_.begin()->second;
+  for (size_t i = 0; i < internal_sockets_.size(); ++i)
+    delete internal_sockets_[i];
+  for (size_t i = 0; i < external_sockets_.size(); ++i)
+    delete external_sockets_[i];
+  for (size_t i = 0; i < removed_sockets_.size(); ++i)
+    delete removed_sockets_[i];
+  while (!server_sockets_.empty()) {
+    rtc::AsyncSocket* socket = server_sockets_.begin()->first;
+    server_sockets_.erase(server_sockets_.begin()->first);
+    delete socket;
+  }
+}
+
+void RelayServer::AddInternalSocket(rtc::AsyncPacketSocket* socket) {
+  ASSERT(internal_sockets_.end() ==
+      std::find(internal_sockets_.begin(), internal_sockets_.end(), socket));
+  internal_sockets_.push_back(socket);
+  socket->SignalReadPacket.connect(this, &RelayServer::OnInternalPacket);
+}
+
+void RelayServer::RemoveInternalSocket(rtc::AsyncPacketSocket* socket) {
+  SocketList::iterator iter =
+      std::find(internal_sockets_.begin(), internal_sockets_.end(), socket);
+  ASSERT(iter != internal_sockets_.end());
+  internal_sockets_.erase(iter);
+  removed_sockets_.push_back(socket);
+  socket->SignalReadPacket.disconnect(this);
+}
+
+void RelayServer::AddExternalSocket(rtc::AsyncPacketSocket* socket) {
+  ASSERT(external_sockets_.end() ==
+      std::find(external_sockets_.begin(), external_sockets_.end(), socket));
+  external_sockets_.push_back(socket);
+  socket->SignalReadPacket.connect(this, &RelayServer::OnExternalPacket);
+}
+
+void RelayServer::RemoveExternalSocket(rtc::AsyncPacketSocket* socket) {
+  SocketList::iterator iter =
+      std::find(external_sockets_.begin(), external_sockets_.end(), socket);
+  ASSERT(iter != external_sockets_.end());
+  external_sockets_.erase(iter);
+  removed_sockets_.push_back(socket);
+  socket->SignalReadPacket.disconnect(this);
+}
+
+void RelayServer::AddInternalServerSocket(rtc::AsyncSocket* socket,
+                                          cricket::ProtocolType proto) {
+  ASSERT(server_sockets_.end() ==
+         server_sockets_.find(socket));
+  server_sockets_[socket] = proto;
+  socket->SignalReadEvent.connect(this, &RelayServer::OnReadEvent);
+}
+
+void RelayServer::RemoveInternalServerSocket(
+    rtc::AsyncSocket* socket) {
+  ServerSocketMap::iterator iter = server_sockets_.find(socket);
+  ASSERT(iter != server_sockets_.end());
+  server_sockets_.erase(iter);
+  socket->SignalReadEvent.disconnect(this);
+}
+
+int RelayServer::GetConnectionCount() const {
+  return static_cast<int>(connections_.size());
+}
+
+rtc::SocketAddressPair RelayServer::GetConnection(int connection) const {
+  int i = 0;
+  for (ConnectionMap::const_iterator it = connections_.begin();
+       it != connections_.end(); ++it) {
+    if (i == connection) {
+      return it->second->addr_pair();
+    }
+    ++i;
+  }
+  return rtc::SocketAddressPair();
+}
+
+bool RelayServer::HasConnection(const rtc::SocketAddress& address) const {
+  for (ConnectionMap::const_iterator it = connections_.begin();
+       it != connections_.end(); ++it) {
+    if (it->second->addr_pair().destination() == address) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void RelayServer::OnReadEvent(rtc::AsyncSocket* socket) {
+  ASSERT(server_sockets_.find(socket) != server_sockets_.end());
+  AcceptConnection(socket);
+}
+
+void RelayServer::OnInternalPacket(
+    rtc::AsyncPacketSocket* socket, const char* bytes, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time) {
+
+  // Get the address of the connection we just received on.
+  rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
+  ASSERT(!ap.destination().IsNil());
+
+  // If this did not come from an existing connection, it should be a STUN
+  // allocate request.
+  ConnectionMap::iterator piter = connections_.find(ap);
+  if (piter == connections_.end()) {
+    HandleStunAllocate(bytes, size, ap, socket);
+    return;
+  }
+
+  RelayServerConnection* int_conn = piter->second;
+
+  // Handle STUN requests to the server itself.
+  if (int_conn->binding()->HasMagicCookie(bytes, size)) {
+    HandleStun(int_conn, bytes, size);
+    return;
+  }
+
+  // Otherwise, this is a non-wrapped packet that we are to forward.  Make sure
+  // that this connection has been locked.  (Otherwise, we would not know what
+  // address to forward to.)
+  if (!int_conn->locked()) {
+    LOG(LS_WARNING) << "Dropping packet: connection not locked";
+    return;
+  }
+
+  // Forward this to the destination address into the connection.
+  RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection(
+      int_conn->default_destination());
+  if (ext_conn && ext_conn->locked()) {
+    // TODO: Check the HMAC.
+    ext_conn->Send(bytes, size);
+  } else {
+    // This happens very often and is not an error.
+    LOG(LS_INFO) << "Dropping packet: no external connection";
+  }
+}
+
+void RelayServer::OnExternalPacket(
+    rtc::AsyncPacketSocket* socket, const char* bytes, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time) {
+
+  // Get the address of the connection we just received on.
+  rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
+  ASSERT(!ap.destination().IsNil());
+
+  // If this connection already exists, then forward the traffic.
+  ConnectionMap::iterator piter = connections_.find(ap);
+  if (piter != connections_.end()) {
+    // TODO: Check the HMAC.
+    RelayServerConnection* ext_conn = piter->second;
+    RelayServerConnection* int_conn =
+        ext_conn->binding()->GetInternalConnection(
+            ext_conn->addr_pair().source());
+    ASSERT(int_conn != NULL);
+    int_conn->Send(bytes, size, ext_conn->addr_pair().source());
+    ext_conn->Lock();  // allow outgoing packets
+    return;
+  }
+
+  // The first packet should always be a STUN / TURN packet.  If it isn't, then
+  // we should just ignore this packet.
+  RelayMessage msg;
+  rtc::ByteBuffer buf(bytes, size);
+  if (!msg.Read(&buf)) {
+    LOG(LS_WARNING) << "Dropping packet: first packet not STUN";
+    return;
+  }
+
+  // The initial packet should have a username (which identifies the binding).
+  const StunByteStringAttribute* username_attr =
+      msg.GetByteString(STUN_ATTR_USERNAME);
+  if (!username_attr) {
+    LOG(LS_WARNING) << "Dropping packet: no username";
+    return;
+  }
+
+  uint32 length = rtc::_min(static_cast<uint32>(username_attr->length()),
+                                  USERNAME_LENGTH);
+  std::string username(username_attr->bytes(), length);
+  // TODO: Check the HMAC.
+
+  // The binding should already be present.
+  BindingMap::iterator biter = bindings_.find(username);
+  if (biter == bindings_.end()) {
+    LOG(LS_WARNING) << "Dropping packet: no binding with username";
+    return;
+  }
+
+  // Add this authenticted connection to the binding.
+  RelayServerConnection* ext_conn =
+      new RelayServerConnection(biter->second, ap, socket);
+  ext_conn->binding()->AddExternalConnection(ext_conn);
+  AddConnection(ext_conn);
+
+  // We always know where external packets should be forwarded, so we can lock
+  // them from the beginning.
+  ext_conn->Lock();
+
+  // Send this message on the appropriate internal connection.
+  RelayServerConnection* int_conn = ext_conn->binding()->GetInternalConnection(
+      ext_conn->addr_pair().source());
+  ASSERT(int_conn != NULL);
+  int_conn->Send(bytes, size, ext_conn->addr_pair().source());
+}
+
+bool RelayServer::HandleStun(
+    const char* bytes, size_t size, const rtc::SocketAddress& remote_addr,
+    rtc::AsyncPacketSocket* socket, std::string* username,
+    StunMessage* msg) {
+
+  // Parse this into a stun message. Eat the message if this fails.
+  rtc::ByteBuffer buf(bytes, size);
+  if (!msg->Read(&buf)) {
+    return false;
+  }
+
+  // The initial packet should have a username (which identifies the binding).
+  const StunByteStringAttribute* username_attr =
+      msg->GetByteString(STUN_ATTR_USERNAME);
+  if (!username_attr) {
+    SendStunError(*msg, socket, remote_addr, 432, "Missing Username", "");
+    return false;
+  }
+
+  // Record the username if requested.
+  if (username)
+    username->append(username_attr->bytes(), username_attr->length());
+
+  // TODO: Check for unknown attributes (<= 0x7fff)
+
+  return true;
+}
+
+void RelayServer::HandleStunAllocate(
+    const char* bytes, size_t size, const rtc::SocketAddressPair& ap,
+    rtc::AsyncPacketSocket* socket) {
+
+  // Make sure this is a valid STUN request.
+  RelayMessage request;
+  std::string username;
+  if (!HandleStun(bytes, size, ap.source(), socket, &username, &request))
+    return;
+
+  // Make sure this is a an allocate request.
+  if (request.type() != STUN_ALLOCATE_REQUEST) {
+    SendStunError(request,
+                  socket,
+                  ap.source(),
+                  600,
+                  "Operation Not Supported",
+                  "");
+    return;
+  }
+
+  // TODO: Check the HMAC.
+
+  // Find or create the binding for this username.
+
+  RelayServerBinding* binding;
+
+  BindingMap::iterator biter = bindings_.find(username);
+  if (biter != bindings_.end()) {
+    binding = biter->second;
+  } else {
+    // NOTE: In the future, bindings will be created by the bot only.  This
+    //       else-branch will then disappear.
+
+    // Compute the appropriate lifetime for this binding.
+    uint32 lifetime = MAX_LIFETIME;
+    const StunUInt32Attribute* lifetime_attr =
+        request.GetUInt32(STUN_ATTR_LIFETIME);
+    if (lifetime_attr)
+      lifetime = rtc::_min(lifetime, lifetime_attr->value() * 1000);
+
+    binding = new RelayServerBinding(this, username, "0", lifetime);
+    binding->SignalTimeout.connect(this, &RelayServer::OnTimeout);
+    bindings_[username] = binding;
+
+    if (log_bindings_) {
+      LOG(LS_INFO) << "Added new binding " << username << ", "
+                   << bindings_.size() << " total";
+    }
+  }
+
+  // Add this connection to the binding.  It starts out unlocked.
+  RelayServerConnection* int_conn =
+      new RelayServerConnection(binding, ap, socket);
+  binding->AddInternalConnection(int_conn);
+  AddConnection(int_conn);
+
+  // Now that we have a connection, this other method takes over.
+  HandleStunAllocate(int_conn, request);
+}
+
+void RelayServer::HandleStun(
+    RelayServerConnection* int_conn, const char* bytes, size_t size) {
+
+  // Make sure this is a valid STUN request.
+  RelayMessage request;
+  std::string username;
+  if (!HandleStun(bytes, size, int_conn->addr_pair().source(),
+                  int_conn->socket(), &username, &request))
+    return;
+
+  // Make sure the username is the one were were expecting.
+  if (username != int_conn->binding()->username()) {
+    int_conn->SendStunError(request, 430, "Stale Credentials");
+    return;
+  }
+
+  // TODO: Check the HMAC.
+
+  // Send this request to the appropriate handler.
+  if (request.type() == STUN_SEND_REQUEST)
+    HandleStunSend(int_conn, request);
+  else if (request.type() == STUN_ALLOCATE_REQUEST)
+    HandleStunAllocate(int_conn, request);
+  else
+    int_conn->SendStunError(request, 600, "Operation Not Supported");
+}
+
+void RelayServer::HandleStunAllocate(
+    RelayServerConnection* int_conn, const StunMessage& request) {
+
+  // Create a response message that includes an address with which external
+  // clients can communicate.
+
+  RelayMessage response;
+  response.SetType(STUN_ALLOCATE_RESPONSE);
+  response.SetTransactionID(request.transaction_id());
+
+  StunByteStringAttribute* magic_cookie_attr =
+      StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+  magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
+                               int_conn->binding()->magic_cookie().size());
+  response.AddAttribute(magic_cookie_attr);
+
+  size_t index = rand() % external_sockets_.size();
+  rtc::SocketAddress ext_addr =
+      external_sockets_[index]->GetLocalAddress();
+
+  StunAddressAttribute* addr_attr =
+      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+  addr_attr->SetIP(ext_addr.ipaddr());
+  addr_attr->SetPort(ext_addr.port());
+  response.AddAttribute(addr_attr);
+
+  StunUInt32Attribute* res_lifetime_attr =
+      StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
+  res_lifetime_attr->SetValue(int_conn->binding()->lifetime() / 1000);
+  response.AddAttribute(res_lifetime_attr);
+
+  // TODO: Support transport-prefs (preallocate RTCP port).
+  // TODO: Support bandwidth restrictions.
+  // TODO: Add message integrity check.
+
+  // Send a response to the caller.
+  int_conn->SendStun(response);
+}
+
+void RelayServer::HandleStunSend(
+    RelayServerConnection* int_conn, const StunMessage& request) {
+
+  const StunAddressAttribute* addr_attr =
+      request.GetAddress(STUN_ATTR_DESTINATION_ADDRESS);
+  if (!addr_attr) {
+    int_conn->SendStunError(request, 400, "Bad Request");
+    return;
+  }
+
+  const StunByteStringAttribute* data_attr =
+      request.GetByteString(STUN_ATTR_DATA);
+  if (!data_attr) {
+    int_conn->SendStunError(request, 400, "Bad Request");
+    return;
+  }
+
+  rtc::SocketAddress ext_addr(addr_attr->ipaddr(), addr_attr->port());
+  RelayServerConnection* ext_conn =
+      int_conn->binding()->GetExternalConnection(ext_addr);
+  if (!ext_conn) {
+    // Create a new connection to establish the relationship with this binding.
+    ASSERT(external_sockets_.size() == 1);
+    rtc::AsyncPacketSocket* socket = external_sockets_[0];
+    rtc::SocketAddressPair ap(ext_addr, socket->GetLocalAddress());
+    ext_conn = new RelayServerConnection(int_conn->binding(), ap, socket);
+    ext_conn->binding()->AddExternalConnection(ext_conn);
+    AddConnection(ext_conn);
+  }
+
+  // If this connection has pinged us, then allow outgoing traffic.
+  if (ext_conn->locked())
+    ext_conn->Send(data_attr->bytes(), data_attr->length());
+
+  const StunUInt32Attribute* options_attr =
+      request.GetUInt32(STUN_ATTR_OPTIONS);
+  if (options_attr && (options_attr->value() & 0x01)) {
+    int_conn->set_default_destination(ext_addr);
+    int_conn->Lock();
+
+    RelayMessage response;
+    response.SetType(STUN_SEND_RESPONSE);
+    response.SetTransactionID(request.transaction_id());
+
+    StunByteStringAttribute* magic_cookie_attr =
+        StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+    magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
+                                 int_conn->binding()->magic_cookie().size());
+    response.AddAttribute(magic_cookie_attr);
+
+    StunUInt32Attribute* options2_attr =
+      StunAttribute::CreateUInt32(cricket::STUN_ATTR_OPTIONS);
+    options2_attr->SetValue(0x01);
+    response.AddAttribute(options2_attr);
+
+    int_conn->SendStun(response);
+  }
+}
+
+void RelayServer::AddConnection(RelayServerConnection* conn) {
+  ASSERT(connections_.find(conn->addr_pair()) == connections_.end());
+  connections_[conn->addr_pair()] = conn;
+}
+
+void RelayServer::RemoveConnection(RelayServerConnection* conn) {
+  ConnectionMap::iterator iter = connections_.find(conn->addr_pair());
+  ASSERT(iter != connections_.end());
+  connections_.erase(iter);
+}
+
+void RelayServer::RemoveBinding(RelayServerBinding* binding) {
+  BindingMap::iterator iter = bindings_.find(binding->username());
+  ASSERT(iter != bindings_.end());
+  bindings_.erase(iter);
+
+  if (log_bindings_) {
+    LOG(LS_INFO) << "Removed binding " << binding->username() << ", "
+                 << bindings_.size() << " remaining";
+  }
+}
+
+void RelayServer::OnMessage(rtc::Message *pmsg) {
+#if ENABLE_DEBUG
+  static const uint32 kMessageAcceptConnection = 1;
+  ASSERT(pmsg->message_id == kMessageAcceptConnection);
+#endif
+  rtc::MessageData* data = pmsg->pdata;
+  rtc::AsyncSocket* socket =
+      static_cast <rtc::TypedMessageData<rtc::AsyncSocket*>*>
+      (data)->data();
+  AcceptConnection(socket);
+  delete data;
+}
+
+void RelayServer::OnTimeout(RelayServerBinding* binding) {
+  // This call will result in all of the necessary clean-up. We can't call
+  // delete here, because you can't delete an object that is signaling you.
+  thread_->Dispose(binding);
+}
+
+void RelayServer::AcceptConnection(rtc::AsyncSocket* server_socket) {
+  // Check if someone is trying to connect to us.
+  rtc::SocketAddress accept_addr;
+  rtc::AsyncSocket* accepted_socket =
+      server_socket->Accept(&accept_addr);
+  if (accepted_socket != NULL) {
+    // We had someone trying to connect, now check which protocol to
+    // use and create a packet socket.
+    ASSERT(server_sockets_[server_socket] == cricket::PROTO_TCP ||
+           server_sockets_[server_socket] == cricket::PROTO_SSLTCP);
+    if (server_sockets_[server_socket] == cricket::PROTO_SSLTCP) {
+      accepted_socket = new rtc::AsyncSSLServerSocket(accepted_socket);
+    }
+    rtc::AsyncTCPSocket* tcp_socket =
+        new rtc::AsyncTCPSocket(accepted_socket, false);
+
+    // Finally add the socket so it can start communicating with the client.
+    AddInternalSocket(tcp_socket);
+  }
+}
+
+RelayServerConnection::RelayServerConnection(
+    RelayServerBinding* binding, const rtc::SocketAddressPair& addrs,
+    rtc::AsyncPacketSocket* socket)
+  : binding_(binding), addr_pair_(addrs), socket_(socket), locked_(false) {
+  // The creation of a new connection constitutes a use of the binding.
+  binding_->NoteUsed();
+}
+
+RelayServerConnection::~RelayServerConnection() {
+  // Remove this connection from the server's map (if it exists there).
+  binding_->server()->RemoveConnection(this);
+}
+
+void RelayServerConnection::Send(const char* data, size_t size) {
+  // Note that the binding has been used again.
+  binding_->NoteUsed();
+
+  cricket::Send(socket_, data, size, addr_pair_.source());
+}
+
+void RelayServerConnection::Send(
+    const char* data, size_t size, const rtc::SocketAddress& from_addr) {
+  // If the from address is known to the client, we don't need to send it.
+  if (locked() && (from_addr == default_dest_)) {
+    Send(data, size);
+    return;
+  }
+
+  // Wrap the given data in a data-indication packet.
+
+  RelayMessage msg;
+  msg.SetType(STUN_DATA_INDICATION);
+
+  StunByteStringAttribute* magic_cookie_attr =
+      StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
+  magic_cookie_attr->CopyBytes(binding_->magic_cookie().c_str(),
+                               binding_->magic_cookie().size());
+  msg.AddAttribute(magic_cookie_attr);
+
+  StunAddressAttribute* addr_attr =
+      StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
+  addr_attr->SetIP(from_addr.ipaddr());
+  addr_attr->SetPort(from_addr.port());
+  msg.AddAttribute(addr_attr);
+
+  StunByteStringAttribute* data_attr =
+      StunAttribute::CreateByteString(STUN_ATTR_DATA);
+  ASSERT(size <= 65536);
+  data_attr->CopyBytes(data, uint16(size));
+  msg.AddAttribute(data_attr);
+
+  SendStun(msg);
+}
+
+void RelayServerConnection::SendStun(const StunMessage& msg) {
+  // Note that the binding has been used again.
+  binding_->NoteUsed();
+
+  cricket::SendStun(msg, socket_, addr_pair_.source());
+}
+
+void RelayServerConnection::SendStunError(
+      const StunMessage& request, int error_code, const char* error_desc) {
+  // An error does not indicate use.  If no legitimate use off the binding
+  // occurs, we want it to be cleaned up even if errors are still occuring.
+
+  cricket::SendStunError(
+      request, socket_, addr_pair_.source(), error_code, error_desc,
+      binding_->magic_cookie());
+}
+
+void RelayServerConnection::Lock() {
+  locked_ = true;
+}
+
+void RelayServerConnection::Unlock() {
+  locked_ = false;
+}
+
+// IDs used for posted messages:
+const uint32 MSG_LIFETIME_TIMER = 1;
+
+RelayServerBinding::RelayServerBinding(
+    RelayServer* server, const std::string& username,
+    const std::string& password, uint32 lifetime)
+  : server_(server), username_(username), password_(password),
+    lifetime_(lifetime) {
+  // For now, every connection uses the standard magic cookie value.
+  magic_cookie_.append(
+      reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE),
+      sizeof(TURN_MAGIC_COOKIE_VALUE));
+
+  // Initialize the last-used time to now.
+  NoteUsed();
+
+  // Set the first timeout check.
+  server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
+}
+
+RelayServerBinding::~RelayServerBinding() {
+  // Clear the outstanding timeout check.
+  server_->thread()->Clear(this);
+
+  // Clean up all of the connections.
+  for (size_t i = 0; i < internal_connections_.size(); ++i)
+    delete internal_connections_[i];
+  for (size_t i = 0; i < external_connections_.size(); ++i)
+    delete external_connections_[i];
+
+  // Remove this binding from the server's map.
+  server_->RemoveBinding(this);
+}
+
+void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) {
+  internal_connections_.push_back(conn);
+}
+
+void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) {
+  external_connections_.push_back(conn);
+}
+
+void RelayServerBinding::NoteUsed() {
+  last_used_ = rtc::Time();
+}
+
+bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const {
+  if (size < 24 + magic_cookie_.size()) {
+    return false;
+  } else {
+    return memcmp(bytes + 24, magic_cookie_.c_str(), magic_cookie_.size()) == 0;
+  }
+}
+
+RelayServerConnection* RelayServerBinding::GetInternalConnection(
+    const rtc::SocketAddress& ext_addr) {
+
+  // Look for an internal connection that is locked to this address.
+  for (size_t i = 0; i < internal_connections_.size(); ++i) {
+    if (internal_connections_[i]->locked() &&
+        (ext_addr == internal_connections_[i]->default_destination()))
+      return internal_connections_[i];
+  }
+
+  // If one was not found, we send to the first connection.
+  ASSERT(internal_connections_.size() > 0);
+  return internal_connections_[0];
+}
+
+RelayServerConnection* RelayServerBinding::GetExternalConnection(
+    const rtc::SocketAddress& ext_addr) {
+  for (size_t i = 0; i < external_connections_.size(); ++i) {
+    if (ext_addr == external_connections_[i]->addr_pair().source())
+      return external_connections_[i];
+  }
+  return 0;
+}
+
+void RelayServerBinding::OnMessage(rtc::Message *pmsg) {
+  if (pmsg->message_id == MSG_LIFETIME_TIMER) {
+    ASSERT(!pmsg->pdata);
+
+    // If the lifetime timeout has been exceeded, then send a signal.
+    // Otherwise, just keep waiting.
+    if (rtc::Time() >= last_used_ + lifetime_) {
+      LOG(LS_INFO) << "Expiring binding " << username_;
+      SignalTimeout(this);
+    } else {
+      server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER);
+    }
+
+  } else {
+    ASSERT(false);
+  }
+}
+
+}  // namespace cricket
diff --git a/p2p/base/relayserver.h b/p2p/base/relayserver.h
new file mode 100644
index 0000000..e0e45d5
--- /dev/null
+++ b/p2p/base/relayserver.h
@@ -0,0 +1,235 @@
+/*
+ *  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_P2P_BASE_RELAYSERVER_H_
+#define WEBRTC_P2P_BASE_RELAYSERVER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/asyncudpsocket.h"
+#include "webrtc/base/socketaddresspair.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/timeutils.h"
+
+namespace cricket {
+
+class RelayServerBinding;
+class RelayServerConnection;
+
+// Relays traffic between connections to the server that are "bound" together.
+// All connections created with the same username/password are bound together.
+class RelayServer : public rtc::MessageHandler,
+                    public sigslot::has_slots<> {
+ public:
+  // Creates a server, which will use this thread to post messages to itself.
+  explicit RelayServer(rtc::Thread* thread);
+  ~RelayServer();
+
+  rtc::Thread* thread() { return thread_; }
+
+  // Indicates whether we will print updates of the number of bindings.
+  bool log_bindings() const { return log_bindings_; }
+  void set_log_bindings(bool log_bindings) { log_bindings_ = log_bindings; }
+
+  // Updates the set of sockets that the server uses to talk to "internal"
+  // clients.  These are clients that do the "port allocations".
+  void AddInternalSocket(rtc::AsyncPacketSocket* socket);
+  void RemoveInternalSocket(rtc::AsyncPacketSocket* socket);
+
+  // Updates the set of sockets that the server uses to talk to "external"
+  // clients.  These are the clients that do not do allocations.  They do not
+  // know that these addresses represent a relay server.
+  void AddExternalSocket(rtc::AsyncPacketSocket* socket);
+  void RemoveExternalSocket(rtc::AsyncPacketSocket* socket);
+
+  // Starts listening for connections on this sockets. When someone
+  // tries to connect, the connection will be accepted and a new
+  // internal socket will be added.
+  void AddInternalServerSocket(rtc::AsyncSocket* socket,
+                               cricket::ProtocolType proto);
+
+  // Removes this server socket from the list.
+  void RemoveInternalServerSocket(rtc::AsyncSocket* socket);
+
+  // Methods for testing and debuging.
+  int GetConnectionCount() const;
+  rtc::SocketAddressPair GetConnection(int connection) const;
+  bool HasConnection(const rtc::SocketAddress& address) const;
+
+ private:
+  typedef std::vector<rtc::AsyncPacketSocket*> SocketList;
+  typedef std::map<rtc::AsyncSocket*,
+                   cricket::ProtocolType> ServerSocketMap;
+  typedef std::map<std::string, RelayServerBinding*> BindingMap;
+  typedef std::map<rtc::SocketAddressPair,
+                   RelayServerConnection*> ConnectionMap;
+
+  rtc::Thread* thread_;
+  bool log_bindings_;
+  SocketList internal_sockets_;
+  SocketList external_sockets_;
+  SocketList removed_sockets_;
+  ServerSocketMap server_sockets_;
+  BindingMap bindings_;
+  ConnectionMap connections_;
+
+  // Called when a packet is received by the server on one of its sockets.
+  void OnInternalPacket(rtc::AsyncPacketSocket* socket,
+                        const char* bytes, size_t size,
+                        const rtc::SocketAddress& remote_addr,
+                        const rtc::PacketTime& packet_time);
+  void OnExternalPacket(rtc::AsyncPacketSocket* socket,
+                        const char* bytes, size_t size,
+                        const rtc::SocketAddress& remote_addr,
+                        const rtc::PacketTime& packet_time);
+
+  void OnReadEvent(rtc::AsyncSocket* socket);
+
+  // Processes the relevant STUN request types from the client.
+  bool HandleStun(const char* bytes, size_t size,
+                  const rtc::SocketAddress& remote_addr,
+                  rtc::AsyncPacketSocket* socket,
+                  std::string* username, StunMessage* msg);
+  void HandleStunAllocate(const char* bytes, size_t size,
+                          const rtc::SocketAddressPair& ap,
+                          rtc::AsyncPacketSocket* socket);
+  void HandleStun(RelayServerConnection* int_conn, const char* bytes,
+                  size_t size);
+  void HandleStunAllocate(RelayServerConnection* int_conn,
+                          const StunMessage& msg);
+  void HandleStunSend(RelayServerConnection* int_conn, const StunMessage& msg);
+
+  // Adds/Removes the a connection or binding.
+  void AddConnection(RelayServerConnection* conn);
+  void RemoveConnection(RelayServerConnection* conn);
+  void RemoveBinding(RelayServerBinding* binding);
+
+  // Handle messages in our worker thread.
+  void OnMessage(rtc::Message *pmsg);
+
+  // Called when the timer for checking lifetime times out.
+  void OnTimeout(RelayServerBinding* binding);
+
+  // Accept connections on this server socket.
+  void AcceptConnection(rtc::AsyncSocket* server_socket);
+
+  friend class RelayServerConnection;
+  friend class RelayServerBinding;
+};
+
+// Maintains information about a connection to the server.  Each connection is
+// part of one and only one binding.
+class RelayServerConnection {
+ public:
+  RelayServerConnection(RelayServerBinding* binding,
+                        const rtc::SocketAddressPair& addrs,
+                        rtc::AsyncPacketSocket* socket);
+  ~RelayServerConnection();
+
+  RelayServerBinding* binding() { return binding_; }
+  rtc::AsyncPacketSocket* socket() { return socket_; }
+
+  // Returns a pair where the source is the remote address and the destination
+  // is the local address.
+  const rtc::SocketAddressPair& addr_pair() { return addr_pair_; }
+
+  // Sends a packet to the connected client.  If an address is provided, then
+  // we make sure the internal client receives it, wrapping if necessary.
+  void Send(const char* data, size_t size);
+  void Send(const char* data, size_t size,
+            const rtc::SocketAddress& ext_addr);
+
+  // Sends a STUN message to the connected client with no wrapping.
+  void SendStun(const StunMessage& msg);
+  void SendStunError(const StunMessage& request, int code, const char* desc);
+
+  // A locked connection is one for which we know the intended destination of
+  // any raw packet received.
+  bool locked() const { return locked_; }
+  void Lock();
+  void Unlock();
+
+  // Records the address that raw packets should be forwarded to (for internal
+  // packets only; for external, we already know where they go).
+  const rtc::SocketAddress& default_destination() const {
+    return default_dest_;
+  }
+  void set_default_destination(const rtc::SocketAddress& addr) {
+    default_dest_ = addr;
+  }
+
+ private:
+  RelayServerBinding* binding_;
+  rtc::SocketAddressPair addr_pair_;
+  rtc::AsyncPacketSocket* socket_;
+  bool locked_;
+  rtc::SocketAddress default_dest_;
+};
+
+// Records a set of internal and external connections that we relay between,
+// or in other words, that are "bound" together.
+class RelayServerBinding : public rtc::MessageHandler {
+ public:
+  RelayServerBinding(
+      RelayServer* server, const std::string& username,
+      const std::string& password, uint32 lifetime);
+  virtual ~RelayServerBinding();
+
+  RelayServer* server() { return server_; }
+  uint32 lifetime() { return lifetime_; }
+  const std::string& username() { return username_; }
+  const std::string& password() { return password_; }
+  const std::string& magic_cookie() { return magic_cookie_; }
+
+  // Adds/Removes a connection into the binding.
+  void AddInternalConnection(RelayServerConnection* conn);
+  void AddExternalConnection(RelayServerConnection* conn);
+
+  // We keep track of the use of each binding.  If we detect that it was not
+  // used for longer than the lifetime, then we send a signal.
+  void NoteUsed();
+  sigslot::signal1<RelayServerBinding*> SignalTimeout;
+
+  // Determines whether the given packet has the magic cookie present (in the
+  // right place).
+  bool HasMagicCookie(const char* bytes, size_t size) const;
+
+  // Determines the connection to use to send packets to or from the given
+  // external address.
+  RelayServerConnection* GetInternalConnection(
+      const rtc::SocketAddress& ext_addr);
+  RelayServerConnection* GetExternalConnection(
+      const rtc::SocketAddress& ext_addr);
+
+  // MessageHandler:
+  void OnMessage(rtc::Message *pmsg);
+
+ private:
+  RelayServer* server_;
+
+  std::string username_;
+  std::string password_;
+  std::string magic_cookie_;
+
+  std::vector<RelayServerConnection*> internal_connections_;
+  std::vector<RelayServerConnection*> external_connections_;
+
+  uint32 lifetime_;
+  uint32 last_used_;
+  // TODO: bandwidth
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_RELAYSERVER_H_
diff --git a/p2p/base/relayserver_unittest.cc b/p2p/base/relayserver_unittest.cc
new file mode 100644
index 0000000..3349a17
--- /dev/null
+++ b/p2p/base/relayserver_unittest.cc
@@ -0,0 +1,519 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/p2p/base/relayserver.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/testclient.h"
+#include "webrtc/base/thread.h"
+
+using rtc::SocketAddress;
+using namespace cricket;
+
+static const uint32 LIFETIME = 4;  // seconds
+static const SocketAddress server_int_addr("127.0.0.1", 5000);
+static const SocketAddress server_ext_addr("127.0.0.1", 5001);
+static const SocketAddress client1_addr("127.0.0.1", 6000 + (rand() % 1000));
+static const SocketAddress client2_addr("127.0.0.1", 7000 + (rand() % 1000));
+static const char* bad = "this is a completely nonsensical message whose only "
+                         "purpose is to make the parser go 'ack'.  it doesn't "
+                         "look anything like a normal stun message";
+static const char* msg1 = "spamspamspamspamspamspamspambakedbeansspam";
+static const char* msg2 = "Lobster Thermidor a Crevette with a mornay sauce...";
+
+class RelayServerTest : public testing::Test {
+ public:
+  RelayServerTest()
+      : main_(rtc::Thread::Current()), ss_(main_->socketserver()),
+        username_(rtc::CreateRandomString(12)),
+        password_(rtc::CreateRandomString(12)) {
+  }
+ protected:
+  virtual void SetUp() {
+    server_.reset(new RelayServer(main_));
+
+    server_->AddInternalSocket(
+        rtc::AsyncUDPSocket::Create(ss_, server_int_addr));
+    server_->AddExternalSocket(
+        rtc::AsyncUDPSocket::Create(ss_, server_ext_addr));
+
+    client1_.reset(new rtc::TestClient(
+        rtc::AsyncUDPSocket::Create(ss_, client1_addr)));
+    client2_.reset(new rtc::TestClient(
+        rtc::AsyncUDPSocket::Create(ss_, client2_addr)));
+  }
+
+  void Allocate() {
+    rtc::scoped_ptr<StunMessage> req(
+        CreateStunMessage(STUN_ALLOCATE_REQUEST));
+    AddUsernameAttr(req.get(), username_);
+    AddLifetimeAttr(req.get(), LIFETIME);
+    Send1(req.get());
+    delete Receive1();
+  }
+  void Bind() {
+    rtc::scoped_ptr<StunMessage> req(
+        CreateStunMessage(STUN_BINDING_REQUEST));
+    AddUsernameAttr(req.get(), username_);
+    Send2(req.get());
+    delete Receive1();
+  }
+
+  void Send1(const StunMessage* msg) {
+    rtc::ByteBuffer buf;
+    msg->Write(&buf);
+    SendRaw1(buf.Data(), static_cast<int>(buf.Length()));
+  }
+  void Send2(const StunMessage* msg) {
+    rtc::ByteBuffer buf;
+    msg->Write(&buf);
+    SendRaw2(buf.Data(), static_cast<int>(buf.Length()));
+  }
+  void SendRaw1(const char* data, int len) {
+    return Send(client1_.get(), data, len, server_int_addr);
+  }
+  void SendRaw2(const char* data, int len) {
+    return Send(client2_.get(), data, len, server_ext_addr);
+  }
+  void Send(rtc::TestClient* client, const char* data,
+            int len, const SocketAddress& addr) {
+    client->SendTo(data, len, addr);
+  }
+
+  StunMessage* Receive1() {
+    return Receive(client1_.get());
+  }
+  StunMessage* Receive2() {
+    return Receive(client2_.get());
+  }
+  std::string ReceiveRaw1() {
+    return ReceiveRaw(client1_.get());
+  }
+  std::string ReceiveRaw2() {
+    return ReceiveRaw(client2_.get());
+  }
+  StunMessage* Receive(rtc::TestClient* client) {
+    StunMessage* msg = NULL;
+    rtc::TestClient::Packet* packet = client->NextPacket();
+    if (packet) {
+      rtc::ByteBuffer buf(packet->buf, packet->size);
+      msg = new RelayMessage();
+      msg->Read(&buf);
+      delete packet;
+    }
+    return msg;
+  }
+  std::string ReceiveRaw(rtc::TestClient* client) {
+    std::string raw;
+    rtc::TestClient::Packet* packet = client->NextPacket();
+    if (packet) {
+      raw = std::string(packet->buf, packet->size);
+      delete packet;
+    }
+    return raw;
+  }
+
+  static StunMessage* CreateStunMessage(int type) {
+    StunMessage* msg = new RelayMessage();
+    msg->SetType(type);
+    msg->SetTransactionID(
+        rtc::CreateRandomString(kStunTransactionIdLength));
+    return msg;
+  }
+  static void AddMagicCookieAttr(StunMessage* msg) {
+    StunByteStringAttribute* attr =
+        StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+    attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE, sizeof(TURN_MAGIC_COOKIE_VALUE));
+    msg->AddAttribute(attr);
+  }
+  static void AddUsernameAttr(StunMessage* msg, const std::string& val) {
+    StunByteStringAttribute* attr =
+        StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+    attr->CopyBytes(val.c_str(), val.size());
+    msg->AddAttribute(attr);
+  }
+  static void AddLifetimeAttr(StunMessage* msg, int val) {
+    StunUInt32Attribute* attr =
+        StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
+    attr->SetValue(val);
+    msg->AddAttribute(attr);
+  }
+  static void AddDestinationAttr(StunMessage* msg, const SocketAddress& addr) {
+    StunAddressAttribute* attr =
+        StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+    attr->SetIP(addr.ipaddr());
+    attr->SetPort(addr.port());
+    msg->AddAttribute(attr);
+  }
+
+  rtc::Thread* main_;
+  rtc::SocketServer* ss_;
+  rtc::scoped_ptr<RelayServer> server_;
+  rtc::scoped_ptr<rtc::TestClient> client1_;
+  rtc::scoped_ptr<rtc::TestClient> client2_;
+  std::string username_;
+  std::string password_;
+};
+
+// Send a complete nonsense message and verify that it is eaten.
+TEST_F(RelayServerTest, TestBadRequest) {
+  rtc::scoped_ptr<StunMessage> res;
+
+  SendRaw1(bad, static_cast<int>(strlen(bad)));
+  res.reset(Receive1());
+
+  ASSERT_TRUE(!res);
+}
+
+// Send an allocate request without a username and verify it is rejected.
+TEST_F(RelayServerTest, TestAllocateNoUsername) {
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_ALLOCATE_REQUEST)), res;
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_ALLOCATE_ERROR_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(4, err->eclass());
+  EXPECT_EQ(32, err->number());
+  EXPECT_EQ("Missing Username", err->reason());
+}
+
+// Send a binding request and verify that it is rejected.
+TEST_F(RelayServerTest, TestBindingRequest) {
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_BINDING_REQUEST)), res;
+  AddUsernameAttr(req.get(), username_);
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(6, err->eclass());
+  EXPECT_EQ(0, err->number());
+  EXPECT_EQ("Operation Not Supported", err->reason());
+}
+
+// Send an allocate request and verify that it is accepted.
+TEST_F(RelayServerTest, TestAllocate) {
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_ALLOCATE_REQUEST)), res;
+  AddUsernameAttr(req.get(), username_);
+  AddLifetimeAttr(req.get(), LIFETIME);
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunAddressAttribute* mapped_addr =
+      res->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  ASSERT_TRUE(mapped_addr != NULL);
+  EXPECT_EQ(1, mapped_addr->family());
+  EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
+  EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
+
+  const StunUInt32Attribute* res_lifetime_attr =
+      res->GetUInt32(STUN_ATTR_LIFETIME);
+  ASSERT_TRUE(res_lifetime_attr != NULL);
+  EXPECT_EQ(LIFETIME, res_lifetime_attr->value());
+}
+
+// Send a second allocate request and verify that it is also accepted, though
+// the lifetime should be ignored.
+TEST_F(RelayServerTest, TestReallocate) {
+  Allocate();
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_ALLOCATE_REQUEST)), res;
+  AddMagicCookieAttr(req.get());
+  AddUsernameAttr(req.get(), username_);
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunAddressAttribute* mapped_addr =
+      res->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  ASSERT_TRUE(mapped_addr != NULL);
+  EXPECT_EQ(1, mapped_addr->family());
+  EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
+  EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
+
+  const StunUInt32Attribute* lifetime_attr =
+      res->GetUInt32(STUN_ATTR_LIFETIME);
+  ASSERT_TRUE(lifetime_attr != NULL);
+  EXPECT_EQ(LIFETIME, lifetime_attr->value());
+}
+
+// Send a request from another client and see that it arrives at the first
+// client in the binding.
+TEST_F(RelayServerTest, TestRemoteBind) {
+  Allocate();
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_BINDING_REQUEST)), res;
+  AddUsernameAttr(req.get(), username_);
+
+  Send2(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_DATA_INDICATION, res->type());
+
+  const StunByteStringAttribute* recv_data =
+      res->GetByteString(STUN_ATTR_DATA);
+  ASSERT_TRUE(recv_data != NULL);
+
+  rtc::ByteBuffer buf(recv_data->bytes(), recv_data->length());
+  rtc::scoped_ptr<StunMessage> res2(new StunMessage());
+  EXPECT_TRUE(res2->Read(&buf));
+  EXPECT_EQ(STUN_BINDING_REQUEST, res2->type());
+  EXPECT_EQ(req->transaction_id(), res2->transaction_id());
+
+  const StunAddressAttribute* src_addr =
+      res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
+  ASSERT_TRUE(src_addr != NULL);
+  EXPECT_EQ(1, src_addr->family());
+  EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
+  EXPECT_EQ(client2_addr.port(), src_addr->port());
+
+  EXPECT_TRUE(Receive2() == NULL);
+}
+
+// Send a complete nonsense message to the established connection and verify
+// that it is dropped by the server.
+TEST_F(RelayServerTest, TestRemoteBadRequest) {
+  Allocate();
+  Bind();
+
+  SendRaw1(bad, static_cast<int>(strlen(bad)));
+  EXPECT_TRUE(Receive1() == NULL);
+  EXPECT_TRUE(Receive2() == NULL);
+}
+
+// Send a send request without a username and verify it is rejected.
+TEST_F(RelayServerTest, TestSendRequestMissingUsername) {
+  Allocate();
+  Bind();
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_SEND_REQUEST)), res;
+  AddMagicCookieAttr(req.get());
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(4, err->eclass());
+  EXPECT_EQ(32, err->number());
+  EXPECT_EQ("Missing Username", err->reason());
+}
+
+// Send a send request with the wrong username and verify it is rejected.
+TEST_F(RelayServerTest, TestSendRequestBadUsername) {
+  Allocate();
+  Bind();
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_SEND_REQUEST)), res;
+  AddMagicCookieAttr(req.get());
+  AddUsernameAttr(req.get(), "foobarbizbaz");
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(4, err->eclass());
+  EXPECT_EQ(30, err->number());
+  EXPECT_EQ("Stale Credentials", err->reason());
+}
+
+// Send a send request without a destination address and verify that it is
+// rejected.
+TEST_F(RelayServerTest, TestSendRequestNoDestinationAddress) {
+  Allocate();
+  Bind();
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_SEND_REQUEST)), res;
+  AddMagicCookieAttr(req.get());
+  AddUsernameAttr(req.get(), username_);
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(4, err->eclass());
+  EXPECT_EQ(0, err->number());
+  EXPECT_EQ("Bad Request", err->reason());
+}
+
+// Send a send request without data and verify that it is rejected.
+TEST_F(RelayServerTest, TestSendRequestNoData) {
+  Allocate();
+  Bind();
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_SEND_REQUEST)), res;
+  AddMagicCookieAttr(req.get());
+  AddUsernameAttr(req.get(), username_);
+  AddDestinationAttr(req.get(), client2_addr);
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(4, err->eclass());
+  EXPECT_EQ(00, err->number());
+  EXPECT_EQ("Bad Request", err->reason());
+}
+
+// Send a binding request after an allocate and verify that it is rejected.
+TEST_F(RelayServerTest, TestSendRequestWrongType) {
+  Allocate();
+  Bind();
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_BINDING_REQUEST)), res;
+  AddMagicCookieAttr(req.get());
+  AddUsernameAttr(req.get(), username_);
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type());
+  EXPECT_EQ(req->transaction_id(), res->transaction_id());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(6, err->eclass());
+  EXPECT_EQ(0, err->number());
+  EXPECT_EQ("Operation Not Supported", err->reason());
+}
+
+// Verify that we can send traffic back and forth between the clients after a
+// successful allocate and bind.
+TEST_F(RelayServerTest, TestSendRaw) {
+  Allocate();
+  Bind();
+
+  for (int i = 0; i < 10; i++) {
+    rtc::scoped_ptr<StunMessage> req(
+        CreateStunMessage(STUN_SEND_REQUEST)), res;
+    AddMagicCookieAttr(req.get());
+    AddUsernameAttr(req.get(), username_);
+    AddDestinationAttr(req.get(), client2_addr);
+
+    StunByteStringAttribute* send_data =
+        StunAttribute::CreateByteString(STUN_ATTR_DATA);
+    send_data->CopyBytes(msg1);
+    req->AddAttribute(send_data);
+
+    Send1(req.get());
+    EXPECT_EQ(msg1, ReceiveRaw2());
+    SendRaw2(msg2, static_cast<int>(strlen(msg2)));
+    res.reset(Receive1());
+
+    ASSERT_TRUE(res);
+    EXPECT_EQ(STUN_DATA_INDICATION, res->type());
+
+    const StunAddressAttribute* src_addr =
+        res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
+    ASSERT_TRUE(src_addr != NULL);
+    EXPECT_EQ(1, src_addr->family());
+    EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
+    EXPECT_EQ(client2_addr.port(), src_addr->port());
+
+    const StunByteStringAttribute* recv_data =
+        res->GetByteString(STUN_ATTR_DATA);
+    ASSERT_TRUE(recv_data != NULL);
+    EXPECT_EQ(strlen(msg2), recv_data->length());
+    EXPECT_EQ(0, memcmp(msg2, recv_data->bytes(), recv_data->length()));
+  }
+}
+
+// Verify that a binding expires properly, and rejects send requests.
+TEST_F(RelayServerTest, TestExpiration) {
+  Allocate();
+  Bind();
+
+  // Wait twice the lifetime to make sure the server has expired the binding.
+  rtc::Thread::Current()->ProcessMessages((LIFETIME * 2) * 1000);
+
+  rtc::scoped_ptr<StunMessage> req(
+      CreateStunMessage(STUN_SEND_REQUEST)), res;
+  AddMagicCookieAttr(req.get());
+  AddUsernameAttr(req.get(), username_);
+  AddDestinationAttr(req.get(), client2_addr);
+
+  StunByteStringAttribute* data_attr =
+      StunAttribute::CreateByteString(STUN_ATTR_DATA);
+  data_attr->CopyBytes(msg1);
+  req->AddAttribute(data_attr);
+
+  Send1(req.get());
+  res.reset(Receive1());
+
+  ASSERT_TRUE(res.get() != NULL);
+  EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
+
+  const StunErrorCodeAttribute* err = res->GetErrorCode();
+  ASSERT_TRUE(err != NULL);
+  EXPECT_EQ(6, err->eclass());
+  EXPECT_EQ(0, err->number());
+  EXPECT_EQ("Operation Not Supported", err->reason());
+
+  // Also verify that traffic from the external client is ignored.
+  SendRaw2(msg2, static_cast<int>(strlen(msg2)));
+  EXPECT_TRUE(ReceiveRaw1().empty());
+}
diff --git a/p2p/base/session.cc b/p2p/base/session.cc
new file mode 100644
index 0000000..9749b14
--- /dev/null
+++ b/p2p/base/session.cc
@@ -0,0 +1,1760 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/session.h"
+
+#include "webrtc/p2p/base/dtlstransport.h"
+#include "webrtc/p2p/base/p2ptransport.h"
+#include "webrtc/p2p/base/sessionclient.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannelproxy.h"
+#include "webrtc/p2p/base/transportinfo.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/base/bind.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sslstreamadapter.h"
+
+#include "webrtc/p2p/base/constants.h"
+
+namespace cricket {
+
+using rtc::Bind;
+
+bool BadMessage(const buzz::QName type,
+                const std::string& text,
+                MessageError* err) {
+  err->SetType(type);
+  err->SetText(text);
+  return false;
+}
+
+TransportProxy::~TransportProxy() {
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end(); ++iter) {
+    iter->second->SignalDestroyed(iter->second);
+    delete iter->second;
+  }
+}
+
+const std::string& TransportProxy::type() const {
+  return transport_->get()->type();
+}
+
+TransportChannel* TransportProxy::GetChannel(int component) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  return GetChannelProxy(component);
+}
+
+TransportChannel* TransportProxy::CreateChannel(
+    const std::string& name, int component) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(GetChannel(component) == NULL);
+  ASSERT(!transport_->get()->HasChannel(component));
+
+  // We always create a proxy in case we need to change out the transport later.
+  TransportChannelProxy* channel =
+      new TransportChannelProxy(content_name(), name, component);
+  channels_[component] = channel;
+
+  // If we're already negotiated, create an impl and hook it up to the proxy
+  // channel. If we're connecting, create an impl but don't hook it up yet.
+  if (negotiated_) {
+    SetupChannelProxy_w(component, channel);
+  } else if (connecting_) {
+    GetOrCreateChannelProxyImpl_w(component);
+  }
+  return channel;
+}
+
+bool TransportProxy::HasChannel(int component) {
+  return transport_->get()->HasChannel(component);
+}
+
+void TransportProxy::DestroyChannel(int component) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  TransportChannel* channel = GetChannel(component);
+  if (channel) {
+    // If the state of TransportProxy is not NEGOTIATED
+    // then TransportChannelProxy and its impl are not
+    // connected. Both must be connected before
+    // deletion.
+    if (!negotiated_) {
+      SetupChannelProxy_w(component, GetChannelProxy(component));
+    }
+
+    channels_.erase(component);
+    channel->SignalDestroyed(channel);
+    delete channel;
+  }
+}
+
+void TransportProxy::ConnectChannels() {
+  if (!connecting_) {
+    if (!negotiated_) {
+      for (ChannelMap::iterator iter = channels_.begin();
+           iter != channels_.end(); ++iter) {
+        GetOrCreateChannelProxyImpl(iter->first);
+      }
+    }
+    connecting_ = true;
+  }
+  // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we
+  // don't have any channels yet, so we need to allow this method to be called
+  // multiple times. Once we fix Transport, we can move this call inside the
+  // if (!connecting_) block.
+  transport_->get()->ConnectChannels();
+}
+
+void TransportProxy::CompleteNegotiation() {
+  if (!negotiated_) {
+    for (ChannelMap::iterator iter = channels_.begin();
+         iter != channels_.end(); ++iter) {
+      SetupChannelProxy(iter->first, iter->second);
+    }
+    negotiated_ = true;
+  }
+}
+
+void TransportProxy::AddSentCandidates(const Candidates& candidates) {
+  for (Candidates::const_iterator cand = candidates.begin();
+       cand != candidates.end(); ++cand) {
+    sent_candidates_.push_back(*cand);
+  }
+}
+
+void TransportProxy::AddUnsentCandidates(const Candidates& candidates) {
+  for (Candidates::const_iterator cand = candidates.begin();
+       cand != candidates.end(); ++cand) {
+    unsent_candidates_.push_back(*cand);
+  }
+}
+
+bool TransportProxy::GetChannelNameFromComponent(
+    int component, std::string* channel_name) const {
+  const TransportChannelProxy* channel = GetChannelProxy(component);
+  if (channel == NULL) {
+    return false;
+  }
+
+  *channel_name = channel->name();
+  return true;
+}
+
+bool TransportProxy::GetComponentFromChannelName(
+    const std::string& channel_name, int* component) const {
+  const TransportChannelProxy* channel = GetChannelProxyByName(channel_name);
+  if (channel == NULL) {
+    return false;
+  }
+
+  *component = channel->component();
+  return true;
+}
+
+TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
+  ChannelMap::const_iterator iter = channels_.find(component);
+  return (iter != channels_.end()) ? iter->second : NULL;
+}
+
+TransportChannelProxy* TransportProxy::GetChannelProxyByName(
+    const std::string& name) const {
+  for (ChannelMap::const_iterator iter = channels_.begin();
+       iter != channels_.end();
+       ++iter) {
+    if (iter->second->name() == name) {
+      return iter->second;
+    }
+  }
+  return NULL;
+}
+
+TransportChannelImpl* TransportProxy::GetOrCreateChannelProxyImpl(
+    int component) {
+  return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
+      &TransportProxy::GetOrCreateChannelProxyImpl_w, this, component));
+}
+
+TransportChannelImpl* TransportProxy::GetOrCreateChannelProxyImpl_w(
+    int component) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  TransportChannelImpl* impl = transport_->get()->GetChannel(component);
+  if (impl == NULL) {
+    impl = transport_->get()->CreateChannel(component);
+  }
+  return impl;
+}
+
+void TransportProxy::SetupChannelProxy(
+    int component, TransportChannelProxy* transproxy) {
+  worker_thread_->Invoke<void>(Bind(
+      &TransportProxy::SetupChannelProxy_w, this, component, transproxy));
+}
+
+void TransportProxy::SetupChannelProxy_w(
+    int component, TransportChannelProxy* transproxy) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  TransportChannelImpl* impl = GetOrCreateChannelProxyImpl(component);
+  ASSERT(impl != NULL);
+  transproxy->SetImplementation(impl);
+}
+
+void TransportProxy::ReplaceChannelProxyImpl(TransportChannelProxy* proxy,
+                                             TransportChannelImpl* impl) {
+  worker_thread_->Invoke<void>(Bind(
+      &TransportProxy::ReplaceChannelProxyImpl_w, this, proxy, impl));
+}
+
+void TransportProxy::ReplaceChannelProxyImpl_w(TransportChannelProxy* proxy,
+                                               TransportChannelImpl* impl) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(proxy != NULL);
+  proxy->SetImplementation(impl);
+}
+
+// This function muxes |this| onto |target| by repointing |this| at
+// |target|'s transport and setting our TransportChannelProxies
+// to point to |target|'s underlying implementations.
+bool TransportProxy::SetupMux(TransportProxy* target) {
+  // Bail out if there's nothing to do.
+  if (transport_ == target->transport_) {
+    return true;
+  }
+
+  // Run through all channels and remove any non-rtp transport channels before
+  // setting target transport channels.
+  for (ChannelMap::const_iterator iter = channels_.begin();
+       iter != channels_.end(); ++iter) {
+    if (!target->transport_->get()->HasChannel(iter->first)) {
+      // Remove if channel doesn't exist in |transport_|.
+      ReplaceChannelProxyImpl(iter->second, NULL);
+    } else {
+      // Replace the impl for all the TransportProxyChannels with the channels
+      // from |target|'s transport. Fail if there's not an exact match.
+      ReplaceChannelProxyImpl(
+          iter->second, target->transport_->get()->CreateChannel(iter->first));
+    }
+  }
+
+  // Now replace our transport. Must happen afterwards because
+  // it deletes all impls as a side effect.
+  transport_ = target->transport_;
+  transport_->get()->SignalCandidatesReady.connect(
+      this, &TransportProxy::OnTransportCandidatesReady);
+  set_candidates_allocated(target->candidates_allocated());
+  return true;
+}
+
+void TransportProxy::SetIceRole(IceRole role) {
+  transport_->get()->SetIceRole(role);
+}
+
+bool TransportProxy::SetLocalTransportDescription(
+    const TransportDescription& description,
+    ContentAction action,
+    std::string* error_desc) {
+  // If this is an answer, finalize the negotiation.
+  if (action == CA_ANSWER) {
+    CompleteNegotiation();
+  }
+  bool result = transport_->get()->SetLocalTransportDescription(description,
+                                                                action,
+                                                                error_desc);
+  if (result)
+    local_description_set_ = true;
+  return result;
+}
+
+bool TransportProxy::SetRemoteTransportDescription(
+    const TransportDescription& description,
+    ContentAction action,
+    std::string* error_desc) {
+  // If this is an answer, finalize the negotiation.
+  if (action == CA_ANSWER) {
+    CompleteNegotiation();
+  }
+  bool result = transport_->get()->SetRemoteTransportDescription(description,
+                                                                 action,
+                                                                 error_desc);
+  if (result)
+    remote_description_set_ = true;
+  return result;
+}
+
+void TransportProxy::OnSignalingReady() {
+  // If we're starting a new allocation sequence, reset our state.
+  set_candidates_allocated(false);
+  transport_->get()->OnSignalingReady();
+}
+
+bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
+                                        std::string* error) {
+  // Ensure the transport is negotiated before handling candidates.
+  // TODO(juberti): Remove this once everybody calls SetLocalTD.
+  CompleteNegotiation();
+
+  // Verify each candidate before passing down to transport layer.
+  for (Candidates::const_iterator cand = candidates.begin();
+       cand != candidates.end(); ++cand) {
+    if (!transport_->get()->VerifyCandidate(*cand, error))
+      return false;
+    if (!HasChannel(cand->component())) {
+      *error = "Candidate has unknown component: " + cand->ToString() +
+               " for content: " + content_name_;
+      return false;
+    }
+  }
+  transport_->get()->OnRemoteCandidates(candidates);
+  return true;
+}
+
+void TransportProxy::SetIdentity(
+    rtc::SSLIdentity* identity) {
+  transport_->get()->SetIdentity(identity);
+}
+
+std::string BaseSession::StateToString(State state) {
+  switch (state) {
+    case Session::STATE_INIT:
+      return "STATE_INIT";
+    case Session::STATE_SENTINITIATE:
+      return "STATE_SENTINITIATE";
+    case Session::STATE_RECEIVEDINITIATE:
+      return "STATE_RECEIVEDINITIATE";
+    case Session::STATE_SENTPRACCEPT:
+      return "STATE_SENTPRACCEPT";
+    case Session::STATE_SENTACCEPT:
+      return "STATE_SENTACCEPT";
+    case Session::STATE_RECEIVEDPRACCEPT:
+      return "STATE_RECEIVEDPRACCEPT";
+    case Session::STATE_RECEIVEDACCEPT:
+      return "STATE_RECEIVEDACCEPT";
+    case Session::STATE_SENTMODIFY:
+      return "STATE_SENTMODIFY";
+    case Session::STATE_RECEIVEDMODIFY:
+      return "STATE_RECEIVEDMODIFY";
+    case Session::STATE_SENTREJECT:
+      return "STATE_SENTREJECT";
+    case Session::STATE_RECEIVEDREJECT:
+      return "STATE_RECEIVEDREJECT";
+    case Session::STATE_SENTREDIRECT:
+      return "STATE_SENTREDIRECT";
+    case Session::STATE_SENTTERMINATE:
+      return "STATE_SENTTERMINATE";
+    case Session::STATE_RECEIVEDTERMINATE:
+      return "STATE_RECEIVEDTERMINATE";
+    case Session::STATE_INPROGRESS:
+      return "STATE_INPROGRESS";
+    case Session::STATE_DEINIT:
+      return "STATE_DEINIT";
+    default:
+      break;
+  }
+  return "STATE_" + rtc::ToString(state);
+}
+
+BaseSession::BaseSession(rtc::Thread* signaling_thread,
+                         rtc::Thread* worker_thread,
+                         PortAllocator* port_allocator,
+                         const std::string& sid,
+                         const std::string& content_type,
+                         bool initiator)
+    : state_(STATE_INIT),
+      error_(ERROR_NONE),
+      signaling_thread_(signaling_thread),
+      worker_thread_(worker_thread),
+      port_allocator_(port_allocator),
+      sid_(sid),
+      content_type_(content_type),
+      transport_type_(NS_GINGLE_P2P),
+      initiator_(initiator),
+      identity_(NULL),
+      ice_tiebreaker_(rtc::CreateRandomId64()),
+      role_switch_(false) {
+  ASSERT(signaling_thread->IsCurrent());
+}
+
+BaseSession::~BaseSession() {
+  ASSERT(signaling_thread()->IsCurrent());
+
+  ASSERT(state_ != STATE_DEINIT);
+  LogState(state_, STATE_DEINIT);
+  state_ = STATE_DEINIT;
+  SignalState(this, state_);
+
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    delete iter->second;
+  }
+}
+
+const SessionDescription* BaseSession::local_description() const {
+  // TODO(tommi): Assert on thread correctness.
+  return local_description_.get();
+}
+
+const SessionDescription* BaseSession::remote_description() const {
+  // TODO(tommi): Assert on thread correctness.
+  return remote_description_.get();
+}
+
+SessionDescription* BaseSession::remote_description() {
+  // TODO(tommi): Assert on thread correctness.
+  return remote_description_.get();
+}
+
+void BaseSession::set_local_description(const SessionDescription* sdesc) {
+  // TODO(tommi): Assert on thread correctness.
+  if (sdesc != local_description_.get())
+    local_description_.reset(sdesc);
+}
+
+void BaseSession::set_remote_description(SessionDescription* sdesc) {
+  // TODO(tommi): Assert on thread correctness.
+  if (sdesc != remote_description_)
+    remote_description_.reset(sdesc);
+}
+
+const SessionDescription* BaseSession::initiator_description() const {
+  // TODO(tommi): Assert on thread correctness.
+  return initiator_ ? local_description_.get() : remote_description_.get();
+}
+
+bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) {
+  if (identity_)
+    return false;
+  identity_ = identity;
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    iter->second->SetIdentity(identity_);
+  }
+  return true;
+}
+
+bool BaseSession::PushdownTransportDescription(ContentSource source,
+                                               ContentAction action,
+                                               std::string* error_desc) {
+  if (source == CS_LOCAL) {
+    return PushdownLocalTransportDescription(local_description(),
+                                             action,
+                                             error_desc);
+  }
+  return PushdownRemoteTransportDescription(remote_description(),
+                                            action,
+                                            error_desc);
+}
+
+bool BaseSession::PushdownLocalTransportDescription(
+    const SessionDescription* sdesc,
+    ContentAction action,
+    std::string* error_desc) {
+  // Update the Transports with the right information, and trigger them to
+  // start connecting.
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    // If no transport info was in this session description, ret == false
+    // and we just skip this one.
+    TransportDescription tdesc;
+    bool ret = GetTransportDescription(
+        sdesc, iter->second->content_name(), &tdesc);
+    if (ret) {
+      if (!iter->second->SetLocalTransportDescription(tdesc, action,
+                                                      error_desc)) {
+        return false;
+      }
+
+      iter->second->ConnectChannels();
+    }
+  }
+
+  return true;
+}
+
+bool BaseSession::PushdownRemoteTransportDescription(
+    const SessionDescription* sdesc,
+    ContentAction action,
+    std::string* error_desc) {
+  // Update the Transports with the right information.
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    TransportDescription tdesc;
+
+    // If no transport info was in this session description, ret == false
+    // and we just skip this one.
+    bool ret = GetTransportDescription(
+        sdesc, iter->second->content_name(), &tdesc);
+    if (ret) {
+      if (!iter->second->SetRemoteTransportDescription(tdesc, action,
+                                                       error_desc)) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
+                                             const std::string& channel_name,
+                                             int component) {
+  // We create the proxy "on demand" here because we need to support
+  // creating channels at any time, even before we send or receive
+  // initiate messages, which is before we create the transports.
+  TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
+  return transproxy->CreateChannel(channel_name, component);
+}
+
+TransportChannel* BaseSession::GetChannel(const std::string& content_name,
+                                          int component) {
+  TransportProxy* transproxy = GetTransportProxy(content_name);
+  if (transproxy == NULL)
+    return NULL;
+
+  return transproxy->GetChannel(component);
+}
+
+void BaseSession::DestroyChannel(const std::string& content_name,
+                                 int component) {
+  TransportProxy* transproxy = GetTransportProxy(content_name);
+  ASSERT(transproxy != NULL);
+  transproxy->DestroyChannel(component);
+}
+
+TransportProxy* BaseSession::GetOrCreateTransportProxy(
+    const std::string& content_name) {
+  TransportProxy* transproxy = GetTransportProxy(content_name);
+  if (transproxy)
+    return transproxy;
+
+  Transport* transport = CreateTransport(content_name);
+  transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
+  transport->SetIceTiebreaker(ice_tiebreaker_);
+  // TODO: Connect all the Transport signals to TransportProxy
+  // then to the BaseSession.
+  transport->SignalConnecting.connect(
+      this, &BaseSession::OnTransportConnecting);
+  transport->SignalWritableState.connect(
+      this, &BaseSession::OnTransportWritable);
+  transport->SignalRequestSignaling.connect(
+      this, &BaseSession::OnTransportRequestSignaling);
+  transport->SignalTransportError.connect(
+      this, &BaseSession::OnTransportSendError);
+  transport->SignalRouteChange.connect(
+      this, &BaseSession::OnTransportRouteChange);
+  transport->SignalCandidatesAllocationDone.connect(
+      this, &BaseSession::OnTransportCandidatesAllocationDone);
+  transport->SignalRoleConflict.connect(
+      this, &BaseSession::OnRoleConflict);
+  transport->SignalCompleted.connect(
+      this, &BaseSession::OnTransportCompleted);
+  transport->SignalFailed.connect(
+      this, &BaseSession::OnTransportFailed);
+
+  transproxy = new TransportProxy(worker_thread_, sid_, content_name,
+                                  new TransportWrapper(transport));
+  transproxy->SignalCandidatesReady.connect(
+      this, &BaseSession::OnTransportProxyCandidatesReady);
+  if (identity_)
+    transproxy->SetIdentity(identity_);
+  transports_[content_name] = transproxy;
+
+  return transproxy;
+}
+
+Transport* BaseSession::GetTransport(const std::string& content_name) {
+  TransportProxy* transproxy = GetTransportProxy(content_name);
+  if (transproxy == NULL)
+    return NULL;
+  return transproxy->impl();
+}
+
+TransportProxy* BaseSession::GetTransportProxy(
+    const std::string& content_name) {
+  TransportMap::iterator iter = transports_.find(content_name);
+  return (iter != transports_.end()) ? iter->second : NULL;
+}
+
+TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) {
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    TransportProxy* transproxy = iter->second;
+    if (transproxy->impl() == transport) {
+      return transproxy;
+    }
+  }
+  return NULL;
+}
+
+TransportProxy* BaseSession::GetFirstTransportProxy() {
+  if (transports_.empty())
+    return NULL;
+  return transports_.begin()->second;
+}
+
+void BaseSession::DestroyTransportProxy(
+    const std::string& content_name) {
+  TransportMap::iterator iter = transports_.find(content_name);
+  if (iter != transports_.end()) {
+    delete iter->second;
+    transports_.erase(content_name);
+  }
+}
+
+cricket::Transport* BaseSession::CreateTransport(
+    const std::string& content_name) {
+  ASSERT(transport_type_ == NS_GINGLE_P2P);
+  return new cricket::DtlsTransport<P2PTransport>(
+      signaling_thread(), worker_thread(), content_name,
+      port_allocator(), identity_);
+}
+
+bool BaseSession::GetStats(SessionStats* stats) {
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    std::string proxy_id = iter->second->content_name();
+    // We are ignoring not-yet-instantiated transports.
+    if (iter->second->impl()) {
+      std::string transport_id = iter->second->impl()->content_name();
+      stats->proxy_to_transport[proxy_id] = transport_id;
+      if (stats->transport_stats.find(transport_id)
+          == stats->transport_stats.end()) {
+        TransportStats subinfos;
+        if (!iter->second->impl()->GetStats(&subinfos)) {
+          return false;
+        }
+        stats->transport_stats[transport_id] = subinfos;
+      }
+    }
+  }
+  return true;
+}
+
+void BaseSession::SetState(State state) {
+  ASSERT(signaling_thread_->IsCurrent());
+  if (state != state_) {
+    LogState(state_, state);
+    state_ = state;
+    SignalState(this, state_);
+    signaling_thread_->Post(this, MSG_STATE);
+  }
+  SignalNewDescription();
+}
+
+void BaseSession::SetError(Error error, const std::string& error_desc) {
+  ASSERT(signaling_thread_->IsCurrent());
+  if (error != error_) {
+    error_ = error;
+    error_desc_ = error_desc;
+    SignalError(this, error);
+  }
+}
+
+void BaseSession::OnSignalingReady() {
+  ASSERT(signaling_thread()->IsCurrent());
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    iter->second->OnSignalingReady();
+  }
+}
+
+// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
+// start, remove this method once everyone calls PushdownLocalTD.
+void BaseSession::SpeculativelyConnectAllTransportChannels() {
+  // Put all transports into the connecting state.
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    iter->second->ConnectChannels();
+  }
+}
+
+bool BaseSession::OnRemoteCandidates(const std::string& content_name,
+                                     const Candidates& candidates,
+                                     std::string* error) {
+  // Give candidates to the appropriate transport, and tell that transport
+  // to start connecting, if it's not already doing so.
+  TransportProxy* transproxy = GetTransportProxy(content_name);
+  if (!transproxy) {
+    *error = "Unknown content name " + content_name;
+    return false;
+  }
+  if (!transproxy->OnRemoteCandidates(candidates, error)) {
+    return false;
+  }
+  // TODO(juberti): Remove this call once we can be sure that we always have
+  // a local transport description (which will trigger the connection).
+  transproxy->ConnectChannels();
+  return true;
+}
+
+bool BaseSession::MaybeEnableMuxingSupport() {
+  // We need both a local and remote description to decide if we should mux.
+  if ((state_ == STATE_SENTINITIATE ||
+      state_ == STATE_RECEIVEDINITIATE) &&
+      ((local_description_ == NULL) ||
+      (remote_description_ == NULL))) {
+    return false;
+  }
+
+  // In order to perform the multiplexing, we need all proxies to be in the
+  // negotiated state, i.e. to have implementations underneath.
+  // Ensure that this is the case, regardless of whether we are going to mux.
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    ASSERT(iter->second->negotiated());
+    if (!iter->second->negotiated())
+      return false;
+  }
+
+  // If both sides agree to BUNDLE, mux all the specified contents onto the
+  // transport belonging to the first content name in the BUNDLE group.
+  // If the contents are already muxed, this will be a no-op.
+  // TODO(juberti): Should this check that local and remote have configured
+  // BUNDLE the same way?
+  bool candidates_allocated = IsCandidateAllocationDone();
+  const ContentGroup* local_bundle_group =
+      local_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
+  const ContentGroup* remote_bundle_group =
+      remote_description()->GetGroupByName(GROUP_TYPE_BUNDLE);
+  if (local_bundle_group && remote_bundle_group &&
+      local_bundle_group->FirstContentName()) {
+    const std::string* content_name = local_bundle_group->FirstContentName();
+    const ContentInfo* content =
+        local_description_->GetContentByName(*content_name);
+    ASSERT(content != NULL);
+    if (!SetSelectedProxy(content->name, local_bundle_group)) {
+      LOG(LS_WARNING) << "Failed to set up BUNDLE";
+      return false;
+    }
+
+    // If we weren't done gathering before, we might be done now, as a result
+    // of enabling mux.
+    LOG(LS_INFO) << "Enabling BUNDLE, bundling onto transport: "
+                 << *content_name;
+    if (!candidates_allocated) {
+      MaybeCandidateAllocationDone();
+    }
+  } else {
+    LOG(LS_INFO) << "No BUNDLE information, not bundling.";
+  }
+  return true;
+}
+
+bool BaseSession::SetSelectedProxy(const std::string& content_name,
+                                   const ContentGroup* muxed_group) {
+  TransportProxy* selected_proxy = GetTransportProxy(content_name);
+  if (!selected_proxy) {
+    return false;
+  }
+
+  ASSERT(selected_proxy->negotiated());
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    // If content is part of the mux group, then repoint its proxy at the
+    // transport object that we have chosen to mux onto. If the proxy
+    // is already pointing at the right object, it will be a no-op.
+    if (muxed_group->HasContentName(iter->first) &&
+        !iter->second->SetupMux(selected_proxy)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
+  // TODO(juberti): This is a clunky way of processing the done signal. Instead,
+  // TransportProxy should receive the done signal directly, set its allocated
+  // flag internally, and then reissue the done signal to Session.
+  // Overall we should make TransportProxy receive *all* the signals from
+  // Transport, since this removes the need to manually iterate over all
+  // the transports, as is needed to make sure signals are handled properly
+  // when BUNDLEing.
+  // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
+  // that make it prohibitively difficult to run dbg builds. Disabled for now.
+  //ASSERT(!IsCandidateAllocationDone());
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    if (iter->second->impl() == transport) {
+      iter->second->set_candidates_allocated(true);
+    }
+  }
+  MaybeCandidateAllocationDone();
+}
+
+bool BaseSession::IsCandidateAllocationDone() const {
+  for (TransportMap::const_iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    if (!iter->second->candidates_allocated())
+      return false;
+  }
+  return true;
+}
+
+void BaseSession::MaybeCandidateAllocationDone() {
+  if (IsCandidateAllocationDone()) {
+    LOG(LS_INFO) << "Candidate gathering is complete.";
+    OnCandidatesAllocationDone();
+  }
+}
+
+void BaseSession::OnRoleConflict() {
+  if (role_switch_) {
+    LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
+    return;
+  }
+
+  role_switch_ = true;
+  for (TransportMap::iterator iter = transports_.begin();
+       iter != transports_.end(); ++iter) {
+    // Role will be reverse of initial role setting.
+    IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
+    iter->second->SetIceRole(role);
+  }
+}
+
+void BaseSession::LogState(State old_state, State new_state) {
+  LOG(LS_INFO) << "Session:" << id()
+               << " Old state:" << StateToString(old_state)
+               << " New state:" << StateToString(new_state)
+               << " Type:" << content_type()
+               << " Transport:" << transport_type();
+}
+
+// static
+bool BaseSession::GetTransportDescription(const SessionDescription* description,
+                                          const std::string& content_name,
+                                          TransportDescription* tdesc) {
+  if (!description || !tdesc) {
+    return false;
+  }
+  const TransportInfo* transport_info =
+      description->GetTransportInfoByName(content_name);
+  if (!transport_info) {
+    return false;
+  }
+  *tdesc = transport_info->description;
+  return true;
+}
+
+void BaseSession::SignalNewDescription() {
+  ContentAction action;
+  ContentSource source;
+  if (!GetContentAction(&action, &source)) {
+    return;
+  }
+  if (source == CS_LOCAL) {
+    SignalNewLocalDescription(this, action);
+  } else {
+    SignalNewRemoteDescription(this, action);
+  }
+}
+
+bool BaseSession::GetContentAction(ContentAction* action,
+                                   ContentSource* source) {
+  switch (state_) {
+    // new local description
+    case STATE_SENTINITIATE:
+      *action = CA_OFFER;
+      *source = CS_LOCAL;
+      break;
+    case STATE_SENTPRACCEPT:
+      *action = CA_PRANSWER;
+      *source = CS_LOCAL;
+      break;
+    case STATE_SENTACCEPT:
+      *action = CA_ANSWER;
+      *source = CS_LOCAL;
+      break;
+    // new remote description
+    case STATE_RECEIVEDINITIATE:
+      *action = CA_OFFER;
+      *source = CS_REMOTE;
+      break;
+    case STATE_RECEIVEDPRACCEPT:
+      *action = CA_PRANSWER;
+      *source = CS_REMOTE;
+      break;
+    case STATE_RECEIVEDACCEPT:
+      *action = CA_ANSWER;
+      *source = CS_REMOTE;
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+void BaseSession::OnMessage(rtc::Message *pmsg) {
+  switch (pmsg->message_id) {
+  case MSG_TIMEOUT:
+    // Session timeout has occured.
+    SetError(ERROR_TIME, "Session timeout has occured.");
+    break;
+
+  case MSG_STATE:
+    switch (state_) {
+    case STATE_SENTACCEPT:
+    case STATE_RECEIVEDACCEPT:
+      SetState(STATE_INPROGRESS);
+      break;
+
+    default:
+      // Explicitly ignoring some states here.
+      break;
+    }
+    break;
+  }
+}
+
+Session::Session(SessionManager* session_manager,
+                 const std::string& local_name,
+                 const std::string& initiator_name,
+                 const std::string& sid,
+                 const std::string& content_type,
+                 SessionClient* client)
+    : BaseSession(session_manager->signaling_thread(),
+                  session_manager->worker_thread(),
+                  session_manager->port_allocator(),
+                  sid, content_type, initiator_name == local_name) {
+  ASSERT(client != NULL);
+  session_manager_ = session_manager;
+  local_name_ = local_name;
+  initiator_name_ = initiator_name;
+  transport_parser_ = new P2PTransportParser();
+  client_ = client;
+  initiate_acked_ = false;
+  current_protocol_ = PROTOCOL_HYBRID;
+}
+
+Session::~Session() {
+  delete transport_parser_;
+}
+
+bool Session::Initiate(const std::string& to,
+                       const SessionDescription* sdesc) {
+  ASSERT(signaling_thread()->IsCurrent());
+  SessionError error;
+
+  // Only from STATE_INIT
+  if (state() != STATE_INIT)
+    return false;
+
+  // Setup for signaling.
+  set_remote_name(to);
+  set_local_description(sdesc);
+  if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
+                              &error)) {
+    LOG(LS_ERROR) << "Could not create transports: " << error.text;
+    return false;
+  }
+
+  if (!SendInitiateMessage(sdesc, &error)) {
+    LOG(LS_ERROR) << "Could not send initiate message: " << error.text;
+    return false;
+  }
+
+  // We need to connect transport proxy and impl here so that we can process
+  // the TransportDescriptions.
+  SpeculativelyConnectAllTransportChannels();
+
+  PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL);
+  SetState(Session::STATE_SENTINITIATE);
+  return true;
+}
+
+bool Session::Accept(const SessionDescription* sdesc) {
+  ASSERT(signaling_thread()->IsCurrent());
+
+  // Only if just received initiate
+  if (state() != STATE_RECEIVEDINITIATE)
+    return false;
+
+  // Setup for signaling.
+  set_local_description(sdesc);
+
+  SessionError error;
+  if (!SendAcceptMessage(sdesc, &error)) {
+    LOG(LS_ERROR) << "Could not send accept message: " << error.text;
+    return false;
+  }
+  // TODO(juberti): Add BUNDLE support to transport-info messages.
+  PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL);
+  MaybeEnableMuxingSupport();  // Enable transport channel mux if supported.
+  SetState(Session::STATE_SENTACCEPT);
+  return true;
+}
+
+bool Session::Reject(const std::string& reason) {
+  ASSERT(signaling_thread()->IsCurrent());
+
+  // Reject is sent in response to an initiate or modify, to reject the
+  // request
+  if (state() != STATE_RECEIVEDINITIATE && state() != STATE_RECEIVEDMODIFY)
+    return false;
+
+  SessionError error;
+  if (!SendRejectMessage(reason, &error)) {
+    LOG(LS_ERROR) << "Could not send reject message: " << error.text;
+    return false;
+  }
+
+  SetState(STATE_SENTREJECT);
+  return true;
+}
+
+bool Session::TerminateWithReason(const std::string& reason) {
+  ASSERT(signaling_thread()->IsCurrent());
+
+  // Either side can terminate, at any time.
+  switch (state()) {
+    case STATE_SENTTERMINATE:
+    case STATE_RECEIVEDTERMINATE:
+      return false;
+
+    case STATE_SENTREJECT:
+    case STATE_RECEIVEDREJECT:
+      // We don't need to send terminate if we sent or received a reject...
+      // it's implicit.
+      break;
+
+    default:
+      SessionError error;
+      if (!SendTerminateMessage(reason, &error)) {
+        LOG(LS_ERROR) << "Could not send terminate message: " << error.text;
+        return false;
+      }
+      break;
+  }
+
+  SetState(STATE_SENTTERMINATE);
+  return true;
+}
+
+bool Session::SendInfoMessage(const XmlElements& elems,
+                              const std::string& remote_name) {
+  ASSERT(signaling_thread()->IsCurrent());
+  SessionError error;
+  if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) {
+    LOG(LS_ERROR) << "Could not send info message " << error.text;
+    return false;
+  }
+  return true;
+}
+
+bool Session::SendDescriptionInfoMessage(const ContentInfos& contents) {
+  XmlElements elems;
+  WriteError write_error;
+  if (!WriteDescriptionInfo(current_protocol_,
+                            contents,
+                            GetContentParsers(),
+                            &elems, &write_error)) {
+    LOG(LS_ERROR) << "Could not write description info message: "
+                  << write_error.text;
+    return false;
+  }
+  SessionError error;
+  if (!SendMessage(ACTION_DESCRIPTION_INFO, elems, &error)) {
+    LOG(LS_ERROR) << "Could not send description info message: "
+                  << error.text;
+    return false;
+  }
+  return true;
+}
+
+TransportInfos Session::GetEmptyTransportInfos(
+    const ContentInfos& contents) const {
+  TransportInfos tinfos;
+  for (ContentInfos::const_iterator content = contents.begin();
+       content != contents.end(); ++content) {
+    tinfos.push_back(TransportInfo(content->name,
+                                   TransportDescription(transport_type(),
+                                                        std::string(),
+                                                        std::string())));
+  }
+  return tinfos;
+}
+
+bool Session::OnRemoteCandidates(
+    const TransportInfos& tinfos, ParseError* error) {
+  for (TransportInfos::const_iterator tinfo = tinfos.begin();
+       tinfo != tinfos.end(); ++tinfo) {
+    std::string str_error;
+    if (!BaseSession::OnRemoteCandidates(
+        tinfo->content_name, tinfo->description.candidates, &str_error)) {
+      return BadParse(str_error, error);
+    }
+  }
+  return true;
+}
+
+bool Session::CreateTransportProxies(const TransportInfos& tinfos,
+                                     SessionError* error) {
+  for (TransportInfos::const_iterator tinfo = tinfos.begin();
+       tinfo != tinfos.end(); ++tinfo) {
+    if (tinfo->description.transport_type != transport_type()) {
+      error->SetText("No supported transport in offer.");
+      return false;
+    }
+
+    GetOrCreateTransportProxy(tinfo->content_name);
+  }
+  return true;
+}
+
+TransportParserMap Session::GetTransportParsers() {
+  TransportParserMap parsers;
+  parsers[transport_type()] = transport_parser_;
+  return parsers;
+}
+
+CandidateTranslatorMap Session::GetCandidateTranslators() {
+  CandidateTranslatorMap translators;
+  // NOTE: This technique makes it impossible to parse G-ICE
+  // candidates in session-initiate messages because the channels
+  // aren't yet created at that point.  Since we don't use candidates
+  // in session-initiate messages, we should be OK.  Once we switch to
+  // ICE, this translation shouldn't be necessary.
+  for (TransportMap::const_iterator iter = transport_proxies().begin();
+       iter != transport_proxies().end(); ++iter) {
+    translators[iter->first] = iter->second;
+  }
+  return translators;
+}
+
+ContentParserMap Session::GetContentParsers() {
+  ContentParserMap parsers;
+  parsers[content_type()] = client_;
+  // We need to be able parse both RTP-based and SCTP-based Jingle
+  // with the same client.
+  if (content_type() == NS_JINGLE_RTP) {
+    parsers[NS_JINGLE_DRAFT_SCTP] = client_;
+  }
+  return parsers;
+}
+
+void Session::OnTransportRequestSignaling(Transport* transport) {
+  ASSERT(signaling_thread()->IsCurrent());
+  TransportProxy* transproxy = GetTransportProxy(transport);
+  ASSERT(transproxy != NULL);
+  if (transproxy) {
+    // Reset candidate allocation status for the transport proxy.
+    transproxy->set_candidates_allocated(false);
+  }
+  SignalRequestSignaling(this);
+}
+
+void Session::OnTransportConnecting(Transport* transport) {
+  // This is an indication that we should begin watching the writability
+  // state of the transport.
+  OnTransportWritable(transport);
+}
+
+void Session::OnTransportWritable(Transport* transport) {
+  ASSERT(signaling_thread()->IsCurrent());
+
+  // If the transport is not writable, start a timer to make sure that it
+  // becomes writable within a reasonable amount of time.  If it does not, we
+  // terminate since we can't actually send data.  If the transport is writable,
+  // cancel the timer.  Note that writability transitions may occur repeatedly
+  // during the lifetime of the session.
+  signaling_thread()->Clear(this, MSG_TIMEOUT);
+  if (transport->HasChannels() && !transport->writable()) {
+    signaling_thread()->PostDelayed(
+        session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
+  }
+}
+
+void Session::OnTransportProxyCandidatesReady(TransportProxy* transproxy,
+                                              const Candidates& candidates) {
+  ASSERT(signaling_thread()->IsCurrent());
+  if (transproxy != NULL) {
+    if (initiator() && !initiate_acked_) {
+      // TODO: This is to work around server re-ordering
+      // messages.  We send the candidates once the session-initiate
+      // is acked.  Once we have fixed the server to guarantee message
+      // order, we can remove this case.
+      transproxy->AddUnsentCandidates(candidates);
+    } else {
+      if (!transproxy->negotiated()) {
+        transproxy->AddSentCandidates(candidates);
+      }
+      SessionError error;
+      if (!SendTransportInfoMessage(transproxy, candidates, &error)) {
+        LOG(LS_ERROR) << "Could not send transport info message: "
+                      << error.text;
+        return;
+      }
+    }
+  }
+}
+
+void Session::OnTransportSendError(Transport* transport,
+                                   const buzz::XmlElement* stanza,
+                                   const buzz::QName& name,
+                                   const std::string& type,
+                                   const std::string& text,
+                                   const buzz::XmlElement* extra_info) {
+  ASSERT(signaling_thread()->IsCurrent());
+  SignalErrorMessage(this, stanza, name, type, text, extra_info);
+}
+
+void Session::OnIncomingMessage(const SessionMessage& msg) {
+  ASSERT(signaling_thread()->IsCurrent());
+  ASSERT(state() == STATE_INIT || msg.from == remote_name());
+
+  if (current_protocol_== PROTOCOL_HYBRID) {
+    if (msg.protocol == PROTOCOL_GINGLE) {
+      current_protocol_ = PROTOCOL_GINGLE;
+    } else {
+      current_protocol_ = PROTOCOL_JINGLE;
+    }
+  }
+
+  bool valid = false;
+  MessageError error;
+  switch (msg.type) {
+    case ACTION_SESSION_INITIATE:
+      valid = OnInitiateMessage(msg, &error);
+      break;
+    case ACTION_SESSION_INFO:
+      valid = OnInfoMessage(msg);
+      break;
+    case ACTION_SESSION_ACCEPT:
+      valid = OnAcceptMessage(msg, &error);
+      break;
+    case ACTION_SESSION_REJECT:
+      valid = OnRejectMessage(msg, &error);
+      break;
+    case ACTION_SESSION_TERMINATE:
+      valid = OnTerminateMessage(msg, &error);
+      break;
+    case ACTION_TRANSPORT_INFO:
+      valid = OnTransportInfoMessage(msg, &error);
+      break;
+    case ACTION_TRANSPORT_ACCEPT:
+      valid = OnTransportAcceptMessage(msg, &error);
+      break;
+    case ACTION_DESCRIPTION_INFO:
+      valid = OnDescriptionInfoMessage(msg, &error);
+      break;
+    default:
+      valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
+                         "unknown session message type",
+                         &error);
+  }
+
+  if (valid) {
+    SendAcknowledgementMessage(msg.stanza);
+  } else {
+    SignalErrorMessage(this, msg.stanza, error.type,
+                       "modify", error.text, NULL);
+  }
+}
+
+void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
+                                 const buzz::XmlElement* response_stanza,
+                                 const SessionMessage& msg) {
+  ASSERT(signaling_thread()->IsCurrent());
+
+  if (msg.type == ACTION_SESSION_INITIATE) {
+    OnInitiateAcked();
+  }
+}
+
+void Session::OnInitiateAcked() {
+  // TODO: This is to work around server re-ordering
+  // messages.  We send the candidates once the session-initiate
+  // is acked.  Once we have fixed the server to guarantee message
+  // order, we can remove this case.
+  if (!initiate_acked_) {
+    initiate_acked_ = true;
+    SessionError error;
+    SendAllUnsentTransportInfoMessages(&error);
+  }
+}
+
+void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
+                           const buzz::XmlElement* error_stanza) {
+  ASSERT(signaling_thread()->IsCurrent());
+
+  SessionMessage msg;
+  ParseError parse_error;
+  if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) {
+    LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text
+                  << ":" << orig_stanza;
+    return;
+  }
+
+  // If the error is a session redirect, call OnRedirectError, which will
+  // continue the session with a new remote JID.
+  SessionRedirect redirect;
+  if (FindSessionRedirect(error_stanza, &redirect)) {
+    SessionError error;
+    if (!OnRedirectError(redirect, &error)) {
+      // TODO: Should we send a message back?  The standard
+      // says nothing about it.
+      std::ostringstream desc;
+      desc << "Failed to redirect: " << error.text;
+      LOG(LS_ERROR) << desc.str();
+      SetError(ERROR_RESPONSE, desc.str());
+    }
+    return;
+  }
+
+  std::string error_type = "cancel";
+
+  const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
+  if (error) {
+    error_type = error->Attr(buzz::QN_TYPE);
+
+    LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
+                  << "in response to:\n" << orig_stanza->Str();
+  } else {
+    // don't crash if <error> is missing
+    LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
+    return;
+  }
+
+  if (msg.type == ACTION_TRANSPORT_INFO) {
+    // Transport messages frequently generate errors because they are sent right
+    // when we detect a network failure.  For that reason, we ignore such
+    // errors, because if we do not establish writability again, we will
+    // terminate anyway.  The exceptions are transport-specific error tags,
+    // which we pass on to the respective transport.
+  } else if ((error_type != "continue") && (error_type != "wait")) {
+    // We do not set an error if the other side said it is okay to continue
+    // (possibly after waiting).  These errors can be ignored.
+    SetError(ERROR_RESPONSE, "");
+  }
+}
+
+bool Session::OnInitiateMessage(const SessionMessage& msg,
+                                MessageError* error) {
+  if (!CheckState(STATE_INIT, error))
+    return false;
+
+  SessionInitiate init;
+  if (!ParseSessionInitiate(msg.protocol, msg.action_elem,
+                            GetContentParsers(), GetTransportParsers(),
+                            GetCandidateTranslators(),
+                            &init, error))
+    return false;
+
+  SessionError session_error;
+  if (!CreateTransportProxies(init.transports, &session_error)) {
+    return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE,
+                      session_error.text, error);
+  }
+
+  set_remote_name(msg.from);
+  set_initiator_name(msg.initiator);
+  set_remote_description(new SessionDescription(init.ClearContents(),
+                                                init.transports,
+                                                init.groups));
+  // Updating transport with TransportDescription.
+  PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL);
+  SetState(STATE_RECEIVEDINITIATE);
+
+  // Users of Session may listen to state change and call Reject().
+  if (state() != STATE_SENTREJECT) {
+    if (!OnRemoteCandidates(init.transports, error))
+      return false;
+
+    // TODO(juberti): Auto-generate and push down the local transport answer.
+    // This is necessary for trickling to work with RFC 5245 ICE.
+  }
+  return true;
+}
+
+bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
+  if (!CheckState(STATE_SENTINITIATE, error))
+    return false;
+
+  SessionAccept accept;
+  if (!ParseSessionAccept(msg.protocol, msg.action_elem,
+                          GetContentParsers(), GetTransportParsers(),
+                          GetCandidateTranslators(),
+                          &accept, error)) {
+    return false;
+  }
+
+  // If we get an accept, we can assume the initiate has been
+  // received, even if we haven't gotten an IQ response.
+  OnInitiateAcked();
+
+  set_remote_description(new SessionDescription(accept.ClearContents(),
+                                                accept.transports,
+                                                accept.groups));
+  // Updating transport with TransportDescription.
+  PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL);
+  MaybeEnableMuxingSupport();  // Enable transport channel mux if supported.
+  SetState(STATE_RECEIVEDACCEPT);
+
+  if (!OnRemoteCandidates(accept.transports, error))
+    return false;
+
+  return true;
+}
+
+bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) {
+  if (!CheckState(STATE_SENTINITIATE, error))
+    return false;
+
+  SetState(STATE_RECEIVEDREJECT);
+  return true;
+}
+
+bool Session::OnInfoMessage(const SessionMessage& msg) {
+  SignalInfoMessage(this, msg.action_elem);
+  return true;
+}
+
+bool Session::OnTerminateMessage(const SessionMessage& msg,
+                                 MessageError* error) {
+  SessionTerminate term;
+  if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error))
+    return false;
+
+  SignalReceivedTerminateReason(this, term.reason);
+  if (term.debug_reason != buzz::STR_EMPTY) {
+    LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
+  }
+
+  SetState(STATE_RECEIVEDTERMINATE);
+  return true;
+}
+
+bool Session::OnTransportInfoMessage(const SessionMessage& msg,
+                                     MessageError* error) {
+  TransportInfos tinfos;
+  if (!ParseTransportInfos(msg.protocol, msg.action_elem,
+                           initiator_description()->contents(),
+                           GetTransportParsers(), GetCandidateTranslators(),
+                           &tinfos, error))
+    return false;
+
+  if (!OnRemoteCandidates(tinfos, error))
+    return false;
+
+  return true;
+}
+
+bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
+                                       MessageError* error) {
+  // TODO: Currently here only for compatibility with
+  // Gingle 1.1 clients (notably, Google Voice).
+  return true;
+}
+
+bool Session::OnDescriptionInfoMessage(const SessionMessage& msg,
+                              MessageError* error) {
+  if (!CheckState(STATE_INPROGRESS, error))
+    return false;
+
+  DescriptionInfo description_info;
+  if (!ParseDescriptionInfo(msg.protocol, msg.action_elem,
+                            GetContentParsers(), GetTransportParsers(),
+                            GetCandidateTranslators(),
+                            &description_info, error)) {
+    return false;
+  }
+
+  ContentInfos& updated_contents = description_info.contents;
+
+  // TODO: Currently, reflector sends back
+  // video stream updates even for an audio-only call, which causes
+  // this to fail.  Put this back once reflector is fixed.
+  //
+  // ContentInfos::iterator it;
+  // First, ensure all updates are valid before modifying remote_description_.
+  // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
+  //   if (remote_description()->GetContentByName(it->name) == NULL) {
+  //     return false;
+  //   }
+  // }
+
+  // TODO: We used to replace contents from an update, but
+  // that no longer works with partial updates.  We need to figure out
+  // a way to merge patial updates into contents.  For now, users of
+  // Session should listen to SignalRemoteDescriptionUpdate and handle
+  // updates.  They should not expect remote_description to be the
+  // latest value.
+  //
+  // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
+  //     remote_description()->RemoveContentByName(it->name);
+  //     remote_description()->AddContent(it->name, it->type, it->description);
+  //   }
+  // }
+
+  SignalRemoteDescriptionUpdate(this, updated_contents);
+  return true;
+}
+
+bool BareJidsEqual(const std::string& name1,
+                   const std::string& name2) {
+  buzz::Jid jid1(name1);
+  buzz::Jid jid2(name2);
+
+  return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2);
+}
+
+bool Session::OnRedirectError(const SessionRedirect& redirect,
+                              SessionError* error) {
+  MessageError message_error;
+  if (!CheckState(STATE_SENTINITIATE, &message_error)) {
+    return BadWrite(message_error.text, error);
+  }
+
+  if (!BareJidsEqual(remote_name(), redirect.target))
+    return BadWrite("Redirection not allowed: must be the same bare jid.",
+                    error);
+
+  // When we receive a redirect, we point the session at the new JID
+  // and resend the candidates.
+  set_remote_name(redirect.target);
+  return (SendInitiateMessage(local_description(), error) &&
+          ResendAllTransportInfoMessages(error));
+}
+
+bool Session::CheckState(State expected, MessageError* error) {
+  if (state() != expected) {
+    // The server can deliver messages out of order/repeated for various
+    // reasons. For example, if the server does not recive our iq response,
+    // it could assume that the iq it sent was lost, and will then send
+    // it again. Ideally, we should implement reliable messaging with
+    // duplicate elimination.
+    return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
+                      "message not allowed in current state",
+                      error);
+  }
+  return true;
+}
+
+void Session::SetError(Error error, const std::string& error_desc) {
+  BaseSession::SetError(error, error_desc);
+  if (error != ERROR_NONE)
+    signaling_thread()->Post(this, MSG_ERROR);
+}
+
+void Session::OnMessage(rtc::Message* pmsg) {
+  // preserve this because BaseSession::OnMessage may modify it
+  State orig_state = state();
+
+  BaseSession::OnMessage(pmsg);
+
+  switch (pmsg->message_id) {
+  case MSG_ERROR:
+    TerminateWithReason(STR_TERMINATE_ERROR);
+    break;
+
+  case MSG_STATE:
+    switch (orig_state) {
+    case STATE_SENTREJECT:
+    case STATE_RECEIVEDREJECT:
+      // Assume clean termination.
+      Terminate();
+      break;
+
+    case STATE_SENTTERMINATE:
+    case STATE_RECEIVEDTERMINATE:
+      session_manager_->DestroySession(this);
+      break;
+
+    default:
+      // Explicitly ignoring some states here.
+      break;
+    }
+    break;
+  }
+}
+
+bool Session::SendInitiateMessage(const SessionDescription* sdesc,
+                                  SessionError* error) {
+  SessionInitiate init;
+  init.contents = sdesc->contents();
+  init.transports = GetEmptyTransportInfos(init.contents);
+  init.groups = sdesc->groups();
+  return SendMessage(ACTION_SESSION_INITIATE, init, error);
+}
+
+bool Session::WriteSessionAction(
+    SignalingProtocol protocol, const SessionInitiate& init,
+    XmlElements* elems, WriteError* error) {
+  return WriteSessionInitiate(protocol, init.contents, init.transports,
+                              GetContentParsers(), GetTransportParsers(),
+                              GetCandidateTranslators(), init.groups,
+                              elems, error);
+}
+
+bool Session::SendAcceptMessage(const SessionDescription* sdesc,
+                                SessionError* error) {
+  XmlElements elems;
+  if (!WriteSessionAccept(current_protocol_,
+                          sdesc->contents(),
+                          GetEmptyTransportInfos(sdesc->contents()),
+                          GetContentParsers(), GetTransportParsers(),
+                          GetCandidateTranslators(), sdesc->groups(),
+                          &elems, error)) {
+    return false;
+  }
+  return SendMessage(ACTION_SESSION_ACCEPT, elems, error);
+}
+
+bool Session::SendRejectMessage(const std::string& reason,
+                                SessionError* error) {
+  SessionTerminate term(reason);
+  return SendMessage(ACTION_SESSION_REJECT, term, error);
+}
+
+bool Session::SendTerminateMessage(const std::string& reason,
+                                   SessionError* error) {
+  SessionTerminate term(reason);
+  return SendMessage(ACTION_SESSION_TERMINATE, term, error);
+}
+
+bool Session::WriteSessionAction(SignalingProtocol protocol,
+                                 const SessionTerminate& term,
+                                 XmlElements* elems, WriteError* error) {
+  WriteSessionTerminate(protocol, term, elems);
+  return true;
+}
+
+bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
+                                       SessionError* error) {
+  return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
+}
+
+bool Session::SendTransportInfoMessage(const TransportProxy* transproxy,
+                                       const Candidates& candidates,
+                                       SessionError* error) {
+  return SendTransportInfoMessage(TransportInfo(transproxy->content_name(),
+      TransportDescription(transproxy->type(), std::vector<std::string>(),
+                           std::string(), std::string(), ICEMODE_FULL,
+                           CONNECTIONROLE_NONE, NULL, candidates)), error);
+}
+
+bool Session::WriteSessionAction(SignalingProtocol protocol,
+                                 const TransportInfo& tinfo,
+                                 XmlElements* elems, WriteError* error) {
+  TransportInfos tinfos;
+  tinfos.push_back(tinfo);
+  return WriteTransportInfos(protocol, tinfos,
+                             GetTransportParsers(), GetCandidateTranslators(),
+                             elems, error);
+}
+
+bool Session::ResendAllTransportInfoMessages(SessionError* error) {
+  for (TransportMap::const_iterator iter = transport_proxies().begin();
+       iter != transport_proxies().end(); ++iter) {
+    TransportProxy* transproxy = iter->second;
+    if (transproxy->sent_candidates().size() > 0) {
+      if (!SendTransportInfoMessage(
+              transproxy, transproxy->sent_candidates(), error)) {
+        LOG(LS_ERROR) << "Could not resend transport info messages: "
+                      << error->text;
+        return false;
+      }
+      transproxy->ClearSentCandidates();
+    }
+  }
+  return true;
+}
+
+bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
+  for (TransportMap::const_iterator iter = transport_proxies().begin();
+       iter != transport_proxies().end(); ++iter) {
+    TransportProxy* transproxy = iter->second;
+    if (transproxy->unsent_candidates().size() > 0) {
+      if (!SendTransportInfoMessage(
+              transproxy, transproxy->unsent_candidates(), error)) {
+        LOG(LS_ERROR) << "Could not send unsent transport info messages: "
+                      << error->text;
+        return false;
+      }
+      transproxy->ClearUnsentCandidates();
+    }
+  }
+  return true;
+}
+
+bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
+                          SessionError* error) {
+    return SendMessage(type, action_elems, remote_name(), error);
+}
+
+bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
+                          const std::string& remote_name, SessionError* error) {
+  rtc::scoped_ptr<buzz::XmlElement> stanza(
+      new buzz::XmlElement(buzz::QN_IQ));
+
+  SessionMessage msg(current_protocol_, type, id(), initiator_name());
+  msg.to = remote_name;
+  WriteSessionMessage(msg, action_elems, stanza.get());
+
+  SignalOutgoingMessage(this, stanza.get());
+  return true;
+}
+
+template <typename Action>
+bool Session::SendMessage(ActionType type, const Action& action,
+                          SessionError* error) {
+  rtc::scoped_ptr<buzz::XmlElement> stanza(
+      new buzz::XmlElement(buzz::QN_IQ));
+  if (!WriteActionMessage(type, action, stanza.get(), error))
+    return false;
+
+  SignalOutgoingMessage(this, stanza.get());
+  return true;
+}
+
+template <typename Action>
+bool Session::WriteActionMessage(ActionType type, const Action& action,
+                                 buzz::XmlElement* stanza,
+                                 WriteError* error) {
+  if (current_protocol_ == PROTOCOL_HYBRID) {
+    if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error))
+      return false;
+    if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error))
+      return false;
+  } else {
+    if (!WriteActionMessage(current_protocol_, type, action, stanza, error))
+      return false;
+  }
+  return true;
+}
+
+template <typename Action>
+bool Session::WriteActionMessage(SignalingProtocol protocol,
+                                 ActionType type, const Action& action,
+                                 buzz::XmlElement* stanza, WriteError* error) {
+  XmlElements action_elems;
+  if (!WriteSessionAction(protocol, action, &action_elems, error))
+    return false;
+
+  SessionMessage msg(protocol, type, id(), initiator_name());
+  msg.to = remote_name();
+
+  WriteSessionMessage(msg, action_elems, stanza);
+  return true;
+}
+
+void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
+  rtc::scoped_ptr<buzz::XmlElement> ack(
+      new buzz::XmlElement(buzz::QN_IQ));
+  ack->SetAttr(buzz::QN_TO, remote_name());
+  ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
+  ack->SetAttr(buzz::QN_TYPE, "result");
+
+  SignalOutgoingMessage(this, ack.get());
+}
+
+}  // namespace cricket
diff --git a/p2p/base/session.h b/p2p/base/session.h
new file mode 100644
index 0000000..f5eaf41
--- /dev/null
+++ b/p2p/base/session.h
@@ -0,0 +1,730 @@
+/*
+ *  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_P2P_BASE_SESSION_H_
+#define WEBRTC_P2P_BASE_SESSION_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/sessionclient.h"
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/p2p/base/sessionmessages.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/refcount.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace cricket {
+
+class BaseSession;
+class P2PTransportChannel;
+class Transport;
+class TransportChannel;
+class TransportChannelProxy;
+class TransportChannelImpl;
+
+typedef rtc::RefCountedObject<rtc::scoped_ptr<Transport> >
+TransportWrapper;
+
+// Used for errors that will send back a specific error message to the
+// remote peer.  We add "type" to the errors because it's needed for
+// SignalErrorMessage.
+struct MessageError : ParseError {
+  buzz::QName type;
+
+  // if unset, assume type is a parse error
+  MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {}
+
+  void SetType(const buzz::QName type) {
+    this->type = type;
+  }
+};
+
+// Used for errors that may be returned by public session methods that
+// can fail.
+// TODO: Use this error in Session::Initiate and
+// Session::Accept.
+struct SessionError : WriteError {
+};
+
+// Bundles a Transport and ChannelMap together. ChannelMap is used to
+// create transport channels before receiving or sending a session
+// initiate, and for speculatively connecting channels.  Previously, a
+// session had one ChannelMap and transport.  Now, with multiple
+// transports per session, we need multiple ChannelMaps as well.
+
+typedef std::map<int, TransportChannelProxy*> ChannelMap;
+
+class TransportProxy : public sigslot::has_slots<>,
+                       public CandidateTranslator {
+ public:
+  TransportProxy(
+      rtc::Thread* worker_thread,
+      const std::string& sid,
+      const std::string& content_name,
+      TransportWrapper* transport)
+      : worker_thread_(worker_thread),
+        sid_(sid),
+        content_name_(content_name),
+        transport_(transport),
+        connecting_(false),
+        negotiated_(false),
+        sent_candidates_(false),
+        candidates_allocated_(false),
+        local_description_set_(false),
+        remote_description_set_(false) {
+    transport_->get()->SignalCandidatesReady.connect(
+        this, &TransportProxy::OnTransportCandidatesReady);
+  }
+  ~TransportProxy();
+
+  const std::string& content_name() const { return content_name_; }
+  // TODO(juberti): It's not good form to expose the object you're wrapping,
+  // since callers can mutate it. Can we make this return a const Transport*?
+  Transport* impl() const { return transport_->get(); }
+
+  const std::string& type() const;
+  bool negotiated() const { return negotiated_; }
+  const Candidates& sent_candidates() const { return sent_candidates_; }
+  const Candidates& unsent_candidates() const { return unsent_candidates_; }
+  bool candidates_allocated() const { return candidates_allocated_; }
+  void set_candidates_allocated(bool allocated) {
+    candidates_allocated_ = allocated;
+  }
+
+  TransportChannel* GetChannel(int component);
+  TransportChannel* CreateChannel(const std::string& channel_name,
+                                  int component);
+  bool HasChannel(int component);
+  void DestroyChannel(int component);
+
+  void AddSentCandidates(const Candidates& candidates);
+  void AddUnsentCandidates(const Candidates& candidates);
+  void ClearSentCandidates() { sent_candidates_.clear(); }
+  void ClearUnsentCandidates() { unsent_candidates_.clear(); }
+
+  // Start the connection process for any channels, creating impls if needed.
+  void ConnectChannels();
+  // Hook up impls to the proxy channels. Doesn't change connect state.
+  void CompleteNegotiation();
+
+  // Mux this proxy onto the specified proxy's transport.
+  bool SetupMux(TransportProxy* proxy);
+
+  // Simple functions that thunk down to the same functions on Transport.
+  void SetIceRole(IceRole role);
+  void SetIdentity(rtc::SSLIdentity* identity);
+  bool SetLocalTransportDescription(const TransportDescription& description,
+                                    ContentAction action,
+                                    std::string* error_desc);
+  bool SetRemoteTransportDescription(const TransportDescription& description,
+                                     ContentAction action,
+                                     std::string* error_desc);
+  void OnSignalingReady();
+  bool OnRemoteCandidates(const Candidates& candidates, std::string* error);
+
+  // CandidateTranslator methods.
+  virtual bool GetChannelNameFromComponent(
+      int component, std::string* channel_name) const;
+  virtual bool GetComponentFromChannelName(
+      const std::string& channel_name, int* component) const;
+
+  // Called when a transport signals that it has new candidates.
+  void OnTransportCandidatesReady(cricket::Transport* transport,
+                                  const Candidates& candidates) {
+    SignalCandidatesReady(this, candidates);
+  }
+
+  bool local_description_set() const {
+    return local_description_set_;
+  }
+  bool remote_description_set() const {
+    return remote_description_set_;
+  }
+
+  // Handles sending of ready candidates and receiving of remote candidates.
+  sigslot::signal2<TransportProxy*,
+                         const std::vector<Candidate>&> SignalCandidatesReady;
+
+ private:
+  TransportChannelProxy* GetChannelProxy(int component) const;
+  TransportChannelProxy* GetChannelProxyByName(const std::string& name) const;
+
+  TransportChannelImpl* GetOrCreateChannelProxyImpl(int component);
+  TransportChannelImpl* GetOrCreateChannelProxyImpl_w(int component);
+
+  // Manipulators of transportchannelimpl in channel proxy.
+  void SetupChannelProxy(int component,
+                           TransportChannelProxy* proxy);
+  void SetupChannelProxy_w(int component,
+                             TransportChannelProxy* proxy);
+  void ReplaceChannelProxyImpl(TransportChannelProxy* proxy,
+                               TransportChannelImpl* impl);
+  void ReplaceChannelProxyImpl_w(TransportChannelProxy* proxy,
+                                 TransportChannelImpl* impl);
+
+  rtc::Thread* const worker_thread_;
+  const std::string sid_;
+  const std::string content_name_;
+  rtc::scoped_refptr<TransportWrapper> transport_;
+  bool connecting_;
+  bool negotiated_;
+  ChannelMap channels_;
+  Candidates sent_candidates_;
+  Candidates unsent_candidates_;
+  bool candidates_allocated_;
+  bool local_description_set_;
+  bool remote_description_set_;
+};
+
+typedef std::map<std::string, TransportProxy*> TransportMap;
+
+// Statistics for all the transports of this session.
+typedef std::map<std::string, TransportStats> TransportStatsMap;
+typedef std::map<std::string, std::string> ProxyTransportMap;
+
+struct SessionStats {
+  ProxyTransportMap proxy_to_transport;
+  TransportStatsMap transport_stats;
+};
+
+// A BaseSession manages general session state. This includes negotiation
+// of both the application-level and network-level protocols:  the former
+// defines what will be sent and the latter defines how it will be sent.  Each
+// network-level protocol is represented by a Transport object.  Each Transport
+// participates in the network-level negotiation.  The individual streams of
+// packets are represented by TransportChannels.  The application-level protocol
+// is represented by SessionDecription objects.
+class BaseSession : public sigslot::has_slots<>,
+                    public rtc::MessageHandler {
+ public:
+  enum {
+    MSG_TIMEOUT = 0,
+    MSG_ERROR,
+    MSG_STATE,
+  };
+
+  enum State {
+    STATE_INIT = 0,
+    STATE_SENTINITIATE,       // sent initiate, waiting for Accept or Reject
+    STATE_RECEIVEDINITIATE,   // received an initiate. Call Accept or Reject
+    STATE_SENTPRACCEPT,       // sent provisional Accept
+    STATE_SENTACCEPT,         // sent accept. begin connecting transport
+    STATE_RECEIVEDPRACCEPT,   // received provisional Accept, waiting for Accept
+    STATE_RECEIVEDACCEPT,     // received accept. begin connecting transport
+    STATE_SENTMODIFY,         // sent modify, waiting for Accept or Reject
+    STATE_RECEIVEDMODIFY,     // received modify, call Accept or Reject
+    STATE_SENTREJECT,         // sent reject after receiving initiate
+    STATE_RECEIVEDREJECT,     // received reject after sending initiate
+    STATE_SENTREDIRECT,       // sent direct after receiving initiate
+    STATE_SENTTERMINATE,      // sent terminate (any time / either side)
+    STATE_RECEIVEDTERMINATE,  // received terminate (any time / either side)
+    STATE_INPROGRESS,         // session accepted and in progress
+    STATE_DEINIT,             // session is being destroyed
+  };
+
+  enum Error {
+    ERROR_NONE = 0,       // no error
+    ERROR_TIME = 1,       // no response to signaling
+    ERROR_RESPONSE = 2,   // error during signaling
+    ERROR_NETWORK = 3,    // network error, could not allocate network resources
+    ERROR_CONTENT = 4,    // channel errors in SetLocalContent/SetRemoteContent
+    ERROR_TRANSPORT = 5,  // transport error of some kind
+  };
+
+  // Convert State to a readable string.
+  static std::string StateToString(State state);
+
+  BaseSession(rtc::Thread* signaling_thread,
+              rtc::Thread* worker_thread,
+              PortAllocator* port_allocator,
+              const std::string& sid,
+              const std::string& content_type,
+              bool initiator);
+  virtual ~BaseSession();
+
+  // These are const to allow them to be called from const methods.
+  rtc::Thread* signaling_thread() const { return signaling_thread_; }
+  rtc::Thread* worker_thread() const { return worker_thread_; }
+  PortAllocator* port_allocator() const { return port_allocator_; }
+
+  // The ID of this session.
+  const std::string& id() const { return sid_; }
+
+  // TODO(juberti): This data is largely redundant, as it can now be obtained
+  // from local/remote_description(). Remove these functions and members.
+  // Returns the XML namespace identifying the type of this session.
+  const std::string& content_type() const { return content_type_; }
+  // Returns the XML namespace identifying the transport used for this session.
+  const std::string& transport_type() const { return transport_type_; }
+
+  // Indicates whether we initiated this session.
+  bool initiator() const { return initiator_; }
+
+  // Returns the application-level description given by our client.
+  // If we are the recipient, this will be NULL until we send an accept.
+  const SessionDescription* local_description() const;
+
+  // Returns the application-level description given by the other client.
+  // If we are the initiator, this will be NULL until we receive an accept.
+  const SessionDescription* remote_description() const;
+
+  SessionDescription* remote_description();
+
+  // Takes ownership of SessionDescription*
+  void set_local_description(const SessionDescription* sdesc);
+
+  // Takes ownership of SessionDescription*
+  void set_remote_description(SessionDescription* sdesc);
+
+  const SessionDescription* initiator_description() const;
+
+  // Returns the current state of the session.  See the enum above for details.
+  // Each time the state changes, we will fire this signal.
+  State state() const { return state_; }
+  sigslot::signal2<BaseSession* , State> SignalState;
+
+  // Returns the last error in the session.  See the enum above for details.
+  // Each time the an error occurs, we will fire this signal.
+  Error error() const { return error_; }
+  const std::string& error_desc() const { return error_desc_; }
+  sigslot::signal2<BaseSession* , Error> SignalError;
+
+  // Updates the state, signaling if necessary.
+  virtual void SetState(State state);
+
+  // Updates the error state, signaling if necessary.
+  // TODO(ronghuawu): remove the SetError method that doesn't take |error_desc|.
+  virtual void SetError(Error error, const std::string& error_desc);
+
+  // Fired when the remote description is updated, with the updated
+  // contents.
+  sigslot::signal2<BaseSession* , const ContentInfos&>
+      SignalRemoteDescriptionUpdate;
+
+  // Fired when SetState is called (regardless if there's a state change), which
+  // indicates the session description might have be updated.
+  sigslot::signal2<BaseSession*, ContentAction> SignalNewLocalDescription;
+
+  // Fired when SetState is called (regardless if there's a state change), which
+  // indicates the session description might have be updated.
+  sigslot::signal2<BaseSession*, ContentAction> SignalNewRemoteDescription;
+
+  // Returns the transport that has been negotiated or NULL if
+  // negotiation is still in progress.
+  virtual Transport* GetTransport(const std::string& content_name);
+
+  // Creates a new channel with the given names.  This method may be called
+  // immediately after creating the session.  However, the actual
+  // implementation may not be fixed until transport negotiation completes.
+  // This will usually be called from the worker thread, but that
+  // shouldn't be an issue since the main thread will be blocked in
+  // Send when doing so.
+  virtual TransportChannel* CreateChannel(const std::string& content_name,
+                                          const std::string& channel_name,
+                                          int component);
+
+  // Returns the channel with the given names.
+  virtual TransportChannel* GetChannel(const std::string& content_name,
+                                       int component);
+
+  // Destroys the channel with the given names.
+  // This will usually be called from the worker thread, but that
+  // shouldn't be an issue since the main thread will be blocked in
+  // Send when doing so.
+  virtual void DestroyChannel(const std::string& content_name,
+                              int component);
+
+  // Returns stats for all channels of all transports.
+  // This avoids exposing the internal structures used to track them.
+  virtual bool GetStats(SessionStats* stats);
+
+  rtc::SSLIdentity* identity() { return identity_; }
+
+ protected:
+  // Specifies the identity to use in this session.
+  bool SetIdentity(rtc::SSLIdentity* identity);
+
+  bool PushdownTransportDescription(ContentSource source,
+                                    ContentAction action,
+                                    std::string* error_desc);
+  void set_initiator(bool initiator) { initiator_ = initiator; }
+
+  const TransportMap& transport_proxies() const { return transports_; }
+  // Get a TransportProxy by content_name or transport. NULL if not found.
+  TransportProxy* GetTransportProxy(const std::string& content_name);
+  TransportProxy* GetTransportProxy(const Transport* transport);
+  TransportProxy* GetFirstTransportProxy();
+  void DestroyTransportProxy(const std::string& content_name);
+  // TransportProxy is owned by session.  Return proxy just for convenience.
+  TransportProxy* GetOrCreateTransportProxy(const std::string& content_name);
+  // Creates the actual transport object. Overridable for testing.
+  virtual Transport* CreateTransport(const std::string& content_name);
+
+  void OnSignalingReady();
+  void SpeculativelyConnectAllTransportChannels();
+  // Helper method to provide remote candidates to the transport.
+  bool OnRemoteCandidates(const std::string& content_name,
+                          const Candidates& candidates,
+                          std::string* error);
+
+  // This method will mux transport channels by content_name.
+  // First content is used for muxing.
+  bool MaybeEnableMuxingSupport();
+
+  // Called when a transport requests signaling.
+  virtual void OnTransportRequestSignaling(Transport* transport) {
+  }
+
+  // Called when the first channel of a transport begins connecting.  We use
+  // this to start a timer, to make sure that the connection completes in a
+  // reasonable amount of time.
+  virtual void OnTransportConnecting(Transport* transport) {
+  }
+
+  // Called when a transport changes its writable state.  We track this to make
+  // sure that the transport becomes writable within a reasonable amount of
+  // time.  If this does not occur, we signal an error.
+  virtual void OnTransportWritable(Transport* transport) {
+  }
+  virtual void OnTransportReadable(Transport* transport) {
+  }
+
+  // Called when a transport has found its steady-state connections.
+  virtual void OnTransportCompleted(Transport* transport) {
+  }
+
+  // Called when a transport has failed permanently.
+  virtual void OnTransportFailed(Transport* transport) {
+  }
+
+  // Called when a transport signals that it has new candidates.
+  virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy,
+                                               const Candidates& candidates) {
+  }
+
+  // Called when a transport signals that it found an error in an incoming
+  // message.
+  virtual void OnTransportSendError(Transport* transport,
+                                    const buzz::XmlElement* stanza,
+                                    const buzz::QName& name,
+                                    const std::string& type,
+                                    const std::string& text,
+                                    const buzz::XmlElement* extra_info) {
+  }
+
+  virtual void OnTransportRouteChange(
+      Transport* transport,
+      int component,
+      const cricket::Candidate& remote_candidate) {
+  }
+
+  virtual void OnTransportCandidatesAllocationDone(Transport* transport);
+
+  // Called when all transport channels allocated required candidates.
+  // This method should be used as an indication of candidates gathering process
+  // is completed and application can now send local candidates list to remote.
+  virtual void OnCandidatesAllocationDone() {
+  }
+
+  // Handles the ice role change callback from Transport. This must be
+  // propagated to all the transports.
+  virtual void OnRoleConflict();
+
+  // Handles messages posted to us.
+  virtual void OnMessage(rtc::Message *pmsg);
+
+ protected:
+  State state_;
+  Error error_;
+  std::string error_desc_;
+
+ private:
+  // Helper methods to push local and remote transport descriptions.
+  bool PushdownLocalTransportDescription(
+      const SessionDescription* sdesc, ContentAction action,
+      std::string* error_desc);
+  bool PushdownRemoteTransportDescription(
+      const SessionDescription* sdesc, ContentAction action,
+      std::string* error_desc);
+
+  bool IsCandidateAllocationDone() const;
+  void MaybeCandidateAllocationDone();
+
+  // This method will delete the Transport and TransportChannelImpls and
+  // replace those with the selected Transport objects. Selection is done
+  // based on the content_name and in this case first MediaContent information
+  // is used for mux.
+  bool SetSelectedProxy(const std::string& content_name,
+                        const ContentGroup* muxed_group);
+  // Log session state.
+  void LogState(State old_state, State new_state);
+
+  // Returns true and the TransportInfo of the given |content_name|
+  // from |description|. Returns false if it's not available.
+  static bool GetTransportDescription(const SessionDescription* description,
+                                      const std::string& content_name,
+                                      TransportDescription* info);
+
+  // Fires the new description signal according to the current state.
+  void SignalNewDescription();
+
+  // Gets the ContentAction and ContentSource according to the session state.
+  bool GetContentAction(ContentAction* action, ContentSource* source);
+
+  rtc::Thread* const signaling_thread_;
+  rtc::Thread* const worker_thread_;
+  PortAllocator* const port_allocator_;
+  const std::string sid_;
+  const std::string content_type_;
+  const std::string transport_type_;
+  bool initiator_;
+  rtc::SSLIdentity* identity_;
+  rtc::scoped_ptr<const SessionDescription> local_description_;
+  rtc::scoped_ptr<SessionDescription> remote_description_;
+  uint64 ice_tiebreaker_;
+  // This flag will be set to true after the first role switch. This flag
+  // will enable us to stop any role switch during the call.
+  bool role_switch_;
+  TransportMap transports_;
+};
+
+// A specific Session created by the SessionManager, using XMPP for protocol.
+class Session : public BaseSession {
+ public:
+  // Returns the manager that created and owns this session.
+  SessionManager* session_manager() const { return session_manager_; }
+
+  // Returns the client that is handling the application data of this session.
+  SessionClient* client() const { return client_; }
+
+    // Returns the JID of this client.
+  const std::string& local_name() const { return local_name_; }
+
+  // Returns the JID of the other peer in this session.
+  const std::string& remote_name() const { return remote_name_; }
+
+  // Set the JID of the other peer in this session.
+  // Typically the remote_name_ is set when the session is initiated.
+  // However, sometimes (e.g when a proxy is used) the peer name is
+  // known after the BaseSession has been initiated and it must be updated
+  // explicitly.
+  void set_remote_name(const std::string& name) { remote_name_ = name; }
+
+  // Set the JID of the initiator of this session. Allows for the overriding
+  // of the initiator to be a third-party, eg. the MUC JID when creating p2p
+  // sessions.
+  void set_initiator_name(const std::string& name) { initiator_name_ = name; }
+
+  // Indicates the JID of the entity who initiated this session.
+  // In special cases, may be different than both local_name and remote_name.
+  const std::string& initiator_name() const { return initiator_name_; }
+
+  SignalingProtocol current_protocol() const { return current_protocol_; }
+
+  void set_current_protocol(SignalingProtocol protocol) {
+    current_protocol_ = protocol;
+  }
+
+  // Updates the error state, signaling if necessary.
+  virtual void SetError(Error error, const std::string& error_desc);
+
+  // When the session needs to send signaling messages, it beings by requesting
+  // signaling.  The client should handle this by calling OnSignalingReady once
+  // it is ready to send the messages.
+  // (These are called only by SessionManager.)
+  sigslot::signal1<Session*> SignalRequestSignaling;
+  void OnSignalingReady() { BaseSession::OnSignalingReady(); }
+
+  // Takes ownership of session description.
+  // TODO: Add an error argument to pass back to the caller.
+  bool Initiate(const std::string& to,
+                const SessionDescription* sdesc);
+
+  // When we receive an initiate, we create a session in the
+  // RECEIVEDINITIATE state and respond by accepting or rejecting.
+  // Takes ownership of session description.
+  // TODO: Add an error argument to pass back to the caller.
+  bool Accept(const SessionDescription* sdesc);
+  bool Reject(const std::string& reason);
+  bool Terminate() {
+    return TerminateWithReason(STR_TERMINATE_SUCCESS);
+  }
+  bool TerminateWithReason(const std::string& reason);
+  // Fired whenever we receive a terminate message along with a reason
+  sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
+
+  // The two clients in the session may also send one another
+  // arbitrary XML messages, which are called "info" messages. Sending
+  // takes ownership of the given elements.  The signal does not; the
+  // parent element will be deleted after the signal.
+  bool SendInfoMessage(const XmlElements& elems,
+                       const std::string& remote_name);
+  bool SendDescriptionInfoMessage(const ContentInfos& contents);
+  sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage;
+
+ private:
+  // Creates or destroys a session.  (These are called only SessionManager.)
+  Session(SessionManager *session_manager,
+          const std::string& local_name, const std::string& initiator_name,
+          const std::string& sid, const std::string& content_type,
+          SessionClient* client);
+  ~Session();
+  // For each transport info, create a transport proxy.  Can fail for
+  // incompatible transport types.
+  bool CreateTransportProxies(const TransportInfos& tinfos,
+                              SessionError* error);
+  bool OnRemoteCandidates(const TransportInfos& tinfos,
+                          ParseError* error);
+  // Returns a TransportInfo without candidates for each content name.
+  // Uses the transport_type_ of the session.
+  TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const;
+
+    // Maps passed to serialization functions.
+  TransportParserMap GetTransportParsers();
+  ContentParserMap GetContentParsers();
+  CandidateTranslatorMap GetCandidateTranslators();
+
+  virtual void OnTransportRequestSignaling(Transport* transport);
+  virtual void OnTransportConnecting(Transport* transport);
+  virtual void OnTransportWritable(Transport* transport);
+  virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy,
+                                               const Candidates& candidates);
+  virtual void OnTransportSendError(Transport* transport,
+                                    const buzz::XmlElement* stanza,
+                                    const buzz::QName& name,
+                                    const std::string& type,
+                                    const std::string& text,
+                                    const buzz::XmlElement* extra_info);
+  virtual void OnMessage(rtc::Message *pmsg);
+
+  // Send various kinds of session messages.
+  bool SendInitiateMessage(const SessionDescription* sdesc,
+                           SessionError* error);
+  bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error);
+  bool SendRejectMessage(const std::string& reason, SessionError* error);
+  bool SendTerminateMessage(const std::string& reason, SessionError* error);
+  bool SendTransportInfoMessage(const TransportInfo& tinfo,
+                                SessionError* error);
+  bool SendTransportInfoMessage(const TransportProxy* transproxy,
+                                const Candidates& candidates,
+                                SessionError* error);
+
+  bool ResendAllTransportInfoMessages(SessionError* error);
+  bool SendAllUnsentTransportInfoMessages(SessionError* error);
+
+  // All versions of SendMessage send a message of the given type to
+  // the other client.  Can pass either a set of elements or an
+  // "action", which must have a WriteSessionAction method to go along
+  // with it.  Sending with an action supports sending a "hybrid"
+  // message.  Sending with elements must be sent as Jingle or Gingle.
+
+  // When passing elems, must be either Jingle or Gingle protocol.
+  // Takes ownership of action_elems.
+  bool SendMessage(ActionType type, const XmlElements& action_elems,
+                   SessionError* error);
+  // Sends a messge, but overrides the remote name.
+  bool SendMessage(ActionType type, const XmlElements& action_elems,
+                   const std::string& remote_name,
+                   SessionError* error);
+  // When passing an action, may be Hybrid protocol.
+  template <typename Action>
+  bool SendMessage(ActionType type, const Action& action,
+                   SessionError* error);
+
+  // Helper methods to write the session message stanza.
+  template <typename Action>
+  bool WriteActionMessage(ActionType type, const Action& action,
+                          buzz::XmlElement* stanza, WriteError* error);
+  template <typename Action>
+  bool WriteActionMessage(SignalingProtocol protocol,
+                          ActionType type, const Action& action,
+                          buzz::XmlElement* stanza, WriteError* error);
+
+  // Sending messages in hybrid form requires being able to write them
+  // on a per-protocol basis with a common method signature, which all
+  // of these have.
+  bool WriteSessionAction(SignalingProtocol protocol,
+                          const SessionInitiate& init,
+                          XmlElements* elems, WriteError* error);
+  bool WriteSessionAction(SignalingProtocol protocol,
+                          const TransportInfo& tinfo,
+                          XmlElements* elems, WriteError* error);
+  bool WriteSessionAction(SignalingProtocol protocol,
+                          const SessionTerminate& term,
+                          XmlElements* elems, WriteError* error);
+
+  // Sends a message back to the other client indicating that we have received
+  // and accepted their message.
+  void SendAcknowledgementMessage(const buzz::XmlElement* stanza);
+
+  // Once signaling is ready, the session will use this signal to request the
+  // sending of each message.  When messages are received by the other client,
+  // they should be handed to OnIncomingMessage.
+  // (These are called only by SessionManager.)
+  sigslot::signal2<Session* , const buzz::XmlElement*> SignalOutgoingMessage;
+  void OnIncomingMessage(const SessionMessage& msg);
+
+  void OnIncomingResponse(const buzz::XmlElement* orig_stanza,
+                          const buzz::XmlElement* response_stanza,
+                          const SessionMessage& msg);
+  void OnInitiateAcked();
+  void OnFailedSend(const buzz::XmlElement* orig_stanza,
+                    const buzz::XmlElement* error_stanza);
+
+  // Invoked when an error is found in an incoming message.  This is translated
+  // into the appropriate XMPP response by SessionManager.
+  sigslot::signal6<BaseSession*,
+                   const buzz::XmlElement*,
+                   const buzz::QName&,
+                   const std::string&,
+                   const std::string&,
+                   const buzz::XmlElement*> SignalErrorMessage;
+
+  // Handlers for the various types of messages.  These functions may take
+  // pointers to the whole stanza or to just the session element.
+  bool OnInitiateMessage(const SessionMessage& msg, MessageError* error);
+  bool OnAcceptMessage(const SessionMessage& msg, MessageError* error);
+  bool OnRejectMessage(const SessionMessage& msg, MessageError* error);
+  bool OnInfoMessage(const SessionMessage& msg);
+  bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
+  bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
+  bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
+  bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error);
+  bool OnRedirectError(const SessionRedirect& redirect, SessionError* error);
+
+  // Verifies that we are in the appropriate state to receive this message.
+  bool CheckState(State state, MessageError* error);
+
+  SessionManager* session_manager_;
+  bool initiate_acked_;
+  std::string local_name_;
+  std::string initiator_name_;
+  std::string remote_name_;
+  SessionClient* client_;
+  TransportParser* transport_parser_;
+  // Keeps track of what protocol we are speaking.
+  SignalingProtocol current_protocol_;
+
+  friend class SessionManager;  // For access to constructor, destructor,
+                                // and signaling related methods.
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_SESSION_H_
diff --git a/p2p/base/session_unittest.cc b/p2p/base/session_unittest.cc
new file mode 100644
index 0000000..d6f94b2
--- /dev/null
+++ b/p2p/base/session_unittest.cc
@@ -0,0 +1,2430 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string.h>
+
+#include <deque>
+#include <map>
+#include <sstream>
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/p2ptransport.h"
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/p2p/base/relayserver.h"
+#include "webrtc/p2p/base/session.h"
+#include "webrtc/p2p/base/sessionclient.h"
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/p2p/base/stunport.h"
+#include "webrtc/p2p/base/stunserver.h"
+#include "webrtc/p2p/base/transportchannel.h"
+#include "webrtc/p2p/base/transportchannelproxy.h"
+#include "webrtc/p2p/base/udpport.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/base64.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/natserver.h"
+#include "webrtc/base/natsocketfactory.h"
+#include "webrtc/base/stringencode.h"
+
+using cricket::SignalingProtocol;
+using cricket::PROTOCOL_HYBRID;
+using cricket::PROTOCOL_JINGLE;
+using cricket::PROTOCOL_GINGLE;
+
+static const std::string kInitiator = "init@init.com";
+static const std::string kResponder = "resp@resp.com";
+// Expected from test random number generator.
+static const std::string kSessionId = "9254631414740579489";
+// TODO: When we need to test more than one transport type,
+// allow this to be injected like the content types are.
+static const std::string kTransportType = "http://www.google.com/transport/p2p";
+
+// Controls how long we wait for a session to send messages that we
+// expect, in milliseconds.  We put it high to avoid flaky tests.
+static const int kEventTimeout = 5000;
+
+static const int kNumPorts = 2;
+static const int kPort0 = 28653;
+static const int kPortStep = 5;
+
+int GetPort(int port_index) {
+  return kPort0 + (port_index * kPortStep);
+}
+
+std::string GetPortString(int port_index) {
+  return rtc::ToString(GetPort(port_index));
+}
+
+// Only works for port_index < 10, which is fine for our purposes.
+std::string GetUsername(int port_index) {
+  return "username" + std::string(8, rtc::ToString(port_index)[0]);
+}
+
+// Only works for port_index < 10, which is fine for our purposes.
+std::string GetPassword(int port_index) {
+  return "password" + std::string(8, rtc::ToString(port_index)[0]);
+}
+
+std::string IqAck(const std::string& id,
+                  const std::string& from,
+                  const std::string& to) {
+  return "<cli:iq"
+      " to=\"" + to + "\""
+      " id=\"" + id + "\""
+      " type=\"result\""
+      " from=\"" + from + "\""
+      " xmlns:cli=\"jabber:client\""
+      "/>";
+}
+
+std::string IqSet(const std::string& id,
+                  const std::string& from,
+                  const std::string& to,
+                  const std::string& content) {
+  return "<cli:iq"
+      " to=\"" + to + "\""
+      " type=\"set\""
+      " from=\"" + from + "\""
+      " id=\"" + id + "\""
+      " xmlns:cli=\"jabber:client\""
+      ">"
+      + content +
+      "</cli:iq>";
+}
+
+std::string IqError(const std::string& id,
+                    const std::string& from,
+                    const std::string& to,
+                    const std::string& content) {
+  return "<cli:error"
+      " to=\"" + to + "\""
+      " type=\"error\""
+      " from=\"" + from + "\""
+      " id=\"" + id + "\""
+      " xmlns:cli=\"jabber:client\""
+      ">"
+      + content +
+      "</cli:error>";
+}
+
+std::string GingleSessionXml(const std::string& type,
+                             const std::string& content) {
+  return "<session"
+      " xmlns=\"http://www.google.com/session\""
+      " type=\"" + type + "\""
+      " id=\"" + kSessionId + "\""
+      " initiator=\"" + kInitiator + "\""
+      ">"
+      + content +
+      "</session>";
+}
+
+std::string GingleDescriptionXml(const std::string& content_type) {
+  return "<description"
+      " xmlns=\"" + content_type + "\""
+      "/>";
+}
+
+std::string P2pCandidateXml(const std::string& name, int port_index) {
+  // Port will update the rtcp username by +1 on the last character. So we need
+  // to compensate here. See Port::username_fragment() for detail.
+  std::string username = GetUsername(port_index);
+  // TODO: Use the component id instead of the channel name to
+  // determinte if we need to covert the username here.
+  if (name == "rtcp" || name == "video_rtcp" || name == "chanb") {
+    char next_ch = username[username.size() - 1];
+    ASSERT(username.size() > 0);
+    rtc::Base64::GetNextBase64Char(next_ch, &next_ch);
+    username[username.size() - 1] = next_ch;
+  }
+  return "<candidate"
+      " name=\"" + name + "\""
+      " address=\"127.0.0.1\""
+      " port=\"" + GetPortString(port_index) + "\""
+      " preference=\"0.99\""
+      " username=\"" + username + "\""
+      " protocol=\"udp\""
+      " generation=\"0\""
+      " password=\"" + GetPassword(port_index) + "\""
+      " type=\"local\""
+      " network=\"network\""
+      "/>";
+}
+
+std::string JingleActionXml(const std::string& action,
+                            const std::string& content) {
+  return "<jingle"
+      " xmlns=\"urn:xmpp:jingle:1\""
+      " action=\"" + action + "\""
+      " sid=\"" + kSessionId + "\""
+      ">"
+      + content +
+      "</jingle>";
+}
+
+std::string JingleInitiateActionXml(const std::string& content) {
+  return "<jingle"
+      " xmlns=\"urn:xmpp:jingle:1\""
+      " action=\"session-initiate\""
+      " sid=\"" + kSessionId + "\""
+      " initiator=\"" + kInitiator + "\""
+      ">"
+      + content +
+      "</jingle>";
+}
+
+std::string JingleGroupInfoXml(const std::string& content_name_a,
+                               const std::string& content_name_b) {
+  std::string group_info = "<jin:group"
+      " type=\"BUNDLE\""
+      " xmlns:jin=\"google:jingle\""
+      ">";
+  if (!content_name_a.empty())
+    group_info += "<content name=\"" + content_name_a + "\""
+    "/>";
+  if (!content_name_b.empty())
+    group_info += "<content name=\"" + content_name_b + "\""
+    "/>";
+  group_info += "</jin:group>";
+  return group_info;
+}
+
+
+std::string JingleEmptyContentXml(const std::string& content_name,
+                                  const std::string& content_type,
+                                  const std::string& transport_type) {
+  return "<content"
+      " name=\"" + content_name + "\""
+      " creator=\"initiator\""
+      ">"
+      "<description"
+      " xmlns=\"" + content_type + "\""
+      "/>"
+      "<transport"
+      " xmlns=\"" + transport_type + "\""
+      "/>"
+      "</content>";
+}
+
+std::string JingleContentXml(const std::string& content_name,
+                             const std::string& content_type,
+                             const std::string& transport_type,
+                             const std::string& transport_main) {
+  std::string transport = transport_type.empty() ? "" :
+      "<transport"
+      " xmlns=\"" + transport_type + "\""
+      ">"
+      + transport_main +
+      "</transport>";
+
+  return"<content"
+      " name=\"" + content_name + "\""
+      " creator=\"initiator\""
+      ">"
+      "<description"
+      " xmlns=\"" + content_type + "\""
+      "/>"
+      + transport +
+      "</content>";
+}
+
+std::string JingleTransportContentXml(const std::string& content_name,
+                                      const std::string& transport_type,
+                                      const std::string& content) {
+  return "<content"
+      " name=\"" + content_name + "\""
+      " creator=\"initiator\""
+      ">"
+      "<transport"
+      " xmlns=\"" + transport_type + "\""
+      ">"
+      + content +
+      "</transport>"
+      "</content>";
+}
+
+std::string GingleInitiateXml(const std::string& content_type) {
+  return GingleSessionXml(
+      "initiate",
+      GingleDescriptionXml(content_type));
+}
+
+std::string JingleInitiateXml(const std::string& content_name_a,
+                              const std::string& content_type_a,
+                              const std::string& content_name_b,
+                              const std::string& content_type_b,
+                              bool bundle = false) {
+  std::string content_xml;
+  if (content_name_b.empty()) {
+    content_xml = JingleEmptyContentXml(
+        content_name_a, content_type_a, kTransportType);
+  } else {
+    content_xml = JingleEmptyContentXml(
+           content_name_a, content_type_a, kTransportType) +
+       JingleEmptyContentXml(
+           content_name_b, content_type_b, kTransportType);
+    if (bundle) {
+      content_xml += JingleGroupInfoXml(content_name_a, content_name_b);
+    }
+  }
+  return JingleInitiateActionXml(content_xml);
+}
+
+std::string GingleAcceptXml(const std::string& content_type) {
+  return GingleSessionXml(
+      "accept",
+      GingleDescriptionXml(content_type));
+}
+
+std::string JingleAcceptXml(const std::string& content_name_a,
+                            const std::string& content_type_a,
+                            const std::string& content_name_b,
+                            const std::string& content_type_b,
+                            bool bundle = false) {
+  std::string content_xml;
+  if (content_name_b.empty()) {
+    content_xml = JingleEmptyContentXml(
+        content_name_a, content_type_a, kTransportType);
+  } else {
+    content_xml = JingleEmptyContentXml(
+        content_name_a, content_type_a, kTransportType) +
+        JingleEmptyContentXml(
+            content_name_b, content_type_b, kTransportType);
+  }
+  if (bundle) {
+    content_xml += JingleGroupInfoXml(content_name_a, content_name_b);
+  }
+
+  return JingleActionXml("session-accept", content_xml);
+}
+
+std::string Gingle2CandidatesXml(const std::string& channel_name,
+                                 int port_index0,
+                                 int port_index1) {
+  return GingleSessionXml(
+      "candidates",
+      P2pCandidateXml(channel_name, port_index0) +
+      P2pCandidateXml(channel_name, port_index1));
+}
+
+std::string Gingle4CandidatesXml(const std::string& channel_name_a,
+                                 int port_index0,
+                                 int port_index1,
+                                 const std::string& channel_name_b,
+                                 int port_index2,
+                                 int port_index3) {
+  return GingleSessionXml(
+      "candidates",
+      P2pCandidateXml(channel_name_a, port_index0) +
+      P2pCandidateXml(channel_name_a, port_index1) +
+      P2pCandidateXml(channel_name_b, port_index2) +
+      P2pCandidateXml(channel_name_b, port_index3));
+}
+
+std::string Jingle2TransportInfoXml(const std::string& content_name,
+                                    const std::string& channel_name,
+                                    int port_index0,
+                                    int port_index1) {
+  return JingleActionXml(
+      "transport-info",
+      JingleTransportContentXml(
+          content_name, kTransportType,
+          P2pCandidateXml(channel_name, port_index0) +
+          P2pCandidateXml(channel_name, port_index1)));
+}
+
+std::string Jingle4TransportInfoXml(const std::string& content_name,
+                                    const std::string& channel_name_a,
+                                    int port_index0,
+                                    int port_index1,
+                                    const std::string& channel_name_b,
+                                    int port_index2,
+                                    int port_index3) {
+  return JingleActionXml(
+      "transport-info",
+      JingleTransportContentXml(
+          content_name, kTransportType,
+          P2pCandidateXml(channel_name_a, port_index0) +
+          P2pCandidateXml(channel_name_a, port_index1) +
+          P2pCandidateXml(channel_name_b, port_index2) +
+          P2pCandidateXml(channel_name_b, port_index3)));
+}
+
+std::string JingleDescriptionInfoXml(const std::string& content_name,
+                                     const std::string& content_type) {
+  return JingleActionXml(
+      "description-info",
+      JingleContentXml(content_name, content_type, "", ""));
+}
+
+std::string GingleRejectXml(const std::string& reason) {
+  return GingleSessionXml(
+      "reject",
+      "<" + reason + "/>");
+}
+
+std::string JingleTerminateXml(const std::string& reason) {
+    return JingleActionXml(
+        "session-terminate",
+        "<reason><" + reason + "/></reason>");
+}
+
+std::string GingleTerminateXml(const std::string& reason) {
+  return GingleSessionXml(
+      "terminate",
+      "<" + reason + "/>");
+}
+
+std::string GingleRedirectXml(const std::string& intitiate,
+                              const std::string& target) {
+  return intitiate +
+    "<error code=\"302\" type=\"modify\">"
+    "<redirect xmlns=\"http://www.google.com/session\">"
+    "xmpp:" + target +
+    "</redirect>"
+    "</error>";
+}
+
+std::string JingleRedirectXml(const std::string& intitiate,
+                              const std::string& target) {
+  return intitiate +
+    "<error code=\"302\" type=\"modify\">"
+    "<redirect xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">"
+    "xmpp:" + target +
+    "</redirect>"
+    "</error>";
+}
+
+std::string InitiateXml(SignalingProtocol protocol,
+                        const std::string& gingle_content_type,
+                        const std::string& content_name_a,
+                        const std::string& content_type_a,
+                        const std::string& content_name_b,
+                        const std::string& content_type_b,
+                        bool bundle = false) {
+  switch (protocol) {
+    case PROTOCOL_JINGLE:
+      return JingleInitiateXml(content_name_a, content_type_a,
+                               content_name_b, content_type_b,
+                               bundle);
+    case PROTOCOL_GINGLE:
+      return GingleInitiateXml(gingle_content_type);
+    case PROTOCOL_HYBRID:
+      return JingleInitiateXml(content_name_a, content_type_a,
+                               content_name_b, content_type_b) +
+          GingleInitiateXml(gingle_content_type);
+  }
+  return "";
+}
+
+std::string InitiateXml(SignalingProtocol protocol,
+                        const std::string& content_name,
+                        const std::string& content_type) {
+  return InitiateXml(protocol,
+                     content_type,
+                     content_name, content_type,
+                     "", "");
+}
+
+std::string AcceptXml(SignalingProtocol protocol,
+                      const std::string& gingle_content_type,
+                      const std::string& content_name_a,
+                      const std::string& content_type_a,
+                      const std::string& content_name_b,
+                      const std::string& content_type_b,
+                      bool bundle = false) {
+  switch (protocol) {
+    case PROTOCOL_JINGLE:
+      return JingleAcceptXml(content_name_a, content_type_a,
+                             content_name_b, content_type_b, bundle);
+    case PROTOCOL_GINGLE:
+      return GingleAcceptXml(gingle_content_type);
+    case PROTOCOL_HYBRID:
+      return
+          JingleAcceptXml(content_name_a, content_type_a,
+                          content_name_b, content_type_b) +
+          GingleAcceptXml(gingle_content_type);
+  }
+  return "";
+}
+
+
+std::string AcceptXml(SignalingProtocol protocol,
+                      const std::string& content_name,
+                      const std::string& content_type,
+                      bool bundle = false) {
+  return AcceptXml(protocol,
+                   content_type,
+                   content_name, content_type,
+                   "", "");
+}
+
+std::string TransportInfo2Xml(SignalingProtocol protocol,
+                              const std::string& content_name,
+                              const std::string& channel_name,
+                              int port_index0,
+                              int port_index1) {
+  switch (protocol) {
+    case PROTOCOL_JINGLE:
+      return Jingle2TransportInfoXml(
+          content_name,
+          channel_name, port_index0, port_index1);
+    case PROTOCOL_GINGLE:
+      return Gingle2CandidatesXml(
+          channel_name, port_index0, port_index1);
+    case PROTOCOL_HYBRID:
+      return
+          Jingle2TransportInfoXml(
+              content_name,
+              channel_name, port_index0, port_index1) +
+          Gingle2CandidatesXml(
+              channel_name, port_index0, port_index1);
+  }
+  return "";
+}
+
+std::string TransportInfo4Xml(SignalingProtocol protocol,
+                              const std::string& content_name,
+                              const std::string& channel_name_a,
+                              int port_index0,
+                              int port_index1,
+                              const std::string& channel_name_b,
+                              int port_index2,
+                              int port_index3) {
+  switch (protocol) {
+    case PROTOCOL_JINGLE:
+      return Jingle4TransportInfoXml(
+          content_name,
+          channel_name_a, port_index0, port_index1,
+          channel_name_b, port_index2, port_index3);
+    case PROTOCOL_GINGLE:
+      return Gingle4CandidatesXml(
+          channel_name_a, port_index0, port_index1,
+          channel_name_b, port_index2, port_index3);
+    case PROTOCOL_HYBRID:
+      return
+          Jingle4TransportInfoXml(
+              content_name,
+              channel_name_a, port_index0, port_index1,
+              channel_name_b, port_index2, port_index3) +
+          Gingle4CandidatesXml(
+              channel_name_a, port_index0, port_index1,
+              channel_name_b, port_index2, port_index3);
+  }
+  return "";
+}
+
+std::string RejectXml(SignalingProtocol protocol,
+                      const std::string& reason) {
+  switch (protocol) {
+    case PROTOCOL_JINGLE:
+      return JingleTerminateXml(reason);
+    case PROTOCOL_GINGLE:
+      return GingleRejectXml(reason);
+    case PROTOCOL_HYBRID:
+      return JingleTerminateXml(reason) +
+          GingleRejectXml(reason);
+  }
+  return "";
+}
+
+std::string TerminateXml(SignalingProtocol protocol,
+                         const std::string& reason) {
+  switch (protocol) {
+    case PROTOCOL_JINGLE:
+      return JingleTerminateXml(reason);
+    case PROTOCOL_GINGLE:
+      return GingleTerminateXml(reason);
+    case PROTOCOL_HYBRID:
+      return JingleTerminateXml(reason) +
+          GingleTerminateXml(reason);
+  }
+  return "";
+}
+
+std::string RedirectXml(SignalingProtocol protocol,
+                        const std::string& initiate,
+                        const std::string& target) {
+  switch (protocol) {
+    case PROTOCOL_JINGLE:
+      return JingleRedirectXml(initiate, target);
+    case PROTOCOL_GINGLE:
+      return GingleRedirectXml(initiate, target);
+    default:
+      break;
+  }
+  return "";
+}
+
+// TODO: Break out and join with fakeportallocator.h
+class TestPortAllocatorSession : public cricket::PortAllocatorSession {
+ public:
+  TestPortAllocatorSession(const std::string& content_name,
+                           int component,
+                           const std::string& ice_ufrag,
+                           const std::string& ice_pwd,
+                           const int port_offset)
+      : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, 0),
+        port_offset_(port_offset),
+        ports_(kNumPorts),
+        address_("127.0.0.1", 0),
+        network_("network", "unittest",
+                 rtc::IPAddress(INADDR_LOOPBACK), 8),
+        socket_factory_(rtc::Thread::Current()),
+        running_(false) {
+    network_.AddIP(address_.ipaddr());
+  }
+
+  ~TestPortAllocatorSession() {
+    for (size_t i = 0; i < ports_.size(); i++)
+      delete ports_[i];
+  }
+
+  virtual void StartGettingPorts() {
+    for (int i = 0; i < kNumPorts; i++) {
+      int index = port_offset_ + i;
+      ports_[i] = cricket::UDPPort::Create(
+          rtc::Thread::Current(), &socket_factory_,
+          &network_, address_.ipaddr(), GetPort(index), GetPort(index),
+          GetUsername(index), GetPassword(index));
+      AddPort(ports_[i]);
+    }
+    running_ = true;
+  }
+
+  virtual void StopGettingPorts() { running_ = false; }
+  virtual bool IsGettingPorts() { return running_; }
+
+  void AddPort(cricket::Port* port) {
+    port->set_component(component_);
+    port->set_generation(0);
+    port->SignalDestroyed.connect(
+        this, &TestPortAllocatorSession::OnPortDestroyed);
+    port->SignalPortComplete.connect(
+        this, &TestPortAllocatorSession::OnPortComplete);
+    port->PrepareAddress();
+    SignalPortReady(this, port);
+  }
+
+  void OnPortDestroyed(cricket::PortInterface* port) {
+    for (size_t i = 0; i < ports_.size(); i++) {
+      if (ports_[i] == port)
+        ports_[i] = NULL;
+    }
+  }
+
+  void OnPortComplete(cricket::Port* port) {
+    SignalCandidatesReady(this, port->Candidates());
+  }
+
+ private:
+  int port_offset_;
+  std::vector<cricket::Port*> ports_;
+  rtc::SocketAddress address_;
+  rtc::Network network_;
+  rtc::BasicPacketSocketFactory socket_factory_;
+  bool running_;
+};
+
+class TestPortAllocator : public cricket::PortAllocator {
+ public:
+  TestPortAllocator() : port_offset_(0) {}
+
+  virtual cricket::PortAllocatorSession*
+  CreateSessionInternal(
+                const std::string& content_name,
+                int component,
+                const std::string& ice_ufrag,
+                const std::string& ice_pwd) {
+    port_offset_ += 2;
+    return new TestPortAllocatorSession(content_name, component,
+                                        ice_ufrag, ice_pwd, port_offset_ - 2);
+  }
+
+  int port_offset_;
+};
+
+class TestContentDescription : public cricket::ContentDescription {
+ public:
+  explicit TestContentDescription(const std::string& gingle_content_type,
+                                  const std::string& content_type)
+      : gingle_content_type(gingle_content_type),
+        content_type(content_type) {
+  }
+  virtual ContentDescription* Copy() const {
+    return new TestContentDescription(*this);
+  }
+
+  std::string gingle_content_type;
+  std::string content_type;
+};
+
+cricket::SessionDescription* NewTestSessionDescription(
+    const std::string gingle_content_type,
+    const std::string& content_name_a, const std::string& content_type_a,
+    const std::string& content_name_b, const std::string& content_type_b) {
+
+  cricket::SessionDescription* offer = new cricket::SessionDescription();
+  offer->AddContent(content_name_a, content_type_a,
+                    new TestContentDescription(gingle_content_type,
+                                               content_type_a));
+  cricket::TransportDescription desc(cricket::NS_GINGLE_P2P,
+                                     std::string(), std::string());
+  offer->AddTransportInfo(cricket::TransportInfo(content_name_a, desc));
+
+  if (content_name_a != content_name_b) {
+    offer->AddContent(content_name_b, content_type_b,
+                      new TestContentDescription(gingle_content_type,
+                                                 content_type_b));
+    offer->AddTransportInfo(cricket::TransportInfo(content_name_b, desc));
+  }
+  return offer;
+}
+
+cricket::SessionDescription* NewTestSessionDescription(
+    const std::string& content_name, const std::string& content_type) {
+
+  cricket::SessionDescription* offer = new cricket::SessionDescription();
+  offer->AddContent(content_name, content_type,
+                    new TestContentDescription(content_type,
+                                               content_type));
+  offer->AddTransportInfo(cricket::TransportInfo
+                          (content_name, cricket::TransportDescription(
+                          cricket::NS_GINGLE_P2P,
+                          std::string(), std::string())));
+  return offer;
+}
+
+struct TestSessionClient: public cricket::SessionClient,
+                          public sigslot::has_slots<> {
+ public:
+  TestSessionClient() {
+  }
+
+  ~TestSessionClient() {
+  }
+
+  virtual bool ParseContent(SignalingProtocol protocol,
+                            const buzz::XmlElement* elem,
+                            cricket::ContentDescription** content,
+                            cricket::ParseError* error) {
+    std::string content_type;
+    std::string gingle_content_type;
+    if (protocol == PROTOCOL_GINGLE) {
+      gingle_content_type = elem->Name().Namespace();
+    } else {
+      content_type = elem->Name().Namespace();
+    }
+
+    *content = new TestContentDescription(gingle_content_type, content_type);
+    return true;
+  }
+
+  virtual bool WriteContent(SignalingProtocol protocol,
+                            const cricket::ContentDescription* untyped_content,
+                            buzz::XmlElement** elem,
+                            cricket::WriteError* error) {
+    const TestContentDescription* content =
+        static_cast<const TestContentDescription*>(untyped_content);
+    std::string content_type = (protocol == PROTOCOL_GINGLE ?
+                                content->gingle_content_type :
+                                content->content_type);
+     *elem = new buzz::XmlElement(
+        buzz::QName(content_type, "description"), true);
+    return true;
+  }
+
+  void OnSessionCreate(cricket::Session* session, bool initiate) {
+  }
+
+  void OnSessionDestroy(cricket::Session* session) {
+  }
+};
+
+struct ChannelHandler : sigslot::has_slots<> {
+  explicit ChannelHandler(cricket::TransportChannel* p, const std::string& name)
+    : channel(p), last_readable(false), last_writable(false), data_count(0),
+      last_size(0), name(name) {
+    p->SignalReadableState.connect(this, &ChannelHandler::OnReadableState);
+    p->SignalWritableState.connect(this, &ChannelHandler::OnWritableState);
+    p->SignalReadPacket.connect(this, &ChannelHandler::OnReadPacket);
+  }
+
+  bool writable() const {
+    return last_writable && channel->writable();
+  }
+
+  bool readable() const {
+    return last_readable && channel->readable();
+  }
+
+  void OnReadableState(cricket::TransportChannel* p) {
+    EXPECT_EQ(channel, p);
+    last_readable = channel->readable();
+  }
+
+  void OnWritableState(cricket::TransportChannel* p) {
+    EXPECT_EQ(channel, p);
+    last_writable = channel->writable();
+  }
+
+  void OnReadPacket(cricket::TransportChannel* p, const char* buf,
+                    size_t size, const rtc::PacketTime& time, int flags) {
+    if (memcmp(buf, name.c_str(), name.size()) != 0)
+      return;  // drop packet if packet doesn't belong to this channel. This
+               // can happen when transport channels are muxed together.
+    buf += name.size();  // Remove channel name from the message.
+    size -= name.size();  // Decrement size by channel name string size.
+    EXPECT_EQ(channel, p);
+    EXPECT_LE(size, sizeof(last_data));
+    data_count += 1;
+    last_size = size;
+    memcpy(last_data, buf, size);
+  }
+
+  void Send(const char* data, size_t size) {
+    rtc::PacketOptions options;
+    std::string data_with_id(name);
+    data_with_id += data;
+    int result = channel->SendPacket(data_with_id.c_str(), data_with_id.size(),
+                                     options, 0);
+    EXPECT_EQ(static_cast<int>(data_with_id.size()), result);
+  }
+
+  cricket::TransportChannel* channel;
+  bool last_readable, last_writable;
+  int data_count;
+  char last_data[4096];
+  size_t last_size;
+  std::string name;
+};
+
+void PrintStanza(const std::string& message,
+                 const buzz::XmlElement* stanza) {
+  printf("%s: %s\n", message.c_str(), stanza->Str().c_str());
+}
+
+class TestClient : public sigslot::has_slots<> {
+ public:
+  // TODO: Add channel_component_a/b as inputs to the ctor.
+  TestClient(cricket::PortAllocator* port_allocator,
+             int* next_message_id,
+             const std::string& local_name,
+             SignalingProtocol start_protocol,
+             const std::string& content_type,
+             const std::string& content_name_a,
+             const std::string& channel_name_a,
+             const std::string& content_name_b,
+             const std::string& channel_name_b) {
+    Construct(port_allocator, next_message_id, local_name, start_protocol,
+              content_type, content_name_a, channel_name_a,
+              content_name_b, channel_name_b);
+  }
+
+  ~TestClient() {
+    if (session) {
+      session_manager->DestroySession(session);
+      EXPECT_EQ(1U, session_destroyed_count);
+    }
+    delete session_manager;
+    delete client;
+    for (std::deque<buzz::XmlElement*>::iterator it = sent_stanzas.begin();
+         it != sent_stanzas.end(); ++it) {
+      delete *it;
+    }
+  }
+
+  void Construct(cricket::PortAllocator* pa,
+                 int* message_id,
+                 const std::string& lname,
+                 SignalingProtocol protocol,
+                 const std::string& cont_type,
+                 const std::string& cont_name_a,
+                 const std::string& chan_name_a,
+                 const std::string& cont_name_b,
+                 const std::string& chan_name_b) {
+    port_allocator_ = pa;
+    next_message_id = message_id;
+    local_name = lname;
+    start_protocol = protocol;
+    content_type = cont_type;
+    content_name_a = cont_name_a;
+    channel_name_a = chan_name_a;
+    content_name_b = cont_name_b;
+    channel_name_b = chan_name_b;
+    session_created_count = 0;
+    session_destroyed_count = 0;
+    session_remote_description_update_count = 0;
+    new_local_description = false;
+    new_remote_description = false;
+    last_content_action = cricket::CA_OFFER;
+    last_content_source = cricket::CS_LOCAL;
+    session = NULL;
+    last_session_state = cricket::BaseSession::STATE_INIT;
+    blow_up_on_error = true;
+    error_count = 0;
+
+    session_manager = new cricket::SessionManager(port_allocator_);
+    session_manager->SignalSessionCreate.connect(
+        this, &TestClient::OnSessionCreate);
+    session_manager->SignalSessionDestroy.connect(
+        this, &TestClient::OnSessionDestroy);
+    session_manager->SignalOutgoingMessage.connect(
+        this, &TestClient::OnOutgoingMessage);
+
+    client = new TestSessionClient();
+    session_manager->AddClient(content_type, client);
+    EXPECT_EQ(client, session_manager->GetClient(content_type));
+  }
+
+  uint32 sent_stanza_count() const {
+    return static_cast<uint32>(sent_stanzas.size());
+  }
+
+  const buzz::XmlElement* stanza() const {
+    return last_expected_sent_stanza.get();
+  }
+
+  cricket::BaseSession::State session_state() const {
+    EXPECT_EQ(last_session_state, session->state());
+    return session->state();
+  }
+
+  void SetSessionState(cricket::BaseSession::State state) {
+    session->SetState(state);
+    EXPECT_EQ_WAIT(last_session_state, session->state(), kEventTimeout);
+  }
+
+  void CreateSession() {
+    session_manager->CreateSession(local_name, content_type);
+  }
+
+  void DeliverStanza(const buzz::XmlElement* stanza) {
+    session_manager->OnIncomingMessage(stanza);
+  }
+
+  void DeliverStanza(const std::string& str) {
+    buzz::XmlElement* stanza = buzz::XmlElement::ForStr(str);
+    session_manager->OnIncomingMessage(stanza);
+    delete stanza;
+  }
+
+  void DeliverAckToLastStanza() {
+    const buzz::XmlElement* orig_stanza = stanza();
+    const buzz::XmlElement* response_stanza =
+        buzz::XmlElement::ForStr(IqAck(orig_stanza->Attr(buzz::QN_IQ), "", ""));
+    session_manager->OnIncomingResponse(orig_stanza, response_stanza);
+    delete response_stanza;
+  }
+
+  void ExpectSentStanza(const std::string& expected) {
+    EXPECT_TRUE(!sent_stanzas.empty()) <<
+        "Found no stanza when expected " << expected;
+
+    last_expected_sent_stanza.reset(sent_stanzas.front());
+    sent_stanzas.pop_front();
+
+    std::string actual = last_expected_sent_stanza->Str();
+    EXPECT_EQ(expected, actual);
+  }
+
+  void SkipUnsentStanza() {
+    GetNextOutgoingMessageID();
+  }
+
+  bool HasTransport(const std::string& content_name) const {
+    ASSERT(session != NULL);
+    const cricket::Transport* transport = session->GetTransport(content_name);
+    return transport != NULL && (kTransportType == transport->type());
+  }
+
+  bool HasChannel(const std::string& content_name,
+                  int component) const {
+    ASSERT(session != NULL);
+    const cricket::TransportChannel* channel =
+        session->GetChannel(content_name, component);
+    return channel != NULL && (component == channel->component());
+  }
+
+  cricket::TransportChannel* GetChannel(const std::string& content_name,
+                                        int component) const {
+    ASSERT(session != NULL);
+    return session->GetChannel(content_name, component);
+  }
+
+  void OnSessionCreate(cricket::Session* created_session, bool initiate) {
+    session_created_count += 1;
+
+    session = created_session;
+    session->set_current_protocol(start_protocol);
+    session->SignalState.connect(this, &TestClient::OnSessionState);
+    session->SignalError.connect(this, &TestClient::OnSessionError);
+    session->SignalRemoteDescriptionUpdate.connect(
+        this, &TestClient::OnSessionRemoteDescriptionUpdate);
+    session->SignalNewLocalDescription.connect(
+        this, &TestClient::OnNewLocalDescription);
+    session->SignalNewRemoteDescription.connect(
+        this, &TestClient::OnNewRemoteDescription);
+
+    CreateChannels();
+  }
+
+  void OnSessionDestroy(cricket::Session *session) {
+    session_destroyed_count += 1;
+  }
+
+  void OnSessionState(cricket::BaseSession* session,
+                      cricket::BaseSession::State state) {
+    // EXPECT_EQ does not allow use of this, hence the tmp variable.
+    cricket::BaseSession* tmp = this->session;
+    EXPECT_EQ(tmp, session);
+    last_session_state = state;
+  }
+
+  void OnSessionError(cricket::BaseSession* session,
+                      cricket::BaseSession::Error error) {
+    // EXPECT_EQ does not allow use of this, hence the tmp variable.
+    cricket::BaseSession* tmp = this->session;
+    EXPECT_EQ(tmp, session);
+    if (blow_up_on_error) {
+      EXPECT_TRUE(false);
+    } else {
+      error_count++;
+    }
+  }
+
+  void OnSessionRemoteDescriptionUpdate(cricket::BaseSession* session,
+      const cricket::ContentInfos& contents) {
+    session_remote_description_update_count++;
+  }
+
+  void OnNewLocalDescription(cricket::BaseSession* session,
+                             cricket::ContentAction action) {
+    new_local_description = true;
+    last_content_action = action;
+    last_content_source = cricket::CS_LOCAL;
+  }
+
+  void OnNewRemoteDescription(cricket::BaseSession* session,
+                              cricket::ContentAction action) {
+    new_remote_description = true;
+    last_content_action = action;
+    last_content_source = cricket::CS_REMOTE;
+  }
+
+  void PrepareCandidates() {
+    session_manager->OnSignalingReady();
+  }
+
+  void OnOutgoingMessage(cricket::SessionManager* manager,
+                         const buzz::XmlElement* stanza) {
+    buzz::XmlElement* elem = new buzz::XmlElement(*stanza);
+    EXPECT_TRUE(elem->Name() == buzz::QN_IQ);
+    EXPECT_TRUE(elem->HasAttr(buzz::QN_TO));
+    EXPECT_FALSE(elem->HasAttr(buzz::QN_FROM));
+    EXPECT_TRUE(elem->HasAttr(buzz::QN_TYPE));
+    EXPECT_TRUE((elem->Attr(buzz::QN_TYPE) == "set") ||
+                (elem->Attr(buzz::QN_TYPE) == "result") ||
+                (elem->Attr(buzz::QN_TYPE) == "error"));
+
+    elem->SetAttr(buzz::QN_FROM, local_name);
+    if (elem->Attr(buzz::QN_TYPE) == "set") {
+      EXPECT_FALSE(elem->HasAttr(buzz::QN_ID));
+      elem->SetAttr(buzz::QN_ID, GetNextOutgoingMessageID());
+    }
+
+    // Uncommenting this is useful for debugging.
+    // PrintStanza("OutgoingMessage", elem);
+    sent_stanzas.push_back(elem);
+  }
+
+  std::string GetNextOutgoingMessageID() {
+    int message_id = (*next_message_id)++;
+    std::ostringstream ost;
+    ost << message_id;
+    return ost.str();
+  }
+
+  void CreateChannels() {
+    ASSERT(session != NULL);
+    // We either have a single content with multiple components (RTP/RTCP), or
+    // multiple contents with single components, but not both.
+    int component_a = 1;
+    int component_b = (content_name_a == content_name_b) ? 2 : 1;
+    chan_a.reset(new ChannelHandler(
+        session->CreateChannel(content_name_a, channel_name_a, component_a),
+        channel_name_a));
+    chan_b.reset(new ChannelHandler(
+        session->CreateChannel(content_name_b, channel_name_b, component_b),
+        channel_name_b));
+  }
+
+  int* next_message_id;
+  std::string local_name;
+  SignalingProtocol start_protocol;
+  std::string content_type;
+  std::string content_name_a;
+  std::string channel_name_a;
+  std::string content_name_b;
+  std::string channel_name_b;
+
+  uint32 session_created_count;
+  uint32 session_destroyed_count;
+  uint32 session_remote_description_update_count;
+  bool new_local_description;
+  bool new_remote_description;
+  cricket::ContentAction last_content_action;
+  cricket::ContentSource last_content_source;
+  std::deque<buzz::XmlElement*> sent_stanzas;
+  rtc::scoped_ptr<buzz::XmlElement> last_expected_sent_stanza;
+
+  cricket::SessionManager* session_manager;
+  TestSessionClient* client;
+  cricket::PortAllocator* port_allocator_;
+  cricket::Session* session;
+  cricket::BaseSession::State last_session_state;
+  rtc::scoped_ptr<ChannelHandler> chan_a;
+  rtc::scoped_ptr<ChannelHandler> chan_b;
+  bool blow_up_on_error;
+  int error_count;
+};
+
+class SessionTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Seed needed for each test to satisfy expectations.
+    rtc::SetRandomTestMode(true);
+  }
+
+  virtual void TearDown() {
+    rtc::SetRandomTestMode(false);
+  }
+
+  // Tests sending data between two clients, over two channels.
+  void TestSendRecv(ChannelHandler* chan1a,
+                    ChannelHandler* chan1b,
+                    ChannelHandler* chan2a,
+                    ChannelHandler* chan2b) {
+    const char* dat1a = "spamspamspamspamspamspamspambakedbeansspam";
+    const char* dat2a = "mapssnaebdekabmapsmapsmapsmapsmapsmapsmaps";
+    const char* dat1b = "Lobster Thermidor a Crevette with a mornay sauce...";
+    const char* dat2b = "...ecuas yanrom a htiw etteverC a rodimrehT retsboL";
+
+    for (int i = 0; i < 20; i++) {
+      chan1a->Send(dat1a, strlen(dat1a));
+      chan1b->Send(dat1b, strlen(dat1b));
+      chan2a->Send(dat2a, strlen(dat2a));
+      chan2b->Send(dat2b, strlen(dat2b));
+
+      EXPECT_EQ_WAIT(i + 1, chan1a->data_count, kEventTimeout);
+      EXPECT_EQ_WAIT(i + 1, chan1b->data_count, kEventTimeout);
+      EXPECT_EQ_WAIT(i + 1, chan2a->data_count, kEventTimeout);
+      EXPECT_EQ_WAIT(i + 1, chan2b->data_count, kEventTimeout);
+
+      EXPECT_EQ(strlen(dat2a), chan1a->last_size);
+      EXPECT_EQ(strlen(dat2b), chan1b->last_size);
+      EXPECT_EQ(strlen(dat1a), chan2a->last_size);
+      EXPECT_EQ(strlen(dat1b), chan2b->last_size);
+
+      EXPECT_EQ(0, memcmp(chan1a->last_data, dat2a, strlen(dat2a)));
+      EXPECT_EQ(0, memcmp(chan1b->last_data, dat2b, strlen(dat2b)));
+      EXPECT_EQ(0, memcmp(chan2a->last_data, dat1a, strlen(dat1a)));
+      EXPECT_EQ(0, memcmp(chan2b->last_data, dat1b, strlen(dat1b)));
+    }
+  }
+
+  // Test an initiate from one client to another, each with
+  // independent initial protocols.  Checks for the correct initiates,
+  // candidates, and accept messages, and tests that working network
+  // channels are established.
+  void TestSession(SignalingProtocol initiator_protocol,
+                   SignalingProtocol responder_protocol,
+                   SignalingProtocol resulting_protocol,
+                   const std::string& gingle_content_type,
+                   const std::string& content_type,
+                   const std::string& content_name_a,
+                   const std::string& channel_name_a,
+                   const std::string& content_name_b,
+                   const std::string& channel_name_b,
+                   const std::string& initiate_xml,
+                   const std::string& transport_info_a_xml,
+                   const std::string& transport_info_b_xml,
+                   const std::string& transport_info_reply_a_xml,
+                   const std::string& transport_info_reply_b_xml,
+                   const std::string& accept_xml,
+                   bool bundle = false) {
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, initiator_protocol,
+                       content_type,
+                       content_name_a,  channel_name_a,
+                       content_name_b,  channel_name_b));
+    rtc::scoped_ptr<TestClient> responder(
+        new TestClient(allocator.get(), &next_message_id,
+                       kResponder, responder_protocol,
+                       content_type,
+                       content_name_a,  channel_name_a,
+                       content_name_b,  channel_name_b));
+
+    // Create Session and check channels and state.
+    initiator->CreateSession();
+    EXPECT_EQ(1U, initiator->session_created_count);
+    EXPECT_EQ(kSessionId, initiator->session->id());
+    EXPECT_EQ(initiator->session->local_name(), kInitiator);
+    EXPECT_EQ(cricket::BaseSession::STATE_INIT,
+              initiator->session_state());
+
+    // See comment in CreateChannels about how we choose component IDs.
+    int component_a = 1;
+    int component_b = (content_name_a == content_name_b) ? 2 : 1;
+    EXPECT_TRUE(initiator->HasTransport(content_name_a));
+    EXPECT_TRUE(initiator->HasChannel(content_name_a, component_a));
+    EXPECT_TRUE(initiator->HasTransport(content_name_b));
+    EXPECT_TRUE(initiator->HasChannel(content_name_b, component_b));
+
+    // Initiate and expect initiate message sent.
+    cricket::SessionDescription* offer = NewTestSessionDescription(
+        gingle_content_type,
+        content_name_a, content_type,
+        content_name_b, content_type);
+    if (bundle) {
+      cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
+      group.AddContentName(content_name_a);
+      group.AddContentName(content_name_b);
+      EXPECT_TRUE(group.HasContentName(content_name_a));
+      EXPECT_TRUE(group.HasContentName(content_name_b));
+      offer->AddGroup(group);
+    }
+    EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
+    EXPECT_EQ(initiator->session->remote_name(), kResponder);
+    EXPECT_EQ(initiator->session->local_description(), offer);
+
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
+              initiator->session_state());
+
+    initiator->ExpectSentStanza(
+        IqSet("0", kInitiator, kResponder, initiate_xml));
+
+    // Deliver the initiate. Expect ack and session created with
+    // transports.
+    responder->DeliverStanza(initiator->stanza());
+    responder->ExpectSentStanza(
+        IqAck("0", kResponder, kInitiator));
+    EXPECT_EQ(0U, responder->sent_stanza_count());
+
+    EXPECT_EQ(1U, responder->session_created_count);
+    EXPECT_EQ(kSessionId, responder->session->id());
+    EXPECT_EQ(responder->session->local_name(), kResponder);
+    EXPECT_EQ(responder->session->remote_name(), kInitiator);
+    EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
+              responder->session_state());
+
+    EXPECT_TRUE(responder->HasTransport(content_name_a));
+    EXPECT_TRUE(responder->HasChannel(content_name_a, component_a));
+    EXPECT_TRUE(responder->HasTransport(content_name_b));
+    EXPECT_TRUE(responder->HasChannel(content_name_b, component_b));
+
+    // Expect transport-info message from initiator.
+    // But don't send candidates until initiate ack is received.
+    initiator->PrepareCandidates();
+    WAIT(initiator->sent_stanza_count() > 0, 100);
+    EXPECT_EQ(0U, initiator->sent_stanza_count());
+    initiator->DeliverAckToLastStanza();
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqSet("1", kInitiator, kResponder, transport_info_a_xml));
+
+    // Deliver transport-info and expect ack.
+    responder->DeliverStanza(initiator->stanza());
+    responder->ExpectSentStanza(
+        IqAck("1", kResponder, kInitiator));
+
+    if (!transport_info_b_xml.empty()) {
+      // Expect second transport-info message from initiator.
+      EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+      initiator->ExpectSentStanza(
+          IqSet("2", kInitiator, kResponder, transport_info_b_xml));
+      EXPECT_EQ(0U, initiator->sent_stanza_count());
+
+      // Deliver second transport-info message and expect ack.
+      responder->DeliverStanza(initiator->stanza());
+      responder->ExpectSentStanza(
+          IqAck("2", kResponder, kInitiator));
+    } else {
+      EXPECT_EQ(0U, initiator->sent_stanza_count());
+      EXPECT_EQ(0U, responder->sent_stanza_count());
+      initiator->SkipUnsentStanza();
+    }
+
+    // Expect reply transport-info message from responder.
+    responder->PrepareCandidates();
+    EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
+    responder->ExpectSentStanza(
+        IqSet("3", kResponder, kInitiator, transport_info_reply_a_xml));
+
+    // Deliver reply transport-info and expect ack.
+    initiator->DeliverStanza(responder->stanza());
+    initiator->ExpectSentStanza(
+        IqAck("3", kInitiator, kResponder));
+
+    if (!transport_info_reply_b_xml.empty()) {
+      // Expect second reply transport-info message from responder.
+      EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
+      responder->ExpectSentStanza(
+          IqSet("4", kResponder, kInitiator, transport_info_reply_b_xml));
+      EXPECT_EQ(0U, responder->sent_stanza_count());
+
+      // Deliver second reply transport-info message and expect ack.
+      initiator->DeliverStanza(responder->stanza());
+      initiator->ExpectSentStanza(
+          IqAck("4", kInitiator, kResponder));
+      EXPECT_EQ(0U, initiator->sent_stanza_count());
+    } else {
+      EXPECT_EQ(0U, initiator->sent_stanza_count());
+      EXPECT_EQ(0U, responder->sent_stanza_count());
+      responder->SkipUnsentStanza();
+    }
+
+    // The channels should be able to become writable at this point.  This
+    // requires pinging, so it may take a little while.
+    EXPECT_TRUE_WAIT(initiator->chan_a->writable() &&
+                     initiator->chan_a->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(initiator->chan_b->writable() &&
+                     initiator->chan_b->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(responder->chan_a->writable() &&
+                     responder->chan_a->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(responder->chan_b->writable() &&
+                     responder->chan_b->readable(), kEventTimeout);
+
+    // Accept the session and expect accept stanza.
+    cricket::SessionDescription* answer = NewTestSessionDescription(
+        gingle_content_type,
+        content_name_a, content_type,
+        content_name_b, content_type);
+    if (bundle) {
+      cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
+      group.AddContentName(content_name_a);
+      group.AddContentName(content_name_b);
+      EXPECT_TRUE(group.HasContentName(content_name_a));
+      EXPECT_TRUE(group.HasContentName(content_name_b));
+      answer->AddGroup(group);
+    }
+    EXPECT_TRUE(responder->session->Accept(answer));
+    EXPECT_EQ(responder->session->local_description(), answer);
+
+    responder->ExpectSentStanza(
+        IqSet("5", kResponder, kInitiator, accept_xml));
+
+    EXPECT_EQ(0U, responder->sent_stanza_count());
+
+    // Deliver the accept message and expect an ack.
+    initiator->DeliverStanza(responder->stanza());
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqAck("5", kInitiator, kResponder));
+    EXPECT_EQ(0U, initiator->sent_stanza_count());
+
+    // Both sessions should be in progress and have functioning
+    // channels.
+    EXPECT_EQ(resulting_protocol, initiator->session->current_protocol());
+    EXPECT_EQ(resulting_protocol, responder->session->current_protocol());
+    EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
+                   initiator->session_state(), kEventTimeout);
+    EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
+                   responder->session_state(), kEventTimeout);
+    if (bundle) {
+      cricket::TransportChannel* initiator_chan_a = initiator->chan_a->channel;
+      cricket::TransportChannel* initiator_chan_b = initiator->chan_b->channel;
+
+      // Since we know these are TransportChannelProxy, type cast it.
+      cricket::TransportChannelProxy* initiator_proxy_chan_a =
+          static_cast<cricket::TransportChannelProxy*>(initiator_chan_a);
+      cricket::TransportChannelProxy* initiator_proxy_chan_b =
+              static_cast<cricket::TransportChannelProxy*>(initiator_chan_b);
+      EXPECT_TRUE(initiator_proxy_chan_a->impl() != NULL);
+      EXPECT_TRUE(initiator_proxy_chan_b->impl() != NULL);
+      EXPECT_EQ(initiator_proxy_chan_a->impl(), initiator_proxy_chan_b->impl());
+
+      cricket::TransportChannel* responder_chan_a = responder->chan_a->channel;
+      cricket::TransportChannel* responder_chan_b = responder->chan_b->channel;
+
+      // Since we know these are TransportChannelProxy, type cast it.
+      cricket::TransportChannelProxy* responder_proxy_chan_a =
+          static_cast<cricket::TransportChannelProxy*>(responder_chan_a);
+      cricket::TransportChannelProxy* responder_proxy_chan_b =
+              static_cast<cricket::TransportChannelProxy*>(responder_chan_b);
+      EXPECT_TRUE(responder_proxy_chan_a->impl() != NULL);
+      EXPECT_TRUE(responder_proxy_chan_b->impl() != NULL);
+      EXPECT_EQ(responder_proxy_chan_a->impl(), responder_proxy_chan_b->impl());
+    }
+    TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
+                 responder->chan_a.get(), responder->chan_b.get());
+
+    if (resulting_protocol == PROTOCOL_JINGLE) {
+      // Deliver a description-info message to the initiator and check if the
+      // content description changes.
+      EXPECT_EQ(0U, initiator->session_remote_description_update_count);
+
+      const cricket::SessionDescription* old_session_desc =
+          initiator->session->remote_description();
+      const cricket::ContentInfo* old_content_a =
+          old_session_desc->GetContentByName(content_name_a);
+      const cricket::ContentDescription* old_content_desc_a =
+          old_content_a->description;
+      const cricket::ContentInfo* old_content_b =
+          old_session_desc->GetContentByName(content_name_b);
+      const cricket::ContentDescription* old_content_desc_b =
+          old_content_b->description;
+      EXPECT_TRUE(old_content_desc_a != NULL);
+      EXPECT_TRUE(old_content_desc_b != NULL);
+
+      LOG(LS_INFO) << "A " << old_content_a->name;
+      LOG(LS_INFO) << "B " << old_content_b->name;
+
+      std::string description_info_xml =
+          JingleDescriptionInfoXml(content_name_a, content_type);
+      initiator->DeliverStanza(
+          IqSet("6", kResponder, kInitiator, description_info_xml));
+      responder->SkipUnsentStanza();
+      EXPECT_EQ(1U, initiator->session_remote_description_update_count);
+
+      const cricket::SessionDescription* new_session_desc =
+          initiator->session->remote_description();
+      const cricket::ContentInfo* new_content_a =
+          new_session_desc->GetContentByName(content_name_a);
+      const cricket::ContentDescription* new_content_desc_a =
+          new_content_a->description;
+      const cricket::ContentInfo* new_content_b =
+          new_session_desc->GetContentByName(content_name_b);
+      const cricket::ContentDescription* new_content_desc_b =
+          new_content_b->description;
+      EXPECT_TRUE(new_content_desc_a != NULL);
+      EXPECT_TRUE(new_content_desc_b != NULL);
+
+      // TODO: We used to replace contents from an update, but
+      // that no longer works with partial updates.  We need to figure out
+      // a way to merge patial updates into contents.  For now, users of
+      // Session should listen to SignalRemoteDescriptionUpdate and handle
+      // updates.  They should not expect remote_description to be the
+      // latest value.
+      // See session.cc OnDescriptionInfoMessage.
+
+      // EXPECT_NE(old_content_desc_a, new_content_desc_a);
+
+      // if (content_name_a != content_name_b) {
+      //   // If content_name_a != content_name_b, then b's content description
+      //   // should not have changed since the description-info message only
+      //   // contained an update for content_name_a.
+      //   EXPECT_EQ(old_content_desc_b, new_content_desc_b);
+      // }
+
+      EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+      initiator->ExpectSentStanza(
+          IqAck("6", kInitiator, kResponder));
+      EXPECT_EQ(0U, initiator->sent_stanza_count());
+    } else {
+      responder->SkipUnsentStanza();
+    }
+
+    initiator->session->Terminate();
+    initiator->ExpectSentStanza(
+        IqSet("7", kInitiator, kResponder,
+              TerminateXml(resulting_protocol,
+                           cricket::STR_TERMINATE_SUCCESS)));
+
+    responder->DeliverStanza(initiator->stanza());
+    responder->ExpectSentStanza(
+        IqAck("7", kResponder, kInitiator));
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE,
+              initiator->session_state());
+    EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE,
+              responder->session_state());
+  }
+
+  // Test an initiate with other content, called "main".
+  void TestOtherContent(SignalingProtocol initiator_protocol,
+                        SignalingProtocol responder_protocol,
+                        SignalingProtocol resulting_protocol) {
+    std::string content_name = "main";
+    std::string content_type = "http://oink.splat/session";
+    std::string content_name_a = content_name;
+    std::string channel_name_a = "rtp";
+    std::string content_name_b = content_name;
+    std::string channel_name_b = "rtcp";
+    std::string initiate_xml = InitiateXml(
+        initiator_protocol,
+        content_name_a, content_type);
+    std::string transport_info_a_xml = TransportInfo4Xml(
+        initiator_protocol, content_name,
+        channel_name_a, 0, 1,
+        channel_name_b, 2, 3);
+    std::string transport_info_b_xml = "";
+    std::string transport_info_reply_a_xml = TransportInfo4Xml(
+        resulting_protocol, content_name,
+        channel_name_a, 4, 5,
+        channel_name_b, 6, 7);
+    std::string transport_info_reply_b_xml = "";
+    std::string accept_xml = AcceptXml(
+        resulting_protocol,
+        content_name_a, content_type);
+
+
+    TestSession(initiator_protocol, responder_protocol, resulting_protocol,
+                content_type,
+                content_type,
+                content_name_a, channel_name_a,
+                content_name_b, channel_name_b,
+                initiate_xml,
+                transport_info_a_xml, transport_info_b_xml,
+                transport_info_reply_a_xml, transport_info_reply_b_xml,
+                accept_xml);
+  }
+
+  // Test an initiate with audio content.
+  void TestAudioContent(SignalingProtocol initiator_protocol,
+                        SignalingProtocol responder_protocol,
+                        SignalingProtocol resulting_protocol) {
+    std::string gingle_content_type = cricket::NS_GINGLE_AUDIO;
+    std::string content_name = cricket::CN_AUDIO;
+    std::string content_type = cricket::NS_JINGLE_RTP;
+    std::string channel_name_a = "rtp";
+    std::string channel_name_b = "rtcp";
+    std::string initiate_xml = InitiateXml(
+        initiator_protocol,
+        gingle_content_type,
+        content_name, content_type,
+        "", "");
+    std::string transport_info_a_xml = TransportInfo4Xml(
+        initiator_protocol, content_name,
+        channel_name_a, 0, 1,
+        channel_name_b, 2, 3);
+    std::string transport_info_b_xml = "";
+    std::string transport_info_reply_a_xml = TransportInfo4Xml(
+        resulting_protocol, content_name,
+        channel_name_a, 4, 5,
+        channel_name_b, 6, 7);
+    std::string transport_info_reply_b_xml = "";
+    std::string accept_xml = AcceptXml(
+        resulting_protocol,
+        gingle_content_type,
+        content_name, content_type,
+        "", "");
+
+
+    TestSession(initiator_protocol, responder_protocol, resulting_protocol,
+                gingle_content_type,
+                content_type,
+                content_name, channel_name_a,
+                content_name, channel_name_b,
+                initiate_xml,
+                transport_info_a_xml, transport_info_b_xml,
+                transport_info_reply_a_xml, transport_info_reply_b_xml,
+                accept_xml);
+  }
+
+  // Since media content is "split" into two contents (audio and
+  // video), we need to treat it special.
+  void TestVideoContents(SignalingProtocol initiator_protocol,
+                         SignalingProtocol responder_protocol,
+                         SignalingProtocol resulting_protocol) {
+    std::string content_type = cricket::NS_JINGLE_RTP;
+    std::string gingle_content_type = cricket::NS_GINGLE_VIDEO;
+    std::string content_name_a = cricket::CN_AUDIO;
+    std::string channel_name_a = "rtp";
+    std::string content_name_b = cricket::CN_VIDEO;
+    std::string channel_name_b = "video_rtp";
+
+    std::string initiate_xml = InitiateXml(
+        initiator_protocol,
+        gingle_content_type,
+        content_name_a, content_type,
+        content_name_b, content_type);
+    std::string transport_info_a_xml = TransportInfo2Xml(
+        initiator_protocol, content_name_a,
+        channel_name_a, 0, 1);
+    std::string transport_info_b_xml = TransportInfo2Xml(
+        initiator_protocol, content_name_b,
+        channel_name_b, 2, 3);
+    std::string transport_info_reply_a_xml = TransportInfo2Xml(
+        resulting_protocol, content_name_a,
+        channel_name_a, 4, 5);
+    std::string transport_info_reply_b_xml = TransportInfo2Xml(
+        resulting_protocol, content_name_b,
+        channel_name_b, 6, 7);
+    std::string accept_xml = AcceptXml(
+        resulting_protocol,
+        gingle_content_type,
+        content_name_a, content_type,
+        content_name_b, content_type);
+
+    TestSession(initiator_protocol, responder_protocol, resulting_protocol,
+                gingle_content_type,
+                content_type,
+                content_name_a, channel_name_a,
+                content_name_b, channel_name_b,
+                initiate_xml,
+                transport_info_a_xml, transport_info_b_xml,
+                transport_info_reply_a_xml, transport_info_reply_b_xml,
+                accept_xml);
+  }
+
+  void TestBadRedirect(SignalingProtocol protocol) {
+    std::string content_name = "main";
+    std::string content_type = "http://oink.splat/session";
+    std::string channel_name_a = "chana";
+    std::string channel_name_b = "chanb";
+    std::string initiate_xml = InitiateXml(
+        protocol, content_name, content_type);
+    std::string transport_info_xml = TransportInfo4Xml(
+        protocol, content_name,
+        channel_name_a, 0, 1,
+        channel_name_b, 2, 3);
+    std::string transport_info_reply_xml = TransportInfo4Xml(
+        protocol, content_name,
+        channel_name_a, 4, 5,
+        channel_name_b, 6, 7);
+    std::string accept_xml = AcceptXml(
+        protocol, content_name, content_type);
+    std::string responder_full = kResponder + "/full";
+
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, protocol,
+                       content_type,
+                       content_name, channel_name_a,
+                       content_name, channel_name_b));
+
+    rtc::scoped_ptr<TestClient> responder(
+        new TestClient(allocator.get(), &next_message_id,
+                       responder_full, protocol,
+                       content_type,
+                       content_name,  channel_name_a,
+                       content_name,  channel_name_b));
+
+    // Create Session and check channels and state.
+    initiator->CreateSession();
+    EXPECT_EQ(1U, initiator->session_created_count);
+    EXPECT_EQ(kSessionId, initiator->session->id());
+    EXPECT_EQ(initiator->session->local_name(), kInitiator);
+    EXPECT_EQ(cricket::BaseSession::STATE_INIT,
+              initiator->session_state());
+
+    EXPECT_TRUE(initiator->HasChannel(content_name, 1));
+    EXPECT_TRUE(initiator->HasChannel(content_name, 2));
+
+    // Initiate and expect initiate message sent.
+    cricket::SessionDescription* offer = NewTestSessionDescription(
+        content_name, content_type);
+    EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
+    EXPECT_EQ(initiator->session->remote_name(), kResponder);
+    EXPECT_EQ(initiator->session->local_description(), offer);
+
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
+              initiator->session_state());
+    initiator->ExpectSentStanza(
+        IqSet("0", kInitiator, kResponder, initiate_xml));
+
+    // Expect transport-info message from initiator.
+    initiator->DeliverAckToLastStanza();
+    initiator->PrepareCandidates();
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqSet("1", kInitiator, kResponder, transport_info_xml));
+
+    // Send an unauthorized redirect to the initiator and expect it be ignored.
+    initiator->blow_up_on_error = false;
+    const buzz::XmlElement* initiate_stanza = initiator->stanza();
+    rtc::scoped_ptr<buzz::XmlElement> redirect_stanza(
+        buzz::XmlElement::ForStr(
+            IqError("ER", kResponder, kInitiator,
+                    RedirectXml(protocol, initiate_xml, "not@allowed.com"))));
+    initiator->session_manager->OnFailedSend(
+        initiate_stanza, redirect_stanza.get());
+    EXPECT_EQ(initiator->session->remote_name(), kResponder);
+    initiator->blow_up_on_error = true;
+    EXPECT_EQ(initiator->error_count, 1);
+  }
+
+  void TestGoodRedirect(SignalingProtocol protocol) {
+    std::string content_name = "main";
+    std::string content_type = "http://oink.splat/session";
+    std::string channel_name_a = "chana";
+    std::string channel_name_b = "chanb";
+    std::string initiate_xml = InitiateXml(
+        protocol, content_name, content_type);
+    std::string transport_info_xml = TransportInfo4Xml(
+        protocol, content_name,
+        channel_name_a, 0, 1,
+        channel_name_b, 2, 3);
+    std::string transport_info_reply_xml = TransportInfo4Xml(
+        protocol, content_name,
+        channel_name_a, 4, 5,
+        channel_name_b, 6, 7);
+    std::string accept_xml = AcceptXml(
+        protocol, content_name, content_type);
+    std::string responder_full = kResponder + "/full";
+
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, protocol,
+                       content_type,
+                       content_name, channel_name_a,
+                       content_name, channel_name_b));
+
+    rtc::scoped_ptr<TestClient> responder(
+        new TestClient(allocator.get(), &next_message_id,
+                       responder_full, protocol,
+                       content_type,
+                       content_name,  channel_name_a,
+                       content_name,  channel_name_b));
+
+    // Create Session and check channels and state.
+    initiator->CreateSession();
+    EXPECT_EQ(1U, initiator->session_created_count);
+    EXPECT_EQ(kSessionId, initiator->session->id());
+    EXPECT_EQ(initiator->session->local_name(), kInitiator);
+    EXPECT_EQ(cricket::BaseSession::STATE_INIT,
+              initiator->session_state());
+
+    EXPECT_TRUE(initiator->HasChannel(content_name, 1));
+    EXPECT_TRUE(initiator->HasChannel(content_name, 2));
+
+    // Initiate and expect initiate message sent.
+    cricket::SessionDescription* offer = NewTestSessionDescription(
+        content_name, content_type);
+    EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
+    EXPECT_EQ(initiator->session->remote_name(), kResponder);
+    EXPECT_EQ(initiator->session->local_description(), offer);
+
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
+              initiator->session_state());
+    initiator->ExpectSentStanza(
+        IqSet("0", kInitiator, kResponder, initiate_xml));
+
+    // Expect transport-info message from initiator.
+    initiator->DeliverAckToLastStanza();
+    initiator->PrepareCandidates();
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqSet("1", kInitiator, kResponder, transport_info_xml));
+
+    // Send a redirect to the initiator and expect all of the message
+    // to be resent.
+    const buzz::XmlElement* initiate_stanza = initiator->stanza();
+    rtc::scoped_ptr<buzz::XmlElement> redirect_stanza(
+        buzz::XmlElement::ForStr(
+            IqError("ER2", kResponder, kInitiator,
+                    RedirectXml(protocol, initiate_xml, responder_full))));
+    initiator->session_manager->OnFailedSend(
+        initiate_stanza, redirect_stanza.get());
+    EXPECT_EQ(initiator->session->remote_name(), responder_full);
+
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqSet("2", kInitiator, responder_full, initiate_xml));
+    initiator->ExpectSentStanza(
+        IqSet("3", kInitiator, responder_full, transport_info_xml));
+
+    // Deliver the initiate. Expect ack and session created with
+    // transports.
+    responder->DeliverStanza(
+        IqSet("2", kInitiator, responder_full, initiate_xml));
+    responder->ExpectSentStanza(
+        IqAck("2", responder_full, kInitiator));
+    EXPECT_EQ(0U, responder->sent_stanza_count());
+
+    EXPECT_EQ(1U, responder->session_created_count);
+    EXPECT_EQ(kSessionId, responder->session->id());
+    EXPECT_EQ(responder->session->local_name(), responder_full);
+    EXPECT_EQ(responder->session->remote_name(), kInitiator);
+    EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
+              responder->session_state());
+
+    EXPECT_TRUE(responder->HasChannel(content_name, 1));
+    EXPECT_TRUE(responder->HasChannel(content_name, 2));
+
+    // Deliver transport-info and expect ack.
+    responder->DeliverStanza(
+        IqSet("3", kInitiator, responder_full, transport_info_xml));
+    responder->ExpectSentStanza(
+        IqAck("3", responder_full, kInitiator));
+
+    // Expect reply transport-infos sent to new remote JID
+    responder->PrepareCandidates();
+    EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
+    responder->ExpectSentStanza(
+        IqSet("4", responder_full, kInitiator, transport_info_reply_xml));
+
+    initiator->DeliverStanza(responder->stanza());
+    initiator->ExpectSentStanza(
+        IqAck("4", kInitiator, responder_full));
+
+    // The channels should be able to become writable at this point.  This
+    // requires pinging, so it may take a little while.
+    EXPECT_TRUE_WAIT(initiator->chan_a->writable() &&
+                     initiator->chan_a->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(initiator->chan_b->writable() &&
+                     initiator->chan_b->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(responder->chan_a->writable() &&
+                     responder->chan_a->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(responder->chan_b->writable() &&
+                     responder->chan_b->readable(), kEventTimeout);
+
+    // Accept the session and expect accept stanza.
+    cricket::SessionDescription* answer = NewTestSessionDescription(
+        content_name, content_type);
+    EXPECT_TRUE(responder->session->Accept(answer));
+    EXPECT_EQ(responder->session->local_description(), answer);
+
+    responder->ExpectSentStanza(
+        IqSet("5", responder_full, kInitiator, accept_xml));
+    EXPECT_EQ(0U, responder->sent_stanza_count());
+
+    // Deliver the accept message and expect an ack.
+    initiator->DeliverStanza(responder->stanza());
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqAck("5", kInitiator, responder_full));
+    EXPECT_EQ(0U, initiator->sent_stanza_count());
+
+    // Both sessions should be in progress and have functioning
+    // channels.
+    EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
+                   initiator->session_state(), kEventTimeout);
+    EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
+                   responder->session_state(), kEventTimeout);
+    TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
+                 responder->chan_a.get(), responder->chan_b.get());
+  }
+
+  void TestCandidatesInInitiateAndAccept(const std::string& test_name) {
+    std::string content_name = "main";
+    std::string content_type = "http://oink.splat/session";
+    std::string channel_name_a = "rtp";
+    std::string channel_name_b = "rtcp";
+    cricket::SignalingProtocol protocol = PROTOCOL_JINGLE;
+
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, protocol,
+                       content_type,
+                       content_name,  channel_name_a,
+                       content_name,  channel_name_b));
+
+    rtc::scoped_ptr<TestClient> responder(
+        new TestClient(allocator.get(), &next_message_id,
+                       kResponder, protocol,
+                       content_type,
+                       content_name,  channel_name_a,
+                       content_name,  channel_name_b));
+
+    // Create Session and check channels and state.
+    initiator->CreateSession();
+    EXPECT_TRUE(initiator->HasTransport(content_name));
+    EXPECT_TRUE(initiator->HasChannel(content_name, 1));
+    EXPECT_TRUE(initiator->HasTransport(content_name));
+    EXPECT_TRUE(initiator->HasChannel(content_name, 2));
+
+    // Initiate and expect initiate message sent.
+    cricket::SessionDescription* offer = NewTestSessionDescription(
+        content_name, content_type);
+    EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
+
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
+              initiator->session_state());
+    initiator->ExpectSentStanza(
+        IqSet("0", kInitiator, kResponder,
+              InitiateXml(protocol, content_name, content_type)));
+
+    // Fake the delivery the initiate and candidates together.
+    responder->DeliverStanza(
+        IqSet("A", kInitiator, kResponder,
+            JingleInitiateActionXml(
+                JingleContentXml(
+                    content_name, content_type, kTransportType,
+                    P2pCandidateXml(channel_name_a, 0) +
+                    P2pCandidateXml(channel_name_a, 1) +
+                    P2pCandidateXml(channel_name_b, 2) +
+                    P2pCandidateXml(channel_name_b, 3)))));
+    responder->ExpectSentStanza(
+        IqAck("A", kResponder, kInitiator));
+    EXPECT_EQ(0U, responder->sent_stanza_count());
+
+    EXPECT_EQ(1U, responder->session_created_count);
+    EXPECT_EQ(kSessionId, responder->session->id());
+    EXPECT_EQ(responder->session->local_name(), kResponder);
+    EXPECT_EQ(responder->session->remote_name(), kInitiator);
+    EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
+              responder->session_state());
+
+    EXPECT_TRUE(responder->HasTransport(content_name));
+    EXPECT_TRUE(responder->HasChannel(content_name, 1));
+    EXPECT_TRUE(responder->HasTransport(content_name));
+    EXPECT_TRUE(responder->HasChannel(content_name, 2));
+
+    // Expect transport-info message from initiator.
+    // But don't send candidates until initiate ack is received.
+    initiator->DeliverAckToLastStanza();
+    initiator->PrepareCandidates();
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqSet("1", kInitiator, kResponder,
+              TransportInfo4Xml(protocol, content_name,
+                                channel_name_a, 0, 1,
+                                channel_name_b, 2, 3)));
+
+    responder->PrepareCandidates();
+    EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
+    responder->ExpectSentStanza(
+        IqSet("2", kResponder, kInitiator,
+              TransportInfo4Xml(protocol, content_name,
+                                channel_name_a, 4, 5,
+                                channel_name_b, 6, 7)));
+
+    // Accept the session and expect accept stanza.
+    cricket::SessionDescription* answer = NewTestSessionDescription(
+        content_name, content_type);
+    EXPECT_TRUE(responder->session->Accept(answer));
+
+    responder->ExpectSentStanza(
+        IqSet("3", kResponder, kInitiator,
+              AcceptXml(protocol, content_name, content_type)));
+    EXPECT_EQ(0U, responder->sent_stanza_count());
+
+    // Fake the delivery the accept and candidates together.
+    initiator->DeliverStanza(
+        IqSet("B", kResponder, kInitiator,
+            JingleActionXml("session-accept",
+                JingleContentXml(
+                    content_name, content_type, kTransportType,
+                    P2pCandidateXml(channel_name_a, 4) +
+                    P2pCandidateXml(channel_name_a, 5) +
+                    P2pCandidateXml(channel_name_b, 6) +
+                    P2pCandidateXml(channel_name_b, 7)))));
+    EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
+    initiator->ExpectSentStanza(
+        IqAck("B", kInitiator, kResponder));
+    EXPECT_EQ(0U, initiator->sent_stanza_count());
+
+    // The channels should be able to become writable at this point.  This
+    // requires pinging, so it may take a little while.
+    EXPECT_TRUE_WAIT(initiator->chan_a->writable() &&
+                     initiator->chan_a->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(initiator->chan_b->writable() &&
+                     initiator->chan_b->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(responder->chan_a->writable() &&
+                     responder->chan_a->readable(), kEventTimeout);
+    EXPECT_TRUE_WAIT(responder->chan_b->writable() &&
+                     responder->chan_b->readable(), kEventTimeout);
+
+
+    // Both sessions should be in progress and have functioning
+    // channels.
+    EXPECT_EQ(protocol, initiator->session->current_protocol());
+    EXPECT_EQ(protocol, responder->session->current_protocol());
+    EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
+                   initiator->session_state(), kEventTimeout);
+    EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
+                   responder->session_state(), kEventTimeout);
+    TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
+                 responder->chan_a.get(), responder->chan_b.get());
+  }
+
+  // Tests that when an initiator terminates right after initiate,
+  // everything behaves correctly.
+  void TestEarlyTerminationFromInitiator(SignalingProtocol protocol) {
+    std::string content_name = "main";
+    std::string content_type = "http://oink.splat/session";
+
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, protocol,
+                       content_type,
+                       content_name, "a",
+                       content_name, "b"));
+
+    rtc::scoped_ptr<TestClient> responder(
+        new TestClient(allocator.get(), &next_message_id,
+                       kResponder, protocol,
+                       content_type,
+                       content_name,  "a",
+                       content_name,  "b"));
+
+    // Send initiate
+    initiator->CreateSession();
+    EXPECT_TRUE(initiator->session->Initiate(
+        kResponder, NewTestSessionDescription(content_name, content_type)));
+    initiator->ExpectSentStanza(
+        IqSet("0", kInitiator, kResponder,
+              InitiateXml(protocol, content_name, content_type)));
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
+              initiator->session_state());
+
+    responder->DeliverStanza(initiator->stanza());
+    responder->ExpectSentStanza(
+        IqAck("0", kResponder, kInitiator));
+    EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
+              responder->session_state());
+
+    initiator->session->TerminateWithReason(cricket::STR_TERMINATE_ERROR);
+    initiator->ExpectSentStanza(
+        IqSet("1", kInitiator, kResponder,
+              TerminateXml(protocol, cricket::STR_TERMINATE_ERROR)));
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE,
+              initiator->session_state());
+
+    responder->DeliverStanza(initiator->stanza());
+    responder->ExpectSentStanza(
+        IqAck("1", kResponder, kInitiator));
+    EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE,
+              responder->session_state());
+  }
+
+  // Tests that when the responder rejects, everything behaves
+  // correctly.
+  void TestRejection(SignalingProtocol protocol) {
+    std::string content_name = "main";
+    std::string content_type = "http://oink.splat/session";
+
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, protocol,
+                       content_type,
+                       content_name, "a",
+                       content_name, "b"));
+
+    // Send initiate
+    initiator->CreateSession();
+    EXPECT_TRUE(initiator->session->Initiate(
+        kResponder, NewTestSessionDescription(content_name, content_type)));
+    initiator->ExpectSentStanza(
+        IqSet("0", kInitiator, kResponder,
+              InitiateXml(protocol, content_name, content_type)));
+    EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
+              initiator->session_state());
+
+    initiator->DeliverStanza(
+        IqSet("1", kResponder, kInitiator,
+              RejectXml(protocol, cricket::STR_TERMINATE_ERROR)));
+    initiator->ExpectSentStanza(
+        IqAck("1", kInitiator, kResponder));
+    if (protocol == PROTOCOL_JINGLE) {
+      EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE,
+                initiator->session_state());
+    } else {
+      EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDREJECT,
+                initiator->session_state());
+    }
+  }
+
+  void TestTransportMux() {
+    SignalingProtocol initiator_protocol = PROTOCOL_JINGLE;
+    SignalingProtocol responder_protocol = PROTOCOL_JINGLE;
+    SignalingProtocol resulting_protocol = PROTOCOL_JINGLE;
+    std::string content_type = cricket::NS_JINGLE_RTP;
+    std::string gingle_content_type = cricket::NS_GINGLE_VIDEO;
+    std::string content_name_a = cricket::CN_AUDIO;
+    std::string channel_name_a = "rtp";
+    std::string content_name_b = cricket::CN_VIDEO;
+    std::string channel_name_b = "video_rtp";
+
+    std::string initiate_xml = InitiateXml(
+        initiator_protocol,
+        gingle_content_type,
+        content_name_a, content_type,
+        content_name_b, content_type, true);
+    std::string transport_info_a_xml = TransportInfo2Xml(
+        initiator_protocol, content_name_a,
+        channel_name_a, 0, 1);
+    std::string transport_info_b_xml = TransportInfo2Xml(
+        initiator_protocol, content_name_b,
+        channel_name_b, 2, 3);
+    std::string transport_info_reply_a_xml = TransportInfo2Xml(
+        resulting_protocol, content_name_a,
+        channel_name_a, 4, 5);
+    std::string transport_info_reply_b_xml = TransportInfo2Xml(
+        resulting_protocol, content_name_b,
+        channel_name_b, 6, 7);
+    std::string accept_xml = AcceptXml(
+        resulting_protocol,
+        gingle_content_type,
+        content_name_a, content_type,
+        content_name_b, content_type, true);
+
+    TestSession(initiator_protocol, responder_protocol, resulting_protocol,
+                gingle_content_type,
+                content_type,
+                content_name_a, channel_name_a,
+                content_name_b, channel_name_b,
+                initiate_xml,
+                transport_info_a_xml, transport_info_b_xml,
+                transport_info_reply_a_xml, transport_info_reply_b_xml,
+                accept_xml,
+                true);
+  }
+
+  void TestSendDescriptionInfo() {
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    std::string content_name = "content-name";
+    std::string content_type = "content-type";
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, PROTOCOL_JINGLE,
+                       content_type,
+                       content_name, "",
+                       "",  ""));
+
+    initiator->CreateSession();
+    cricket::SessionDescription* offer = NewTestSessionDescription(
+        content_name, content_type);
+    std::string initiate_xml = InitiateXml(
+        PROTOCOL_JINGLE, content_name, content_type);
+
+    cricket::ContentInfos contents;
+    TestContentDescription content(content_type, content_type);
+    contents.push_back(
+        cricket::ContentInfo(content_name, content_type, &content));
+    std::string description_info_xml = JingleDescriptionInfoXml(
+        content_name, content_type);
+
+    EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
+    initiator->ExpectSentStanza(
+        IqSet("0", kInitiator, kResponder, initiate_xml));
+
+    EXPECT_TRUE(initiator->session->SendDescriptionInfoMessage(contents));
+    initiator->ExpectSentStanza(
+        IqSet("1", kInitiator, kResponder, description_info_xml));
+  }
+
+  void DoTestSignalNewDescription(
+      TestClient* client,
+      cricket::BaseSession::State state,
+      cricket::ContentAction expected_content_action,
+      cricket::ContentSource expected_content_source) {
+    // Clean up before the new test.
+    client->new_local_description = false;
+    client->new_remote_description = false;
+
+    client->SetSessionState(state);
+    EXPECT_EQ((expected_content_source == cricket::CS_LOCAL),
+               client->new_local_description);
+    EXPECT_EQ((expected_content_source == cricket::CS_REMOTE),
+               client->new_remote_description);
+    EXPECT_EQ(expected_content_action, client->last_content_action);
+    EXPECT_EQ(expected_content_source, client->last_content_source);
+  }
+
+  void TestCallerSignalNewDescription() {
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    std::string content_name = "content-name";
+    std::string content_type = "content-type";
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, PROTOCOL_JINGLE,
+                       content_type,
+                       content_name, "",
+                       "",  ""));
+
+    initiator->CreateSession();
+
+    // send offer -> send update offer ->
+    // receive pr answer -> receive update pr answer ->
+    // receive answer
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_SENTINITIATE,
+        cricket::CA_OFFER, cricket::CS_LOCAL);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_SENTINITIATE,
+        cricket::CA_OFFER, cricket::CS_LOCAL);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT,
+        cricket::CA_PRANSWER, cricket::CS_REMOTE);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT,
+        cricket::CA_PRANSWER, cricket::CS_REMOTE);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_RECEIVEDACCEPT,
+        cricket::CA_ANSWER, cricket::CS_REMOTE);
+  }
+
+  void TestCalleeSignalNewDescription() {
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    std::string content_name = "content-name";
+    std::string content_type = "content-type";
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, PROTOCOL_JINGLE,
+                       content_type,
+                       content_name, "",
+                       "",  ""));
+
+    initiator->CreateSession();
+
+    // receive offer -> receive update offer ->
+    // send pr answer -> send update pr answer ->
+    // send answer
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE,
+        cricket::CA_OFFER, cricket::CS_REMOTE);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE,
+        cricket::CA_OFFER, cricket::CS_REMOTE);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT,
+        cricket::CA_PRANSWER, cricket::CS_LOCAL);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT,
+        cricket::CA_PRANSWER, cricket::CS_LOCAL);
+
+    DoTestSignalNewDescription(
+        initiator.get(), cricket::BaseSession::STATE_SENTACCEPT,
+        cricket::CA_ANSWER, cricket::CS_LOCAL);
+  }
+
+  void TestGetTransportStats() {
+    rtc::scoped_ptr<cricket::PortAllocator> allocator(
+        new TestPortAllocator());
+    int next_message_id = 0;
+
+    std::string content_name = "content-name";
+    std::string content_type = "content-type";
+    rtc::scoped_ptr<TestClient> initiator(
+        new TestClient(allocator.get(), &next_message_id,
+                       kInitiator, PROTOCOL_JINGLE,
+                       content_type,
+                       content_name, "",
+                       "",  ""));
+    initiator->CreateSession();
+
+    cricket::SessionStats stats;
+    EXPECT_TRUE(initiator->session->GetStats(&stats));
+    // At initiation, there are 2 transports.
+    EXPECT_EQ(2ul, stats.proxy_to_transport.size());
+    EXPECT_EQ(2ul, stats.transport_stats.size());
+  }
+};
+
+// For each of these, "X => Y = Z" means "if a client with protocol X
+// initiates to a client with protocol Y, they end up speaking protocol Z.
+
+// Gingle => Gingle = Gingle (with other content)
+TEST_F(SessionTest, GingleToGingleOtherContent) {
+  TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
+}
+
+// Gingle => Gingle = Gingle (with audio content)
+TEST_F(SessionTest, GingleToGingleAudioContent) {
+  TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
+}
+
+// Gingle => Gingle = Gingle (with video contents)
+TEST_F(SessionTest, GingleToGingleVideoContents) {
+  TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
+}
+
+// Jingle => Jingle = Jingle (with other content)
+TEST_F(SessionTest, JingleToJingleOtherContent) {
+  TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
+}
+
+// Jingle => Jingle = Jingle (with audio content)
+TEST_F(SessionTest, JingleToJingleAudioContent) {
+  TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
+}
+
+// Jingle => Jingle = Jingle (with video contents)
+TEST_F(SessionTest, JingleToJingleVideoContents) {
+  TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
+}
+
+// Hybrid => Hybrid = Jingle (with other content)
+TEST_F(SessionTest, HybridToHybridOtherContent) {
+  TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
+}
+
+// Hybrid => Hybrid = Jingle (with audio content)
+TEST_F(SessionTest, HybridToHybridAudioContent) {
+  TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
+}
+
+// Hybrid => Hybrid = Jingle (with video contents)
+TEST_F(SessionTest, HybridToHybridVideoContents) {
+  TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
+}
+
+// Gingle => Hybrid = Gingle (with other content)
+TEST_F(SessionTest, GingleToHybridOtherContent) {
+  TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
+}
+
+// Gingle => Hybrid = Gingle (with audio content)
+TEST_F(SessionTest, GingleToHybridAudioContent) {
+  TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
+}
+
+// Gingle => Hybrid = Gingle (with video contents)
+TEST_F(SessionTest, GingleToHybridVideoContents) {
+  TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
+}
+
+// Jingle => Hybrid = Jingle (with other content)
+TEST_F(SessionTest, JingleToHybridOtherContent) {
+  TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
+}
+
+// Jingle => Hybrid = Jingle (with audio content)
+TEST_F(SessionTest, JingleToHybridAudioContent) {
+  TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
+}
+
+// Jingle => Hybrid = Jingle (with video contents)
+TEST_F(SessionTest, JingleToHybridVideoContents) {
+  TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
+}
+
+// Hybrid => Gingle = Gingle (with other content)
+TEST_F(SessionTest, HybridToGingleOtherContent) {
+  TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
+}
+
+// Hybrid => Gingle = Gingle (with audio content)
+TEST_F(SessionTest, HybridToGingleAudioContent) {
+  TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
+}
+
+// Hybrid => Gingle = Gingle (with video contents)
+TEST_F(SessionTest, HybridToGingleVideoContents) {
+  TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
+}
+
+// Hybrid => Jingle = Jingle (with other content)
+TEST_F(SessionTest, HybridToJingleOtherContent) {
+  TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
+}
+
+// Hybrid => Jingle = Jingle (with audio content)
+TEST_F(SessionTest, HybridToJingleAudioContent) {
+  TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
+}
+
+// Hybrid => Jingle = Jingle (with video contents)
+TEST_F(SessionTest, HybridToJingleVideoContents) {
+  TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
+}
+
+TEST_F(SessionTest, GingleEarlyTerminationFromInitiator) {
+  TestEarlyTerminationFromInitiator(PROTOCOL_GINGLE);
+}
+
+TEST_F(SessionTest, JingleEarlyTerminationFromInitiator) {
+  TestEarlyTerminationFromInitiator(PROTOCOL_JINGLE);
+}
+
+TEST_F(SessionTest, HybridEarlyTerminationFromInitiator) {
+  TestEarlyTerminationFromInitiator(PROTOCOL_HYBRID);
+}
+
+TEST_F(SessionTest, GingleRejection) {
+  TestRejection(PROTOCOL_GINGLE);
+}
+
+TEST_F(SessionTest, JingleRejection) {
+  TestRejection(PROTOCOL_JINGLE);
+}
+
+TEST_F(SessionTest, GingleGoodRedirect) {
+  TestGoodRedirect(PROTOCOL_GINGLE);
+}
+
+TEST_F(SessionTest, JingleGoodRedirect) {
+  TestGoodRedirect(PROTOCOL_JINGLE);
+}
+
+TEST_F(SessionTest, GingleBadRedirect) {
+  TestBadRedirect(PROTOCOL_GINGLE);
+}
+
+TEST_F(SessionTest, JingleBadRedirect) {
+  TestBadRedirect(PROTOCOL_JINGLE);
+}
+
+TEST_F(SessionTest, TestCandidatesInInitiateAndAccept) {
+  TestCandidatesInInitiateAndAccept("Candidates in initiate/accept");
+}
+
+TEST_F(SessionTest, TestTransportMux) {
+  TestTransportMux();
+}
+
+TEST_F(SessionTest, TestSendDescriptionInfo) {
+  TestSendDescriptionInfo();
+}
+
+TEST_F(SessionTest, TestCallerSignalNewDescription) {
+  TestCallerSignalNewDescription();
+}
+
+TEST_F(SessionTest, TestCalleeSignalNewDescription) {
+  TestCalleeSignalNewDescription();
+}
+
+TEST_F(SessionTest, TestGetTransportStats) {
+  TestGetTransportStats();
+}
diff --git a/p2p/base/sessionclient.h b/p2p/base/sessionclient.h
new file mode 100644
index 0000000..8968788
--- /dev/null
+++ b/p2p/base/sessionclient.h
@@ -0,0 +1,78 @@
+/*
+ *  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_P2P_BASE_SESSIONCLIENT_H_
+#define WEBRTC_P2P_BASE_SESSIONCLIENT_H_
+
+#include "webrtc/p2p/base/constants.h"
+
+namespace buzz {
+class XmlElement;
+}
+
+namespace cricket {
+
+struct ParseError;
+class Session;
+class ContentDescription;
+
+class ContentParser {
+ public:
+  virtual bool ParseContent(SignalingProtocol protocol,
+                            const buzz::XmlElement* elem,
+                            ContentDescription** content,
+                            ParseError* error) = 0;
+  // If not IsWriteable, then a given content should be "skipped" when
+  // writing in the given protocol, as if it didn't exist.  We assume
+  // most things are writeable.  We do this to avoid strange cases
+  // like data contents in Gingle, which aren't writable.
+  virtual bool IsWritable(SignalingProtocol protocol,
+                          const ContentDescription* content) {
+    return true;
+  }
+  virtual bool WriteContent(SignalingProtocol protocol,
+                            const ContentDescription* content,
+                            buzz::XmlElement** elem,
+                            WriteError* error) = 0;
+  virtual ~ContentParser() {}
+};
+
+// A SessionClient exists in 1-1 relation with each session.  The implementor
+// of this interface is the one that understands *what* the two sides are
+// trying to send to one another.  The lower-level layers only know how to send
+// data; they do not know what is being sent.
+class SessionClient : public ContentParser {
+ public:
+  // Notifies the client of the creation / destruction of sessions of this type.
+  //
+  // IMPORTANT: The SessionClient, in its handling of OnSessionCreate, must
+  // create whatever channels are indicate in the description.  This is because
+  // the remote client may already be attempting to connect those channels. If
+  // we do not create our channel right away, then connection may fail or be
+  // delayed.
+  virtual void OnSessionCreate(Session* session, bool received_initiate) = 0;
+  virtual void OnSessionDestroy(Session* session) = 0;
+
+  virtual bool ParseContent(SignalingProtocol protocol,
+                            const buzz::XmlElement* elem,
+                            ContentDescription** content,
+                            ParseError* error) = 0;
+  virtual bool WriteContent(SignalingProtocol protocol,
+                            const ContentDescription* content,
+                            buzz::XmlElement** elem,
+                            WriteError* error) = 0;
+ protected:
+  // The SessionClient interface explicitly does not include destructor
+  virtual ~SessionClient() { }
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_SESSIONCLIENT_H_
diff --git a/p2p/base/sessiondescription.cc b/p2p/base/sessiondescription.cc
new file mode 100644
index 0000000..b05dc51
--- /dev/null
+++ b/p2p/base/sessiondescription.cc
@@ -0,0 +1,222 @@
+/*
+ *  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 "webrtc/p2p/base/sessiondescription.h"
+
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+
+namespace cricket {
+
+ContentInfo* FindContentInfoByName(
+    ContentInfos& contents, const std::string& name) {
+  for (ContentInfos::iterator content = contents.begin();
+       content != contents.end(); ++content) {
+    if (content->name == name) {
+      return &(*content);
+    }
+  }
+  return NULL;
+}
+
+const ContentInfo* FindContentInfoByName(
+    const ContentInfos& contents, const std::string& name) {
+  for (ContentInfos::const_iterator content = contents.begin();
+       content != contents.end(); ++content) {
+    if (content->name == name) {
+      return &(*content);
+    }
+  }
+  return NULL;
+}
+
+const ContentInfo* FindContentInfoByType(
+    const ContentInfos& contents, const std::string& type) {
+  for (ContentInfos::const_iterator content = contents.begin();
+       content != contents.end(); ++content) {
+    if (content->type == type) {
+      return &(*content);
+    }
+  }
+  return NULL;
+}
+
+const std::string* ContentGroup::FirstContentName() const {
+  return (!content_names_.empty()) ? &(*content_names_.begin()) : NULL;
+}
+
+bool ContentGroup::HasContentName(const std::string& content_name) const {
+  return (std::find(content_names_.begin(), content_names_.end(),
+                    content_name) != content_names_.end());
+}
+
+void ContentGroup::AddContentName(const std::string& content_name) {
+  if (!HasContentName(content_name)) {
+    content_names_.push_back(content_name);
+  }
+}
+
+bool ContentGroup::RemoveContentName(const std::string& content_name) {
+  ContentNames::iterator iter = std::find(
+      content_names_.begin(), content_names_.end(), content_name);
+  if (iter == content_names_.end()) {
+    return false;
+  }
+  content_names_.erase(iter);
+  return true;
+}
+
+SessionDescription* SessionDescription::Copy() const {
+  SessionDescription* copy = new SessionDescription(*this);
+  // Copy all ContentDescriptions.
+  for (ContentInfos::iterator content = copy->contents_.begin();
+      content != copy->contents().end(); ++content) {
+    content->description = content->description->Copy();
+  }
+  return copy;
+}
+
+const ContentInfo* SessionDescription::GetContentByName(
+    const std::string& name) const {
+  return FindContentInfoByName(contents_, name);
+}
+
+ContentInfo* SessionDescription::GetContentByName(
+    const std::string& name)  {
+  return FindContentInfoByName(contents_, name);
+}
+
+const ContentDescription* SessionDescription::GetContentDescriptionByName(
+    const std::string& name) const {
+  const ContentInfo* cinfo = FindContentInfoByName(contents_, name);
+  if (cinfo == NULL) {
+    return NULL;
+  }
+
+  return cinfo->description;
+}
+
+ContentDescription* SessionDescription::GetContentDescriptionByName(
+    const std::string& name) {
+  ContentInfo* cinfo = FindContentInfoByName(contents_, name);
+  if (cinfo == NULL) {
+    return NULL;
+  }
+
+  return cinfo->description;
+}
+
+const ContentInfo* SessionDescription::FirstContentByType(
+    const std::string& type) const {
+  return FindContentInfoByType(contents_, type);
+}
+
+const ContentInfo* SessionDescription::FirstContent() const {
+  return (contents_.empty()) ? NULL : &(*contents_.begin());
+}
+
+void SessionDescription::AddContent(const std::string& name,
+                                    const std::string& type,
+                                    ContentDescription* description) {
+  contents_.push_back(ContentInfo(name, type, description));
+}
+
+void SessionDescription::AddContent(const std::string& name,
+                                    const std::string& type,
+                                    bool rejected,
+                                    ContentDescription* description) {
+  contents_.push_back(ContentInfo(name, type, rejected, description));
+}
+
+bool SessionDescription::RemoveContentByName(const std::string& name) {
+  for (ContentInfos::iterator content = contents_.begin();
+       content != contents_.end(); ++content) {
+    if (content->name == name) {
+      delete content->description;
+      contents_.erase(content);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool SessionDescription::AddTransportInfo(const TransportInfo& transport_info) {
+  if (GetTransportInfoByName(transport_info.content_name) != NULL) {
+    return false;
+  }
+  transport_infos_.push_back(transport_info);
+  return true;
+}
+
+bool SessionDescription::RemoveTransportInfoByName(const std::string& name) {
+  for (TransportInfos::iterator transport_info = transport_infos_.begin();
+       transport_info != transport_infos_.end(); ++transport_info) {
+    if (transport_info->content_name == name) {
+      transport_infos_.erase(transport_info);
+      return true;
+    }
+  }
+  return false;
+}
+
+const TransportInfo* SessionDescription::GetTransportInfoByName(
+    const std::string& name) const {
+  for (TransportInfos::const_iterator iter = transport_infos_.begin();
+       iter != transport_infos_.end(); ++iter) {
+    if (iter->content_name == name) {
+      return &(*iter);
+    }
+  }
+  return NULL;
+}
+
+TransportInfo* SessionDescription::GetTransportInfoByName(
+    const std::string& name) {
+  for (TransportInfos::iterator iter = transport_infos_.begin();
+       iter != transport_infos_.end(); ++iter) {
+    if (iter->content_name == name) {
+      return &(*iter);
+    }
+  }
+  return NULL;
+}
+
+void SessionDescription::RemoveGroupByName(const std::string& name) {
+  for (ContentGroups::iterator iter = content_groups_.begin();
+       iter != content_groups_.end(); ++iter) {
+    if (iter->semantics() == name) {
+      content_groups_.erase(iter);
+      break;
+    }
+  }
+}
+
+bool SessionDescription::HasGroup(const std::string& name) const {
+  for (ContentGroups::const_iterator iter = content_groups_.begin();
+       iter != content_groups_.end(); ++iter) {
+    if (iter->semantics() == name) {
+      return true;
+    }
+  }
+  return false;
+}
+
+const ContentGroup* SessionDescription::GetGroupByName(
+    const std::string& name) const {
+  for (ContentGroups::const_iterator iter = content_groups_.begin();
+       iter != content_groups_.end(); ++iter) {
+    if (iter->semantics() == name) {
+      return &(*iter);
+    }
+  }
+  return NULL;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/sessiondescription.h b/p2p/base/sessiondescription.h
new file mode 100644
index 0000000..1182a67
--- /dev/null
+++ b/p2p/base/sessiondescription.h
@@ -0,0 +1,185 @@
+/*
+ *  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_P2P_BASE_SESSIONDESCRIPTION_H_
+#define WEBRTC_P2P_BASE_SESSIONDESCRIPTION_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/transportinfo.h"
+#include "webrtc/base/constructormagic.h"
+
+namespace cricket {
+
+// Describes a session content. Individual content types inherit from
+// this class.  Analagous to a <jingle><content><description> or
+// <session><description>.
+class ContentDescription {
+ public:
+  virtual ~ContentDescription() {}
+  virtual ContentDescription* Copy() const = 0;
+};
+
+// Analagous to a <jingle><content> or <session><description>.
+// name = name of <content name="...">
+// type = xmlns of <content>
+struct ContentInfo {
+  ContentInfo() : description(NULL) {}
+  ContentInfo(const std::string& name,
+              const std::string& type,
+              ContentDescription* description) :
+      name(name), type(type), rejected(false), description(description) {}
+  ContentInfo(const std::string& name,
+              const std::string& type,
+              bool rejected,
+              ContentDescription* description) :
+      name(name), type(type), rejected(rejected), description(description) {}
+  std::string name;
+  std::string type;
+  bool rejected;
+  ContentDescription* description;
+};
+
+typedef std::vector<std::string> ContentNames;
+
+// This class provides a mechanism to aggregate different media contents into a
+// group. This group can also be shared with the peers in a pre-defined format.
+// GroupInfo should be populated only with the |content_name| of the
+// MediaDescription.
+class ContentGroup {
+ public:
+  explicit ContentGroup(const std::string& semantics) :
+      semantics_(semantics) {}
+
+  const std::string& semantics() const { return semantics_; }
+  const ContentNames& content_names() const { return content_names_; }
+
+  const std::string* FirstContentName() const;
+  bool HasContentName(const std::string& content_name) const;
+  void AddContentName(const std::string& content_name);
+  bool RemoveContentName(const std::string& content_name);
+
+ private:
+  std::string semantics_;
+  ContentNames content_names_;
+};
+
+typedef std::vector<ContentInfo> ContentInfos;
+typedef std::vector<ContentGroup> ContentGroups;
+
+const ContentInfo* FindContentInfoByName(
+    const ContentInfos& contents, const std::string& name);
+const ContentInfo* FindContentInfoByType(
+    const ContentInfos& contents, const std::string& type);
+
+// Describes a collection of contents, each with its own name and
+// type.  Analogous to a <jingle> or <session> stanza.  Assumes that
+// contents are unique be name, but doesn't enforce that.
+class SessionDescription {
+ public:
+  SessionDescription() {}
+  explicit SessionDescription(const ContentInfos& contents) :
+      contents_(contents) {}
+  SessionDescription(const ContentInfos& contents,
+                     const ContentGroups& groups) :
+      contents_(contents),
+      content_groups_(groups) {}
+  SessionDescription(const ContentInfos& contents,
+                     const TransportInfos& transports,
+                     const ContentGroups& groups) :
+      contents_(contents),
+      transport_infos_(transports),
+      content_groups_(groups) {}
+  ~SessionDescription() {
+    for (ContentInfos::iterator content = contents_.begin();
+         content != contents_.end(); ++content) {
+      delete content->description;
+    }
+  }
+
+  SessionDescription* Copy() const;
+
+  // Content accessors.
+  const ContentInfos& contents() const { return contents_; }
+  ContentInfos& contents() { return contents_; }
+  const ContentInfo* GetContentByName(const std::string& name) const;
+  ContentInfo* GetContentByName(const std::string& name);
+  const ContentDescription* GetContentDescriptionByName(
+      const std::string& name) const;
+  ContentDescription* GetContentDescriptionByName(const std::string& name);
+  const ContentInfo* FirstContentByType(const std::string& type) const;
+  const ContentInfo* FirstContent() const;
+
+  // Content mutators.
+  // Adds a content to this description. Takes ownership of ContentDescription*.
+  void AddContent(const std::string& name,
+                  const std::string& type,
+                  ContentDescription* description);
+  void AddContent(const std::string& name,
+                  const std::string& type,
+                  bool rejected,
+                  ContentDescription* description);
+  bool RemoveContentByName(const std::string& name);
+
+  // Transport accessors.
+  const TransportInfos& transport_infos() const { return transport_infos_; }
+  TransportInfos& transport_infos() { return transport_infos_; }
+  const TransportInfo* GetTransportInfoByName(
+      const std::string& name) const;
+  TransportInfo* GetTransportInfoByName(const std::string& name);
+  const TransportDescription* GetTransportDescriptionByName(
+      const std::string& name) const {
+    const TransportInfo* tinfo = GetTransportInfoByName(name);
+    return tinfo ? &tinfo->description : NULL;
+  }
+
+  // Transport mutators.
+  void set_transport_infos(const TransportInfos& transport_infos) {
+    transport_infos_ = transport_infos;
+  }
+  // Adds a TransportInfo to this description.
+  // Returns false if a TransportInfo with the same name already exists.
+  bool AddTransportInfo(const TransportInfo& transport_info);
+  bool RemoveTransportInfoByName(const std::string& name);
+
+  // Group accessors.
+  const ContentGroups& groups() const { return content_groups_; }
+  const ContentGroup* GetGroupByName(const std::string& name) const;
+  bool HasGroup(const std::string& name) const;
+
+  // Group mutators.
+  void AddGroup(const ContentGroup& group) { content_groups_.push_back(group); }
+  // Remove the first group with the same semantics specified by |name|.
+  void RemoveGroupByName(const std::string& name);
+
+ private:
+  ContentInfos contents_;
+  TransportInfos transport_infos_;
+  ContentGroups content_groups_;
+};
+
+// Indicates whether a ContentDescription was an offer or an answer, as
+// described in http://www.ietf.org/rfc/rfc3264.txt. CA_UPDATE
+// indicates a jingle update message which contains a subset of a full
+// session description
+enum ContentAction {
+  CA_OFFER, CA_PRANSWER, CA_ANSWER, CA_UPDATE
+};
+
+// Indicates whether a ContentDescription was sent by the local client
+// or received from the remote client.
+enum ContentSource {
+  CS_LOCAL, CS_REMOTE
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_SESSIONDESCRIPTION_H_
diff --git a/p2p/base/sessionid.h b/p2p/base/sessionid.h
new file mode 100644
index 0000000..f695700
--- /dev/null
+++ b/p2p/base/sessionid.h
@@ -0,0 +1,20 @@
+/*
+ *  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_P2P_BASE_SESSIONID_H_
+#define WEBRTC_P2P_BASE_SESSIONID_H_
+
+// TODO: Remove this file.
+
+namespace cricket {
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_SESSIONID_H_
diff --git a/p2p/base/sessionmanager.cc b/p2p/base/sessionmanager.cc
new file mode 100644
index 0000000..f375dea
--- /dev/null
+++ b/p2p/base/sessionmanager.cc
@@ -0,0 +1,309 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/sessionmanager.h"
+
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/session.h"
+#include "webrtc/p2p/base/sessionmessages.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/stringencode.h"
+
+namespace cricket {
+
+SessionManager::SessionManager(PortAllocator *allocator,
+                               rtc::Thread *worker) {
+  allocator_ = allocator;
+  signaling_thread_ = rtc::Thread::Current();
+  if (worker == NULL) {
+    worker_thread_ = rtc::Thread::Current();
+  } else {
+    worker_thread_ = worker;
+  }
+  timeout_ = 50;
+}
+
+SessionManager::~SessionManager() {
+  // Note: Session::Terminate occurs asynchronously, so it's too late to
+  // delete them now.  They better be all gone.
+  ASSERT(session_map_.empty());
+  // TerminateAll();
+  SignalDestroyed();
+}
+
+void SessionManager::AddClient(const std::string& content_type,
+                               SessionClient* client) {
+  ASSERT(client_map_.find(content_type) == client_map_.end());
+  client_map_[content_type] = client;
+}
+
+void SessionManager::RemoveClient(const std::string& content_type) {
+  ClientMap::iterator iter = client_map_.find(content_type);
+  ASSERT(iter != client_map_.end());
+  client_map_.erase(iter);
+}
+
+SessionClient* SessionManager::GetClient(const std::string& content_type) {
+  ClientMap::iterator iter = client_map_.find(content_type);
+  return (iter != client_map_.end()) ? iter->second : NULL;
+}
+
+Session* SessionManager::CreateSession(const std::string& local_name,
+                                       const std::string& content_type) {
+  std::string id;
+  return CreateSession(id, local_name, content_type);
+}
+
+Session* SessionManager::CreateSession(const std::string& id,
+                                       const std::string& local_name,
+                                       const std::string& content_type) {
+  std::string sid =
+      id.empty() ? rtc::ToString(rtc::CreateRandomId64()) : id;
+  return CreateSession(local_name, local_name, sid, content_type, false);
+}
+
+Session* SessionManager::CreateSession(
+    const std::string& local_name, const std::string& initiator_name,
+    const std::string& sid, const std::string& content_type,
+    bool received_initiate) {
+  SessionClient* client = GetClient(content_type);
+  ASSERT(client != NULL);
+
+  Session* session = new Session(this, local_name, initiator_name,
+                                 sid, content_type, client);
+  session->SetIdentity(transport_desc_factory_.identity());
+  session_map_[session->id()] = session;
+  session->SignalRequestSignaling.connect(
+      this, &SessionManager::OnRequestSignaling);
+  session->SignalOutgoingMessage.connect(
+      this, &SessionManager::OnOutgoingMessage);
+  session->SignalErrorMessage.connect(this, &SessionManager::OnErrorMessage);
+  SignalSessionCreate(session, received_initiate);
+  session->client()->OnSessionCreate(session, received_initiate);
+  return session;
+}
+
+void SessionManager::DestroySession(Session* session) {
+  if (session != NULL) {
+    SessionMap::iterator it = session_map_.find(session->id());
+    if (it != session_map_.end()) {
+      SignalSessionDestroy(session);
+      session->client()->OnSessionDestroy(session);
+      session_map_.erase(it);
+      delete session;
+    }
+  }
+}
+
+Session* SessionManager::GetSession(const std::string& sid) {
+  SessionMap::iterator it = session_map_.find(sid);
+  if (it != session_map_.end())
+    return it->second;
+  return NULL;
+}
+
+void SessionManager::TerminateAll() {
+  while (session_map_.begin() != session_map_.end()) {
+    Session* session = session_map_.begin()->second;
+    session->Terminate();
+  }
+}
+
+bool SessionManager::IsSessionMessage(const buzz::XmlElement* stanza) {
+  return cricket::IsSessionMessage(stanza);
+}
+
+Session* SessionManager::FindSession(const std::string& sid,
+                                     const std::string& remote_name) {
+  SessionMap::iterator iter = session_map_.find(sid);
+  if (iter == session_map_.end())
+    return NULL;
+
+  Session* session = iter->second;
+  if (buzz::Jid(remote_name) != buzz::Jid(session->remote_name()))
+    return NULL;
+
+  return session;
+}
+
+void SessionManager::OnIncomingMessage(const buzz::XmlElement* stanza) {
+  SessionMessage msg;
+  ParseError error;
+
+  if (!ParseSessionMessage(stanza, &msg, &error)) {
+    SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
+                     error.text, NULL);
+    return;
+  }
+
+  Session* session = FindSession(msg.sid, msg.from);
+  if (session) {
+    session->OnIncomingMessage(msg);
+    return;
+  }
+  if (msg.type != ACTION_SESSION_INITIATE) {
+    SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
+                     "unknown session", NULL);
+    return;
+  }
+
+  std::string content_type;
+  if (!ParseContentType(msg.protocol, msg.action_elem,
+                        &content_type, &error)) {
+    SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
+                     error.text, NULL);
+    return;
+  }
+
+  if (!GetClient(content_type)) {
+    SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
+                     "unknown content type: " + content_type, NULL);
+    return;
+  }
+
+  session = CreateSession(msg.to, msg.initiator, msg.sid,
+                          content_type, true);
+  session->OnIncomingMessage(msg);
+}
+
+void SessionManager::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
+    const buzz::XmlElement* response_stanza) {
+  if (orig_stanza == NULL || response_stanza == NULL) {
+    return;
+  }
+
+  SessionMessage msg;
+  ParseError error;
+  if (!ParseSessionMessage(orig_stanza, &msg, &error)) {
+    LOG(LS_WARNING) << "Error parsing incoming response: " << error.text
+                    << ":" << orig_stanza;
+    return;
+  }
+
+  Session* session = FindSession(msg.sid, msg.to);
+  if (!session) {
+    // Also try the QN_FROM in the response stanza, in case we sent the request
+    // to a bare JID but got the response from a full JID.
+    std::string ack_from = response_stanza->Attr(buzz::QN_FROM);
+    session = FindSession(msg.sid, ack_from);
+  }
+  if (session) {
+    session->OnIncomingResponse(orig_stanza, response_stanza, msg);
+  }
+}
+
+void SessionManager::OnFailedSend(const buzz::XmlElement* orig_stanza,
+                                  const buzz::XmlElement* error_stanza) {
+  SessionMessage msg;
+  ParseError error;
+  if (!ParseSessionMessage(orig_stanza, &msg, &error)) {
+    return;  // TODO: log somewhere?
+  }
+
+  Session* session = FindSession(msg.sid, msg.to);
+  if (session) {
+    rtc::scoped_ptr<buzz::XmlElement> synthetic_error;
+    if (!error_stanza) {
+      // A failed send is semantically equivalent to an error response, so we
+      // can just turn the former into the latter.
+      synthetic_error.reset(
+        CreateErrorMessage(orig_stanza, buzz::QN_STANZA_ITEM_NOT_FOUND,
+                           "cancel", "Recipient did not respond", NULL));
+      error_stanza = synthetic_error.get();
+    }
+
+    session->OnFailedSend(orig_stanza, error_stanza);
+  }
+}
+
+void SessionManager::SendErrorMessage(const buzz::XmlElement* stanza,
+                                      const buzz::QName& name,
+                                      const std::string& type,
+                                      const std::string& text,
+                                      const buzz::XmlElement* extra_info) {
+  rtc::scoped_ptr<buzz::XmlElement> msg(
+      CreateErrorMessage(stanza, name, type, text, extra_info));
+  SignalOutgoingMessage(this, msg.get());
+}
+
+buzz::XmlElement* SessionManager::CreateErrorMessage(
+    const buzz::XmlElement* stanza,
+    const buzz::QName& name,
+    const std::string& type,
+    const std::string& text,
+    const buzz::XmlElement* extra_info) {
+  buzz::XmlElement* iq = new buzz::XmlElement(buzz::QN_IQ);
+  iq->SetAttr(buzz::QN_TO, stanza->Attr(buzz::QN_FROM));
+  iq->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
+  iq->SetAttr(buzz::QN_TYPE, "error");
+
+  CopyXmlChildren(stanza, iq);
+
+  buzz::XmlElement* error = new buzz::XmlElement(buzz::QN_ERROR);
+  error->SetAttr(buzz::QN_TYPE, type);
+  iq->AddElement(error);
+
+  // If the error name is not in the standard namespace, we have to first add
+  // some error from that namespace.
+  if (name.Namespace() != buzz::NS_STANZA) {
+     error->AddElement(
+         new buzz::XmlElement(buzz::QN_STANZA_UNDEFINED_CONDITION));
+  }
+  error->AddElement(new buzz::XmlElement(name));
+
+  if (extra_info)
+    error->AddElement(new buzz::XmlElement(*extra_info));
+
+  if (text.size() > 0) {
+    // It's okay to always use English here.  This text is for debugging
+    // purposes only.
+    buzz::XmlElement* text_elem = new buzz::XmlElement(buzz::QN_STANZA_TEXT);
+    text_elem->SetAttr(buzz::QN_XML_LANG, "en");
+    text_elem->SetBodyText(text);
+    error->AddElement(text_elem);
+  }
+
+  // TODO: Should we include error codes as well for SIP compatibility?
+
+  return iq;
+}
+
+void SessionManager::OnOutgoingMessage(Session* session,
+                                       const buzz::XmlElement* stanza) {
+  SignalOutgoingMessage(this, stanza);
+}
+
+void SessionManager::OnErrorMessage(BaseSession* session,
+                                    const buzz::XmlElement* stanza,
+                                    const buzz::QName& name,
+                                    const std::string& type,
+                                    const std::string& text,
+                                    const buzz::XmlElement* extra_info) {
+  SendErrorMessage(stanza, name, type, text, extra_info);
+}
+
+void SessionManager::OnSignalingReady() {
+  for (SessionMap::iterator it = session_map_.begin();
+      it != session_map_.end();
+      ++it) {
+    it->second->OnSignalingReady();
+  }
+}
+
+void SessionManager::OnRequestSignaling(Session* session) {
+  SignalRequestSignaling();
+}
+
+}  // namespace cricket
diff --git a/p2p/base/sessionmanager.h b/p2p/base/sessionmanager.h
new file mode 100644
index 0000000..74ee5c0
--- /dev/null
+++ b/p2p/base/sessionmanager.h
@@ -0,0 +1,194 @@
+/*
+ *  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_P2P_BASE_SESSIONMANAGER_H_
+#define WEBRTC_P2P_BASE_SESSIONMANAGER_H_
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/transportdescriptionfactory.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/thread.h"
+
+namespace buzz {
+class QName;
+class XmlElement;
+}
+
+namespace cricket {
+
+class Session;
+class BaseSession;
+class SessionClient;
+
+// SessionManager manages session instances.
+class SessionManager : public sigslot::has_slots<> {
+ public:
+  SessionManager(PortAllocator *allocator,
+                 rtc::Thread *worker_thread = NULL);
+  virtual ~SessionManager();
+
+  PortAllocator *port_allocator() const { return allocator_; }
+  rtc::Thread *worker_thread() const { return worker_thread_; }
+  rtc::Thread *signaling_thread() const { return signaling_thread_; }
+
+  int session_timeout() const { return timeout_; }
+  void set_session_timeout(int timeout) { timeout_ = timeout; }
+
+  // Set what transport protocol we want to default to.
+  void set_transport_protocol(TransportProtocol proto) {
+     transport_desc_factory_.set_protocol(proto);
+  }
+
+  // Control use of DTLS. An identity must be supplied if DTLS is enabled.
+  void set_secure(SecurePolicy policy) {
+    transport_desc_factory_.set_secure(policy);
+  }
+  void set_identity(rtc::SSLIdentity* identity) {
+    transport_desc_factory_.set_identity(identity);
+  }
+  const TransportDescriptionFactory* transport_desc_factory() const {
+    return &transport_desc_factory_;
+  }
+
+  // Registers support for the given client.  If we receive an initiate
+  // describing a session of the given type, we will automatically create a
+  // Session object and notify this client.  The client may then accept or
+  // reject the session.
+  void AddClient(const std::string& content_type, SessionClient* client);
+  void RemoveClient(const std::string& content_type);
+  SessionClient* GetClient(const std::string& content_type);
+
+  // Creates a new session.  The given name is the JID of the client on whose
+  // behalf we initiate the session.
+  Session *CreateSession(const std::string& local_name,
+                         const std::string& content_type);
+
+  Session *CreateSession(const std::string& id,
+                         const std::string& local_name,
+                         const std::string& content_type);
+
+  // Destroys the given session.
+  void DestroySession(Session *session);
+
+  // Returns the session with the given ID or NULL if none exists.
+  Session *GetSession(const std::string& sid);
+
+  // Terminates all of the sessions created by this manager.
+  void TerminateAll();
+
+  // These are signaled whenever the set of existing sessions changes.
+  sigslot::signal2<Session *, bool> SignalSessionCreate;
+  sigslot::signal1<Session *> SignalSessionDestroy;
+
+  // Determines whether the given stanza is intended for some session.
+  bool IsSessionMessage(const buzz::XmlElement* stanza);
+
+  // Given a sid, initiator, and remote_name, this finds the matching Session
+  Session* FindSession(const std::string& sid,
+                       const std::string& remote_name);
+
+  // Called when we receive a stanza for which IsSessionMessage is true.
+  void OnIncomingMessage(const buzz::XmlElement* stanza);
+
+  // Called when we get a response to a message that we sent.
+  void OnIncomingResponse(const buzz::XmlElement* orig_stanza,
+                          const buzz::XmlElement* response_stanza);
+
+  // Called if an attempted to send times out or an error is returned.  In the
+  // timeout case error_stanza will be NULL
+  void OnFailedSend(const buzz::XmlElement* orig_stanza,
+                    const buzz::XmlElement* error_stanza);
+
+  // Signalled each time a session generates a signaling message to send.
+  // Also signalled on errors, but with a NULL session.
+  sigslot::signal2<SessionManager*,
+                   const buzz::XmlElement*> SignalOutgoingMessage;
+
+  // Signaled before sessions try to send certain signaling messages.  The
+  // client should call OnSignalingReady once it is safe to send them.  These
+  // steps are taken so that we don't send signaling messages trying to
+  // re-establish the connectivity of a session when the client cannot send
+  // the messages (and would probably just drop them on the floor).
+  //
+  // Note: you can connect this directly to OnSignalingReady(), if a signalling
+  // check is not supported.
+  sigslot::signal0<> SignalRequestSignaling;
+  void OnSignalingReady();
+
+  // Signaled when this SessionManager is deleted.
+  sigslot::signal0<> SignalDestroyed;
+
+ private:
+  typedef std::map<std::string, Session*> SessionMap;
+  typedef std::map<std::string, SessionClient*> ClientMap;
+
+  // Helper function for CreateSession.  This is also invoked when we receive
+  // a message attempting to initiate a session with this client.
+  Session *CreateSession(const std::string& local_name,
+                         const std::string& initiator,
+                         const std::string& sid,
+                         const std::string& content_type,
+                         bool received_initiate);
+
+  // Attempts to find a registered session type whose description appears as
+  // a child of the session element.  Such a child should be present indicating
+  // the application they hope to initiate.
+  std::string FindClient(const buzz::XmlElement* session);
+
+  // Sends a message back to the other client indicating that we found an error
+  // in the stanza they sent.  name identifies the error, type is one of the
+  // standard XMPP types (cancel, continue, modify, auth, wait), and text is a
+  // description for debugging purposes.
+  void SendErrorMessage(const buzz::XmlElement* stanza,
+                        const buzz::QName& name,
+                        const std::string& type,
+                        const std::string& text,
+                        const buzz::XmlElement* extra_info);
+
+  // Creates and returns an error message from the given components.  The
+  // caller is responsible for deleting this.
+  buzz::XmlElement* CreateErrorMessage(
+      const buzz::XmlElement* stanza,
+      const buzz::QName& name,
+      const std::string& type,
+      const std::string& text,
+      const buzz::XmlElement* extra_info);
+
+  // Called each time a session requests signaling.
+  void OnRequestSignaling(Session* session);
+
+  // Called each time a session has an outgoing message.
+  void OnOutgoingMessage(Session* session, const buzz::XmlElement* stanza);
+
+  // Called each time a session has an error to send.
+  void OnErrorMessage(BaseSession* session,
+                      const buzz::XmlElement* stanza,
+                      const buzz::QName& name,
+                      const std::string& type,
+                      const std::string& text,
+                      const buzz::XmlElement* extra_info);
+
+  PortAllocator *allocator_;
+  rtc::Thread *signaling_thread_;
+  rtc::Thread *worker_thread_;
+  int timeout_;
+  TransportDescriptionFactory transport_desc_factory_;
+  SessionMap session_map_;
+  ClientMap client_map_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_SESSIONMANAGER_H_
diff --git a/p2p/base/sessionmessages.cc b/p2p/base/sessionmessages.cc
new file mode 100644
index 0000000..cc63673
--- /dev/null
+++ b/p2p/base/sessionmessages.cc
@@ -0,0 +1,1132 @@
+/*
+ *  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 "webrtc/p2p/base/sessionmessages.h"
+
+#include <stdio.h>
+#include <string>
+
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/p2ptransport.h"
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/sessionclient.h"
+#include "webrtc/p2p/base/sessiondescription.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/libjingle/xmllite/xmlconstants.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/stringutils.h"
+
+namespace cricket {
+
+ActionType ToActionType(const std::string& type) {
+  if (type == GINGLE_ACTION_INITIATE)
+    return ACTION_SESSION_INITIATE;
+  if (type == GINGLE_ACTION_INFO)
+    return ACTION_SESSION_INFO;
+  if (type == GINGLE_ACTION_ACCEPT)
+    return ACTION_SESSION_ACCEPT;
+  if (type == GINGLE_ACTION_REJECT)
+    return ACTION_SESSION_REJECT;
+  if (type == GINGLE_ACTION_TERMINATE)
+    return ACTION_SESSION_TERMINATE;
+  if (type == GINGLE_ACTION_CANDIDATES)
+    return ACTION_TRANSPORT_INFO;
+  if (type == JINGLE_ACTION_SESSION_INITIATE)
+    return ACTION_SESSION_INITIATE;
+  if (type == JINGLE_ACTION_TRANSPORT_INFO)
+    return ACTION_TRANSPORT_INFO;
+  if (type == JINGLE_ACTION_TRANSPORT_ACCEPT)
+    return ACTION_TRANSPORT_ACCEPT;
+  if (type == JINGLE_ACTION_SESSION_INFO)
+    return ACTION_SESSION_INFO;
+  if (type == JINGLE_ACTION_SESSION_ACCEPT)
+    return ACTION_SESSION_ACCEPT;
+  if (type == JINGLE_ACTION_SESSION_TERMINATE)
+    return ACTION_SESSION_TERMINATE;
+  if (type == JINGLE_ACTION_TRANSPORT_INFO)
+    return ACTION_TRANSPORT_INFO;
+  if (type == JINGLE_ACTION_TRANSPORT_ACCEPT)
+    return ACTION_TRANSPORT_ACCEPT;
+  if (type == JINGLE_ACTION_DESCRIPTION_INFO)
+    return ACTION_DESCRIPTION_INFO;
+  if (type == GINGLE_ACTION_UPDATE)
+    return ACTION_DESCRIPTION_INFO;
+
+  return ACTION_UNKNOWN;
+}
+
+std::string ToJingleString(ActionType type) {
+  switch (type) {
+    case ACTION_SESSION_INITIATE:
+      return JINGLE_ACTION_SESSION_INITIATE;
+    case ACTION_SESSION_INFO:
+      return JINGLE_ACTION_SESSION_INFO;
+    case ACTION_DESCRIPTION_INFO:
+      return JINGLE_ACTION_DESCRIPTION_INFO;
+    case ACTION_SESSION_ACCEPT:
+      return JINGLE_ACTION_SESSION_ACCEPT;
+    // Notice that reject and terminate both go to
+    // "session-terminate", but there is no "session-reject".
+    case ACTION_SESSION_REJECT:
+    case ACTION_SESSION_TERMINATE:
+      return JINGLE_ACTION_SESSION_TERMINATE;
+    case ACTION_TRANSPORT_INFO:
+      return JINGLE_ACTION_TRANSPORT_INFO;
+    case ACTION_TRANSPORT_ACCEPT:
+      return JINGLE_ACTION_TRANSPORT_ACCEPT;
+    default:
+      return "";
+  }
+}
+
+std::string ToGingleString(ActionType type) {
+  switch (type) {
+    case ACTION_SESSION_INITIATE:
+      return GINGLE_ACTION_INITIATE;
+    case ACTION_SESSION_INFO:
+      return GINGLE_ACTION_INFO;
+    case ACTION_SESSION_ACCEPT:
+      return GINGLE_ACTION_ACCEPT;
+    case ACTION_SESSION_REJECT:
+      return GINGLE_ACTION_REJECT;
+    case ACTION_SESSION_TERMINATE:
+      return GINGLE_ACTION_TERMINATE;
+    case ACTION_TRANSPORT_INFO:
+      return GINGLE_ACTION_CANDIDATES;
+    default:
+      return "";
+  }
+}
+
+
+bool IsJingleMessage(const buzz::XmlElement* stanza) {
+  const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE);
+  if (jingle == NULL)
+    return false;
+
+  return (jingle->HasAttr(buzz::QN_ACTION) && jingle->HasAttr(QN_SID));
+}
+
+bool IsGingleMessage(const buzz::XmlElement* stanza) {
+  const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION);
+  if (session == NULL)
+    return false;
+
+  return (session->HasAttr(buzz::QN_TYPE) &&
+          session->HasAttr(buzz::QN_ID)   &&
+          session->HasAttr(QN_INITIATOR));
+}
+
+bool IsSessionMessage(const buzz::XmlElement* stanza) {
+  return (stanza->Name() == buzz::QN_IQ &&
+          stanza->Attr(buzz::QN_TYPE) == buzz::STR_SET &&
+          (IsJingleMessage(stanza) ||
+           IsGingleMessage(stanza)));
+}
+
+bool ParseGingleSessionMessage(const buzz::XmlElement* session,
+                               SessionMessage* msg,
+                               ParseError* error) {
+  msg->protocol = PROTOCOL_GINGLE;
+  std::string type_string = session->Attr(buzz::QN_TYPE);
+  msg->type = ToActionType(type_string);
+  msg->sid = session->Attr(buzz::QN_ID);
+  msg->initiator = session->Attr(QN_INITIATOR);
+  msg->action_elem = session;
+
+  if (msg->type == ACTION_UNKNOWN)
+    return BadParse("unknown action: " + type_string, error);
+
+  return true;
+}
+
+bool ParseJingleSessionMessage(const buzz::XmlElement* jingle,
+                               SessionMessage* msg,
+                               ParseError* error) {
+  msg->protocol = PROTOCOL_JINGLE;
+  std::string type_string = jingle->Attr(buzz::QN_ACTION);
+  msg->type = ToActionType(type_string);
+  msg->sid = jingle->Attr(QN_SID);
+  msg->initiator = GetXmlAttr(jingle, QN_INITIATOR, buzz::STR_EMPTY);
+  msg->action_elem = jingle;
+
+  if (msg->type == ACTION_UNKNOWN)
+    return BadParse("unknown action: " + type_string, error);
+
+  return true;
+}
+
+bool ParseHybridSessionMessage(const buzz::XmlElement* jingle,
+                               SessionMessage* msg,
+                               ParseError* error) {
+  if (!ParseJingleSessionMessage(jingle, msg, error))
+    return false;
+  msg->protocol = PROTOCOL_HYBRID;
+
+  return true;
+}
+
+bool ParseSessionMessage(const buzz::XmlElement* stanza,
+                         SessionMessage* msg,
+                         ParseError* error) {
+  msg->id = stanza->Attr(buzz::QN_ID);
+  msg->from = stanza->Attr(buzz::QN_FROM);
+  msg->to = stanza->Attr(buzz::QN_TO);
+  msg->stanza = stanza;
+
+  const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE);
+  const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION);
+  if (jingle && session)
+    return ParseHybridSessionMessage(jingle, msg, error);
+  if (jingle != NULL)
+    return ParseJingleSessionMessage(jingle, msg, error);
+  if (session != NULL)
+    return ParseGingleSessionMessage(session, msg, error);
+  return false;
+}
+
+buzz::XmlElement* WriteGingleAction(const SessionMessage& msg,
+                                    const XmlElements& action_elems) {
+  buzz::XmlElement* session = new buzz::XmlElement(QN_GINGLE_SESSION, true);
+  session->AddAttr(buzz::QN_TYPE, ToGingleString(msg.type));
+  session->AddAttr(buzz::QN_ID, msg.sid);
+  session->AddAttr(QN_INITIATOR, msg.initiator);
+  AddXmlChildren(session, action_elems);
+  return session;
+}
+
+buzz::XmlElement* WriteJingleAction(const SessionMessage& msg,
+                                    const XmlElements& action_elems) {
+  buzz::XmlElement* jingle = new buzz::XmlElement(QN_JINGLE, true);
+  jingle->AddAttr(buzz::QN_ACTION, ToJingleString(msg.type));
+  jingle->AddAttr(QN_SID, msg.sid);
+  if (msg.type == ACTION_SESSION_INITIATE) {
+    jingle->AddAttr(QN_INITIATOR, msg.initiator);
+  }
+  AddXmlChildren(jingle, action_elems);
+  return jingle;
+}
+
+void WriteSessionMessage(const SessionMessage& msg,
+                         const XmlElements& action_elems,
+                         buzz::XmlElement* stanza) {
+  stanza->SetAttr(buzz::QN_TO, msg.to);
+  stanza->SetAttr(buzz::QN_TYPE, buzz::STR_SET);
+
+  if (msg.protocol == PROTOCOL_GINGLE) {
+    stanza->AddElement(WriteGingleAction(msg, action_elems));
+  } else {
+    stanza->AddElement(WriteJingleAction(msg, action_elems));
+  }
+}
+
+
+TransportParser* GetTransportParser(const TransportParserMap& trans_parsers,
+                                    const std::string& transport_type) {
+  TransportParserMap::const_iterator map = trans_parsers.find(transport_type);
+  if (map == trans_parsers.end()) {
+    return NULL;
+  } else {
+    return map->second;
+  }
+}
+
+CandidateTranslator* GetCandidateTranslator(
+    const CandidateTranslatorMap& translators,
+    const std::string& content_name) {
+  CandidateTranslatorMap::const_iterator map = translators.find(content_name);
+  if (map == translators.end()) {
+    return NULL;
+  } else {
+    return map->second;
+  }
+}
+
+bool GetParserAndTranslator(const TransportParserMap& trans_parsers,
+                            const CandidateTranslatorMap& translators,
+                            const std::string& transport_type,
+                            const std::string& content_name,
+                            TransportParser** parser,
+                            CandidateTranslator** translator,
+                            ParseError* error) {
+  *parser = GetTransportParser(trans_parsers, transport_type);
+  if (*parser == NULL) {
+    return BadParse("unknown transport type: " + transport_type, error);
+  }
+  // Not having a translator isn't fatal when parsing. If this is called for an
+  // initiate message, we won't have our proxies set up to do the translation.
+  // Fortunately, for the cases where translation is needed, candidates are
+  // never sent in initiates.
+  *translator = GetCandidateTranslator(translators, content_name);
+  return true;
+}
+
+bool GetParserAndTranslator(const TransportParserMap& trans_parsers,
+                            const CandidateTranslatorMap& translators,
+                            const std::string& transport_type,
+                            const std::string& content_name,
+                            TransportParser** parser,
+                            CandidateTranslator** translator,
+                            WriteError* error) {
+  *parser = GetTransportParser(trans_parsers, transport_type);
+  if (*parser == NULL) {
+    return BadWrite("unknown transport type: " + transport_type, error);
+  }
+  *translator = GetCandidateTranslator(translators, content_name);
+  if (*translator == NULL) {
+    return BadWrite("unknown content name: " + content_name, error);
+  }
+  return true;
+}
+
+bool ParseGingleCandidate(const buzz::XmlElement* candidate_elem,
+                          const TransportParserMap& trans_parsers,
+                          const CandidateTranslatorMap& translators,
+                          const std::string& content_name,
+                          Candidates* candidates,
+                          ParseError* error) {
+  TransportParser* trans_parser;
+  CandidateTranslator* translator;
+  if (!GetParserAndTranslator(trans_parsers, translators,
+                              NS_GINGLE_P2P, content_name,
+                              &trans_parser, &translator, error))
+    return false;
+
+  Candidate candidate;
+  if (!trans_parser->ParseGingleCandidate(
+          candidate_elem, translator, &candidate, error)) {
+    return false;
+  }
+
+  candidates->push_back(candidate);
+  return true;
+}
+
+bool ParseGingleCandidates(const buzz::XmlElement* parent,
+                           const TransportParserMap& trans_parsers,
+                           const CandidateTranslatorMap& translators,
+                           const std::string& content_name,
+                           Candidates* candidates,
+                           ParseError* error) {
+  for (const buzz::XmlElement* candidate_elem = parent->FirstElement();
+       candidate_elem != NULL;
+       candidate_elem = candidate_elem->NextElement()) {
+    if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) {
+      if (!ParseGingleCandidate(candidate_elem, trans_parsers, translators,
+                                content_name, candidates, error)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool ParseGingleTransportInfos(const buzz::XmlElement* action_elem,
+                               const ContentInfos& contents,
+                               const TransportParserMap& trans_parsers,
+                               const CandidateTranslatorMap& translators,
+                               TransportInfos* tinfos,
+                               ParseError* error) {
+  bool has_audio = FindContentInfoByName(contents, CN_AUDIO) != NULL;
+  bool has_video = FindContentInfoByName(contents, CN_VIDEO) != NULL;
+
+  // If we don't have media, no need to separate the candidates.
+  if (!has_audio && !has_video) {
+    TransportInfo tinfo(CN_OTHER,
+        TransportDescription(NS_GINGLE_P2P, std::string(), std::string()));
+    if (!ParseGingleCandidates(action_elem, trans_parsers, translators,
+                               CN_OTHER, &tinfo.description.candidates,
+                               error)) {
+      return false;
+    }
+
+    tinfos->push_back(tinfo);
+    return true;
+  }
+
+  // If we have media, separate the candidates.
+  TransportInfo audio_tinfo(
+      CN_AUDIO,
+      TransportDescription(NS_GINGLE_P2P, std::string(), std::string()));
+  TransportInfo video_tinfo(
+      CN_VIDEO,
+      TransportDescription(NS_GINGLE_P2P, std::string(), std::string()));
+  for (const buzz::XmlElement* candidate_elem = action_elem->FirstElement();
+       candidate_elem != NULL;
+       candidate_elem = candidate_elem->NextElement()) {
+    if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) {
+      const std::string& channel_name = candidate_elem->Attr(buzz::QN_NAME);
+      if (has_audio &&
+          (channel_name == GICE_CHANNEL_NAME_RTP ||
+           channel_name == GICE_CHANNEL_NAME_RTCP)) {
+        if (!ParseGingleCandidate(
+                candidate_elem, trans_parsers,
+                translators, CN_AUDIO,
+                &audio_tinfo.description.candidates, error)) {
+          return false;
+        }
+      } else if (has_video &&
+                 (channel_name == GICE_CHANNEL_NAME_VIDEO_RTP ||
+                  channel_name == GICE_CHANNEL_NAME_VIDEO_RTCP)) {
+        if (!ParseGingleCandidate(
+                candidate_elem, trans_parsers,
+                translators, CN_VIDEO,
+                &video_tinfo.description.candidates, error)) {
+          return false;
+        }
+      } else {
+        return BadParse("Unknown channel name: " + channel_name, error);
+      }
+    }
+  }
+
+  if (has_audio) {
+    tinfos->push_back(audio_tinfo);
+  }
+  if (has_video) {
+    tinfos->push_back(video_tinfo);
+  }
+  return true;
+}
+
+bool ParseJingleTransportInfo(const buzz::XmlElement* trans_elem,
+                              const std::string& content_name,
+                              const TransportParserMap& trans_parsers,
+                              const CandidateTranslatorMap& translators,
+                              TransportInfo* tinfo,
+                              ParseError* error) {
+  TransportParser* trans_parser;
+  CandidateTranslator* translator;
+  if (!GetParserAndTranslator(trans_parsers, translators,
+                              trans_elem->Name().Namespace(), content_name,
+                              &trans_parser, &translator, error))
+    return false;
+
+  TransportDescription tdesc;
+  if (!trans_parser->ParseTransportDescription(trans_elem, translator,
+                                               &tdesc, error))
+    return false;
+
+  *tinfo = TransportInfo(content_name, tdesc);
+  return true;
+}
+
+bool ParseJingleTransportInfos(const buzz::XmlElement* jingle,
+                               const ContentInfos& contents,
+                               const TransportParserMap trans_parsers,
+                               const CandidateTranslatorMap& translators,
+                               TransportInfos* tinfos,
+                               ParseError* error) {
+  for (const buzz::XmlElement* pair_elem
+           = jingle->FirstNamed(QN_JINGLE_CONTENT);
+       pair_elem != NULL;
+       pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) {
+    std::string content_name;
+    if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME,
+                        &content_name, error))
+      return false;
+
+    const ContentInfo* content = FindContentInfoByName(contents, content_name);
+    if (!content)
+      return BadParse("Unknown content name: " + content_name, error);
+
+    const buzz::XmlElement* trans_elem;
+    if (!RequireXmlChild(pair_elem, LN_TRANSPORT, &trans_elem, error))
+      return false;
+
+    TransportInfo tinfo;
+    if (!ParseJingleTransportInfo(trans_elem, content->name,
+                                  trans_parsers, translators,
+                                  &tinfo, error))
+      return false;
+
+    tinfos->push_back(tinfo);
+  }
+
+  return true;
+}
+
+buzz::XmlElement* NewTransportElement(const std::string& name) {
+  return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true);
+}
+
+bool WriteGingleCandidates(const Candidates& candidates,
+                           const TransportParserMap& trans_parsers,
+                           const std::string& transport_type,
+                           const CandidateTranslatorMap& translators,
+                           const std::string& content_name,
+                           XmlElements* elems,
+                           WriteError* error) {
+  TransportParser* trans_parser;
+  CandidateTranslator* translator;
+  if (!GetParserAndTranslator(trans_parsers, translators,
+                              transport_type, content_name,
+                              &trans_parser, &translator, error))
+    return false;
+
+  for (size_t i = 0; i < candidates.size(); ++i) {
+    rtc::scoped_ptr<buzz::XmlElement> element;
+    if (!trans_parser->WriteGingleCandidate(candidates[i], translator,
+                                            element.accept(), error)) {
+      return false;
+    }
+
+    elems->push_back(element.release());
+  }
+
+  return true;
+}
+
+bool WriteGingleTransportInfos(const TransportInfos& tinfos,
+                               const TransportParserMap& trans_parsers,
+                               const CandidateTranslatorMap& translators,
+                               XmlElements* elems,
+                               WriteError* error) {
+  for (TransportInfos::const_iterator tinfo = tinfos.begin();
+       tinfo != tinfos.end(); ++tinfo) {
+    if (!WriteGingleCandidates(tinfo->description.candidates,
+                               trans_parsers, tinfo->description.transport_type,
+                               translators, tinfo->content_name,
+                               elems, error))
+      return false;
+  }
+
+  return true;
+}
+
+bool WriteJingleTransportInfo(const TransportInfo& tinfo,
+                              const TransportParserMap& trans_parsers,
+                              const CandidateTranslatorMap& translators,
+                              XmlElements* elems,
+                              WriteError* error) {
+  std::string transport_type = tinfo.description.transport_type;
+  TransportParser* trans_parser;
+  CandidateTranslator* translator;
+  if (!GetParserAndTranslator(trans_parsers, translators,
+                              transport_type, tinfo.content_name,
+                              &trans_parser, &translator, error))
+    return false;
+
+  buzz::XmlElement* trans_elem;
+  if (!trans_parser->WriteTransportDescription(tinfo.description, translator,
+                                               &trans_elem, error)) {
+    return false;
+  }
+
+  elems->push_back(trans_elem);
+  return true;
+}
+
+void WriteJingleContent(const std::string name,
+                        const XmlElements& child_elems,
+                        XmlElements* elems) {
+  buzz::XmlElement* content_elem = new buzz::XmlElement(QN_JINGLE_CONTENT);
+  content_elem->SetAttr(QN_JINGLE_CONTENT_NAME, name);
+  content_elem->SetAttr(QN_CREATOR, LN_INITIATOR);
+  AddXmlChildren(content_elem, child_elems);
+
+  elems->push_back(content_elem);
+}
+
+bool WriteJingleTransportInfos(const TransportInfos& tinfos,
+                               const TransportParserMap& trans_parsers,
+                               const CandidateTranslatorMap& translators,
+                               XmlElements* elems,
+                               WriteError* error) {
+  for (TransportInfos::const_iterator tinfo = tinfos.begin();
+       tinfo != tinfos.end(); ++tinfo) {
+    XmlElements content_child_elems;
+    if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators,
+                                  &content_child_elems, error))
+
+      return false;
+
+    WriteJingleContent(tinfo->content_name, content_child_elems, elems);
+  }
+
+  return true;
+}
+
+ContentParser* GetContentParser(const ContentParserMap& content_parsers,
+                                const std::string& type) {
+  ContentParserMap::const_iterator map = content_parsers.find(type);
+  if (map == content_parsers.end()) {
+    return NULL;
+  } else {
+    return map->second;
+  }
+}
+
+bool ParseContentInfo(SignalingProtocol protocol,
+                      const std::string& name,
+                      const std::string& type,
+                      const buzz::XmlElement* elem,
+                      const ContentParserMap& parsers,
+                      ContentInfos* contents,
+                      ParseError* error) {
+  ContentParser* parser = GetContentParser(parsers, type);
+  if (parser == NULL)
+    return BadParse("unknown application content: " + type, error);
+
+  ContentDescription* desc;
+  if (!parser->ParseContent(protocol, elem, &desc, error))
+    return false;
+
+  contents->push_back(ContentInfo(name, type, desc));
+  return true;
+}
+
+bool ParseContentType(const buzz::XmlElement* parent_elem,
+                      std::string* content_type,
+                      const buzz::XmlElement** content_elem,
+                      ParseError* error) {
+  if (!RequireXmlChild(parent_elem, LN_DESCRIPTION, content_elem, error))
+    return false;
+
+  *content_type = (*content_elem)->Name().Namespace();
+  return true;
+}
+
+bool ParseGingleContentInfos(const buzz::XmlElement* session,
+                             const ContentParserMap& content_parsers,
+                             ContentInfos* contents,
+                             ParseError* error) {
+  std::string content_type;
+  const buzz::XmlElement* content_elem;
+  if (!ParseContentType(session, &content_type, &content_elem, error))
+    return false;
+
+  if (content_type == NS_GINGLE_VIDEO) {
+    // A parser parsing audio or video content should look at the
+    // namespace and only parse the codecs relevant to that namespace.
+    // We use this to control which codecs get parsed: first audio,
+    // then video.
+    rtc::scoped_ptr<buzz::XmlElement> audio_elem(
+        new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT));
+    CopyXmlChildren(content_elem, audio_elem.get());
+    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP,
+                          audio_elem.get(), content_parsers,
+                          contents, error))
+      return false;
+
+    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_VIDEO, NS_JINGLE_RTP,
+                          content_elem, content_parsers,
+                          contents, error))
+      return false;
+  } else if (content_type == NS_GINGLE_AUDIO) {
+    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP,
+                          content_elem, content_parsers,
+                          contents, error))
+      return false;
+  } else {
+    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_OTHER, content_type,
+                          content_elem, content_parsers,
+                          contents, error))
+      return false;
+  }
+  return true;
+}
+
+bool ParseJingleContentInfos(const buzz::XmlElement* jingle,
+                             const ContentParserMap& content_parsers,
+                             ContentInfos* contents,
+                             ParseError* error) {
+  for (const buzz::XmlElement* pair_elem
+           = jingle->FirstNamed(QN_JINGLE_CONTENT);
+       pair_elem != NULL;
+       pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) {
+    std::string content_name;
+    if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME,
+                        &content_name, error))
+      return false;
+
+    std::string content_type;
+    const buzz::XmlElement* content_elem;
+    if (!ParseContentType(pair_elem, &content_type, &content_elem, error))
+      return false;
+
+    if (!ParseContentInfo(PROTOCOL_JINGLE, content_name, content_type,
+                          content_elem, content_parsers,
+                          contents, error))
+      return false;
+  }
+  return true;
+}
+
+bool ParseJingleGroupInfos(const buzz::XmlElement* jingle,
+                           ContentGroups* groups,
+                           ParseError* error) {
+  for (const buzz::XmlElement* pair_elem
+           = jingle->FirstNamed(QN_JINGLE_DRAFT_GROUP);
+       pair_elem != NULL;
+       pair_elem = pair_elem->NextNamed(QN_JINGLE_DRAFT_GROUP)) {
+    std::string group_name;
+    if (!RequireXmlAttr(pair_elem, QN_JINGLE_DRAFT_GROUP_TYPE,
+                        &group_name, error))
+      return false;
+
+    ContentGroup group(group_name);
+    for (const buzz::XmlElement* child_elem
+             = pair_elem->FirstNamed(QN_JINGLE_CONTENT);
+        child_elem != NULL;
+        child_elem = child_elem->NextNamed(QN_JINGLE_CONTENT)) {
+      std::string content_name;
+      if (!RequireXmlAttr(child_elem, QN_JINGLE_CONTENT_NAME,
+                          &content_name, error))
+        return false;
+      group.AddContentName(content_name);
+    }
+    groups->push_back(group);
+  }
+  return true;
+}
+
+buzz::XmlElement* WriteContentInfo(SignalingProtocol protocol,
+                                   const ContentInfo& content,
+                                   const ContentParserMap& parsers,
+                                   WriteError* error) {
+  ContentParser* parser = GetContentParser(parsers, content.type);
+  if (parser == NULL) {
+    BadWrite("unknown content type: " + content.type, error);
+    return NULL;
+  }
+
+  buzz::XmlElement* elem = NULL;
+  if (!parser->WriteContent(protocol, content.description, &elem, error))
+    return NULL;
+
+  return elem;
+}
+
+bool IsWritable(SignalingProtocol protocol,
+                const ContentInfo& content,
+                const ContentParserMap& parsers) {
+  ContentParser* parser = GetContentParser(parsers, content.type);
+  if (parser == NULL) {
+    return false;
+  }
+
+  return parser->IsWritable(protocol, content.description);
+}
+
+bool WriteGingleContentInfos(const ContentInfos& contents,
+                             const ContentParserMap& parsers,
+                             XmlElements* elems,
+                             WriteError* error) {
+  if (contents.size() == 1 ||
+      (contents.size() == 2 &&
+       !IsWritable(PROTOCOL_GINGLE, contents.at(1), parsers))) {
+    if (contents.front().rejected) {
+      return BadWrite("Gingle protocol may not reject individual contents.",
+                      error);
+    }
+    buzz::XmlElement* elem = WriteContentInfo(
+        PROTOCOL_GINGLE, contents.front(), parsers, error);
+    if (!elem)
+      return false;
+
+    elems->push_back(elem);
+  } else if (contents.size() >= 2 &&
+             contents.at(0).type == NS_JINGLE_RTP &&
+             contents.at(1).type == NS_JINGLE_RTP) {
+     // Special-case audio + video contents so that they are "merged"
+     // into one "video" content.
+    if (contents.at(0).rejected || contents.at(1).rejected) {
+      return BadWrite("Gingle protocol may not reject individual contents.",
+                      error);
+    }
+    buzz::XmlElement* audio = WriteContentInfo(
+        PROTOCOL_GINGLE, contents.at(0), parsers, error);
+    if (!audio)
+      return false;
+
+    buzz::XmlElement* video = WriteContentInfo(
+        PROTOCOL_GINGLE, contents.at(1), parsers, error);
+    if (!video) {
+      delete audio;
+      return false;
+    }
+
+    CopyXmlChildren(audio, video);
+    elems->push_back(video);
+    delete audio;
+  } else {
+    return BadWrite("Gingle protocol may only have one content.", error);
+  }
+
+  return true;
+}
+
+const TransportInfo* GetTransportInfoByContentName(
+    const TransportInfos& tinfos, const std::string& content_name) {
+  for (TransportInfos::const_iterator tinfo = tinfos.begin();
+       tinfo != tinfos.end(); ++tinfo) {
+    if (content_name == tinfo->content_name) {
+      return &*tinfo;
+    }
+  }
+  return NULL;
+}
+
+bool WriteJingleContents(const ContentInfos& contents,
+                         const ContentParserMap& content_parsers,
+                         const TransportInfos& tinfos,
+                         const TransportParserMap& trans_parsers,
+                         const CandidateTranslatorMap& translators,
+                         XmlElements* elems,
+                         WriteError* error) {
+  for (ContentInfos::const_iterator content = contents.begin();
+       content != contents.end(); ++content) {
+    if (content->rejected) {
+      continue;
+    }
+    const TransportInfo* tinfo =
+        GetTransportInfoByContentName(tinfos, content->name);
+    if (!tinfo)
+      return BadWrite("No transport for content: " + content->name, error);
+
+    XmlElements pair_elems;
+    buzz::XmlElement* elem = WriteContentInfo(
+        PROTOCOL_JINGLE, *content, content_parsers, error);
+    if (!elem)
+      return false;
+    pair_elems.push_back(elem);
+
+    if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators,
+                                  &pair_elems, error))
+      return false;
+
+    WriteJingleContent(content->name, pair_elems, elems);
+  }
+  return true;
+}
+
+bool WriteJingleContentInfos(const ContentInfos& contents,
+                             const ContentParserMap& content_parsers,
+                             XmlElements* elems,
+                             WriteError* error) {
+  for (ContentInfos::const_iterator content = contents.begin();
+       content != contents.end(); ++content) {
+    if (content->rejected) {
+      continue;
+    }
+    XmlElements content_child_elems;
+    buzz::XmlElement* elem = WriteContentInfo(
+        PROTOCOL_JINGLE, *content, content_parsers, error);
+    if (!elem)
+      return false;
+    content_child_elems.push_back(elem);
+    WriteJingleContent(content->name, content_child_elems, elems);
+  }
+  return true;
+}
+
+bool WriteJingleGroupInfo(const ContentInfos& contents,
+                          const ContentGroups& groups,
+                          XmlElements* elems,
+                          WriteError* error) {
+  if (!groups.empty()) {
+    buzz::XmlElement* pair_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_GROUP);
+    pair_elem->SetAttr(QN_JINGLE_DRAFT_GROUP_TYPE, GROUP_TYPE_BUNDLE);
+
+    XmlElements pair_elems;
+    for (ContentInfos::const_iterator content = contents.begin();
+         content != contents.end(); ++content) {
+      buzz::XmlElement* child_elem =
+          new buzz::XmlElement(QN_JINGLE_CONTENT, false);
+      child_elem->SetAttr(QN_JINGLE_CONTENT_NAME, content->name);
+      pair_elems.push_back(child_elem);
+    }
+    AddXmlChildren(pair_elem, pair_elems);
+    elems->push_back(pair_elem);
+  }
+  return true;
+}
+
+bool ParseContentType(SignalingProtocol protocol,
+                      const buzz::XmlElement* action_elem,
+                      std::string* content_type,
+                      ParseError* error) {
+  const buzz::XmlElement* content_elem;
+  if (protocol == PROTOCOL_GINGLE) {
+    if (!ParseContentType(action_elem, content_type, &content_elem, error))
+      return false;
+
+    // Internally, we only use NS_JINGLE_RTP.
+    if (*content_type == NS_GINGLE_AUDIO ||
+        *content_type == NS_GINGLE_VIDEO)
+      *content_type = NS_JINGLE_RTP;
+  } else {
+    const buzz::XmlElement* pair_elem
+        = action_elem->FirstNamed(QN_JINGLE_CONTENT);
+    if (pair_elem == NULL)
+      return BadParse("No contents found", error);
+
+    if (!ParseContentType(pair_elem, content_type, &content_elem, error))
+      return false;
+  }
+
+  return true;
+}
+
+static bool ParseContentMessage(
+    SignalingProtocol protocol,
+    const buzz::XmlElement* action_elem,
+    bool expect_transports,
+    const ContentParserMap& content_parsers,
+    const TransportParserMap& trans_parsers,
+    const CandidateTranslatorMap& translators,
+    SessionInitiate* init,
+    ParseError* error) {
+  init->owns_contents = true;
+  if (protocol == PROTOCOL_GINGLE) {
+    if (!ParseGingleContentInfos(action_elem, content_parsers,
+                                 &init->contents, error))
+      return false;
+
+    if (expect_transports &&
+        !ParseGingleTransportInfos(action_elem, init->contents,
+                                   trans_parsers, translators,
+                                   &init->transports, error))
+      return false;
+  } else {
+    if (!ParseJingleContentInfos(action_elem, content_parsers,
+                                 &init->contents, error))
+      return false;
+    if (!ParseJingleGroupInfos(action_elem, &init->groups, error))
+      return false;
+
+    if (expect_transports &&
+        !ParseJingleTransportInfos(action_elem, init->contents,
+                                   trans_parsers, translators,
+                                   &init->transports, error))
+      return false;
+  }
+
+  return true;
+}
+
+static bool WriteContentMessage(
+    SignalingProtocol protocol,
+    const ContentInfos& contents,
+    const TransportInfos& tinfos,
+    const ContentParserMap& content_parsers,
+    const TransportParserMap& transport_parsers,
+    const CandidateTranslatorMap& translators,
+    const ContentGroups& groups,
+    XmlElements* elems,
+    WriteError* error) {
+  if (protocol == PROTOCOL_GINGLE) {
+    if (!WriteGingleContentInfos(contents, content_parsers, elems, error))
+      return false;
+
+    if (!WriteGingleTransportInfos(tinfos, transport_parsers, translators,
+                                   elems, error))
+      return false;
+  } else {
+    if (!WriteJingleContents(contents, content_parsers,
+                             tinfos, transport_parsers, translators,
+                             elems, error))
+      return false;
+    if (!WriteJingleGroupInfo(contents, groups, elems, error))
+      return false;
+  }
+
+  return true;
+}
+
+bool ParseSessionInitiate(SignalingProtocol protocol,
+                          const buzz::XmlElement* action_elem,
+                          const ContentParserMap& content_parsers,
+                          const TransportParserMap& trans_parsers,
+                          const CandidateTranslatorMap& translators,
+                          SessionInitiate* init,
+                          ParseError* error) {
+  bool expect_transports = true;
+  return ParseContentMessage(protocol, action_elem, expect_transports,
+                             content_parsers, trans_parsers, translators,
+                             init, error);
+}
+
+
+bool WriteSessionInitiate(SignalingProtocol protocol,
+                          const ContentInfos& contents,
+                          const TransportInfos& tinfos,
+                          const ContentParserMap& content_parsers,
+                          const TransportParserMap& transport_parsers,
+                          const CandidateTranslatorMap& translators,
+                          const ContentGroups& groups,
+                          XmlElements* elems,
+                          WriteError* error) {
+  return WriteContentMessage(protocol, contents, tinfos,
+                             content_parsers, transport_parsers, translators,
+                             groups,
+                             elems, error);
+}
+
+bool ParseSessionAccept(SignalingProtocol protocol,
+                        const buzz::XmlElement* action_elem,
+                        const ContentParserMap& content_parsers,
+                        const TransportParserMap& transport_parsers,
+                        const CandidateTranslatorMap& translators,
+                        SessionAccept* accept,
+                        ParseError* error) {
+  bool expect_transports = true;
+  return ParseContentMessage(protocol, action_elem, expect_transports,
+                             content_parsers, transport_parsers, translators,
+                             accept, error);
+}
+
+bool WriteSessionAccept(SignalingProtocol protocol,
+                        const ContentInfos& contents,
+                        const TransportInfos& tinfos,
+                        const ContentParserMap& content_parsers,
+                        const TransportParserMap& transport_parsers,
+                        const CandidateTranslatorMap& translators,
+                        const ContentGroups& groups,
+                        XmlElements* elems,
+                        WriteError* error) {
+  return WriteContentMessage(protocol, contents, tinfos,
+                             content_parsers, transport_parsers, translators,
+                             groups,
+                             elems, error);
+}
+
+bool ParseSessionTerminate(SignalingProtocol protocol,
+                           const buzz::XmlElement* action_elem,
+                           SessionTerminate* term,
+                           ParseError* error) {
+  if (protocol == PROTOCOL_GINGLE) {
+    const buzz::XmlElement* reason_elem = action_elem->FirstElement();
+    if (reason_elem != NULL) {
+      term->reason = reason_elem->Name().LocalPart();
+      const buzz::XmlElement *debug_elem = reason_elem->FirstElement();
+      if (debug_elem != NULL) {
+        term->debug_reason = debug_elem->Name().LocalPart();
+      }
+    }
+    return true;
+  } else {
+    const buzz::XmlElement* reason_elem =
+        action_elem->FirstNamed(QN_JINGLE_REASON);
+    if (reason_elem) {
+      reason_elem = reason_elem->FirstElement();
+      if (reason_elem) {
+        term->reason = reason_elem->Name().LocalPart();
+      }
+    }
+    return true;
+  }
+}
+
+void WriteSessionTerminate(SignalingProtocol protocol,
+                           const SessionTerminate& term,
+                           XmlElements* elems) {
+  if (protocol == PROTOCOL_GINGLE) {
+    elems->push_back(new buzz::XmlElement(buzz::QName(NS_GINGLE, term.reason)));
+  } else {
+    if (!term.reason.empty()) {
+      buzz::XmlElement* reason_elem = new buzz::XmlElement(QN_JINGLE_REASON);
+      reason_elem->AddElement(new buzz::XmlElement(
+          buzz::QName(NS_JINGLE, term.reason)));
+      elems->push_back(reason_elem);
+    }
+  }
+}
+
+bool ParseDescriptionInfo(SignalingProtocol protocol,
+                          const buzz::XmlElement* action_elem,
+                          const ContentParserMap& content_parsers,
+                          const TransportParserMap& transport_parsers,
+                          const CandidateTranslatorMap& translators,
+                          DescriptionInfo* description_info,
+                          ParseError* error) {
+  bool expect_transports = false;
+  return ParseContentMessage(protocol, action_elem, expect_transports,
+                             content_parsers, transport_parsers, translators,
+                             description_info, error);
+}
+
+bool WriteDescriptionInfo(SignalingProtocol protocol,
+                          const ContentInfos& contents,
+                          const ContentParserMap& content_parsers,
+                          XmlElements* elems,
+                          WriteError* error) {
+  if (protocol == PROTOCOL_GINGLE) {
+    return WriteGingleContentInfos(contents, content_parsers, elems, error);
+  } else {
+    return WriteJingleContentInfos(contents, content_parsers, elems, error);
+  }
+}
+
+bool ParseTransportInfos(SignalingProtocol protocol,
+                         const buzz::XmlElement* action_elem,
+                         const ContentInfos& contents,
+                         const TransportParserMap& trans_parsers,
+                         const CandidateTranslatorMap& translators,
+                         TransportInfos* tinfos,
+                         ParseError* error) {
+  if (protocol == PROTOCOL_GINGLE) {
+    return ParseGingleTransportInfos(
+        action_elem, contents, trans_parsers, translators, tinfos, error);
+  } else {
+    return ParseJingleTransportInfos(
+        action_elem, contents, trans_parsers, translators, tinfos, error);
+  }
+}
+
+bool WriteTransportInfos(SignalingProtocol protocol,
+                         const TransportInfos& tinfos,
+                         const TransportParserMap& trans_parsers,
+                         const CandidateTranslatorMap& translators,
+                         XmlElements* elems,
+                         WriteError* error) {
+  if (protocol == PROTOCOL_GINGLE) {
+    return WriteGingleTransportInfos(tinfos, trans_parsers, translators,
+                                     elems, error);
+  } else {
+    return WriteJingleTransportInfos(tinfos, trans_parsers, translators,
+                                     elems, error);
+  }
+}
+
+bool GetUriTarget(const std::string& prefix, const std::string& str,
+                  std::string* after) {
+  size_t pos = str.find(prefix);
+  if (pos == std::string::npos)
+    return false;
+
+  *after = str.substr(pos + prefix.size(), std::string::npos);
+  return true;
+}
+
+bool FindSessionRedirect(const buzz::XmlElement* stanza,
+                         SessionRedirect* redirect) {
+  const buzz::XmlElement* error_elem = GetXmlChild(stanza, LN_ERROR);
+  if (error_elem == NULL)
+    return false;
+
+  const buzz::XmlElement* redirect_elem =
+      error_elem->FirstNamed(QN_GINGLE_REDIRECT);
+  if (redirect_elem == NULL)
+    redirect_elem = error_elem->FirstNamed(buzz::QN_STANZA_REDIRECT);
+  if (redirect_elem == NULL)
+    return false;
+
+  if (!GetUriTarget(STR_REDIRECT_PREFIX, redirect_elem->BodyText(),
+                    &redirect->target))
+    return false;
+
+  return true;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/sessionmessages.h b/p2p/base/sessionmessages.h
new file mode 100644
index 0000000..7b156d4
--- /dev/null
+++ b/p2p/base/sessionmessages.h
@@ -0,0 +1,226 @@
+/*
+ *  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.
+ */
+
+#ifndef WEBRTC_P2P_BASE_SESSIONMESSAGES_H_
+#define WEBRTC_P2P_BASE_SESSIONMESSAGES_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/sessiondescription.h"  // Needed to delete contents.
+#include "webrtc/p2p/base/transportinfo.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/base/basictypes.h"
+
+namespace cricket {
+
+struct ParseError;
+struct WriteError;
+class Candidate;
+class ContentParser;
+class TransportParser;
+
+typedef std::vector<Candidate> Candidates;
+typedef std::map<std::string, ContentParser*> ContentParserMap;
+typedef std::map<std::string, TransportParser*> TransportParserMap;
+
+enum ActionType {
+  ACTION_UNKNOWN,
+
+  ACTION_SESSION_INITIATE,
+  ACTION_SESSION_INFO,
+  ACTION_SESSION_ACCEPT,
+  ACTION_SESSION_REJECT,
+  ACTION_SESSION_TERMINATE,
+
+  ACTION_TRANSPORT_INFO,
+  ACTION_TRANSPORT_ACCEPT,
+
+  ACTION_DESCRIPTION_INFO,
+};
+
+// Abstraction of a <jingle> element within an <iq> stanza, per XMPP
+// standard XEP-166.  Can be serialized into multiple protocols,
+// including the standard (Jingle) and the draft standard (Gingle).
+// In general, used to communicate actions related to a p2p session,
+// such accept, initiate, terminate, etc.
+
+struct SessionMessage {
+  SessionMessage() : action_elem(NULL), stanza(NULL) {}
+
+  SessionMessage(SignalingProtocol protocol, ActionType type,
+                 const std::string& sid, const std::string& initiator) :
+      protocol(protocol), type(type), sid(sid), initiator(initiator),
+      action_elem(NULL), stanza(NULL) {}
+
+  std::string id;
+  std::string from;
+  std::string to;
+  SignalingProtocol protocol;
+  ActionType type;
+  std::string sid;  // session id
+  std::string initiator;
+
+  // Used for further parsing when necessary.
+  // Represents <session> or <jingle>.
+  const buzz::XmlElement* action_elem;
+  // Mostly used for debugging.
+  const buzz::XmlElement* stanza;
+};
+
+// TODO: Break up this class so we don't have to typedef it into
+// different classes.
+struct ContentMessage {
+  ContentMessage() : owns_contents(false) {}
+
+  ~ContentMessage() {
+    if (owns_contents) {
+      for (ContentInfos::iterator content = contents.begin();
+           content != contents.end(); content++) {
+        delete content->description;
+      }
+    }
+  }
+
+  // Caller takes ownership of contents.
+  ContentInfos ClearContents() {
+    ContentInfos out;
+    contents.swap(out);
+    owns_contents = false;
+    return out;
+  }
+
+  bool owns_contents;
+  ContentInfos contents;
+  TransportInfos transports;
+  ContentGroups groups;
+};
+
+typedef ContentMessage SessionInitiate;
+typedef ContentMessage SessionAccept;
+// Note that a DescriptionInfo does not have TransportInfos.
+typedef ContentMessage DescriptionInfo;
+
+struct SessionTerminate {
+  SessionTerminate() {}
+
+  explicit SessionTerminate(const std::string& reason) :
+      reason(reason) {}
+
+  std::string reason;
+  std::string debug_reason;
+};
+
+struct SessionRedirect {
+  std::string target;
+};
+
+// Used during parsing and writing to map component to channel name
+// and back.  This is primarily for converting old G-ICE candidate
+// signalling to new ICE candidate classes.
+class CandidateTranslator {
+ public:
+  virtual bool GetChannelNameFromComponent(
+      int component, std::string* channel_name) const = 0;
+  virtual bool GetComponentFromChannelName(
+      const std::string& channel_name, int* component) const = 0;
+};
+
+// Content name => translator
+typedef std::map<std::string, CandidateTranslator*> CandidateTranslatorMap;
+
+bool IsSessionMessage(const buzz::XmlElement* stanza);
+bool ParseSessionMessage(const buzz::XmlElement* stanza,
+                         SessionMessage* msg,
+                         ParseError* error);
+// Will return an error if there is more than one content type.
+bool ParseContentType(SignalingProtocol protocol,
+                      const buzz::XmlElement* action_elem,
+                      std::string* content_type,
+                      ParseError* error);
+void WriteSessionMessage(const SessionMessage& msg,
+                         const XmlElements& action_elems,
+                         buzz::XmlElement* stanza);
+bool ParseSessionInitiate(SignalingProtocol protocol,
+                          const buzz::XmlElement* action_elem,
+                          const ContentParserMap& content_parsers,
+                          const TransportParserMap& transport_parsers,
+                          const CandidateTranslatorMap& translators,
+                          SessionInitiate* init,
+                          ParseError* error);
+bool WriteSessionInitiate(SignalingProtocol protocol,
+                          const ContentInfos& contents,
+                          const TransportInfos& tinfos,
+                          const ContentParserMap& content_parsers,
+                          const TransportParserMap& transport_parsers,
+                          const CandidateTranslatorMap& translators,
+                          const ContentGroups& groups,
+                          XmlElements* elems,
+                          WriteError* error);
+bool ParseSessionAccept(SignalingProtocol protocol,
+                        const buzz::XmlElement* action_elem,
+                        const ContentParserMap& content_parsers,
+                        const TransportParserMap& transport_parsers,
+                        const CandidateTranslatorMap& translators,
+                        SessionAccept* accept,
+                        ParseError* error);
+bool WriteSessionAccept(SignalingProtocol protocol,
+                        const ContentInfos& contents,
+                        const TransportInfos& tinfos,
+                        const ContentParserMap& content_parsers,
+                        const TransportParserMap& transport_parsers,
+                        const CandidateTranslatorMap& translators,
+                        const ContentGroups& groups,
+                        XmlElements* elems,
+                        WriteError* error);
+bool ParseSessionTerminate(SignalingProtocol protocol,
+                           const buzz::XmlElement* action_elem,
+                           SessionTerminate* term,
+                           ParseError* error);
+void WriteSessionTerminate(SignalingProtocol protocol,
+                           const SessionTerminate& term,
+                           XmlElements* elems);
+bool ParseDescriptionInfo(SignalingProtocol protocol,
+                          const buzz::XmlElement* action_elem,
+                          const ContentParserMap& content_parsers,
+                          const TransportParserMap& transport_parsers,
+                          const CandidateTranslatorMap& translators,
+                          DescriptionInfo* description_info,
+                          ParseError* error);
+bool WriteDescriptionInfo(SignalingProtocol protocol,
+                          const ContentInfos& contents,
+                          const ContentParserMap& content_parsers,
+                          XmlElements* elems,
+                          WriteError* error);
+// Since a TransportInfo is not a transport-info message, and a
+// transport-info message is just a collection of TransportInfos, we
+// say Parse/Write TransportInfos for transport-info messages.
+bool ParseTransportInfos(SignalingProtocol protocol,
+                         const buzz::XmlElement* action_elem,
+                         const ContentInfos& contents,
+                         const TransportParserMap& trans_parsers,
+                         const CandidateTranslatorMap& translators,
+                         TransportInfos* tinfos,
+                         ParseError* error);
+bool WriteTransportInfos(SignalingProtocol protocol,
+                         const TransportInfos& tinfos,
+                         const TransportParserMap& trans_parsers,
+                         const CandidateTranslatorMap& translators,
+                         XmlElements* elems,
+                         WriteError* error);
+// Handles both Gingle and Jingle syntax.
+bool FindSessionRedirect(const buzz::XmlElement* stanza,
+                         SessionRedirect* redirect);
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_SESSIONMESSAGES_H_
diff --git a/p2p/base/stun.cc b/p2p/base/stun.cc
new file mode 100644
index 0000000..60367fa
--- /dev/null
+++ b/p2p/base/stun.cc
@@ -0,0 +1,915 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/stun.h"
+
+#include <string.h>
+
+#include "webrtc/base/byteorder.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/crc32.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/messagedigest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/stringencode.h"
+
+using rtc::ByteBuffer;
+
+namespace cricket {
+
+const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
+const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
+const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
+const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
+const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
+const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
+const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
+const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
+const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
+const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
+const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
+
+const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
+const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
+const uint32 STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
+
+// StunMessage
+
+StunMessage::StunMessage()
+    : type_(0),
+      length_(0),
+      transaction_id_(EMPTY_TRANSACTION_ID) {
+  ASSERT(IsValidTransactionId(transaction_id_));
+  attrs_ = new std::vector<StunAttribute*>();
+}
+
+StunMessage::~StunMessage() {
+  for (size_t i = 0; i < attrs_->size(); i++)
+    delete (*attrs_)[i];
+  delete attrs_;
+}
+
+bool StunMessage::IsLegacy() const {
+  if (transaction_id_.size() == kStunLegacyTransactionIdLength)
+    return true;
+  ASSERT(transaction_id_.size() == kStunTransactionIdLength);
+  return false;
+}
+
+bool StunMessage::SetTransactionID(const std::string& str) {
+  if (!IsValidTransactionId(str)) {
+    return false;
+  }
+  transaction_id_ = str;
+  return true;
+}
+
+bool StunMessage::AddAttribute(StunAttribute* attr) {
+  // Fail any attributes that aren't valid for this type of message.
+  if (attr->value_type() != GetAttributeValueType(attr->type())) {
+    return false;
+  }
+  attrs_->push_back(attr);
+  attr->SetOwner(this);
+  size_t attr_length = attr->length();
+  if (attr_length % 4 != 0) {
+    attr_length += (4 - (attr_length % 4));
+  }
+  length_ += static_cast<uint16>(attr_length + 4);
+  return true;
+}
+
+const StunAddressAttribute* StunMessage::GetAddress(int type) const {
+  switch (type) {
+    case STUN_ATTR_MAPPED_ADDRESS: {
+      // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
+      // missing.
+      const StunAttribute* mapped_address =
+          GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
+      if (!mapped_address)
+        mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
+      return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
+    }
+
+    default:
+      return static_cast<const StunAddressAttribute*>(GetAttribute(type));
+  }
+}
+
+const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
+  return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
+}
+
+const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
+  return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
+}
+
+const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
+  return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
+}
+
+const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
+  return static_cast<const StunErrorCodeAttribute*>(
+      GetAttribute(STUN_ATTR_ERROR_CODE));
+}
+
+const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
+  return static_cast<const StunUInt16ListAttribute*>(
+      GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
+}
+
+// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
+// procedure outlined in RFC 5389, section 15.4.
+bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
+                                           const std::string& password) {
+  // Verifying the size of the message.
+  if ((size % 4) != 0) {
+    return false;
+  }
+
+  // Getting the message length from the STUN header.
+  uint16 msg_length = rtc::GetBE16(&data[2]);
+  if (size != (msg_length + kStunHeaderSize)) {
+    return false;
+  }
+
+  // Finding Message Integrity attribute in stun message.
+  size_t current_pos = kStunHeaderSize;
+  bool has_message_integrity_attr = false;
+  while (current_pos < size) {
+    uint16 attr_type, attr_length;
+    // Getting attribute type and length.
+    attr_type = rtc::GetBE16(&data[current_pos]);
+    attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
+
+    // If M-I, sanity check it, and break out.
+    if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
+      if (attr_length != kStunMessageIntegritySize ||
+          current_pos + attr_length > size) {
+        return false;
+      }
+      has_message_integrity_attr = true;
+      break;
+    }
+
+    // Otherwise, skip to the next attribute.
+    current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
+    if ((attr_length % 4) != 0) {
+      current_pos += (4 - (attr_length % 4));
+    }
+  }
+
+  if (!has_message_integrity_attr) {
+    return false;
+  }
+
+  // Getting length of the message to calculate Message Integrity.
+  size_t mi_pos = current_pos;
+  rtc::scoped_ptr<char[]> temp_data(new char[current_pos]);
+  memcpy(temp_data.get(), data, current_pos);
+  if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
+    // Stun message has other attributes after message integrity.
+    // Adjust the length parameter in stun message to calculate HMAC.
+    size_t extra_offset = size -
+        (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
+    size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
+
+    // Writing new length of the STUN message @ Message Length in temp buffer.
+    //      0                   1                   2                   3
+    //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //     |0 0|     STUN Message Type     |         Message Length        |
+    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    rtc::SetBE16(temp_data.get() + 2,
+                       static_cast<uint16>(new_adjusted_len));
+  }
+
+  char hmac[kStunMessageIntegritySize];
+  size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
+                                      password.c_str(), password.size(),
+                                      temp_data.get(), mi_pos,
+                                      hmac, sizeof(hmac));
+  ASSERT(ret == sizeof(hmac));
+  if (ret != sizeof(hmac))
+    return false;
+
+  // Comparing the calculated HMAC with the one present in the message.
+  return memcmp(data + current_pos + kStunAttributeHeaderSize,
+                hmac,
+                sizeof(hmac)) == 0;
+}
+
+bool StunMessage::AddMessageIntegrity(const std::string& password) {
+  return AddMessageIntegrity(password.c_str(), password.size());
+}
+
+bool StunMessage::AddMessageIntegrity(const char* key,
+                                      size_t keylen) {
+  // Add the attribute with a dummy value. Since this is a known attribute, it
+  // can't fail.
+  StunByteStringAttribute* msg_integrity_attr =
+      new StunByteStringAttribute(STUN_ATTR_MESSAGE_INTEGRITY,
+          std::string(kStunMessageIntegritySize, '0'));
+  VERIFY(AddAttribute(msg_integrity_attr));
+
+  // Calculate the HMAC for the message.
+  rtc::ByteBuffer buf;
+  if (!Write(&buf))
+    return false;
+
+  int msg_len_for_hmac = static_cast<int>(
+      buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
+  char hmac[kStunMessageIntegritySize];
+  size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
+                                      key, keylen,
+                                      buf.Data(), msg_len_for_hmac,
+                                      hmac, sizeof(hmac));
+  ASSERT(ret == sizeof(hmac));
+  if (ret != sizeof(hmac)) {
+    LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
+                  << "has dummy value.";
+    return false;
+  }
+
+  // Insert correct HMAC into the attribute.
+  msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
+  return true;
+}
+
+// Verifies a message is in fact a STUN message, by performing the checks
+// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
+// in section 15.5.
+bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
+  // Check the message length.
+  size_t fingerprint_attr_size =
+      kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
+  if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
+    return false;
+
+  // Skip the rest if the magic cookie isn't present.
+  const char* magic_cookie =
+      data + kStunTransactionIdOffset - kStunMagicCookieLength;
+  if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
+    return false;
+
+  // Check the fingerprint type and length.
+  const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
+  if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
+      rtc::GetBE16(fingerprint_attr_data + sizeof(uint16)) !=
+          StunUInt32Attribute::SIZE)
+    return false;
+
+  // Check the fingerprint value.
+  uint32 fingerprint =
+      rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
+  return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
+      rtc::ComputeCrc32(data, size - fingerprint_attr_size));
+}
+
+bool StunMessage::AddFingerprint() {
+  // Add the attribute with a dummy value. Since this is a known attribute,
+  // it can't fail.
+  StunUInt32Attribute* fingerprint_attr =
+     new StunUInt32Attribute(STUN_ATTR_FINGERPRINT, 0);
+  VERIFY(AddAttribute(fingerprint_attr));
+
+  // Calculate the CRC-32 for the message and insert it.
+  rtc::ByteBuffer buf;
+  if (!Write(&buf))
+    return false;
+
+  int msg_len_for_crc32 = static_cast<int>(
+      buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
+  uint32 c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
+
+  // Insert the correct CRC-32, XORed with a constant, into the attribute.
+  fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
+  return true;
+}
+
+bool StunMessage::Read(ByteBuffer* buf) {
+  if (!buf->ReadUInt16(&type_))
+    return false;
+
+  if (type_ & 0x8000) {
+    // RTP and RTCP set the MSB of first byte, since first two bits are version,
+    // and version is always 2 (10). If set, this is not a STUN packet.
+    return false;
+  }
+
+  if (!buf->ReadUInt16(&length_))
+    return false;
+
+  std::string magic_cookie;
+  if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
+    return false;
+
+  std::string transaction_id;
+  if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
+    return false;
+
+  uint32 magic_cookie_int =
+      *reinterpret_cast<const uint32*>(magic_cookie.data());
+  if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
+    // If magic cookie is invalid it means that the peer implements
+    // RFC3489 instead of RFC5389.
+    transaction_id.insert(0, magic_cookie);
+  }
+  ASSERT(IsValidTransactionId(transaction_id));
+  transaction_id_ = transaction_id;
+
+  if (length_ != buf->Length())
+    return false;
+
+  attrs_->resize(0);
+
+  size_t rest = buf->Length() - length_;
+  while (buf->Length() > rest) {
+    uint16 attr_type, attr_length;
+    if (!buf->ReadUInt16(&attr_type))
+      return false;
+    if (!buf->ReadUInt16(&attr_length))
+      return false;
+
+    StunAttribute* attr = CreateAttribute(attr_type, attr_length);
+    if (!attr) {
+      // Skip any unknown or malformed attributes.
+      if ((attr_length % 4) != 0) {
+        attr_length += (4 - (attr_length % 4));
+      }
+      if (!buf->Consume(attr_length))
+        return false;
+    } else {
+      if (!attr->Read(buf))
+        return false;
+      attrs_->push_back(attr);
+    }
+  }
+
+  ASSERT(buf->Length() == rest);
+  return true;
+}
+
+bool StunMessage::Write(ByteBuffer* buf) const {
+  buf->WriteUInt16(type_);
+  buf->WriteUInt16(length_);
+  if (!IsLegacy())
+    buf->WriteUInt32(kStunMagicCookie);
+  buf->WriteString(transaction_id_);
+
+  for (size_t i = 0; i < attrs_->size(); ++i) {
+    buf->WriteUInt16((*attrs_)[i]->type());
+    buf->WriteUInt16(static_cast<uint16>((*attrs_)[i]->length()));
+    if (!(*attrs_)[i]->Write(buf))
+      return false;
+  }
+
+  return true;
+}
+
+StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
+  switch (type) {
+    case STUN_ATTR_MAPPED_ADDRESS:      return STUN_VALUE_ADDRESS;
+    case STUN_ATTR_USERNAME:            return STUN_VALUE_BYTE_STRING;
+    case STUN_ATTR_MESSAGE_INTEGRITY:   return STUN_VALUE_BYTE_STRING;
+    case STUN_ATTR_ERROR_CODE:          return STUN_VALUE_ERROR_CODE;
+    case STUN_ATTR_UNKNOWN_ATTRIBUTES:  return STUN_VALUE_UINT16_LIST;
+    case STUN_ATTR_REALM:               return STUN_VALUE_BYTE_STRING;
+    case STUN_ATTR_NONCE:               return STUN_VALUE_BYTE_STRING;
+    case STUN_ATTR_XOR_MAPPED_ADDRESS:  return STUN_VALUE_XOR_ADDRESS;
+    case STUN_ATTR_SOFTWARE:            return STUN_VALUE_BYTE_STRING;
+    case STUN_ATTR_ALTERNATE_SERVER:    return STUN_VALUE_ADDRESS;
+    case STUN_ATTR_FINGERPRINT:         return STUN_VALUE_UINT32;
+    case STUN_ATTR_RETRANSMIT_COUNT:    return STUN_VALUE_UINT32;
+    default:                            return STUN_VALUE_UNKNOWN;
+  }
+}
+
+StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
+  StunAttributeValueType value_type = GetAttributeValueType(type);
+  return StunAttribute::Create(value_type, type,
+                               static_cast<uint16>(length), this);
+}
+
+const StunAttribute* StunMessage::GetAttribute(int type) const {
+  for (size_t i = 0; i < attrs_->size(); ++i) {
+    if ((*attrs_)[i]->type() == type)
+      return (*attrs_)[i];
+  }
+  return NULL;
+}
+
+bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
+  return transaction_id.size() == kStunTransactionIdLength ||
+      transaction_id.size() == kStunLegacyTransactionIdLength;
+}
+
+// StunAttribute
+
+StunAttribute::StunAttribute(uint16 type, uint16 length)
+    : type_(type), length_(length) {
+}
+
+void StunAttribute::ConsumePadding(rtc::ByteBuffer* buf) const {
+  int remainder = length_ % 4;
+  if (remainder > 0) {
+    buf->Consume(4 - remainder);
+  }
+}
+
+void StunAttribute::WritePadding(rtc::ByteBuffer* buf) const {
+  int remainder = length_ % 4;
+  if (remainder > 0) {
+    char zeroes[4] = {0};
+    buf->WriteBytes(zeroes, 4 - remainder);
+  }
+}
+
+StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
+                                     uint16 type, uint16 length,
+                                     StunMessage* owner) {
+  switch (value_type) {
+    case STUN_VALUE_ADDRESS:
+      return new StunAddressAttribute(type, length);
+    case STUN_VALUE_XOR_ADDRESS:
+      return new StunXorAddressAttribute(type, length, owner);
+    case STUN_VALUE_UINT32:
+      return new StunUInt32Attribute(type);
+    case STUN_VALUE_UINT64:
+      return new StunUInt64Attribute(type);
+    case STUN_VALUE_BYTE_STRING:
+      return new StunByteStringAttribute(type, length);
+    case STUN_VALUE_ERROR_CODE:
+      return new StunErrorCodeAttribute(type, length);
+    case STUN_VALUE_UINT16_LIST:
+      return new StunUInt16ListAttribute(type, length);
+    default:
+      return NULL;
+  }
+}
+
+StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) {
+  return new StunAddressAttribute(type, 0);
+}
+
+StunXorAddressAttribute* StunAttribute::CreateXorAddress(uint16 type) {
+  return new StunXorAddressAttribute(type, 0, NULL);
+}
+
+StunUInt64Attribute* StunAttribute::CreateUInt64(uint16 type) {
+  return new StunUInt64Attribute(type);
+}
+
+StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) {
+  return new StunUInt32Attribute(type);
+}
+
+StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) {
+  return new StunByteStringAttribute(type, 0);
+}
+
+StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
+  return new StunErrorCodeAttribute(
+      STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
+}
+
+StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
+  return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
+}
+
+StunAddressAttribute::StunAddressAttribute(uint16 type,
+   const rtc::SocketAddress& addr)
+   : StunAttribute(type, 0) {
+  SetAddress(addr);
+}
+
+StunAddressAttribute::StunAddressAttribute(uint16 type, uint16 length)
+    : StunAttribute(type, length) {
+}
+
+bool StunAddressAttribute::Read(ByteBuffer* buf) {
+  uint8 dummy;
+  if (!buf->ReadUInt8(&dummy))
+    return false;
+
+  uint8 stun_family;
+  if (!buf->ReadUInt8(&stun_family)) {
+    return false;
+  }
+  uint16 port;
+  if (!buf->ReadUInt16(&port))
+    return false;
+  if (stun_family == STUN_ADDRESS_IPV4) {
+    in_addr v4addr;
+    if (length() != SIZE_IP4) {
+      return false;
+    }
+    if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
+      return false;
+    }
+    rtc::IPAddress ipaddr(v4addr);
+    SetAddress(rtc::SocketAddress(ipaddr, port));
+  } else if (stun_family == STUN_ADDRESS_IPV6) {
+    in6_addr v6addr;
+    if (length() != SIZE_IP6) {
+      return false;
+    }
+    if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
+      return false;
+    }
+    rtc::IPAddress ipaddr(v6addr);
+    SetAddress(rtc::SocketAddress(ipaddr, port));
+  } else {
+    return false;
+  }
+  return true;
+}
+
+bool StunAddressAttribute::Write(ByteBuffer* buf) const {
+  StunAddressFamily address_family = family();
+  if (address_family == STUN_ADDRESS_UNDEF) {
+    LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
+    return false;
+  }
+  buf->WriteUInt8(0);
+  buf->WriteUInt8(address_family);
+  buf->WriteUInt16(address_.port());
+  switch (address_.family()) {
+    case AF_INET: {
+      in_addr v4addr = address_.ipaddr().ipv4_address();
+      buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
+      break;
+    }
+    case AF_INET6: {
+      in6_addr v6addr = address_.ipaddr().ipv6_address();
+      buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
+      break;
+    }
+  }
+  return true;
+}
+
+StunXorAddressAttribute::StunXorAddressAttribute(uint16 type,
+    const rtc::SocketAddress& addr)
+    : StunAddressAttribute(type, addr), owner_(NULL) {
+}
+
+StunXorAddressAttribute::StunXorAddressAttribute(uint16 type,
+                                                 uint16 length,
+                                                 StunMessage* owner)
+    : StunAddressAttribute(type, length), owner_(owner) {}
+
+rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
+  if (owner_) {
+    rtc::IPAddress ip = ipaddr();
+    switch (ip.family()) {
+      case AF_INET: {
+        in_addr v4addr = ip.ipv4_address();
+        v4addr.s_addr =
+            (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
+        return rtc::IPAddress(v4addr);
+      }
+      case AF_INET6: {
+        in6_addr v6addr = ip.ipv6_address();
+        const std::string& transaction_id = owner_->transaction_id();
+        if (transaction_id.length() == kStunTransactionIdLength) {
+          uint32 transactionid_as_ints[3];
+          memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
+                 transaction_id.length());
+          uint32* ip_as_ints = reinterpret_cast<uint32*>(&v6addr.s6_addr);
+          // Transaction ID is in network byte order, but magic cookie
+          // is stored in host byte order.
+          ip_as_ints[0] =
+              (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
+          ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
+          ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
+          ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
+          return rtc::IPAddress(v6addr);
+        }
+        break;
+      }
+    }
+  }
+  // Invalid ip family or transaction ID, or missing owner.
+  // Return an AF_UNSPEC address.
+  return rtc::IPAddress();
+}
+
+bool StunXorAddressAttribute::Read(ByteBuffer* buf) {
+  if (!StunAddressAttribute::Read(buf))
+    return false;
+  uint16 xoredport = port() ^ (kStunMagicCookie >> 16);
+  rtc::IPAddress xored_ip = GetXoredIP();
+  SetAddress(rtc::SocketAddress(xored_ip, xoredport));
+  return true;
+}
+
+bool StunXorAddressAttribute::Write(ByteBuffer* buf) const {
+  StunAddressFamily address_family = family();
+  if (address_family == STUN_ADDRESS_UNDEF) {
+    LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
+    return false;
+  }
+  rtc::IPAddress xored_ip = GetXoredIP();
+  if (xored_ip.family() == AF_UNSPEC) {
+    return false;
+  }
+  buf->WriteUInt8(0);
+  buf->WriteUInt8(family());
+  buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
+  switch (xored_ip.family()) {
+    case AF_INET: {
+      in_addr v4addr = xored_ip.ipv4_address();
+      buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
+      break;
+    }
+    case AF_INET6: {
+      in6_addr v6addr = xored_ip.ipv6_address();
+      buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
+      break;
+    }
+  }
+  return true;
+}
+
+StunUInt32Attribute::StunUInt32Attribute(uint16 type, uint32 value)
+    : StunAttribute(type, SIZE), bits_(value) {
+}
+
+StunUInt32Attribute::StunUInt32Attribute(uint16 type)
+    : StunAttribute(type, SIZE), bits_(0) {
+}
+
+bool StunUInt32Attribute::GetBit(size_t index) const {
+  ASSERT(index < 32);
+  return static_cast<bool>((bits_ >> index) & 0x1);
+}
+
+void StunUInt32Attribute::SetBit(size_t index, bool value) {
+  ASSERT(index < 32);
+  bits_ &= ~(1 << index);
+  bits_ |= value ? (1 << index) : 0;
+}
+
+bool StunUInt32Attribute::Read(ByteBuffer* buf) {
+  if (length() != SIZE || !buf->ReadUInt32(&bits_))
+    return false;
+  return true;
+}
+
+bool StunUInt32Attribute::Write(ByteBuffer* buf) const {
+  buf->WriteUInt32(bits_);
+  return true;
+}
+
+StunUInt64Attribute::StunUInt64Attribute(uint16 type, uint64 value)
+    : StunAttribute(type, SIZE), bits_(value) {
+}
+
+StunUInt64Attribute::StunUInt64Attribute(uint16 type)
+    : StunAttribute(type, SIZE), bits_(0) {
+}
+
+bool StunUInt64Attribute::Read(ByteBuffer* buf) {
+  if (length() != SIZE || !buf->ReadUInt64(&bits_))
+    return false;
+  return true;
+}
+
+bool StunUInt64Attribute::Write(ByteBuffer* buf) const {
+  buf->WriteUInt64(bits_);
+  return true;
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16 type)
+    : StunAttribute(type, 0), bytes_(NULL) {
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16 type,
+                                                 const std::string& str)
+    : StunAttribute(type, 0), bytes_(NULL) {
+  CopyBytes(str.c_str(), str.size());
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16 type,
+                                                 const void* bytes,
+                                                 size_t length)
+    : StunAttribute(type, 0), bytes_(NULL) {
+  CopyBytes(bytes, length);
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16 type, uint16 length)
+    : StunAttribute(type, length), bytes_(NULL) {
+}
+
+StunByteStringAttribute::~StunByteStringAttribute() {
+  delete [] bytes_;
+}
+
+void StunByteStringAttribute::CopyBytes(const char* bytes) {
+  CopyBytes(bytes, strlen(bytes));
+}
+
+void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
+  char* new_bytes = new char[length];
+  memcpy(new_bytes, bytes, length);
+  SetBytes(new_bytes, length);
+}
+
+uint8 StunByteStringAttribute::GetByte(size_t index) const {
+  ASSERT(bytes_ != NULL);
+  ASSERT(index < length());
+  return static_cast<uint8>(bytes_[index]);
+}
+
+void StunByteStringAttribute::SetByte(size_t index, uint8 value) {
+  ASSERT(bytes_ != NULL);
+  ASSERT(index < length());
+  bytes_[index] = value;
+}
+
+bool StunByteStringAttribute::Read(ByteBuffer* buf) {
+  bytes_ = new char[length()];
+  if (!buf->ReadBytes(bytes_, length())) {
+    return false;
+  }
+
+  ConsumePadding(buf);
+  return true;
+}
+
+bool StunByteStringAttribute::Write(ByteBuffer* buf) const {
+  buf->WriteBytes(bytes_, length());
+  WritePadding(buf);
+  return true;
+}
+
+void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
+  delete [] bytes_;
+  bytes_ = bytes;
+  SetLength(static_cast<uint16>(length));
+}
+
+StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, int code,
+                                               const std::string& reason)
+    : StunAttribute(type, 0) {
+  SetCode(code);
+  SetReason(reason);
+}
+
+StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, uint16 length)
+    : StunAttribute(type, length), class_(0), number_(0) {
+}
+
+StunErrorCodeAttribute::~StunErrorCodeAttribute() {
+}
+
+int StunErrorCodeAttribute::code() const {
+  return class_ * 100 + number_;
+}
+
+void StunErrorCodeAttribute::SetCode(int code) {
+  class_ = static_cast<uint8>(code / 100);
+  number_ = static_cast<uint8>(code % 100);
+}
+
+void StunErrorCodeAttribute::SetReason(const std::string& reason) {
+  SetLength(MIN_SIZE + static_cast<uint16>(reason.size()));
+  reason_ = reason;
+}
+
+bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
+  uint32 val;
+  if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
+    return false;
+
+  if ((val >> 11) != 0)
+    LOG(LS_ERROR) << "error-code bits not zero";
+
+  class_ = ((val >> 8) & 0x7);
+  number_ = (val & 0xff);
+
+  if (!buf->ReadString(&reason_, length() - 4))
+    return false;
+
+  ConsumePadding(buf);
+  return true;
+}
+
+bool StunErrorCodeAttribute::Write(ByteBuffer* buf) const {
+  buf->WriteUInt32(class_ << 8 | number_);
+  buf->WriteString(reason_);
+  WritePadding(buf);
+  return true;
+}
+
+StunUInt16ListAttribute::StunUInt16ListAttribute(uint16 type, uint16 length)
+    : StunAttribute(type, length) {
+  attr_types_ = new std::vector<uint16>();
+}
+
+StunUInt16ListAttribute::~StunUInt16ListAttribute() {
+  delete attr_types_;
+}
+
+size_t StunUInt16ListAttribute::Size() const {
+  return attr_types_->size();
+}
+
+uint16 StunUInt16ListAttribute::GetType(int index) const {
+  return (*attr_types_)[index];
+}
+
+void StunUInt16ListAttribute::SetType(int index, uint16 value) {
+  (*attr_types_)[index] = value;
+}
+
+void StunUInt16ListAttribute::AddType(uint16 value) {
+  attr_types_->push_back(value);
+  SetLength(static_cast<uint16>(attr_types_->size() * 2));
+}
+
+bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
+  if (length() % 2)
+    return false;
+
+  for (size_t i = 0; i < length() / 2; i++) {
+    uint16 attr;
+    if (!buf->ReadUInt16(&attr))
+      return false;
+    attr_types_->push_back(attr);
+  }
+  // Padding of these attributes is done in RFC 5389 style. This is
+  // slightly different from RFC3489, but it shouldn't be important.
+  // RFC3489 pads out to a 32 bit boundary by duplicating one of the
+  // entries in the list (not necessarily the last one - it's unspecified).
+  // RFC5389 pads on the end, and the bytes are always ignored.
+  ConsumePadding(buf);
+  return true;
+}
+
+bool StunUInt16ListAttribute::Write(ByteBuffer* buf) const {
+  for (size_t i = 0; i < attr_types_->size(); ++i) {
+    buf->WriteUInt16((*attr_types_)[i]);
+  }
+  WritePadding(buf);
+  return true;
+}
+
+int GetStunSuccessResponseType(int req_type) {
+  return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
+}
+
+int GetStunErrorResponseType(int req_type) {
+  return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
+}
+
+bool IsStunRequestType(int msg_type) {
+  return ((msg_type & kStunTypeMask) == 0x000);
+}
+
+bool IsStunIndicationType(int msg_type) {
+  return ((msg_type & kStunTypeMask) == 0x010);
+}
+
+bool IsStunSuccessResponseType(int msg_type) {
+  return ((msg_type & kStunTypeMask) == 0x100);
+}
+
+bool IsStunErrorResponseType(int msg_type) {
+  return ((msg_type & kStunTypeMask) == 0x110);
+}
+
+bool ComputeStunCredentialHash(const std::string& username,
+                               const std::string& realm,
+                               const std::string& password,
+                               std::string* hash) {
+  // http://tools.ietf.org/html/rfc5389#section-15.4
+  // long-term credentials will be calculated using the key and key is
+  // key = MD5(username ":" realm ":" SASLprep(password))
+  std::string input = username;
+  input += ':';
+  input += realm;
+  input += ':';
+  input += password;
+
+  char digest[rtc::MessageDigest::kMaxSize];
+  size_t size = rtc::ComputeDigest(
+      rtc::DIGEST_MD5, input.c_str(), input.size(),
+      digest, sizeof(digest));
+  if (size == 0) {
+    return false;
+  }
+
+  *hash = std::string(digest, size);
+  return true;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/stun.h b/p2p/base/stun.h
new file mode 100644
index 0000000..0f600db
--- /dev/null
+++ b/p2p/base/stun.h
@@ -0,0 +1,632 @@
+/*
+ *  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_P2P_BASE_STUN_H_
+#define WEBRTC_P2P_BASE_STUN_H_
+
+// This file contains classes for dealing with the STUN protocol, as specified
+// in RFC 5389, and its descendants.
+
+#include <string>
+#include <vector>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/bytebuffer.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace cricket {
+
+// These are the types of STUN messages defined in RFC 5389.
+enum StunMessageType {
+  STUN_BINDING_REQUEST                  = 0x0001,
+  STUN_BINDING_INDICATION               = 0x0011,
+  STUN_BINDING_RESPONSE                 = 0x0101,
+  STUN_BINDING_ERROR_RESPONSE           = 0x0111,
+};
+
+// These are all known STUN attributes, defined in RFC 5389 and elsewhere.
+// Next to each is the name of the class (T is StunTAttribute) that implements
+// that type.
+// RETRANSMIT_COUNT is the number of outstanding pings without a response at
+// the time the packet is generated.
+enum StunAttributeType {
+  STUN_ATTR_MAPPED_ADDRESS              = 0x0001,  // Address
+  STUN_ATTR_USERNAME                    = 0x0006,  // ByteString
+  STUN_ATTR_MESSAGE_INTEGRITY           = 0x0008,  // ByteString, 20 bytes
+  STUN_ATTR_ERROR_CODE                  = 0x0009,  // ErrorCode
+  STUN_ATTR_UNKNOWN_ATTRIBUTES          = 0x000a,  // UInt16List
+  STUN_ATTR_REALM                       = 0x0014,  // ByteString
+  STUN_ATTR_NONCE                       = 0x0015,  // ByteString
+  STUN_ATTR_XOR_MAPPED_ADDRESS          = 0x0020,  // XorAddress
+  STUN_ATTR_SOFTWARE                    = 0x8022,  // ByteString
+  STUN_ATTR_ALTERNATE_SERVER            = 0x8023,  // Address
+  STUN_ATTR_FINGERPRINT                 = 0x8028,  // UInt32
+  STUN_ATTR_RETRANSMIT_COUNT            = 0xFF00   // UInt32
+};
+
+// These are the types of the values associated with the attributes above.
+// This allows us to perform some basic validation when reading or adding
+// attributes. Note that these values are for our own use, and not defined in
+// RFC 5389.
+enum StunAttributeValueType {
+  STUN_VALUE_UNKNOWN                    = 0,
+  STUN_VALUE_ADDRESS                    = 1,
+  STUN_VALUE_XOR_ADDRESS                = 2,
+  STUN_VALUE_UINT32                     = 3,
+  STUN_VALUE_UINT64                     = 4,
+  STUN_VALUE_BYTE_STRING                = 5,
+  STUN_VALUE_ERROR_CODE                 = 6,
+  STUN_VALUE_UINT16_LIST                = 7
+};
+
+// These are the types of STUN addresses defined in RFC 5389.
+enum StunAddressFamily {
+  // NB: UNDEF is not part of the STUN spec.
+  STUN_ADDRESS_UNDEF                    = 0,
+  STUN_ADDRESS_IPV4                     = 1,
+  STUN_ADDRESS_IPV6                     = 2
+};
+
+// These are the types of STUN error codes defined in RFC 5389.
+enum StunErrorCode {
+  STUN_ERROR_TRY_ALTERNATE              = 300,
+  STUN_ERROR_BAD_REQUEST                = 400,
+  STUN_ERROR_UNAUTHORIZED               = 401,
+  STUN_ERROR_UNKNOWN_ATTRIBUTE          = 420,
+  STUN_ERROR_STALE_CREDENTIALS          = 430,  // GICE only
+  STUN_ERROR_STALE_NONCE                = 438,
+  STUN_ERROR_SERVER_ERROR               = 500,
+  STUN_ERROR_GLOBAL_FAILURE             = 600
+};
+
+// Strings for the error codes above.
+extern const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[];
+extern const char STUN_ERROR_REASON_BAD_REQUEST[];
+extern const char STUN_ERROR_REASON_UNAUTHORIZED[];
+extern const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[];
+extern const char STUN_ERROR_REASON_STALE_CREDENTIALS[];
+extern const char STUN_ERROR_REASON_STALE_NONCE[];
+extern const char STUN_ERROR_REASON_SERVER_ERROR[];
+
+// The mask used to determine whether a STUN message is a request/response etc.
+const uint32 kStunTypeMask = 0x0110;
+
+// STUN Attribute header length.
+const size_t kStunAttributeHeaderSize = 4;
+
+// Following values correspond to RFC5389.
+const size_t kStunHeaderSize = 20;
+const size_t kStunTransactionIdOffset = 8;
+const size_t kStunTransactionIdLength = 12;
+const uint32 kStunMagicCookie = 0x2112A442;
+const size_t kStunMagicCookieLength = sizeof(kStunMagicCookie);
+
+// Following value corresponds to an earlier version of STUN from
+// RFC3489.
+const size_t kStunLegacyTransactionIdLength = 16;
+
+// STUN Message Integrity HMAC length.
+const size_t kStunMessageIntegritySize = 20;
+
+class StunAttribute;
+class StunAddressAttribute;
+class StunXorAddressAttribute;
+class StunUInt32Attribute;
+class StunUInt64Attribute;
+class StunByteStringAttribute;
+class StunErrorCodeAttribute;
+class StunUInt16ListAttribute;
+
+// Records a complete STUN/TURN message.  Each message consists of a type and
+// any number of attributes.  Each attribute is parsed into an instance of an
+// appropriate class (see above).  The Get* methods will return instances of
+// that attribute class.
+class StunMessage {
+ public:
+  StunMessage();
+  virtual ~StunMessage();
+
+  int type() const { return type_; }
+  size_t length() const { return length_; }
+  const std::string& transaction_id() const { return transaction_id_; }
+
+  // Returns true if the message confirms to RFC3489 rather than
+  // RFC5389. The main difference between two version of the STUN
+  // protocol is the presence of the magic cookie and different length
+  // of transaction ID. For outgoing packets version of the protocol
+  // is determined by the lengths of the transaction ID.
+  bool IsLegacy() const;
+
+  void SetType(int type) { type_ = static_cast<uint16>(type); }
+  bool SetTransactionID(const std::string& str);
+
+  // Gets the desired attribute value, or NULL if no such attribute type exists.
+  const StunAddressAttribute* GetAddress(int type) const;
+  const StunUInt32Attribute* GetUInt32(int type) const;
+  const StunUInt64Attribute* GetUInt64(int type) const;
+  const StunByteStringAttribute* GetByteString(int type) const;
+
+  // Gets these specific attribute values.
+  const StunErrorCodeAttribute* GetErrorCode() const;
+  const StunUInt16ListAttribute* GetUnknownAttributes() const;
+
+  // Takes ownership of the specified attribute, verifies it is of the correct
+  // type, and adds it to the message. The return value indicates whether this
+  // was successful.
+  bool AddAttribute(StunAttribute* attr);
+
+  // Validates that a raw STUN message has a correct MESSAGE-INTEGRITY value.
+  // This can't currently be done on a StunMessage, since it is affected by
+  // padding data (which we discard when reading a StunMessage).
+  static bool ValidateMessageIntegrity(const char* data, size_t size,
+                                       const std::string& password);
+  // Adds a MESSAGE-INTEGRITY attribute that is valid for the current message.
+  bool AddMessageIntegrity(const std::string& password);
+  bool AddMessageIntegrity(const char* key, size_t keylen);
+
+  // Verifies that a given buffer is STUN by checking for a correct FINGERPRINT.
+  static bool ValidateFingerprint(const char* data, size_t size);
+
+  // Adds a FINGERPRINT attribute that is valid for the current message.
+  bool AddFingerprint();
+
+  // Parses the STUN packet in the given buffer and records it here. The
+  // return value indicates whether this was successful.
+  bool Read(rtc::ByteBuffer* buf);
+
+  // Writes this object into a STUN packet. The return value indicates whether
+  // this was successful.
+  bool Write(rtc::ByteBuffer* buf) const;
+
+  // Creates an empty message. Overridable by derived classes.
+  virtual StunMessage* CreateNew() const { return new StunMessage(); }
+
+ protected:
+  // Verifies that the given attribute is allowed for this message.
+  virtual StunAttributeValueType GetAttributeValueType(int type) const;
+
+ private:
+  StunAttribute* CreateAttribute(int type, size_t length) /* const*/;
+  const StunAttribute* GetAttribute(int type) const;
+  static bool IsValidTransactionId(const std::string& transaction_id);
+
+  uint16 type_;
+  uint16 length_;
+  std::string transaction_id_;
+  std::vector<StunAttribute*>* attrs_;
+};
+
+// Base class for all STUN/TURN attributes.
+class StunAttribute {
+ public:
+  virtual ~StunAttribute() {
+  }
+
+  int type() const { return type_; }
+  size_t length() const { return length_; }
+
+  // Return the type of this attribute.
+  virtual StunAttributeValueType value_type() const = 0;
+
+  // Only XorAddressAttribute needs this so far.
+  virtual void SetOwner(StunMessage* owner) {}
+
+  // Reads the body (not the type or length) for this type of attribute from
+  // the given buffer.  Return value is true if successful.
+  virtual bool Read(rtc::ByteBuffer* buf) = 0;
+
+  // Writes the body (not the type or length) to the given buffer.  Return
+  // value is true if successful.
+  virtual bool Write(rtc::ByteBuffer* buf) const = 0;
+
+  // Creates an attribute object with the given type and smallest length.
+  static StunAttribute* Create(StunAttributeValueType value_type, uint16 type,
+                               uint16 length, StunMessage* owner);
+  // TODO: Allow these create functions to take parameters, to reduce
+  // the amount of work callers need to do to initialize attributes.
+  static StunAddressAttribute* CreateAddress(uint16 type);
+  static StunXorAddressAttribute* CreateXorAddress(uint16 type);
+  static StunUInt32Attribute* CreateUInt32(uint16 type);
+  static StunUInt64Attribute* CreateUInt64(uint16 type);
+  static StunByteStringAttribute* CreateByteString(uint16 type);
+  static StunErrorCodeAttribute* CreateErrorCode();
+  static StunUInt16ListAttribute* CreateUnknownAttributes();
+
+ protected:
+  StunAttribute(uint16 type, uint16 length);
+  void SetLength(uint16 length) { length_ = length; }
+  void WritePadding(rtc::ByteBuffer* buf) const;
+  void ConsumePadding(rtc::ByteBuffer* buf) const;
+
+ private:
+  uint16 type_;
+  uint16 length_;
+};
+
+// Implements STUN attributes that record an Internet address.
+class StunAddressAttribute : public StunAttribute {
+ public:
+  static const uint16 SIZE_UNDEF = 0;
+  static const uint16 SIZE_IP4 = 8;
+  static const uint16 SIZE_IP6 = 20;
+  StunAddressAttribute(uint16 type, const rtc::SocketAddress& addr);
+  StunAddressAttribute(uint16 type, uint16 length);
+
+  virtual StunAttributeValueType value_type() const {
+    return STUN_VALUE_ADDRESS;
+  }
+
+  StunAddressFamily family() const {
+    switch (address_.ipaddr().family()) {
+      case AF_INET:
+        return STUN_ADDRESS_IPV4;
+      case AF_INET6:
+        return STUN_ADDRESS_IPV6;
+    }
+    return STUN_ADDRESS_UNDEF;
+  }
+
+  const rtc::SocketAddress& GetAddress() const { return address_; }
+  const rtc::IPAddress& ipaddr() const { return address_.ipaddr(); }
+  uint16 port() const { return address_.port(); }
+
+  void SetAddress(const rtc::SocketAddress& addr) {
+    address_ = addr;
+    EnsureAddressLength();
+  }
+  void SetIP(const rtc::IPAddress& ip) {
+    address_.SetIP(ip);
+    EnsureAddressLength();
+  }
+  void SetPort(uint16 port) { address_.SetPort(port); }
+
+  virtual bool Read(rtc::ByteBuffer* buf);
+  virtual bool Write(rtc::ByteBuffer* buf) const;
+
+ private:
+  void EnsureAddressLength() {
+    switch (family()) {
+      case STUN_ADDRESS_IPV4: {
+        SetLength(SIZE_IP4);
+        break;
+      }
+      case STUN_ADDRESS_IPV6: {
+        SetLength(SIZE_IP6);
+        break;
+      }
+      default: {
+        SetLength(SIZE_UNDEF);
+        break;
+      }
+    }
+  }
+  rtc::SocketAddress address_;
+};
+
+// Implements STUN attributes that record an Internet address. When encoded
+// in a STUN message, the address contained in this attribute is XORed with the
+// transaction ID of the message.
+class StunXorAddressAttribute : public StunAddressAttribute {
+ public:
+  StunXorAddressAttribute(uint16 type, const rtc::SocketAddress& addr);
+  StunXorAddressAttribute(uint16 type, uint16 length,
+                          StunMessage* owner);
+
+  virtual StunAttributeValueType value_type() const {
+    return STUN_VALUE_XOR_ADDRESS;
+  }
+  virtual void SetOwner(StunMessage* owner) {
+    owner_ = owner;
+  }
+  virtual bool Read(rtc::ByteBuffer* buf);
+  virtual bool Write(rtc::ByteBuffer* buf) const;
+
+ private:
+  rtc::IPAddress GetXoredIP() const;
+  StunMessage* owner_;
+};
+
+// Implements STUN attributes that record a 32-bit integer.
+class StunUInt32Attribute : public StunAttribute {
+ public:
+  static const uint16 SIZE = 4;
+  StunUInt32Attribute(uint16 type, uint32 value);
+  explicit StunUInt32Attribute(uint16 type);
+
+  virtual StunAttributeValueType value_type() const {
+    return STUN_VALUE_UINT32;
+  }
+
+  uint32 value() const { return bits_; }
+  void SetValue(uint32 bits) { bits_ = bits; }
+
+  bool GetBit(size_t index) const;
+  void SetBit(size_t index, bool value);
+
+  virtual bool Read(rtc::ByteBuffer* buf);
+  virtual bool Write(rtc::ByteBuffer* buf) const;
+
+ private:
+  uint32 bits_;
+};
+
+class StunUInt64Attribute : public StunAttribute {
+ public:
+  static const uint16 SIZE = 8;
+  StunUInt64Attribute(uint16 type, uint64 value);
+  explicit StunUInt64Attribute(uint16 type);
+
+  virtual StunAttributeValueType value_type() const {
+    return STUN_VALUE_UINT64;
+  }
+
+  uint64 value() const { return bits_; }
+  void SetValue(uint64 bits) { bits_ = bits; }
+
+  virtual bool Read(rtc::ByteBuffer* buf);
+  virtual bool Write(rtc::ByteBuffer* buf) const;
+
+ private:
+  uint64 bits_;
+};
+
+// Implements STUN attributes that record an arbitrary byte string.
+class StunByteStringAttribute : public StunAttribute {
+ public:
+  explicit StunByteStringAttribute(uint16 type);
+  StunByteStringAttribute(uint16 type, const std::string& str);
+  StunByteStringAttribute(uint16 type, const void* bytes, size_t length);
+  StunByteStringAttribute(uint16 type, uint16 length);
+  ~StunByteStringAttribute();
+
+  virtual StunAttributeValueType value_type() const {
+    return STUN_VALUE_BYTE_STRING;
+  }
+
+  const char* bytes() const { return bytes_; }
+  std::string GetString() const { return std::string(bytes_, length()); }
+
+  void CopyBytes(const char* bytes);  // uses strlen
+  void CopyBytes(const void* bytes, size_t length);
+
+  uint8 GetByte(size_t index) const;
+  void SetByte(size_t index, uint8 value);
+
+  virtual bool Read(rtc::ByteBuffer* buf);
+  virtual bool Write(rtc::ByteBuffer* buf) const;
+
+ private:
+  void SetBytes(char* bytes, size_t length);
+
+  char* bytes_;
+};
+
+// Implements STUN attributes that record an error code.
+class StunErrorCodeAttribute : public StunAttribute {
+ public:
+  static const uint16 MIN_SIZE = 4;
+  StunErrorCodeAttribute(uint16 type, int code, const std::string& reason);
+  StunErrorCodeAttribute(uint16 type, uint16 length);
+  ~StunErrorCodeAttribute();
+
+  virtual StunAttributeValueType value_type() const {
+    return STUN_VALUE_ERROR_CODE;
+  }
+
+  // The combined error and class, e.g. 0x400.
+  int code() const;
+  void SetCode(int code);
+
+  // The individual error components.
+  int eclass() const { return class_; }
+  int number() const { return number_; }
+  const std::string& reason() const { return reason_; }
+  void SetClass(uint8 eclass) { class_ = eclass; }
+  void SetNumber(uint8 number) { number_ = number; }
+  void SetReason(const std::string& reason);
+
+  bool Read(rtc::ByteBuffer* buf);
+  bool Write(rtc::ByteBuffer* buf) const;
+
+ private:
+  uint8 class_;
+  uint8 number_;
+  std::string reason_;
+};
+
+// Implements STUN attributes that record a list of attribute names.
+class StunUInt16ListAttribute : public StunAttribute {
+ public:
+  StunUInt16ListAttribute(uint16 type, uint16 length);
+  ~StunUInt16ListAttribute();
+
+  virtual StunAttributeValueType value_type() const {
+    return STUN_VALUE_UINT16_LIST;
+  }
+
+  size_t Size() const;
+  uint16 GetType(int index) const;
+  void SetType(int index, uint16 value);
+  void AddType(uint16 value);
+
+  bool Read(rtc::ByteBuffer* buf);
+  bool Write(rtc::ByteBuffer* buf) const;
+
+ private:
+  std::vector<uint16>* attr_types_;
+};
+
+// Returns the (successful) response type for the given request type.
+// Returns -1 if |request_type| is not a valid request type.
+int GetStunSuccessResponseType(int request_type);
+
+// Returns the error response type for the given request type.
+// Returns -1 if |request_type| is not a valid request type.
+int GetStunErrorResponseType(int request_type);
+
+// Returns whether a given message is a request type.
+bool IsStunRequestType(int msg_type);
+
+// Returns whether a given message is an indication type.
+bool IsStunIndicationType(int msg_type);
+
+// Returns whether a given response is a success type.
+bool IsStunSuccessResponseType(int msg_type);
+
+// Returns whether a given response is an error type.
+bool IsStunErrorResponseType(int msg_type);
+
+// Computes the STUN long-term credential hash.
+bool ComputeStunCredentialHash(const std::string& username,
+    const std::string& realm, const std::string& password, std::string* hash);
+
+// TODO: Move the TURN/ICE stuff below out to separate files.
+extern const char TURN_MAGIC_COOKIE_VALUE[4];
+
+// "GTURN" STUN methods.
+// TODO: Rename these methods to GTURN_ to make it clear they aren't
+// part of standard STUN/TURN.
+enum RelayMessageType {
+  // For now, using the same defs from TurnMessageType below.
+  // STUN_ALLOCATE_REQUEST              = 0x0003,
+  // STUN_ALLOCATE_RESPONSE             = 0x0103,
+  // STUN_ALLOCATE_ERROR_RESPONSE       = 0x0113,
+  STUN_SEND_REQUEST                     = 0x0004,
+  STUN_SEND_RESPONSE                    = 0x0104,
+  STUN_SEND_ERROR_RESPONSE              = 0x0114,
+  STUN_DATA_INDICATION                  = 0x0115,
+};
+
+// "GTURN"-specific STUN attributes.
+// TODO: Rename these attributes to GTURN_ to avoid conflicts.
+enum RelayAttributeType {
+  STUN_ATTR_LIFETIME                    = 0x000d,  // UInt32
+  STUN_ATTR_MAGIC_COOKIE                = 0x000f,  // ByteString, 4 bytes
+  STUN_ATTR_BANDWIDTH                   = 0x0010,  // UInt32
+  STUN_ATTR_DESTINATION_ADDRESS         = 0x0011,  // Address
+  STUN_ATTR_SOURCE_ADDRESS2             = 0x0012,  // Address
+  STUN_ATTR_DATA                        = 0x0013,  // ByteString
+  STUN_ATTR_OPTIONS                     = 0x8001,  // UInt32
+};
+
+// A "GTURN" STUN message.
+class RelayMessage : public StunMessage {
+ protected:
+  virtual StunAttributeValueType GetAttributeValueType(int type) const {
+    switch (type) {
+      case STUN_ATTR_LIFETIME:            return STUN_VALUE_UINT32;
+      case STUN_ATTR_MAGIC_COOKIE:        return STUN_VALUE_BYTE_STRING;
+      case STUN_ATTR_BANDWIDTH:           return STUN_VALUE_UINT32;
+      case STUN_ATTR_DESTINATION_ADDRESS: return STUN_VALUE_ADDRESS;
+      case STUN_ATTR_SOURCE_ADDRESS2:     return STUN_VALUE_ADDRESS;
+      case STUN_ATTR_DATA:                return STUN_VALUE_BYTE_STRING;
+      case STUN_ATTR_OPTIONS:             return STUN_VALUE_UINT32;
+      default: return StunMessage::GetAttributeValueType(type);
+    }
+  }
+  virtual StunMessage* CreateNew() const { return new RelayMessage(); }
+};
+
+// Defined in TURN RFC 5766.
+enum TurnMessageType {
+  STUN_ALLOCATE_REQUEST                 = 0x0003,
+  STUN_ALLOCATE_RESPONSE                = 0x0103,
+  STUN_ALLOCATE_ERROR_RESPONSE          = 0x0113,
+  TURN_REFRESH_REQUEST                  = 0x0004,
+  TURN_REFRESH_RESPONSE                 = 0x0104,
+  TURN_REFRESH_ERROR_RESPONSE           = 0x0114,
+  TURN_SEND_INDICATION                  = 0x0016,
+  TURN_DATA_INDICATION                  = 0x0017,
+  TURN_CREATE_PERMISSION_REQUEST        = 0x0008,
+  TURN_CREATE_PERMISSION_RESPONSE       = 0x0108,
+  TURN_CREATE_PERMISSION_ERROR_RESPONSE = 0x0118,
+  TURN_CHANNEL_BIND_REQUEST             = 0x0009,
+  TURN_CHANNEL_BIND_RESPONSE            = 0x0109,
+  TURN_CHANNEL_BIND_ERROR_RESPONSE      = 0x0119,
+};
+
+enum TurnAttributeType {
+  STUN_ATTR_CHANNEL_NUMBER              = 0x000C,  // UInt32
+  STUN_ATTR_TURN_LIFETIME               = 0x000d,  // UInt32
+  STUN_ATTR_XOR_PEER_ADDRESS            = 0x0012,  // XorAddress
+  // TODO(mallinath) - Uncomment after RelayAttributes are renamed.
+  // STUN_ATTR_DATA                     = 0x0013,  // ByteString
+  STUN_ATTR_XOR_RELAYED_ADDRESS         = 0x0016,  // XorAddress
+  STUN_ATTR_EVEN_PORT                   = 0x0018,  // ByteString, 1 byte.
+  STUN_ATTR_REQUESTED_TRANSPORT         = 0x0019,  // UInt32
+  STUN_ATTR_DONT_FRAGMENT               = 0x001A,  // No content, Length = 0
+  STUN_ATTR_RESERVATION_TOKEN           = 0x0022,  // ByteString, 8 bytes.
+  // TODO(mallinath) - Rename STUN_ATTR_TURN_LIFETIME to STUN_ATTR_LIFETIME and
+  // STUN_ATTR_TURN_DATA to STUN_ATTR_DATA. Also rename RelayMessage attributes
+  // by appending G to attribute name.
+};
+
+// RFC 5766-defined errors.
+enum TurnErrorType {
+  STUN_ERROR_FORBIDDEN                  = 403,
+  STUN_ERROR_ALLOCATION_MISMATCH        = 437,
+  STUN_ERROR_WRONG_CREDENTIALS          = 441,
+  STUN_ERROR_UNSUPPORTED_PROTOCOL       = 442
+};
+extern const char STUN_ERROR_REASON_FORBIDDEN[];
+extern const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[];
+extern const char STUN_ERROR_REASON_WRONG_CREDENTIALS[];
+extern const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[];
+class TurnMessage : public StunMessage {
+ protected:
+  virtual StunAttributeValueType GetAttributeValueType(int type) const {
+    switch (type) {
+      case STUN_ATTR_CHANNEL_NUMBER:      return STUN_VALUE_UINT32;
+      case STUN_ATTR_TURN_LIFETIME:       return STUN_VALUE_UINT32;
+      case STUN_ATTR_XOR_PEER_ADDRESS:    return STUN_VALUE_XOR_ADDRESS;
+      case STUN_ATTR_DATA:                return STUN_VALUE_BYTE_STRING;
+      case STUN_ATTR_XOR_RELAYED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
+      case STUN_ATTR_EVEN_PORT:           return STUN_VALUE_BYTE_STRING;
+      case STUN_ATTR_REQUESTED_TRANSPORT: return STUN_VALUE_UINT32;
+      case STUN_ATTR_DONT_FRAGMENT:       return STUN_VALUE_BYTE_STRING;
+      case STUN_ATTR_RESERVATION_TOKEN:   return STUN_VALUE_BYTE_STRING;
+      default: return StunMessage::GetAttributeValueType(type);
+    }
+  }
+  virtual StunMessage* CreateNew() const { return new TurnMessage(); }
+};
+
+// RFC 5245 ICE STUN attributes.
+enum IceAttributeType {
+  STUN_ATTR_PRIORITY                    = 0x0024,  // UInt32
+  STUN_ATTR_USE_CANDIDATE               = 0x0025,  // No content, Length = 0
+  STUN_ATTR_ICE_CONTROLLED              = 0x8029,  // UInt64
+  STUN_ATTR_ICE_CONTROLLING             = 0x802A   // UInt64
+};
+
+// RFC 5245-defined errors.
+enum IceErrorCode {
+  STUN_ERROR_ROLE_CONFLICT              = 487,
+};
+extern const char STUN_ERROR_REASON_ROLE_CONFLICT[];
+
+// A RFC 5245 ICE STUN message.
+class IceMessage : public StunMessage {
+ protected:
+  virtual StunAttributeValueType GetAttributeValueType(int type) const {
+    switch (type) {
+      case STUN_ATTR_PRIORITY:        return STUN_VALUE_UINT32;
+      case STUN_ATTR_USE_CANDIDATE:   return STUN_VALUE_BYTE_STRING;
+      case STUN_ATTR_ICE_CONTROLLED:  return STUN_VALUE_UINT64;
+      case STUN_ATTR_ICE_CONTROLLING: return STUN_VALUE_UINT64;
+      default: return StunMessage::GetAttributeValueType(type);
+    }
+  }
+  virtual StunMessage* CreateNew() const { return new IceMessage(); }
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_STUN_H_
diff --git a/p2p/base/stun_unittest.cc b/p2p/base/stun_unittest.cc
new file mode 100644
index 0000000..396beb6
--- /dev/null
+++ b/p2p/base/stun_unittest.cc
@@ -0,0 +1,1402 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/bytebuffer.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/messagedigest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace cricket {
+
+class StunTest : public ::testing::Test {
+ protected:
+  void CheckStunHeader(const StunMessage& msg, StunMessageType expected_type,
+                       size_t expected_length) {
+    ASSERT_EQ(expected_type, msg.type());
+    ASSERT_EQ(expected_length, msg.length());
+  }
+
+  void CheckStunTransactionID(const StunMessage& msg,
+                              const unsigned char* expectedID, size_t length) {
+    ASSERT_EQ(length, msg.transaction_id().size());
+    ASSERT_EQ(length == kStunTransactionIdLength + 4, msg.IsLegacy());
+    ASSERT_EQ(length == kStunTransactionIdLength, !msg.IsLegacy());
+    ASSERT_EQ(0, memcmp(msg.transaction_id().c_str(), expectedID, length));
+  }
+
+  void CheckStunAddressAttribute(const StunAddressAttribute* addr,
+                                 StunAddressFamily expected_family,
+                                 int expected_port,
+                                 rtc::IPAddress expected_address) {
+    ASSERT_EQ(expected_family, addr->family());
+    ASSERT_EQ(expected_port, addr->port());
+
+    if (addr->family() == STUN_ADDRESS_IPV4) {
+      in_addr v4_address = expected_address.ipv4_address();
+      in_addr stun_address = addr->ipaddr().ipv4_address();
+      ASSERT_EQ(0, memcmp(&v4_address, &stun_address, sizeof(stun_address)));
+    } else if (addr->family() == STUN_ADDRESS_IPV6) {
+      in6_addr v6_address = expected_address.ipv6_address();
+      in6_addr stun_address = addr->ipaddr().ipv6_address();
+      ASSERT_EQ(0, memcmp(&v6_address, &stun_address, sizeof(stun_address)));
+    } else {
+      ASSERT_TRUE(addr->family() == STUN_ADDRESS_IPV6 ||
+                  addr->family() == STUN_ADDRESS_IPV4);
+    }
+  }
+
+  size_t ReadStunMessageTestCase(StunMessage* msg,
+                                 const unsigned char* testcase,
+                                 size_t size) {
+    const char* input = reinterpret_cast<const char*>(testcase);
+    rtc::ByteBuffer buf(input, size);
+    if (msg->Read(&buf)) {
+      // Returns the size the stun message should report itself as being
+      return (size - 20);
+    } else {
+      return 0;
+    }
+  }
+};
+
+
+// Sample STUN packets with various attributes
+// Gathered by wiresharking pjproject's pjnath test programs
+// pjproject available at www.pjsip.org
+
+static const unsigned char kStunMessageWithIPv6MappedAddress[] = {
+  0x00, 0x01, 0x00, 0x18,  // message header
+  0x21, 0x12, 0xa4, 0x42,  // transaction id
+  0x29, 0x1f, 0xcd, 0x7c,
+  0xba, 0x58, 0xab, 0xd7,
+  0xf2, 0x41, 0x01, 0x00,
+  0x00, 0x01, 0x00, 0x14,  // Address type (mapped), length
+  0x00, 0x02, 0xb8, 0x81,  // family (IPv6), port
+  0x24, 0x01, 0xfa, 0x00,  // an IPv6 address
+  0x00, 0x04, 0x10, 0x00,
+  0xbe, 0x30, 0x5b, 0xff,
+  0xfe, 0xe5, 0x00, 0xc3
+};
+
+static const unsigned char kStunMessageWithIPv4MappedAddress[] = {
+  0x01, 0x01, 0x00, 0x0c,   // binding response, length 12
+  0x21, 0x12, 0xa4, 0x42,   // magic cookie
+  0x29, 0x1f, 0xcd, 0x7c,   // transaction ID
+  0xba, 0x58, 0xab, 0xd7,
+  0xf2, 0x41, 0x01, 0x00,
+  0x00, 0x01, 0x00, 0x08,  // Mapped, 8 byte length
+  0x00, 0x01, 0x9d, 0xfc,  // AF_INET, unxor-ed port
+  0xac, 0x17, 0x44, 0xe6   // IPv4 address
+};
+
+// Test XOR-mapped IP addresses:
+static const unsigned char kStunMessageWithIPv6XorMappedAddress[] = {
+  0x01, 0x01, 0x00, 0x18,  // message header (binding response)
+  0x21, 0x12, 0xa4, 0x42,  // magic cookie (rfc5389)
+  0xe3, 0xa9, 0x46, 0xe1,  // transaction ID
+  0x7c, 0x00, 0xc2, 0x62,
+  0x54, 0x08, 0x01, 0x00,
+  0x00, 0x20, 0x00, 0x14,  // Address Type (XOR), length
+  0x00, 0x02, 0xcb, 0x5b,  // family, XOR-ed port
+  0x05, 0x13, 0x5e, 0x42,  // XOR-ed IPv6 address
+  0xe3, 0xad, 0x56, 0xe1,
+  0xc2, 0x30, 0x99, 0x9d,
+  0xaa, 0xed, 0x01, 0xc3
+};
+
+static const unsigned char kStunMessageWithIPv4XorMappedAddress[] = {
+  0x01, 0x01, 0x00, 0x0c,  // message header (binding response)
+  0x21, 0x12, 0xa4, 0x42,  // magic cookie
+  0x29, 0x1f, 0xcd, 0x7c,  // transaction ID
+  0xba, 0x58, 0xab, 0xd7,
+  0xf2, 0x41, 0x01, 0x00,
+  0x00, 0x20, 0x00, 0x08,  // address type (xor), length
+  0x00, 0x01, 0xfc, 0xb5,  // family (AF_INET), XOR-ed port
+  0x8d, 0x05, 0xe0, 0xa4   // IPv4 address
+};
+
+// ByteString Attribute (username)
+static const unsigned char kStunMessageWithByteStringAttribute[] = {
+  0x00, 0x01, 0x00, 0x0c,
+  0x21, 0x12, 0xa4, 0x42,
+  0xe3, 0xa9, 0x46, 0xe1,
+  0x7c, 0x00, 0xc2, 0x62,
+  0x54, 0x08, 0x01, 0x00,
+  0x00, 0x06, 0x00, 0x08,  // username attribute (length 8)
+  0x61, 0x62, 0x63, 0x64,  // abcdefgh
+  0x65, 0x66, 0x67, 0x68
+};
+
+// Message with an unknown but comprehensible optional attribute.
+// Parsing should succeed despite this unknown attribute.
+static const unsigned char kStunMessageWithUnknownAttribute[] = {
+  0x00, 0x01, 0x00, 0x14,
+  0x21, 0x12, 0xa4, 0x42,
+  0xe3, 0xa9, 0x46, 0xe1,
+  0x7c, 0x00, 0xc2, 0x62,
+  0x54, 0x08, 0x01, 0x00,
+  0x00, 0xaa, 0x00, 0x07,  // Unknown attribute, length 7 (needs padding!)
+  0x61, 0x62, 0x63, 0x64,  // abcdefg + padding
+  0x65, 0x66, 0x67, 0x00,
+  0x00, 0x06, 0x00, 0x03,  // Followed by a known attribute we can
+  0x61, 0x62, 0x63, 0x00   // check for (username of length 3)
+};
+
+// ByteString Attribute (username) with padding byte
+static const unsigned char kStunMessageWithPaddedByteStringAttribute[] = {
+  0x00, 0x01, 0x00, 0x08,
+  0x21, 0x12, 0xa4, 0x42,
+  0xe3, 0xa9, 0x46, 0xe1,
+  0x7c, 0x00, 0xc2, 0x62,
+  0x54, 0x08, 0x01, 0x00,
+  0x00, 0x06, 0x00, 0x03,  // username attribute (length 3)
+  0x61, 0x62, 0x63, 0xcc   // abc
+};
+
+// Message with an Unknown Attributes (uint16 list) attribute.
+static const unsigned char kStunMessageWithUInt16ListAttribute[] = {
+  0x00, 0x01, 0x00, 0x0c,
+  0x21, 0x12, 0xa4, 0x42,
+  0xe3, 0xa9, 0x46, 0xe1,
+  0x7c, 0x00, 0xc2, 0x62,
+  0x54, 0x08, 0x01, 0x00,
+  0x00, 0x0a, 0x00, 0x06,  // username attribute (length 6)
+  0x00, 0x01, 0x10, 0x00,  // three attributes plus padding
+  0xAB, 0xCU, 0xBE, 0xEF
+};
+
+// Error response message (unauthorized)
+static const unsigned char kStunMessageWithErrorAttribute[] = {
+  0x01, 0x11, 0x00, 0x14,
+  0x21, 0x12, 0xa4, 0x42,
+  0x29, 0x1f, 0xcd, 0x7c,
+  0xba, 0x58, 0xab, 0xd7,
+  0xf2, 0x41, 0x01, 0x00,
+  0x00, 0x09, 0x00, 0x10,
+  0x00, 0x00, 0x04, 0x01,
+  0x55, 0x6e, 0x61, 0x75,
+  0x74, 0x68, 0x6f, 0x72,
+  0x69, 0x7a, 0x65, 0x64
+};
+
+// Sample messages with an invalid length Field
+
+// The actual length in bytes of the invalid messages (including STUN header)
+static const int kRealLengthOfInvalidLengthTestCases = 32;
+
+static const unsigned char kStunMessageWithZeroLength[] = {
+  0x00, 0x01, 0x00, 0x00,  // length of 0 (last 2 bytes)
+  0x21, 0x12, 0xA4, 0x42,  // magic cookie
+  '0', '1', '2', '3',      // transaction id
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+  0x00, 0x20, 0x00, 0x08,  // xor mapped address
+  0x00, 0x01, 0x21, 0x1F,
+  0x21, 0x12, 0xA4, 0x53,
+};
+
+static const unsigned char kStunMessageWithExcessLength[] = {
+  0x00, 0x01, 0x00, 0x55,  // length of 85
+  0x21, 0x12, 0xA4, 0x42,  // magic cookie
+  '0', '1', '2', '3',      // transaction id
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+  0x00, 0x20, 0x00, 0x08,  // xor mapped address
+  0x00, 0x01, 0x21, 0x1F,
+  0x21, 0x12, 0xA4, 0x53,
+};
+
+static const unsigned char kStunMessageWithSmallLength[] = {
+  0x00, 0x01, 0x00, 0x03,  // length of 3
+  0x21, 0x12, 0xA4, 0x42,  // magic cookie
+  '0', '1', '2', '3',      // transaction id
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+  0x00, 0x20, 0x00, 0x08,  // xor mapped address
+  0x00, 0x01, 0x21, 0x1F,
+  0x21, 0x12, 0xA4, 0x53,
+};
+
+// RTCP packet, for testing we correctly ignore non stun packet types.
+// V=2, P=false, RC=0, Type=200, Len=6, Sender-SSRC=85, etc
+static const unsigned char kRtcpPacket[] = {
+  0x80, 0xc8, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55,
+  0xce, 0xa5, 0x18, 0x3a, 0x39, 0xcc, 0x7d, 0x09,
+  0x23, 0xed, 0x19, 0x07, 0x00, 0x00, 0x01, 0x56,
+  0x00, 0x03, 0x73, 0x50,
+};
+
+// RFC5769 Test Vectors
+// Software name (request):  "STUN test client" (without quotes)
+// Software name (response): "test vector" (without quotes)
+// Username:  "evtj:h6vY" (without quotes)
+// Password:  "VOkJxbRl1RmTxUk/WvJxBt" (without quotes)
+static const unsigned char kRfc5769SampleMsgTransactionId[] = {
+  0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae
+};
+static const char kRfc5769SampleMsgClientSoftware[] = "STUN test client";
+static const char kRfc5769SampleMsgServerSoftware[] = "test vector";
+static const char kRfc5769SampleMsgUsername[] = "evtj:h6vY";
+static const char kRfc5769SampleMsgPassword[] = "VOkJxbRl1RmTxUk/WvJxBt";
+static const rtc::SocketAddress kRfc5769SampleMsgMappedAddress(
+    "192.0.2.1", 32853);
+static const rtc::SocketAddress kRfc5769SampleMsgIPv6MappedAddress(
+    "2001:db8:1234:5678:11:2233:4455:6677", 32853);
+
+static const unsigned char kRfc5769SampleMsgWithAuthTransactionId[] = {
+  0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72, 0xc0, 0x29, 0xda, 0x41, 0x2e
+};
+static const char kRfc5769SampleMsgWithAuthUsername[] =
+    "\xe3\x83\x9e\xe3\x83\x88\xe3\x83\xaa\xe3\x83\x83\xe3\x82\xaf\xe3\x82\xb9";
+static const char kRfc5769SampleMsgWithAuthPassword[] = "TheMatrIX";
+static const char kRfc5769SampleMsgWithAuthNonce[] =
+    "f//499k954d6OL34oL9FSTvy64sA";
+static const char kRfc5769SampleMsgWithAuthRealm[] = "example.org";
+
+// 2.1.  Sample Request
+static const unsigned char kRfc5769SampleRequest[] = {
+  0x00, 0x01, 0x00, 0x58,   //    Request type and message length
+  0x21, 0x12, 0xa4, 0x42,   //    Magic cookie
+  0xb7, 0xe7, 0xa7, 0x01,   // }
+  0xbc, 0x34, 0xd6, 0x86,   // }  Transaction ID
+  0xfa, 0x87, 0xdf, 0xae,   // }
+  0x80, 0x22, 0x00, 0x10,   //    SOFTWARE attribute header
+  0x53, 0x54, 0x55, 0x4e,   // }
+  0x20, 0x74, 0x65, 0x73,   // }  User-agent...
+  0x74, 0x20, 0x63, 0x6c,   // }  ...name
+  0x69, 0x65, 0x6e, 0x74,   // }
+  0x00, 0x24, 0x00, 0x04,   //    PRIORITY attribute header
+  0x6e, 0x00, 0x01, 0xff,   //    ICE priority value
+  0x80, 0x29, 0x00, 0x08,   //    ICE-CONTROLLED attribute header
+  0x93, 0x2f, 0xf9, 0xb1,   // }  Pseudo-random tie breaker...
+  0x51, 0x26, 0x3b, 0x36,   // }   ...for ICE control
+  0x00, 0x06, 0x00, 0x09,   //    USERNAME attribute header
+  0x65, 0x76, 0x74, 0x6a,   // }
+  0x3a, 0x68, 0x36, 0x76,   // }  Username (9 bytes) and padding (3 bytes)
+  0x59, 0x20, 0x20, 0x20,   // }
+  0x00, 0x08, 0x00, 0x14,   //    MESSAGE-INTEGRITY attribute header
+  0x9a, 0xea, 0xa7, 0x0c,   // }
+  0xbf, 0xd8, 0xcb, 0x56,   // }
+  0x78, 0x1e, 0xf2, 0xb5,   // }  HMAC-SHA1 fingerprint
+  0xb2, 0xd3, 0xf2, 0x49,   // }
+  0xc1, 0xb5, 0x71, 0xa2,   // }
+  0x80, 0x28, 0x00, 0x04,   //    FINGERPRINT attribute header
+  0xe5, 0x7a, 0x3b, 0xcf    //    CRC32 fingerprint
+};
+
+// 2.2.  Sample IPv4 Response
+static const unsigned char kRfc5769SampleResponse[] = {
+  0x01, 0x01, 0x00, 0x3c,  //     Response type and message length
+  0x21, 0x12, 0xa4, 0x42,  //     Magic cookie
+  0xb7, 0xe7, 0xa7, 0x01,  // }
+  0xbc, 0x34, 0xd6, 0x86,  // }  Transaction ID
+  0xfa, 0x87, 0xdf, 0xae,  // }
+  0x80, 0x22, 0x00, 0x0b,  //    SOFTWARE attribute header
+  0x74, 0x65, 0x73, 0x74,  // }
+  0x20, 0x76, 0x65, 0x63,  // }  UTF-8 server name
+  0x74, 0x6f, 0x72, 0x20,  // }
+  0x00, 0x20, 0x00, 0x08,  //    XOR-MAPPED-ADDRESS attribute header
+  0x00, 0x01, 0xa1, 0x47,  //    Address family (IPv4) and xor'd mapped port
+  0xe1, 0x12, 0xa6, 0x43,  //    Xor'd mapped IPv4 address
+  0x00, 0x08, 0x00, 0x14,  //    MESSAGE-INTEGRITY attribute header
+  0x2b, 0x91, 0xf5, 0x99,  // }
+  0xfd, 0x9e, 0x90, 0xc3,  // }
+  0x8c, 0x74, 0x89, 0xf9,  // }  HMAC-SHA1 fingerprint
+  0x2a, 0xf9, 0xba, 0x53,  // }
+  0xf0, 0x6b, 0xe7, 0xd7,  // }
+  0x80, 0x28, 0x00, 0x04,  //    FINGERPRINT attribute header
+  0xc0, 0x7d, 0x4c, 0x96   //    CRC32 fingerprint
+};
+
+// 2.3.  Sample IPv6 Response
+static const unsigned char kRfc5769SampleResponseIPv6[] = {
+  0x01, 0x01, 0x00, 0x48,  //    Response type and message length
+  0x21, 0x12, 0xa4, 0x42,  //    Magic cookie
+  0xb7, 0xe7, 0xa7, 0x01,  // }
+  0xbc, 0x34, 0xd6, 0x86,  // }  Transaction ID
+  0xfa, 0x87, 0xdf, 0xae,  // }
+  0x80, 0x22, 0x00, 0x0b,  //    SOFTWARE attribute header
+  0x74, 0x65, 0x73, 0x74,  // }
+  0x20, 0x76, 0x65, 0x63,  // }  UTF-8 server name
+  0x74, 0x6f, 0x72, 0x20,  // }
+  0x00, 0x20, 0x00, 0x14,  //    XOR-MAPPED-ADDRESS attribute header
+  0x00, 0x02, 0xa1, 0x47,  //    Address family (IPv6) and xor'd mapped port.
+  0x01, 0x13, 0xa9, 0xfa,  // }
+  0xa5, 0xd3, 0xf1, 0x79,  // }  Xor'd mapped IPv6 address
+  0xbc, 0x25, 0xf4, 0xb5,  // }
+  0xbe, 0xd2, 0xb9, 0xd9,  // }
+  0x00, 0x08, 0x00, 0x14,  //    MESSAGE-INTEGRITY attribute header
+  0xa3, 0x82, 0x95, 0x4e,  // }
+  0x4b, 0xe6, 0x7b, 0xf1,  // }
+  0x17, 0x84, 0xc9, 0x7c,  // }  HMAC-SHA1 fingerprint
+  0x82, 0x92, 0xc2, 0x75,  // }
+  0xbf, 0xe3, 0xed, 0x41,  // }
+  0x80, 0x28, 0x00, 0x04,  //    FINGERPRINT attribute header
+  0xc8, 0xfb, 0x0b, 0x4c   //    CRC32 fingerprint
+};
+
+// 2.4.  Sample Request with Long-Term Authentication
+static const unsigned char kRfc5769SampleRequestLongTermAuth[] = {
+  0x00, 0x01, 0x00, 0x60,  //    Request type and message length
+  0x21, 0x12, 0xa4, 0x42,  //    Magic cookie
+  0x78, 0xad, 0x34, 0x33,  // }
+  0xc6, 0xad, 0x72, 0xc0,  // }  Transaction ID
+  0x29, 0xda, 0x41, 0x2e,  // }
+  0x00, 0x06, 0x00, 0x12,  //    USERNAME attribute header
+  0xe3, 0x83, 0x9e, 0xe3,  // }
+  0x83, 0x88, 0xe3, 0x83,  // }
+  0xaa, 0xe3, 0x83, 0x83,  // }  Username value (18 bytes) and padding (2 bytes)
+  0xe3, 0x82, 0xaf, 0xe3,  // }
+  0x82, 0xb9, 0x00, 0x00,  // }
+  0x00, 0x15, 0x00, 0x1c,  //    NONCE attribute header
+  0x66, 0x2f, 0x2f, 0x34,  // }
+  0x39, 0x39, 0x6b, 0x39,  // }
+  0x35, 0x34, 0x64, 0x36,  // }
+  0x4f, 0x4c, 0x33, 0x34,  // }  Nonce value
+  0x6f, 0x4c, 0x39, 0x46,  // }
+  0x53, 0x54, 0x76, 0x79,  // }
+  0x36, 0x34, 0x73, 0x41,  // }
+  0x00, 0x14, 0x00, 0x0b,  //    REALM attribute header
+  0x65, 0x78, 0x61, 0x6d,  // }
+  0x70, 0x6c, 0x65, 0x2e,  // }  Realm value (11 bytes) and padding (1 byte)
+  0x6f, 0x72, 0x67, 0x00,  // }
+  0x00, 0x08, 0x00, 0x14,  //    MESSAGE-INTEGRITY attribute header
+  0xf6, 0x70, 0x24, 0x65,  // }
+  0x6d, 0xd6, 0x4a, 0x3e,  // }
+  0x02, 0xb8, 0xe0, 0x71,  // }  HMAC-SHA1 fingerprint
+  0x2e, 0x85, 0xc9, 0xa2,  // }
+  0x8c, 0xa8, 0x96, 0x66   // }
+};
+
+// Length parameter is changed to 0x38 from 0x58.
+// AddMessageIntegrity will add MI information and update the length param
+// accordingly.
+static const unsigned char kRfc5769SampleRequestWithoutMI[] = {
+  0x00, 0x01, 0x00, 0x38,  //    Request type and message length
+  0x21, 0x12, 0xa4, 0x42,  //    Magic cookie
+  0xb7, 0xe7, 0xa7, 0x01,  // }
+  0xbc, 0x34, 0xd6, 0x86,  // }  Transaction ID
+  0xfa, 0x87, 0xdf, 0xae,  // }
+  0x80, 0x22, 0x00, 0x10,  //    SOFTWARE attribute header
+  0x53, 0x54, 0x55, 0x4e,  // }
+  0x20, 0x74, 0x65, 0x73,  // }  User-agent...
+  0x74, 0x20, 0x63, 0x6c,  // }  ...name
+  0x69, 0x65, 0x6e, 0x74,  // }
+  0x00, 0x24, 0x00, 0x04,  //    PRIORITY attribute header
+  0x6e, 0x00, 0x01, 0xff,  //    ICE priority value
+  0x80, 0x29, 0x00, 0x08,  //    ICE-CONTROLLED attribute header
+  0x93, 0x2f, 0xf9, 0xb1,  // }  Pseudo-random tie breaker...
+  0x51, 0x26, 0x3b, 0x36,  // }   ...for ICE control
+  0x00, 0x06, 0x00, 0x09,  //    USERNAME attribute header
+  0x65, 0x76, 0x74, 0x6a,  // }
+  0x3a, 0x68, 0x36, 0x76,  // }  Username (9 bytes) and padding (3 bytes)
+  0x59, 0x20, 0x20, 0x20   // }
+};
+
+// This HMAC differs from the RFC 5769 SampleRequest message. This differs
+// because spec uses 0x20 for the padding where as our implementation uses 0.
+static const unsigned char kCalculatedHmac1[] = {
+  0x79, 0x07, 0xc2, 0xd2,  // }
+  0xed, 0xbf, 0xea, 0x48,  // }
+  0x0e, 0x4c, 0x76, 0xd8,  // }  HMAC-SHA1 fingerprint
+  0x29, 0x62, 0xd5, 0xc3,  // }
+  0x74, 0x2a, 0xf9, 0xe3   // }
+};
+
+// Length parameter is changed to 0x1c from 0x3c.
+// AddMessageIntegrity will add MI information and update the length param
+// accordingly.
+static const unsigned char kRfc5769SampleResponseWithoutMI[] = {
+  0x01, 0x01, 0x00, 0x1c,  //    Response type and message length
+  0x21, 0x12, 0xa4, 0x42,  //    Magic cookie
+  0xb7, 0xe7, 0xa7, 0x01,  // }
+  0xbc, 0x34, 0xd6, 0x86,  // }  Transaction ID
+  0xfa, 0x87, 0xdf, 0xae,  // }
+  0x80, 0x22, 0x00, 0x0b,  //    SOFTWARE attribute header
+  0x74, 0x65, 0x73, 0x74,  // }
+  0x20, 0x76, 0x65, 0x63,  // }  UTF-8 server name
+  0x74, 0x6f, 0x72, 0x20,  // }
+  0x00, 0x20, 0x00, 0x08,  //    XOR-MAPPED-ADDRESS attribute header
+  0x00, 0x01, 0xa1, 0x47,  //    Address family (IPv4) and xor'd mapped port
+  0xe1, 0x12, 0xa6, 0x43   //    Xor'd mapped IPv4 address
+};
+
+// This HMAC differs from the RFC 5769 SampleResponse message. This differs
+// because spec uses 0x20 for the padding where as our implementation uses 0.
+static const unsigned char kCalculatedHmac2[] = {
+  0x5d, 0x6b, 0x58, 0xbe,  // }
+  0xad, 0x94, 0xe0, 0x7e,  // }
+  0xef, 0x0d, 0xfc, 0x12,  // }  HMAC-SHA1 fingerprint
+  0x82, 0xa2, 0xbd, 0x08,  // }
+  0x43, 0x14, 0x10, 0x28   // }
+};
+
+// A transaction ID without the 'magic cookie' portion
+// pjnat's test programs use this transaction ID a lot.
+const unsigned char kTestTransactionId1[] = { 0x029, 0x01f, 0x0cd, 0x07c,
+                                              0x0ba, 0x058, 0x0ab, 0x0d7,
+                                              0x0f2, 0x041, 0x001, 0x000 };
+
+// They use this one sometimes too.
+const unsigned char kTestTransactionId2[] = { 0x0e3, 0x0a9, 0x046, 0x0e1,
+                                              0x07c, 0x000, 0x0c2, 0x062,
+                                              0x054, 0x008, 0x001, 0x000 };
+
+const in6_addr kIPv6TestAddress1 = { { { 0x24, 0x01, 0xfa, 0x00,
+                                         0x00, 0x04, 0x10, 0x00,
+                                         0xbe, 0x30, 0x5b, 0xff,
+                                         0xfe, 0xe5, 0x00, 0xc3 } } };
+const in6_addr kIPv6TestAddress2 = { { { 0x24, 0x01, 0xfa, 0x00,
+                                         0x00, 0x04, 0x10, 0x12,
+                                         0x06, 0x0c, 0xce, 0xff,
+                                         0xfe, 0x1f, 0x61, 0xa4 } } };
+
+#ifdef WEBRTC_POSIX
+const in_addr kIPv4TestAddress1 =  { 0xe64417ac };
+#elif defined WEBRTC_WIN
+// Windows in_addr has a union with a uchar[] array first.
+const in_addr kIPv4TestAddress1 =  { { 0x0ac, 0x017, 0x044, 0x0e6 } };
+#endif
+const char kTestUserName1[] = "abcdefgh";
+const char kTestUserName2[] = "abc";
+const char kTestErrorReason[] = "Unauthorized";
+const int kTestErrorClass = 4;
+const int kTestErrorNumber = 1;
+const int kTestErrorCode = 401;
+
+const int kTestMessagePort1 = 59977;
+const int kTestMessagePort2 = 47233;
+const int kTestMessagePort3 = 56743;
+const int kTestMessagePort4 = 40444;
+
+#define ReadStunMessage(X, Y) ReadStunMessageTestCase(X, Y, sizeof(Y));
+
+// Test that the GetStun*Type and IsStun*Type methods work as expected.
+TEST_F(StunTest, MessageTypes) {
+  EXPECT_EQ(STUN_BINDING_RESPONSE,
+      GetStunSuccessResponseType(STUN_BINDING_REQUEST));
+  EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE,
+      GetStunErrorResponseType(STUN_BINDING_REQUEST));
+  EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_INDICATION));
+  EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_RESPONSE));
+  EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_ERROR_RESPONSE));
+  EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_INDICATION));
+  EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_RESPONSE));
+  EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_ERROR_RESPONSE));
+
+  int types[] = {
+    STUN_BINDING_REQUEST, STUN_BINDING_INDICATION,
+    STUN_BINDING_RESPONSE, STUN_BINDING_ERROR_RESPONSE
+  };
+  for (int i = 0; i < ARRAY_SIZE(types); ++i) {
+    EXPECT_EQ(i == 0, IsStunRequestType(types[i]));
+    EXPECT_EQ(i == 1, IsStunIndicationType(types[i]));
+    EXPECT_EQ(i == 2, IsStunSuccessResponseType(types[i]));
+    EXPECT_EQ(i == 3, IsStunErrorResponseType(types[i]));
+    EXPECT_EQ(1, types[i] & 0xFEEF);
+  }
+}
+
+TEST_F(StunTest, ReadMessageWithIPv4AddressAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4MappedAddress);
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  rtc::IPAddress test_address(kIPv4TestAddress1);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4,
+                            kTestMessagePort4, test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithIPv4XorAddressAttribute) {
+  StunMessage msg;
+  StunMessage msg2;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress);
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  const StunAddressAttribute* addr =
+      msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  rtc::IPAddress test_address(kIPv4TestAddress1);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4,
+                            kTestMessagePort3, test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithIPv6AddressAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress);
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  rtc::IPAddress test_address(kIPv6TestAddress1);
+
+  const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6,
+                            kTestMessagePort2, test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithInvalidAddressAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress);
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  rtc::IPAddress test_address(kIPv6TestAddress1);
+
+  const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6,
+                            kTestMessagePort2, test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithIPv6XorAddressAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress);
+
+  rtc::IPAddress test_address(kIPv6TestAddress1);
+
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+
+  const StunAddressAttribute* addr =
+      msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6,
+                            kTestMessagePort1, test_address);
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN request.
+TEST_F(StunTest, ReadRfc5769RequestMessage) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kRfc5769SampleRequest);
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+  CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId,
+                         kStunTransactionIdLength);
+
+  const StunByteStringAttribute* software =
+      msg.GetByteString(STUN_ATTR_SOFTWARE);
+  ASSERT_TRUE(software != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgClientSoftware, software->GetString());
+
+  const StunByteStringAttribute* username =
+      msg.GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgUsername, username->GetString());
+
+  // Actual M-I value checked in a later test.
+  ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+
+  // Fingerprint checked in a later test, but double-check the value here.
+  const StunUInt32Attribute* fingerprint =
+      msg.GetUInt32(STUN_ATTR_FINGERPRINT);
+  ASSERT_TRUE(fingerprint != NULL);
+  EXPECT_EQ(0xe57a3bcf, fingerprint->value());
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN response.
+TEST_F(StunTest, ReadRfc5769ResponseMessage) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kRfc5769SampleResponse);
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId,
+                         kStunTransactionIdLength);
+
+  const StunByteStringAttribute* software =
+      msg.GetByteString(STUN_ATTR_SOFTWARE);
+  ASSERT_TRUE(software != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->GetString());
+
+  const StunAddressAttribute* mapped_address =
+      msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  ASSERT_TRUE(mapped_address != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgMappedAddress, mapped_address->GetAddress());
+
+  // Actual M-I and fingerprint checked in later tests.
+  ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+  ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) != NULL);
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN response for IPv6.
+TEST_F(StunTest, ReadRfc5769ResponseMessageIPv6) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kRfc5769SampleResponseIPv6);
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId,
+                         kStunTransactionIdLength);
+
+  const StunByteStringAttribute* software =
+      msg.GetByteString(STUN_ATTR_SOFTWARE);
+  ASSERT_TRUE(software != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->GetString());
+
+  const StunAddressAttribute* mapped_address =
+      msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  ASSERT_TRUE(mapped_address != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgIPv6MappedAddress, mapped_address->GetAddress());
+
+  // Actual M-I and fingerprint checked in later tests.
+  ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+  ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) != NULL);
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN response with auth.
+TEST_F(StunTest, ReadRfc5769RequestMessageLongTermAuth) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kRfc5769SampleRequestLongTermAuth);
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+  CheckStunTransactionID(msg, kRfc5769SampleMsgWithAuthTransactionId,
+                         kStunTransactionIdLength);
+
+  const StunByteStringAttribute* username =
+      msg.GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgWithAuthUsername, username->GetString());
+
+  const StunByteStringAttribute* nonce =
+      msg.GetByteString(STUN_ATTR_NONCE);
+  ASSERT_TRUE(nonce != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgWithAuthNonce, nonce->GetString());
+
+  const StunByteStringAttribute* realm =
+      msg.GetByteString(STUN_ATTR_REALM);
+  ASSERT_TRUE(realm != NULL);
+  EXPECT_EQ(kRfc5769SampleMsgWithAuthRealm, realm->GetString());
+
+  // No fingerprint, actual M-I checked in later tests.
+  ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+  ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) == NULL);
+}
+
+// The RFC3489 packet in this test is the same as
+// kStunMessageWithIPv4MappedAddress, but with a different value where the
+// magic cookie was.
+TEST_F(StunTest, ReadLegacyMessage) {
+  unsigned char rfc3489_packet[sizeof(kStunMessageWithIPv4MappedAddress)];
+  memcpy(rfc3489_packet, kStunMessageWithIPv4MappedAddress,
+      sizeof(kStunMessageWithIPv4MappedAddress));
+  // Overwrite the magic cookie here.
+  memcpy(&rfc3489_packet[4], "ABCD", 4);
+
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, rfc3489_packet);
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, &rfc3489_packet[4], kStunTransactionIdLength + 4);
+
+  const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  rtc::IPAddress test_address(kIPv4TestAddress1);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4,
+                            kTestMessagePort4, test_address);
+}
+
+TEST_F(StunTest, SetIPv6XorAddressAttributeOwner) {
+  StunMessage msg;
+  StunMessage msg2;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress);
+
+  rtc::IPAddress test_address(kIPv6TestAddress1);
+
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+
+  const StunAddressAttribute* addr =
+      msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6,
+                            kTestMessagePort1, test_address);
+
+  // Owner with a different transaction ID.
+  msg2.SetTransactionID("ABCDABCDABCD");
+  StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20, NULL);
+  addr2.SetIP(addr->ipaddr());
+  addr2.SetPort(addr->port());
+  addr2.SetOwner(&msg2);
+  // The internal IP address shouldn't change.
+  ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+
+  rtc::ByteBuffer correct_buf;
+  rtc::ByteBuffer wrong_buf;
+  EXPECT_TRUE(addr->Write(&correct_buf));
+  EXPECT_TRUE(addr2.Write(&wrong_buf));
+  // But when written out, the buffers should look different.
+  ASSERT_NE(0,
+            memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length()));
+  // And when reading a known good value, the address should be wrong.
+  addr2.Read(&correct_buf);
+  ASSERT_NE(addr->ipaddr(), addr2.ipaddr());
+  addr2.SetIP(addr->ipaddr());
+  addr2.SetPort(addr->port());
+  // Try writing with no owner at all, should fail and write nothing.
+  addr2.SetOwner(NULL);
+  ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+  wrong_buf.Consume(wrong_buf.Length());
+  EXPECT_FALSE(addr2.Write(&wrong_buf));
+  ASSERT_EQ(0U, wrong_buf.Length());
+}
+
+TEST_F(StunTest, SetIPv4XorAddressAttributeOwner) {
+  // Unlike the IPv6XorAddressAttributeOwner test, IPv4 XOR address attributes
+  // should _not_ be affected by a change in owner. IPv4 XOR address uses the
+  // magic cookie value which is fixed.
+  StunMessage msg;
+  StunMessage msg2;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress);
+
+  rtc::IPAddress test_address(kIPv4TestAddress1);
+
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  const StunAddressAttribute* addr =
+      msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4,
+                            kTestMessagePort3, test_address);
+
+  // Owner with a different transaction ID.
+  msg2.SetTransactionID("ABCDABCDABCD");
+  StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20, NULL);
+  addr2.SetIP(addr->ipaddr());
+  addr2.SetPort(addr->port());
+  addr2.SetOwner(&msg2);
+  // The internal IP address shouldn't change.
+  ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+
+  rtc::ByteBuffer correct_buf;
+  rtc::ByteBuffer wrong_buf;
+  EXPECT_TRUE(addr->Write(&correct_buf));
+  EXPECT_TRUE(addr2.Write(&wrong_buf));
+  // The same address data should be written.
+  ASSERT_EQ(0,
+            memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length()));
+  // And an attribute should be able to un-XOR an address belonging to a message
+  // with a different transaction ID.
+  EXPECT_TRUE(addr2.Read(&correct_buf));
+  ASSERT_EQ(addr->ipaddr(), addr2.ipaddr());
+
+  // However, no owner is still an error, should fail and write nothing.
+  addr2.SetOwner(NULL);
+  ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+  wrong_buf.Consume(wrong_buf.Length());
+  EXPECT_FALSE(addr2.Write(&wrong_buf));
+}
+
+TEST_F(StunTest, CreateIPv6AddressAttribute) {
+  rtc::IPAddress test_ip(kIPv6TestAddress2);
+
+  StunAddressAttribute* addr =
+      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+  rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+  addr->SetAddress(test_addr);
+
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6,
+                            kTestMessagePort2, test_ip);
+  delete addr;
+}
+
+TEST_F(StunTest, CreateIPv4AddressAttribute) {
+  struct in_addr test_in_addr;
+  test_in_addr.s_addr = 0xBEB0B0BE;
+  rtc::IPAddress test_ip(test_in_addr);
+
+  StunAddressAttribute* addr =
+      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+  rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+  addr->SetAddress(test_addr);
+
+  CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4,
+                            kTestMessagePort2, test_ip);
+  delete addr;
+}
+
+// Test that we don't care what order we set the parts of an address
+TEST_F(StunTest, CreateAddressInArbitraryOrder) {
+  StunAddressAttribute* addr =
+  StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+  // Port first
+  addr->SetPort(kTestMessagePort1);
+  addr->SetIP(rtc::IPAddress(kIPv4TestAddress1));
+  ASSERT_EQ(kTestMessagePort1, addr->port());
+  ASSERT_EQ(rtc::IPAddress(kIPv4TestAddress1), addr->ipaddr());
+
+  StunAddressAttribute* addr2 =
+  StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+  // IP first
+  addr2->SetIP(rtc::IPAddress(kIPv4TestAddress1));
+  addr2->SetPort(kTestMessagePort2);
+  ASSERT_EQ(kTestMessagePort2, addr2->port());
+  ASSERT_EQ(rtc::IPAddress(kIPv4TestAddress1), addr2->ipaddr());
+
+  delete addr;
+  delete addr2;
+}
+
+TEST_F(StunTest, WriteMessageWithIPv6AddressAttribute) {
+  StunMessage msg;
+  size_t size = sizeof(kStunMessageWithIPv6MappedAddress);
+
+  rtc::IPAddress test_ip(kIPv6TestAddress1);
+
+  msg.SetType(STUN_BINDING_REQUEST);
+  msg.SetTransactionID(
+      std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+                  kStunTransactionIdLength));
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  StunAddressAttribute* addr =
+      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+  rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+  addr->SetAddress(test_addr);
+  EXPECT_TRUE(msg.AddAttribute(addr));
+
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20));
+
+  rtc::ByteBuffer out;
+  EXPECT_TRUE(msg.Write(&out));
+  ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6MappedAddress));
+  int len1 = static_cast<int>(out.Length());
+  std::string bytes;
+  out.ReadString(&bytes, len1);
+  ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv6MappedAddress, len1));
+}
+
+TEST_F(StunTest, WriteMessageWithIPv4AddressAttribute) {
+  StunMessage msg;
+  size_t size = sizeof(kStunMessageWithIPv4MappedAddress);
+
+  rtc::IPAddress test_ip(kIPv4TestAddress1);
+
+  msg.SetType(STUN_BINDING_RESPONSE);
+  msg.SetTransactionID(
+      std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+                  kStunTransactionIdLength));
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  StunAddressAttribute* addr =
+      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+  rtc::SocketAddress test_addr(test_ip, kTestMessagePort4);
+  addr->SetAddress(test_addr);
+  EXPECT_TRUE(msg.AddAttribute(addr));
+
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20));
+
+  rtc::ByteBuffer out;
+  EXPECT_TRUE(msg.Write(&out));
+  ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4MappedAddress));
+  int len1 = static_cast<int>(out.Length());
+  std::string bytes;
+  out.ReadString(&bytes, len1);
+  ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv4MappedAddress, len1));
+}
+
+TEST_F(StunTest, WriteMessageWithIPv6XorAddressAttribute) {
+  StunMessage msg;
+  size_t size = sizeof(kStunMessageWithIPv6XorMappedAddress);
+
+  rtc::IPAddress test_ip(kIPv6TestAddress1);
+
+  msg.SetType(STUN_BINDING_RESPONSE);
+  msg.SetTransactionID(
+      std::string(reinterpret_cast<const char*>(kTestTransactionId2),
+                  kStunTransactionIdLength));
+  CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+
+  StunAddressAttribute* addr =
+      StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  rtc::SocketAddress test_addr(test_ip, kTestMessagePort1);
+  addr->SetAddress(test_addr);
+  EXPECT_TRUE(msg.AddAttribute(addr));
+
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20));
+
+  rtc::ByteBuffer out;
+  EXPECT_TRUE(msg.Write(&out));
+  ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6XorMappedAddress));
+  int len1 = static_cast<int>(out.Length());
+  std::string bytes;
+  out.ReadString(&bytes, len1);
+  ASSERT_EQ(0,
+            memcmp(bytes.c_str(), kStunMessageWithIPv6XorMappedAddress, len1));
+}
+
+TEST_F(StunTest, WriteMessageWithIPv4XoreAddressAttribute) {
+  StunMessage msg;
+  size_t size = sizeof(kStunMessageWithIPv4XorMappedAddress);
+
+  rtc::IPAddress test_ip(kIPv4TestAddress1);
+
+  msg.SetType(STUN_BINDING_RESPONSE);
+  msg.SetTransactionID(
+      std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+                  kStunTransactionIdLength));
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+  StunAddressAttribute* addr =
+      StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  rtc::SocketAddress test_addr(test_ip, kTestMessagePort3);
+  addr->SetAddress(test_addr);
+  EXPECT_TRUE(msg.AddAttribute(addr));
+
+  CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20));
+
+  rtc::ByteBuffer out;
+  EXPECT_TRUE(msg.Write(&out));
+  ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4XorMappedAddress));
+  int len1 = static_cast<int>(out.Length());
+  std::string bytes;
+  out.ReadString(&bytes, len1);
+  ASSERT_EQ(0,
+            memcmp(bytes.c_str(), kStunMessageWithIPv4XorMappedAddress, len1));
+}
+
+TEST_F(StunTest, ReadByteStringAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithByteStringAttribute);
+
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+  CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+  const StunByteStringAttribute* username =
+      msg.GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username != NULL);
+  EXPECT_EQ(kTestUserName1, username->GetString());
+}
+
+TEST_F(StunTest, ReadPaddedByteStringAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg,
+                                kStunMessageWithPaddedByteStringAttribute);
+  ASSERT_NE(0U, size);
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+  CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+  const StunByteStringAttribute* username =
+      msg.GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username != NULL);
+  EXPECT_EQ(kTestUserName2, username->GetString());
+}
+
+TEST_F(StunTest, ReadErrorCodeAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithErrorAttribute);
+
+  CheckStunHeader(msg, STUN_BINDING_ERROR_RESPONSE, size);
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+  const StunErrorCodeAttribute* errorcode = msg.GetErrorCode();
+  ASSERT_TRUE(errorcode != NULL);
+  EXPECT_EQ(kTestErrorClass, errorcode->eclass());
+  EXPECT_EQ(kTestErrorNumber, errorcode->number());
+  EXPECT_EQ(kTestErrorReason, errorcode->reason());
+  EXPECT_EQ(kTestErrorCode, errorcode->code());
+}
+
+TEST_F(StunTest, ReadMessageWithAUInt16ListAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithUInt16ListAttribute);
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+  const StunUInt16ListAttribute* types = msg.GetUnknownAttributes();
+  ASSERT_TRUE(types != NULL);
+  EXPECT_EQ(3U, types->Size());
+  EXPECT_EQ(0x1U, types->GetType(0));
+  EXPECT_EQ(0x1000U, types->GetType(1));
+  EXPECT_EQ(0xAB0CU, types->GetType(2));
+}
+
+TEST_F(StunTest, ReadMessageWithAnUnknownAttribute) {
+  StunMessage msg;
+  size_t size = ReadStunMessage(&msg, kStunMessageWithUnknownAttribute);
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+
+  // Parsing should have succeeded and there should be a USERNAME attribute
+  const StunByteStringAttribute* username =
+      msg.GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(username != NULL);
+  EXPECT_EQ(kTestUserName2, username->GetString());
+}
+
+TEST_F(StunTest, WriteMessageWithAnErrorCodeAttribute) {
+  StunMessage msg;
+  size_t size = sizeof(kStunMessageWithErrorAttribute);
+
+  msg.SetType(STUN_BINDING_ERROR_RESPONSE);
+  msg.SetTransactionID(
+      std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+                  kStunTransactionIdLength));
+  CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+  StunErrorCodeAttribute* errorcode = StunAttribute::CreateErrorCode();
+  errorcode->SetCode(kTestErrorCode);
+  errorcode->SetReason(kTestErrorReason);
+  EXPECT_TRUE(msg.AddAttribute(errorcode));
+  CheckStunHeader(msg, STUN_BINDING_ERROR_RESPONSE, (size - 20));
+
+  rtc::ByteBuffer out;
+  EXPECT_TRUE(msg.Write(&out));
+  ASSERT_EQ(size, out.Length());
+  // No padding.
+  ASSERT_EQ(0, memcmp(out.Data(), kStunMessageWithErrorAttribute, size));
+}
+
+TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) {
+  StunMessage msg;
+  size_t size = sizeof(kStunMessageWithUInt16ListAttribute);
+
+  msg.SetType(STUN_BINDING_REQUEST);
+  msg.SetTransactionID(
+      std::string(reinterpret_cast<const char*>(kTestTransactionId2),
+                  kStunTransactionIdLength));
+  CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+  StunUInt16ListAttribute* list = StunAttribute::CreateUnknownAttributes();
+  list->AddType(0x1U);
+  list->AddType(0x1000U);
+  list->AddType(0xAB0CU);
+  EXPECT_TRUE(msg.AddAttribute(list));
+  CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20));
+
+  rtc::ByteBuffer out;
+  EXPECT_TRUE(msg.Write(&out));
+  ASSERT_EQ(size, out.Length());
+  // Check everything up to the padding.
+  ASSERT_EQ(0,
+            memcmp(out.Data(), kStunMessageWithUInt16ListAttribute, size - 2));
+}
+
+// Test that we fail to read messages with invalid lengths.
+void CheckFailureToRead(const unsigned char* testcase, size_t length) {
+  StunMessage msg;
+  const char* input = reinterpret_cast<const char*>(testcase);
+  rtc::ByteBuffer buf(input, length);
+  ASSERT_FALSE(msg.Read(&buf));
+}
+
+TEST_F(StunTest, FailToReadInvalidMessages) {
+  CheckFailureToRead(kStunMessageWithZeroLength,
+                     kRealLengthOfInvalidLengthTestCases);
+  CheckFailureToRead(kStunMessageWithSmallLength,
+                     kRealLengthOfInvalidLengthTestCases);
+  CheckFailureToRead(kStunMessageWithExcessLength,
+                     kRealLengthOfInvalidLengthTestCases);
+}
+
+// Test that we properly fail to read a non-STUN message.
+TEST_F(StunTest, FailToReadRtcpPacket) {
+  CheckFailureToRead(kRtcpPacket, sizeof(kRtcpPacket));
+}
+
+// Check our STUN message validation code against the RFC5769 test messages.
+TEST_F(StunTest, ValidateMessageIntegrity) {
+  // Try the messages from RFC 5769.
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleRequest),
+      sizeof(kRfc5769SampleRequest),
+      kRfc5769SampleMsgPassword));
+  EXPECT_FALSE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleRequest),
+      sizeof(kRfc5769SampleRequest),
+      "InvalidPassword"));
+
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleResponse),
+      sizeof(kRfc5769SampleResponse),
+      kRfc5769SampleMsgPassword));
+  EXPECT_FALSE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleResponse),
+      sizeof(kRfc5769SampleResponse),
+      "InvalidPassword"));
+
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6),
+      sizeof(kRfc5769SampleResponseIPv6),
+      kRfc5769SampleMsgPassword));
+  EXPECT_FALSE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6),
+      sizeof(kRfc5769SampleResponseIPv6),
+      "InvalidPassword"));
+
+  // We first need to compute the key for the long-term authentication HMAC.
+  std::string key;
+  ComputeStunCredentialHash(kRfc5769SampleMsgWithAuthUsername,
+      kRfc5769SampleMsgWithAuthRealm, kRfc5769SampleMsgWithAuthPassword, &key);
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleRequestLongTermAuth),
+      sizeof(kRfc5769SampleRequestLongTermAuth), key));
+  EXPECT_FALSE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kRfc5769SampleRequestLongTermAuth),
+      sizeof(kRfc5769SampleRequestLongTermAuth),
+      "InvalidPassword"));
+
+  // Try some edge cases.
+  EXPECT_FALSE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kStunMessageWithZeroLength),
+      sizeof(kStunMessageWithZeroLength),
+      kRfc5769SampleMsgPassword));
+  EXPECT_FALSE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kStunMessageWithExcessLength),
+      sizeof(kStunMessageWithExcessLength),
+      kRfc5769SampleMsgPassword));
+  EXPECT_FALSE(StunMessage::ValidateMessageIntegrity(
+      reinterpret_cast<const char*>(kStunMessageWithSmallLength),
+      sizeof(kStunMessageWithSmallLength),
+      kRfc5769SampleMsgPassword));
+
+  // Test that munging a single bit anywhere in the message causes the
+  // message-integrity check to fail, unless it is after the M-I attribute.
+  char buf[sizeof(kRfc5769SampleRequest)];
+  memcpy(buf, kRfc5769SampleRequest, sizeof(kRfc5769SampleRequest));
+  for (size_t i = 0; i < sizeof(buf); ++i) {
+    buf[i] ^= 0x01;
+    if (i > 0)
+      buf[i - 1] ^= 0x01;
+    EXPECT_EQ(i >= sizeof(buf) - 8, StunMessage::ValidateMessageIntegrity(
+        buf, sizeof(buf), kRfc5769SampleMsgPassword));
+  }
+}
+
+// Validate that we generate correct MESSAGE-INTEGRITY attributes.
+// Note the use of IceMessage instead of StunMessage; this is necessary because
+// the RFC5769 test messages used include attributes not found in basic STUN.
+TEST_F(StunTest, AddMessageIntegrity) {
+  IceMessage msg;
+  rtc::ByteBuffer buf(
+      reinterpret_cast<const char*>(kRfc5769SampleRequestWithoutMI),
+      sizeof(kRfc5769SampleRequestWithoutMI));
+  EXPECT_TRUE(msg.Read(&buf));
+  EXPECT_TRUE(msg.AddMessageIntegrity(kRfc5769SampleMsgPassword));
+  const StunByteStringAttribute* mi_attr =
+      msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
+  EXPECT_EQ(20U, mi_attr->length());
+  EXPECT_EQ(0, memcmp(
+      mi_attr->bytes(), kCalculatedHmac1, sizeof(kCalculatedHmac1)));
+
+  rtc::ByteBuffer buf1;
+  EXPECT_TRUE(msg.Write(&buf1));
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+        reinterpret_cast<const char*>(buf1.Data()), buf1.Length(),
+        kRfc5769SampleMsgPassword));
+
+  IceMessage msg2;
+  rtc::ByteBuffer buf2(
+      reinterpret_cast<const char*>(kRfc5769SampleResponseWithoutMI),
+      sizeof(kRfc5769SampleResponseWithoutMI));
+  EXPECT_TRUE(msg2.Read(&buf2));
+  EXPECT_TRUE(msg2.AddMessageIntegrity(kRfc5769SampleMsgPassword));
+  const StunByteStringAttribute* mi_attr2 =
+      msg2.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
+  EXPECT_EQ(20U, mi_attr2->length());
+  EXPECT_EQ(
+      0, memcmp(mi_attr2->bytes(), kCalculatedHmac2, sizeof(kCalculatedHmac2)));
+
+  rtc::ByteBuffer buf3;
+  EXPECT_TRUE(msg2.Write(&buf3));
+  EXPECT_TRUE(StunMessage::ValidateMessageIntegrity(
+        reinterpret_cast<const char*>(buf3.Data()), buf3.Length(),
+        kRfc5769SampleMsgPassword));
+}
+
+// Check our STUN message validation code against the RFC5769 test messages.
+TEST_F(StunTest, ValidateFingerprint) {
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(
+      reinterpret_cast<const char*>(kRfc5769SampleRequest),
+      sizeof(kRfc5769SampleRequest)));
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(
+      reinterpret_cast<const char*>(kRfc5769SampleResponse),
+      sizeof(kRfc5769SampleResponse)));
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(
+      reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6),
+      sizeof(kRfc5769SampleResponseIPv6)));
+
+  EXPECT_FALSE(StunMessage::ValidateFingerprint(
+      reinterpret_cast<const char*>(kStunMessageWithZeroLength),
+      sizeof(kStunMessageWithZeroLength)));
+  EXPECT_FALSE(StunMessage::ValidateFingerprint(
+      reinterpret_cast<const char*>(kStunMessageWithExcessLength),
+      sizeof(kStunMessageWithExcessLength)));
+  EXPECT_FALSE(StunMessage::ValidateFingerprint(
+      reinterpret_cast<const char*>(kStunMessageWithSmallLength),
+      sizeof(kStunMessageWithSmallLength)));
+
+  // Test that munging a single bit anywhere in the message causes the
+  // fingerprint check to fail.
+  char buf[sizeof(kRfc5769SampleRequest)];
+  memcpy(buf, kRfc5769SampleRequest, sizeof(kRfc5769SampleRequest));
+  for (size_t i = 0; i < sizeof(buf); ++i) {
+    buf[i] ^= 0x01;
+    if (i > 0)
+      buf[i - 1] ^= 0x01;
+    EXPECT_FALSE(StunMessage::ValidateFingerprint(buf, sizeof(buf)));
+  }
+  // Put them all back to normal and the check should pass again.
+  buf[sizeof(buf) - 1] ^= 0x01;
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(buf, sizeof(buf)));
+}
+
+TEST_F(StunTest, AddFingerprint) {
+  IceMessage msg;
+  rtc::ByteBuffer buf(
+      reinterpret_cast<const char*>(kRfc5769SampleRequestWithoutMI),
+      sizeof(kRfc5769SampleRequestWithoutMI));
+  EXPECT_TRUE(msg.Read(&buf));
+  EXPECT_TRUE(msg.AddFingerprint());
+
+  rtc::ByteBuffer buf1;
+  EXPECT_TRUE(msg.Write(&buf1));
+  EXPECT_TRUE(StunMessage::ValidateFingerprint(
+      reinterpret_cast<const char*>(buf1.Data()), buf1.Length()));
+}
+
+// Sample "GTURN" relay message.
+static const unsigned char kRelayMessage[] = {
+  0x00, 0x01, 0x00, 88,    // message header
+  0x21, 0x12, 0xA4, 0x42,  // magic cookie
+  '0', '1', '2', '3',      // transaction id
+  '4', '5', '6', '7',
+  '8', '9', 'a', 'b',
+  0x00, 0x01, 0x00, 8,     // mapped address
+  0x00, 0x01, 0x00, 13,
+  0x00, 0x00, 0x00, 17,
+  0x00, 0x06, 0x00, 12,    // username
+  'a', 'b', 'c', 'd',
+  'e', 'f', 'g', 'h',
+  'i', 'j', 'k', 'l',
+  0x00, 0x0d, 0x00, 4,     // lifetime
+  0x00, 0x00, 0x00, 11,
+  0x00, 0x0f, 0x00, 4,     // magic cookie
+  0x72, 0xc6, 0x4b, 0xc6,
+  0x00, 0x10, 0x00, 4,     // bandwidth
+  0x00, 0x00, 0x00, 6,
+  0x00, 0x11, 0x00, 8,     // destination address
+  0x00, 0x01, 0x00, 13,
+  0x00, 0x00, 0x00, 17,
+  0x00, 0x12, 0x00, 8,     // source address 2
+  0x00, 0x01, 0x00, 13,
+  0x00, 0x00, 0x00, 17,
+  0x00, 0x13, 0x00, 7,     // data
+  'a', 'b', 'c', 'd',
+  'e', 'f', 'g', 0         // DATA must be padded per rfc5766.
+};
+
+// Test that we can read the GTURN-specific fields.
+TEST_F(StunTest, ReadRelayMessage) {
+  RelayMessage msg, msg2;
+
+  const char* input = reinterpret_cast<const char*>(kRelayMessage);
+  size_t size = sizeof(kRelayMessage);
+  rtc::ByteBuffer buf(input, size);
+  EXPECT_TRUE(msg.Read(&buf));
+
+  EXPECT_EQ(STUN_BINDING_REQUEST, msg.type());
+  EXPECT_EQ(size - 20, msg.length());
+  EXPECT_EQ("0123456789ab", msg.transaction_id());
+
+  msg2.SetType(STUN_BINDING_REQUEST);
+  msg2.SetTransactionID("0123456789ab");
+
+  in_addr legacy_in_addr;
+  legacy_in_addr.s_addr = htonl(17U);
+  rtc::IPAddress legacy_ip(legacy_in_addr);
+
+  const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  ASSERT_TRUE(addr != NULL);
+  EXPECT_EQ(1, addr->family());
+  EXPECT_EQ(13, addr->port());
+  EXPECT_EQ(legacy_ip, addr->ipaddr());
+
+  StunAddressAttribute* addr2 =
+      StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+  addr2->SetPort(13);
+  addr2->SetIP(legacy_ip);
+  EXPECT_TRUE(msg2.AddAttribute(addr2));
+
+  const StunByteStringAttribute* bytes = msg.GetByteString(STUN_ATTR_USERNAME);
+  ASSERT_TRUE(bytes != NULL);
+  EXPECT_EQ(12U, bytes->length());
+  EXPECT_EQ("abcdefghijkl", bytes->GetString());
+
+  StunByteStringAttribute* bytes2 =
+  StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+  bytes2->CopyBytes("abcdefghijkl");
+  EXPECT_TRUE(msg2.AddAttribute(bytes2));
+
+  const StunUInt32Attribute* uval = msg.GetUInt32(STUN_ATTR_LIFETIME);
+  ASSERT_TRUE(uval != NULL);
+  EXPECT_EQ(11U, uval->value());
+
+  StunUInt32Attribute* uval2 = StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
+  uval2->SetValue(11);
+  EXPECT_TRUE(msg2.AddAttribute(uval2));
+
+  bytes = msg.GetByteString(STUN_ATTR_MAGIC_COOKIE);
+  ASSERT_TRUE(bytes != NULL);
+  EXPECT_EQ(4U, bytes->length());
+  EXPECT_EQ(0,
+            memcmp(bytes->bytes(),
+                   TURN_MAGIC_COOKIE_VALUE,
+                   sizeof(TURN_MAGIC_COOKIE_VALUE)));
+
+  bytes2 = StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+  bytes2->CopyBytes(reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE),
+                    sizeof(TURN_MAGIC_COOKIE_VALUE));
+  EXPECT_TRUE(msg2.AddAttribute(bytes2));
+
+  uval = msg.GetUInt32(STUN_ATTR_BANDWIDTH);
+  ASSERT_TRUE(uval != NULL);
+  EXPECT_EQ(6U, uval->value());
+
+  uval2 = StunAttribute::CreateUInt32(STUN_ATTR_BANDWIDTH);
+  uval2->SetValue(6);
+  EXPECT_TRUE(msg2.AddAttribute(uval2));
+
+  addr = msg.GetAddress(STUN_ATTR_DESTINATION_ADDRESS);
+  ASSERT_TRUE(addr != NULL);
+  EXPECT_EQ(1, addr->family());
+  EXPECT_EQ(13, addr->port());
+  EXPECT_EQ(legacy_ip, addr->ipaddr());
+
+  addr2 = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+  addr2->SetPort(13);
+  addr2->SetIP(legacy_ip);
+  EXPECT_TRUE(msg2.AddAttribute(addr2));
+
+  addr = msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
+  ASSERT_TRUE(addr != NULL);
+  EXPECT_EQ(1, addr->family());
+  EXPECT_EQ(13, addr->port());
+  EXPECT_EQ(legacy_ip, addr->ipaddr());
+
+  addr2 = StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
+  addr2->SetPort(13);
+  addr2->SetIP(legacy_ip);
+  EXPECT_TRUE(msg2.AddAttribute(addr2));
+
+  bytes = msg.GetByteString(STUN_ATTR_DATA);
+  ASSERT_TRUE(bytes != NULL);
+  EXPECT_EQ(7U, bytes->length());
+  EXPECT_EQ("abcdefg", bytes->GetString());
+
+  bytes2 = StunAttribute::CreateByteString(STUN_ATTR_DATA);
+  bytes2->CopyBytes("abcdefg");
+  EXPECT_TRUE(msg2.AddAttribute(bytes2));
+
+  rtc::ByteBuffer out;
+  EXPECT_TRUE(msg.Write(&out));
+  EXPECT_EQ(size, out.Length());
+  size_t len1 = out.Length();
+  std::string outstring;
+  out.ReadString(&outstring, len1);
+  EXPECT_EQ(0, memcmp(outstring.c_str(), input, len1));
+
+  rtc::ByteBuffer out2;
+  EXPECT_TRUE(msg2.Write(&out2));
+  EXPECT_EQ(size, out2.Length());
+  size_t len2 = out2.Length();
+  std::string outstring2;
+  out2.ReadString(&outstring2, len2);
+  EXPECT_EQ(0, memcmp(outstring2.c_str(), input, len2));
+}
+
+}  // namespace cricket
diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc
new file mode 100644
index 0000000..ec6232a
--- /dev/null
+++ b/p2p/base/stunport.cc
@@ -0,0 +1,451 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/stunport.h"
+
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/nethelpers.h"
+
+namespace cricket {
+
+// TODO: Move these to a common place (used in relayport too)
+const int KEEPALIVE_DELAY = 10 * 1000;  // 10 seconds - sort timeouts
+const int RETRY_DELAY = 50;             // 50ms, from ICE spec
+const int RETRY_TIMEOUT = 50 * 1000;    // ICE says 50 secs
+
+// Handles a binding request sent to the STUN server.
+class StunBindingRequest : public StunRequest {
+ public:
+  StunBindingRequest(UDPPort* port, bool keep_alive,
+                     const rtc::SocketAddress& addr)
+    : port_(port), keep_alive_(keep_alive), server_addr_(addr) {
+    start_time_ = rtc::Time();
+  }
+
+  virtual ~StunBindingRequest() {
+  }
+
+  const rtc::SocketAddress& server_addr() const { return server_addr_; }
+
+  virtual void Prepare(StunMessage* request) {
+    request->SetType(STUN_BINDING_REQUEST);
+  }
+
+  virtual void OnResponse(StunMessage* response) {
+    const StunAddressAttribute* addr_attr =
+        response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+    if (!addr_attr) {
+      LOG(LS_ERROR) << "Binding response missing mapped address.";
+    } else if (addr_attr->family() != STUN_ADDRESS_IPV4 &&
+               addr_attr->family() != STUN_ADDRESS_IPV6) {
+      LOG(LS_ERROR) << "Binding address has bad family";
+    } else {
+      rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
+      port_->OnStunBindingRequestSucceeded(server_addr_, addr);
+    }
+
+    // We will do a keep-alive regardless of whether this request succeeds.
+    // This should have almost no impact on network usage.
+    if (keep_alive_) {
+      port_->requests_.SendDelayed(
+          new StunBindingRequest(port_, true, server_addr_),
+          port_->stun_keepalive_delay());
+    }
+  }
+
+  virtual void OnErrorResponse(StunMessage* response) {
+    const StunErrorCodeAttribute* attr = response->GetErrorCode();
+    if (!attr) {
+      LOG(LS_ERROR) << "Bad allocate response error code";
+    } else {
+      LOG(LS_ERROR) << "Binding error response:"
+                 << " class=" << attr->eclass()
+                 << " number=" << attr->number()
+                 << " reason='" << attr->reason() << "'";
+    }
+
+    port_->OnStunBindingOrResolveRequestFailed(server_addr_);
+
+    if (keep_alive_
+        && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) {
+      port_->requests_.SendDelayed(
+          new StunBindingRequest(port_, true, server_addr_),
+          port_->stun_keepalive_delay());
+    }
+  }
+
+  virtual void OnTimeout() {
+    LOG(LS_ERROR) << "Binding request timed out from "
+      << port_->GetLocalAddress().ToSensitiveString()
+      << " (" << port_->Network()->name() << ")";
+
+    port_->OnStunBindingOrResolveRequestFailed(server_addr_);
+
+    if (keep_alive_
+        && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) {
+      port_->requests_.SendDelayed(
+          new StunBindingRequest(port_, true, server_addr_),
+          RETRY_DELAY);
+    }
+  }
+
+ private:
+  UDPPort* port_;
+  bool keep_alive_;
+  const rtc::SocketAddress server_addr_;
+  uint32 start_time_;
+};
+
+UDPPort::AddressResolver::AddressResolver(
+    rtc::PacketSocketFactory* factory)
+    : socket_factory_(factory) {}
+
+UDPPort::AddressResolver::~AddressResolver() {
+  for (ResolverMap::iterator it = resolvers_.begin();
+       it != resolvers_.end(); ++it) {
+    it->second->Destroy(true);
+  }
+}
+
+void UDPPort::AddressResolver::Resolve(
+    const rtc::SocketAddress& address) {
+  if (resolvers_.find(address) != resolvers_.end())
+    return;
+
+  rtc::AsyncResolverInterface* resolver =
+      socket_factory_->CreateAsyncResolver();
+  resolvers_.insert(
+      std::pair<rtc::SocketAddress, rtc::AsyncResolverInterface*>(
+          address, resolver));
+
+  resolver->SignalDone.connect(this,
+                               &UDPPort::AddressResolver::OnResolveResult);
+
+  resolver->Start(address);
+}
+
+bool UDPPort::AddressResolver::GetResolvedAddress(
+    const rtc::SocketAddress& input,
+    int family,
+    rtc::SocketAddress* output) const {
+  ResolverMap::const_iterator it = resolvers_.find(input);
+  if (it == resolvers_.end())
+    return false;
+
+  return it->second->GetResolvedAddress(family, output);
+}
+
+void UDPPort::AddressResolver::OnResolveResult(
+    rtc::AsyncResolverInterface* resolver) {
+  for (ResolverMap::iterator it = resolvers_.begin();
+       it != resolvers_.end(); ++it) {
+    if (it->second == resolver) {
+      SignalDone(it->first, resolver->GetError());
+      return;
+    }
+  }
+}
+
+UDPPort::UDPPort(rtc::Thread* thread,
+                 rtc::PacketSocketFactory* factory,
+                 rtc::Network* network,
+                 rtc::AsyncPacketSocket* socket,
+                 const std::string& username, const std::string& password)
+    : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
+           username, password),
+      requests_(thread),
+      socket_(socket),
+      error_(0),
+      ready_(false),
+      stun_keepalive_delay_(KEEPALIVE_DELAY) {
+}
+
+UDPPort::UDPPort(rtc::Thread* thread,
+                 rtc::PacketSocketFactory* factory,
+                 rtc::Network* network,
+                 const rtc::IPAddress& ip, int min_port, int max_port,
+                 const std::string& username, const std::string& password)
+    : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port,
+           username, password),
+      requests_(thread),
+      socket_(NULL),
+      error_(0),
+      ready_(false),
+      stun_keepalive_delay_(KEEPALIVE_DELAY) {
+}
+
+bool UDPPort::Init() {
+  if (!SharedSocket()) {
+    ASSERT(socket_ == NULL);
+    socket_ = socket_factory()->CreateUdpSocket(
+        rtc::SocketAddress(ip(), 0), min_port(), max_port());
+    if (!socket_) {
+      LOG_J(LS_WARNING, this) << "UDP socket creation failed";
+      return false;
+    }
+    socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
+  }
+  socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend);
+  socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady);
+  requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket);
+  return true;
+}
+
+UDPPort::~UDPPort() {
+  if (!SharedSocket())
+    delete socket_;
+}
+
+void UDPPort::PrepareAddress() {
+  ASSERT(requests_.empty());
+  if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
+    OnLocalAddressReady(socket_, socket_->GetLocalAddress());
+  }
+}
+
+void UDPPort::MaybePrepareStunCandidate() {
+  // Sending binding request to the STUN server if address is available to
+  // prepare STUN candidate.
+  if (!server_addresses_.empty()) {
+    SendStunBindingRequests();
+  } else {
+    // Port is done allocating candidates.
+    MaybeSetPortCompleteOrError();
+  }
+}
+
+Connection* UDPPort::CreateConnection(const Candidate& address,
+                                       CandidateOrigin origin) {
+  if (address.protocol() != "udp")
+    return NULL;
+
+  if (!IsCompatibleAddress(address.address())) {
+    return NULL;
+  }
+
+  if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) {
+    ASSERT(false);
+    return NULL;
+  }
+
+  Connection* conn = new ProxyConnection(this, 0, address);
+  AddConnection(conn);
+  return conn;
+}
+
+int UDPPort::SendTo(const void* data, size_t size,
+                    const rtc::SocketAddress& addr,
+                    const rtc::PacketOptions& options,
+                    bool payload) {
+  int sent = socket_->SendTo(data, size, addr, options);
+  if (sent < 0) {
+    error_ = socket_->GetError();
+    LOG_J(LS_ERROR, this) << "UDP send of " << size
+                          << " bytes failed with error " << error_;
+  }
+  return sent;
+}
+
+int UDPPort::SetOption(rtc::Socket::Option opt, int value) {
+  return socket_->SetOption(opt, value);
+}
+
+int UDPPort::GetOption(rtc::Socket::Option opt, int* value) {
+  return socket_->GetOption(opt, value);
+}
+
+int UDPPort::GetError() {
+  return error_;
+}
+
+void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
+                                  const rtc::SocketAddress& address) {
+  AddAddress(address, address, rtc::SocketAddress(),
+             UDP_PROTOCOL_NAME, "", LOCAL_PORT_TYPE,
+             ICE_TYPE_PREFERENCE_HOST, 0, false);
+  MaybePrepareStunCandidate();
+}
+
+void UDPPort::OnReadPacket(
+  rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+  const rtc::SocketAddress& remote_addr,
+  const rtc::PacketTime& packet_time) {
+  ASSERT(socket == socket_);
+  ASSERT(!remote_addr.IsUnresolved());
+
+  // Look for a response from the STUN server.
+  // Even if the response doesn't match one of our outstanding requests, we
+  // will eat it because it might be a response to a retransmitted packet, and
+  // we already cleared the request when we got the first response.
+  if (server_addresses_.find(remote_addr) != server_addresses_.end()) {
+    requests_.CheckResponse(data, size);
+    return;
+  }
+
+  if (Connection* conn = GetConnection(remote_addr)) {
+    conn->OnReadPacket(data, size, packet_time);
+  } else {
+    Port::OnReadPacket(data, size, remote_addr, PROTO_UDP);
+  }
+}
+
+void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
+  Port::OnReadyToSend();
+}
+
+void UDPPort::SendStunBindingRequests() {
+  // We will keep pinging the stun server to make sure our NAT pin-hole stays
+  // open during the call.
+  ASSERT(requests_.empty());
+
+  for (ServerAddresses::const_iterator it = server_addresses_.begin();
+       it != server_addresses_.end(); ++it) {
+    SendStunBindingRequest(*it);
+  }
+}
+
+void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) {
+  if (!resolver_) {
+    resolver_.reset(new AddressResolver(socket_factory()));
+    resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult);
+  }
+
+  resolver_->Resolve(stun_addr);
+}
+
+void UDPPort::OnResolveResult(const rtc::SocketAddress& input,
+                              int error) {
+  ASSERT(resolver_.get() != NULL);
+
+  rtc::SocketAddress resolved;
+  if (error != 0 ||
+      !resolver_->GetResolvedAddress(input, ip().family(), &resolved))  {
+    LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error "
+                            << error;
+    OnStunBindingOrResolveRequestFailed(input);
+    return;
+  }
+
+  server_addresses_.erase(input);
+
+  if (server_addresses_.find(resolved) == server_addresses_.end()) {
+    server_addresses_.insert(resolved);
+    SendStunBindingRequest(resolved);
+  }
+}
+
+void UDPPort::SendStunBindingRequest(
+    const rtc::SocketAddress& stun_addr) {
+  if (stun_addr.IsUnresolved()) {
+    ResolveStunAddress(stun_addr);
+
+  } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
+    // Check if |server_addr_| is compatible with the port's ip.
+    if (IsCompatibleAddress(stun_addr)) {
+      requests_.Send(new StunBindingRequest(this, true, stun_addr));
+    } else {
+      // Since we can't send stun messages to the server, we should mark this
+      // port ready.
+      LOG(LS_WARNING) << "STUN server address is incompatible.";
+      OnStunBindingOrResolveRequestFailed(stun_addr);
+    }
+  }
+}
+
+void UDPPort::OnStunBindingRequestSucceeded(
+    const rtc::SocketAddress& stun_server_addr,
+    const rtc::SocketAddress& stun_reflected_addr) {
+  if (bind_request_succeeded_servers_.find(stun_server_addr) !=
+          bind_request_succeeded_servers_.end()) {
+    return;
+  }
+  bind_request_succeeded_servers_.insert(stun_server_addr);
+
+  // If socket is shared and |stun_reflected_addr| is equal to local socket
+  // address, or if the same address has been added by another STUN server,
+  // then discarding the stun address.
+  // For STUN, related address is the local socket address.
+  if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress()) &&
+      !HasCandidateWithAddress(stun_reflected_addr)) {
+
+    rtc::SocketAddress related_address = socket_->GetLocalAddress();
+    if (!(candidate_filter() & CF_HOST)) {
+      // If candidate filter doesn't have CF_HOST specified, empty raddr to
+      // avoid local address leakage.
+      related_address = rtc::EmptySocketAddressWithFamily(
+          related_address.family());
+    }
+
+    AddAddress(stun_reflected_addr, socket_->GetLocalAddress(),
+               related_address, UDP_PROTOCOL_NAME, "",
+               STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, 0, false);
+  }
+  MaybeSetPortCompleteOrError();
+}
+
+void UDPPort::OnStunBindingOrResolveRequestFailed(
+    const rtc::SocketAddress& stun_server_addr) {
+  if (bind_request_failed_servers_.find(stun_server_addr) !=
+          bind_request_failed_servers_.end()) {
+    return;
+  }
+  bind_request_failed_servers_.insert(stun_server_addr);
+  MaybeSetPortCompleteOrError();
+}
+
+void UDPPort::MaybeSetPortCompleteOrError() {
+  if (ready_)
+    return;
+
+  // Do not set port ready if we are still waiting for bind responses.
+  const size_t servers_done_bind_request = bind_request_failed_servers_.size() +
+      bind_request_succeeded_servers_.size();
+  if (server_addresses_.size() != servers_done_bind_request) {
+    return;
+  }
+
+  // Setting ready status.
+  ready_ = true;
+
+  // The port is "completed" if there is no stun server provided, or the bind
+  // request succeeded for any stun server, or the socket is shared.
+  if (server_addresses_.empty() ||
+      bind_request_succeeded_servers_.size() > 0 ||
+      SharedSocket()) {
+    SignalPortComplete(this);
+  } else {
+    SignalPortError(this);
+  }
+}
+
+// TODO: merge this with SendTo above.
+void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
+  StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
+  rtc::PacketOptions options(DefaultDscpValue());
+  if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0)
+    PLOG(LERROR, socket_->GetError()) << "sendto";
+}
+
+bool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const {
+  const std::vector<Candidate>& existing_candidates = Candidates();
+  std::vector<Candidate>::const_iterator it = existing_candidates.begin();
+  for (; it != existing_candidates.end(); ++it) {
+    if (it->address() == addr)
+      return true;
+  }
+  return false;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/stunport.h b/p2p/base/stunport.h
new file mode 100644
index 0000000..eda7bb9
--- /dev/null
+++ b/p2p/base/stunport.h
@@ -0,0 +1,238 @@
+/*
+ *  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_P2P_BASE_STUNPORT_H_
+#define WEBRTC_P2P_BASE_STUNPORT_H_
+
+#include <string>
+
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/stunrequest.h"
+#include "webrtc/base/asyncpacketsocket.h"
+
+// TODO(mallinath) - Rename stunport.cc|h to udpport.cc|h.
+namespace rtc {
+class AsyncResolver;
+class SignalThread;
+}
+
+namespace cricket {
+
+// Communicates using the address on the outside of a NAT.
+class UDPPort : public Port {
+ public:
+  static UDPPort* Create(rtc::Thread* thread,
+                         rtc::PacketSocketFactory* factory,
+                         rtc::Network* network,
+                         rtc::AsyncPacketSocket* socket,
+                         const std::string& username,
+                         const std::string& password) {
+    UDPPort* port = new UDPPort(thread, factory, network, socket,
+                                username, password);
+    if (!port->Init()) {
+      delete port;
+      port = NULL;
+    }
+    return port;
+  }
+
+  static UDPPort* Create(rtc::Thread* thread,
+                         rtc::PacketSocketFactory* factory,
+                         rtc::Network* network,
+                         const rtc::IPAddress& ip,
+                         int min_port, int max_port,
+                         const std::string& username,
+                         const std::string& password) {
+    UDPPort* port = new UDPPort(thread, factory, network,
+                                ip, min_port, max_port,
+                                username, password);
+    if (!port->Init()) {
+      delete port;
+      port = NULL;
+    }
+    return port;
+  }
+  virtual ~UDPPort();
+
+  rtc::SocketAddress GetLocalAddress() const {
+    return socket_->GetLocalAddress();
+  }
+
+  const ServerAddresses& server_addresses() const {
+    return server_addresses_;
+  }
+  void
+  set_server_addresses(const ServerAddresses& addresses) {
+    server_addresses_ = addresses;
+  }
+
+  virtual void PrepareAddress();
+
+  virtual Connection* CreateConnection(const Candidate& address,
+                                       CandidateOrigin origin);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetOption(rtc::Socket::Option opt, int* value);
+  virtual int GetError();
+
+  virtual bool HandleIncomingPacket(
+      rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+      const rtc::SocketAddress& remote_addr,
+      const rtc::PacketTime& packet_time) {
+    // All packets given to UDP port will be consumed.
+    OnReadPacket(socket, data, size, remote_addr, packet_time);
+    return true;
+  }
+
+  void set_stun_keepalive_delay(int delay) {
+    stun_keepalive_delay_ = delay;
+  }
+  int stun_keepalive_delay() const {
+    return stun_keepalive_delay_;
+  }
+
+ protected:
+  UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+          rtc::Network* network, const rtc::IPAddress& ip,
+          int min_port, int max_port,
+          const std::string& username, const std::string& password);
+
+  UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+          rtc::Network* network, rtc::AsyncPacketSocket* socket,
+          const std::string& username, const std::string& password);
+
+  bool Init();
+
+  virtual int SendTo(const void* data, size_t size,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options,
+                     bool payload);
+
+  void OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
+                           const rtc::SocketAddress& address);
+  void OnReadPacket(rtc::AsyncPacketSocket* socket,
+                    const char* data, size_t size,
+                    const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time);
+
+  void OnReadyToSend(rtc::AsyncPacketSocket* socket);
+
+  // This method will send STUN binding request if STUN server address is set.
+  void MaybePrepareStunCandidate();
+
+  void SendStunBindingRequests();
+
+ private:
+  // A helper class which can be called repeatedly to resolve multiple
+  // addresses, as opposed to rtc::AsyncResolverInterface, which can only
+  // resolve one address per instance.
+  class AddressResolver : public sigslot::has_slots<> {
+   public:
+    explicit AddressResolver(rtc::PacketSocketFactory* factory);
+    ~AddressResolver();
+
+    void Resolve(const rtc::SocketAddress& address);
+    bool GetResolvedAddress(const rtc::SocketAddress& input,
+                            int family,
+                            rtc::SocketAddress* output) const;
+
+    // The signal is sent when resolving the specified address is finished. The
+    // first argument is the input address, the second argument is the error
+    // or 0 if it succeeded.
+    sigslot::signal2<const rtc::SocketAddress&, int> SignalDone;
+
+   private:
+    typedef std::map<rtc::SocketAddress,
+                     rtc::AsyncResolverInterface*> ResolverMap;
+
+    void OnResolveResult(rtc::AsyncResolverInterface* resolver);
+
+    rtc::PacketSocketFactory* socket_factory_;
+    ResolverMap resolvers_;
+  };
+
+  // DNS resolution of the STUN server.
+  void ResolveStunAddress(const rtc::SocketAddress& stun_addr);
+  void OnResolveResult(const rtc::SocketAddress& input, int error);
+
+  void SendStunBindingRequest(const rtc::SocketAddress& stun_addr);
+
+  // Below methods handles binding request responses.
+  void OnStunBindingRequestSucceeded(
+      const rtc::SocketAddress& stun_server_addr,
+      const rtc::SocketAddress& stun_reflected_addr);
+  void OnStunBindingOrResolveRequestFailed(
+      const rtc::SocketAddress& stun_server_addr);
+
+  // Sends STUN requests to the server.
+  void OnSendPacket(const void* data, size_t size, StunRequest* req);
+
+  // TODO(mallinaht) - Move this up to cricket::Port when SignalAddressReady is
+  // changed to SignalPortReady.
+  void MaybeSetPortCompleteOrError();
+
+  bool HasCandidateWithAddress(const rtc::SocketAddress& addr) const;
+
+  ServerAddresses server_addresses_;
+  ServerAddresses bind_request_succeeded_servers_;
+  ServerAddresses bind_request_failed_servers_;
+  StunRequestManager requests_;
+  rtc::AsyncPacketSocket* socket_;
+  int error_;
+  rtc::scoped_ptr<AddressResolver> resolver_;
+  bool ready_;
+  int stun_keepalive_delay_;
+
+  friend class StunBindingRequest;
+};
+
+class StunPort : public UDPPort {
+ public:
+  static StunPort* Create(
+      rtc::Thread* thread,
+      rtc::PacketSocketFactory* factory,
+      rtc::Network* network,
+      const rtc::IPAddress& ip,
+      int min_port, int max_port,
+      const std::string& username,
+      const std::string& password,
+      const ServerAddresses& servers) {
+    StunPort* port = new StunPort(thread, factory, network,
+                                  ip, min_port, max_port,
+                                  username, password, servers);
+    if (!port->Init()) {
+      delete port;
+      port = NULL;
+    }
+    return port;
+  }
+
+  virtual ~StunPort() {}
+
+  virtual void PrepareAddress() {
+    SendStunBindingRequests();
+  }
+
+ protected:
+  StunPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+           rtc::Network* network, const rtc::IPAddress& ip,
+           int min_port, int max_port,
+           const std::string& username, const std::string& password,
+           const ServerAddresses& servers)
+     : UDPPort(thread, factory, network, ip, min_port, max_port, username,
+               password) {
+    // UDPPort will set these to local udp, updating these to STUN.
+    set_type(STUN_PORT_TYPE);
+    set_server_addresses(servers);
+  }
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_STUNPORT_H_
diff --git a/p2p/base/stunport_unittest.cc b/p2p/base/stunport_unittest.cc
new file mode 100644
index 0000000..81b6808
--- /dev/null
+++ b/p2p/base/stunport_unittest.cc
@@ -0,0 +1,283 @@
+/*
+ *  Copyright 2009 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/stunport.h"
+#include "webrtc/p2p/base/teststunserver.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+using cricket::ServerAddresses;
+using rtc::SocketAddress;
+
+static const SocketAddress kLocalAddr("127.0.0.1", 0);
+static const SocketAddress kStunAddr1("127.0.0.1", 5000);
+static const SocketAddress kStunAddr2("127.0.0.1", 4000);
+static const SocketAddress kBadAddr("0.0.0.1", 5000);
+static const SocketAddress kStunHostnameAddr("localhost", 5000);
+static const SocketAddress kBadHostnameAddr("not-a-real-hostname", 5000);
+static const int kTimeoutMs = 10000;
+// stun prio = 100 << 24 | 30 (IPV4) << 8 | 256 - 0
+static const uint32 kStunCandidatePriority = 1677729535;
+
+// Tests connecting a StunPort to a fake STUN server (cricket::StunServer)
+// TODO: Use a VirtualSocketServer here. We have to use a
+// PhysicalSocketServer right now since DNS is not part of SocketServer yet.
+class StunPortTest : public testing::Test,
+                     public sigslot::has_slots<> {
+ public:
+  StunPortTest()
+      : pss_(new rtc::PhysicalSocketServer),
+        ss_(new rtc::VirtualSocketServer(pss_.get())),
+        ss_scope_(ss_.get()),
+        network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32),
+        socket_factory_(rtc::Thread::Current()),
+        stun_server_1_(cricket::TestStunServer::Create(
+          rtc::Thread::Current(), kStunAddr1)),
+        stun_server_2_(cricket::TestStunServer::Create(
+          rtc::Thread::Current(), kStunAddr2)),
+        done_(false), error_(false), stun_keepalive_delay_(0) {
+  }
+
+  const cricket::Port* port() const { return stun_port_.get(); }
+  bool done() const { return done_; }
+  bool error() const { return error_; }
+
+  void CreateStunPort(const rtc::SocketAddress& server_addr) {
+    ServerAddresses stun_servers;
+    stun_servers.insert(server_addr);
+    CreateStunPort(stun_servers);
+  }
+
+  void CreateStunPort(const ServerAddresses& stun_servers) {
+    stun_port_.reset(cricket::StunPort::Create(
+        rtc::Thread::Current(), &socket_factory_, &network_,
+        kLocalAddr.ipaddr(), 0, 0, rtc::CreateRandomString(16),
+        rtc::CreateRandomString(22), stun_servers));
+    stun_port_->set_stun_keepalive_delay(stun_keepalive_delay_);
+    stun_port_->SignalPortComplete.connect(this,
+        &StunPortTest::OnPortComplete);
+    stun_port_->SignalPortError.connect(this,
+        &StunPortTest::OnPortError);
+  }
+
+  void CreateSharedStunPort(const rtc::SocketAddress& server_addr) {
+    socket_.reset(socket_factory_.CreateUdpSocket(
+        rtc::SocketAddress(kLocalAddr.ipaddr(), 0), 0, 0));
+    ASSERT_TRUE(socket_ != NULL);
+    socket_->SignalReadPacket.connect(this, &StunPortTest::OnReadPacket);
+    stun_port_.reset(cricket::UDPPort::Create(
+        rtc::Thread::Current(), &socket_factory_,
+        &network_, socket_.get(),
+        rtc::CreateRandomString(16), rtc::CreateRandomString(22)));
+    ASSERT_TRUE(stun_port_ != NULL);
+    ServerAddresses stun_servers;
+    stun_servers.insert(server_addr);
+    stun_port_->set_server_addresses(stun_servers);
+    stun_port_->SignalPortComplete.connect(this,
+        &StunPortTest::OnPortComplete);
+    stun_port_->SignalPortError.connect(this,
+        &StunPortTest::OnPortError);
+  }
+
+  void PrepareAddress() {
+    stun_port_->PrepareAddress();
+  }
+
+  void OnReadPacket(rtc::AsyncPacketSocket* socket, const char* data,
+                    size_t size, const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time) {
+    stun_port_->HandleIncomingPacket(
+        socket, data, size, remote_addr, rtc::PacketTime());
+  }
+
+  void SendData(const char* data, size_t len) {
+    stun_port_->HandleIncomingPacket(
+        socket_.get(), data, len, rtc::SocketAddress("22.22.22.22", 0),
+        rtc::PacketTime());
+  }
+
+ protected:
+  static void SetUpTestCase() {
+    // Ensure the RNG is inited.
+    rtc::InitRandom(NULL, 0);
+
+  }
+
+  void OnPortComplete(cricket::Port* port) {
+    ASSERT_FALSE(done_);
+    done_ = true;
+    error_ = false;
+  }
+  void OnPortError(cricket::Port* port) {
+    done_ = true;
+    error_ = true;
+  }
+  void SetKeepaliveDelay(int delay) {
+    stun_keepalive_delay_ = delay;
+  }
+
+  cricket::TestStunServer* stun_server_1() {
+    return stun_server_1_.get();
+  }
+  cricket::TestStunServer* stun_server_2() {
+    return stun_server_2_.get();
+  }
+
+ private:
+  rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> ss_;
+  rtc::SocketServerScope ss_scope_;
+  rtc::Network network_;
+  rtc::BasicPacketSocketFactory socket_factory_;
+  rtc::scoped_ptr<cricket::UDPPort> stun_port_;
+  rtc::scoped_ptr<cricket::TestStunServer> stun_server_1_;
+  rtc::scoped_ptr<cricket::TestStunServer> stun_server_2_;
+  rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_;
+  bool done_;
+  bool error_;
+  int stun_keepalive_delay_;
+};
+
+// Test that we can create a STUN port
+TEST_F(StunPortTest, TestBasic) {
+  CreateStunPort(kStunAddr1);
+  EXPECT_EQ("stun", port()->Type());
+  EXPECT_EQ(0U, port()->Candidates().size());
+}
+
+// Test that we can get an address from a STUN server.
+TEST_F(StunPortTest, TestPrepareAddress) {
+  CreateStunPort(kStunAddr1);
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  ASSERT_EQ(1U, port()->Candidates().size());
+  EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+
+  // TODO: Add IPv6 tests here, once either physicalsocketserver supports
+  // IPv6, or this test is changed to use VirtualSocketServer.
+}
+
+// Test that we fail properly if we can't get an address.
+TEST_F(StunPortTest, TestPrepareAddressFail) {
+  CreateStunPort(kBadAddr);
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  EXPECT_TRUE(error());
+  EXPECT_EQ(0U, port()->Candidates().size());
+}
+
+// Test that we can get an address from a STUN server specified by a hostname.
+TEST_F(StunPortTest, TestPrepareAddressHostname) {
+  CreateStunPort(kStunHostnameAddr);
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  ASSERT_EQ(1U, port()->Candidates().size());
+  EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+  EXPECT_EQ(kStunCandidatePriority, port()->Candidates()[0].priority());
+}
+
+// Test that we handle hostname lookup failures properly.
+TEST_F(StunPortTest, TestPrepareAddressHostnameFail) {
+  CreateStunPort(kBadHostnameAddr);
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  EXPECT_TRUE(error());
+  EXPECT_EQ(0U, port()->Candidates().size());
+}
+
+// This test verifies keepalive response messages don't result in
+// additional candidate generation.
+TEST_F(StunPortTest, TestKeepAliveResponse) {
+  SetKeepaliveDelay(500);  // 500ms of keepalive delay.
+  CreateStunPort(kStunHostnameAddr);
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  ASSERT_EQ(1U, port()->Candidates().size());
+  EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+  // Waiting for 1 seond, which will allow us to process
+  // response for keepalive binding request. 500 ms is the keepalive delay.
+  rtc::Thread::Current()->ProcessMessages(1000);
+  ASSERT_EQ(1U, port()->Candidates().size());
+}
+
+// Test that a local candidate can be generated using a shared socket.
+TEST_F(StunPortTest, TestSharedSocketPrepareAddress) {
+  CreateSharedStunPort(kStunAddr1);
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  ASSERT_EQ(1U, port()->Candidates().size());
+  EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+}
+
+// Test that we still a get a local candidate with invalid stun server hostname.
+// Also verifing that UDPPort can receive packets when stun address can't be
+// resolved.
+TEST_F(StunPortTest, TestSharedSocketPrepareAddressInvalidHostname) {
+  CreateSharedStunPort(kBadHostnameAddr);
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  ASSERT_EQ(1U, port()->Candidates().size());
+  EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+
+  // Send data to port after it's ready. This is to make sure, UDP port can
+  // handle data with unresolved stun server address.
+  std::string data = "some random data, sending to cricket::Port.";
+  SendData(data.c_str(), data.length());
+  // No crash is success.
+}
+
+// Test that the same address is added only once if two STUN servers are in use.
+TEST_F(StunPortTest, TestNoDuplicatedAddressWithTwoStunServers) {
+  ServerAddresses stun_servers;
+  stun_servers.insert(kStunAddr1);
+  stun_servers.insert(kStunAddr2);
+  CreateStunPort(stun_servers);
+  EXPECT_EQ("stun", port()->Type());
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  EXPECT_EQ(1U, port()->Candidates().size());
+}
+
+// Test that candidates can be allocated for multiple STUN servers, one of which
+// is not reachable.
+TEST_F(StunPortTest, TestMultipleStunServersWithBadServer) {
+  ServerAddresses stun_servers;
+  stun_servers.insert(kStunAddr1);
+  stun_servers.insert(kBadAddr);
+  CreateStunPort(stun_servers);
+  EXPECT_EQ("stun", port()->Type());
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  EXPECT_EQ(1U, port()->Candidates().size());
+}
+
+// Test that two candidates are allocated if the two STUN servers return
+// different mapped addresses.
+TEST_F(StunPortTest, TestTwoCandidatesWithTwoStunServersAcrossNat) {
+  const SocketAddress kStunMappedAddr1("77.77.77.77", 0);
+  const SocketAddress kStunMappedAddr2("88.77.77.77", 0);
+  stun_server_1()->set_fake_stun_addr(kStunMappedAddr1);
+  stun_server_2()->set_fake_stun_addr(kStunMappedAddr2);
+
+  ServerAddresses stun_servers;
+  stun_servers.insert(kStunAddr1);
+  stun_servers.insert(kStunAddr2);
+  CreateStunPort(stun_servers);
+  EXPECT_EQ("stun", port()->Type());
+  PrepareAddress();
+  EXPECT_TRUE_WAIT(done(), kTimeoutMs);
+  EXPECT_EQ(2U, port()->Candidates().size());
+}
diff --git a/p2p/base/stunrequest.cc b/p2p/base/stunrequest.cc
new file mode 100644
index 0000000..65eb027
--- /dev/null
+++ b/p2p/base/stunrequest.cc
@@ -0,0 +1,193 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/stunrequest.h"
+
+#include "webrtc/base/common.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+
+namespace cricket {
+
+const uint32 MSG_STUN_SEND = 1;
+
+const int MAX_SENDS = 9;
+const int DELAY_UNIT = 100;  // 100 milliseconds
+const int DELAY_MAX_FACTOR = 16;
+
+StunRequestManager::StunRequestManager(rtc::Thread* thread)
+    : thread_(thread) {
+}
+
+StunRequestManager::~StunRequestManager() {
+  while (requests_.begin() != requests_.end()) {
+    StunRequest *request = requests_.begin()->second;
+    requests_.erase(requests_.begin());
+    delete request;
+  }
+}
+
+void StunRequestManager::Send(StunRequest* request) {
+  SendDelayed(request, 0);
+}
+
+void StunRequestManager::SendDelayed(StunRequest* request, int delay) {
+  request->set_manager(this);
+  ASSERT(requests_.find(request->id()) == requests_.end());
+  request->Construct();
+  requests_[request->id()] = request;
+  thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL);
+}
+
+void StunRequestManager::Remove(StunRequest* request) {
+  ASSERT(request->manager() == this);
+  RequestMap::iterator iter = requests_.find(request->id());
+  if (iter != requests_.end()) {
+    ASSERT(iter->second == request);
+    requests_.erase(iter);
+    thread_->Clear(request);
+  }
+}
+
+void StunRequestManager::Clear() {
+  std::vector<StunRequest*> requests;
+  for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i)
+    requests.push_back(i->second);
+
+  for (uint32 i = 0; i < requests.size(); ++i) {
+    // StunRequest destructor calls Remove() which deletes requests
+    // from |requests_|.
+    delete requests[i];
+  }
+}
+
+bool StunRequestManager::CheckResponse(StunMessage* msg) {
+  RequestMap::iterator iter = requests_.find(msg->transaction_id());
+  if (iter == requests_.end())
+    return false;
+
+  StunRequest* request = iter->second;
+  if (msg->type() == GetStunSuccessResponseType(request->type())) {
+    request->OnResponse(msg);
+  } else if (msg->type() == GetStunErrorResponseType(request->type())) {
+    request->OnErrorResponse(msg);
+  } else {
+    LOG(LERROR) << "Received response with wrong type: " << msg->type()
+                << " (expecting "
+                << GetStunSuccessResponseType(request->type()) << ")";
+    return false;
+  }
+
+  delete request;
+  return true;
+}
+
+bool StunRequestManager::CheckResponse(const char* data, size_t size) {
+  // Check the appropriate bytes of the stream to see if they match the
+  // transaction ID of a response we are expecting.
+
+  if (size < 20)
+    return false;
+
+  std::string id;
+  id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
+
+  RequestMap::iterator iter = requests_.find(id);
+  if (iter == requests_.end())
+    return false;
+
+  // Parse the STUN message and continue processing as usual.
+
+  rtc::ByteBuffer buf(data, size);
+  rtc::scoped_ptr<StunMessage> response(iter->second->msg_->CreateNew());
+  if (!response->Read(&buf))
+    return false;
+
+  return CheckResponse(response.get());
+}
+
+StunRequest::StunRequest()
+    : count_(0), timeout_(false), manager_(0),
+      msg_(new StunMessage()), tstamp_(0) {
+  msg_->SetTransactionID(
+      rtc::CreateRandomString(kStunTransactionIdLength));
+}
+
+StunRequest::StunRequest(StunMessage* request)
+    : count_(0), timeout_(false), manager_(0),
+      msg_(request), tstamp_(0) {
+  msg_->SetTransactionID(
+      rtc::CreateRandomString(kStunTransactionIdLength));
+}
+
+StunRequest::~StunRequest() {
+  ASSERT(manager_ != NULL);
+  if (manager_) {
+    manager_->Remove(this);
+    manager_->thread_->Clear(this);
+  }
+  delete msg_;
+}
+
+void StunRequest::Construct() {
+  if (msg_->type() == 0) {
+    Prepare(msg_);
+    ASSERT(msg_->type() != 0);
+  }
+}
+
+int StunRequest::type() {
+  ASSERT(msg_ != NULL);
+  return msg_->type();
+}
+
+const StunMessage* StunRequest::msg() const {
+  return msg_;
+}
+
+uint32 StunRequest::Elapsed() const {
+  return rtc::TimeSince(tstamp_);
+}
+
+
+void StunRequest::set_manager(StunRequestManager* manager) {
+  ASSERT(!manager_);
+  manager_ = manager;
+}
+
+void StunRequest::OnMessage(rtc::Message* pmsg) {
+  ASSERT(manager_ != NULL);
+  ASSERT(pmsg->message_id == MSG_STUN_SEND);
+
+  if (timeout_) {
+    OnTimeout();
+    delete this;
+    return;
+  }
+
+  tstamp_ = rtc::Time();
+
+  rtc::ByteBuffer buf;
+  msg_->Write(&buf);
+  manager_->SignalSendPacket(buf.Data(), buf.Length(), this);
+
+  int delay = GetNextDelay();
+  manager_->thread_->PostDelayed(delay, this, MSG_STUN_SEND, NULL);
+}
+
+int StunRequest::GetNextDelay() {
+  int delay = DELAY_UNIT * rtc::_min(1 << count_, DELAY_MAX_FACTOR);
+  count_ += 1;
+  if (count_ == MAX_SENDS)
+    timeout_ = true;
+  return delay;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/stunrequest.h b/p2p/base/stunrequest.h
new file mode 100644
index 0000000..5fefc2f
--- /dev/null
+++ b/p2p/base/stunrequest.h
@@ -0,0 +1,116 @@
+/*
+ *  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_P2P_BASE_STUNREQUEST_H_
+#define WEBRTC_P2P_BASE_STUNREQUEST_H_
+
+#include <map>
+#include <string>
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+class StunRequest;
+
+// Manages a set of STUN requests, sending and resending until we receive a
+// response or determine that the request has timed out.
+class StunRequestManager {
+public:
+  StunRequestManager(rtc::Thread* thread);
+  ~StunRequestManager();
+
+  // Starts sending the given request (perhaps after a delay).
+  void Send(StunRequest* request);
+  void SendDelayed(StunRequest* request, int delay);
+
+  // Removes a stun request that was added previously.  This will happen
+  // automatically when a request succeeds, fails, or times out.
+  void Remove(StunRequest* request);
+
+  // Removes all stun requests that were added previously.
+  void Clear();
+
+  // Determines whether the given message is a response to one of the
+  // outstanding requests, and if so, processes it appropriately.
+  bool CheckResponse(StunMessage* msg);
+  bool CheckResponse(const char* data, size_t size);
+
+  bool empty() { return requests_.empty(); }
+
+  // Raised when there are bytes to be sent.
+  sigslot::signal3<const void*, size_t, StunRequest*> SignalSendPacket;
+
+private:
+  typedef std::map<std::string, StunRequest*> RequestMap;
+
+  rtc::Thread* thread_;
+  RequestMap requests_;
+
+  friend class StunRequest;
+};
+
+// Represents an individual request to be sent.  The STUN message can either be
+// constructed beforehand or built on demand.
+class StunRequest : public rtc::MessageHandler {
+public:
+  StunRequest();
+  StunRequest(StunMessage* request);
+  virtual ~StunRequest();
+
+  // Causes our wrapped StunMessage to be Prepared
+  void Construct();
+
+  // The manager handling this request (if it has been scheduled for sending).
+  StunRequestManager* manager() { return manager_; }
+
+  // Returns the transaction ID of this request.
+  const std::string& id() { return msg_->transaction_id(); }
+
+  // Returns the STUN type of the request message.
+  int type();
+
+  // Returns a const pointer to |msg_|.
+  const StunMessage* msg() const;
+
+  // Time elapsed since last send (in ms)
+  uint32 Elapsed() const;
+
+protected:
+  int count_;
+  bool timeout_;
+
+  // Fills in a request object to be sent.  Note that request's transaction ID
+  // will already be set and cannot be changed.
+  virtual void Prepare(StunMessage* request) {}
+
+  // Called when the message receives a response or times out.
+  virtual void OnResponse(StunMessage* response) {}
+  virtual void OnErrorResponse(StunMessage* response) {}
+  virtual void OnTimeout() {}
+  virtual int GetNextDelay();
+
+private:
+  void set_manager(StunRequestManager* manager);
+
+  // Handles messages for sending and timeout.
+  void OnMessage(rtc::Message* pmsg);
+
+  StunRequestManager* manager_;
+  StunMessage* msg_;
+  uint32 tstamp_;
+
+  friend class StunRequestManager;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_STUNREQUEST_H_
diff --git a/p2p/base/stunrequest_unittest.cc b/p2p/base/stunrequest_unittest.cc
new file mode 100644
index 0000000..3ff6cba
--- /dev/null
+++ b/p2p/base/stunrequest_unittest.cc
@@ -0,0 +1,203 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/stunrequest.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/timeutils.h"
+
+using namespace cricket;
+
+class StunRequestTest : public testing::Test,
+                        public sigslot::has_slots<> {
+ public:
+  StunRequestTest()
+      : manager_(rtc::Thread::Current()),
+        request_count_(0), response_(NULL),
+        success_(false), failure_(false), timeout_(false) {
+    manager_.SignalSendPacket.connect(this, &StunRequestTest::OnSendPacket);
+  }
+
+  void OnSendPacket(const void* data, size_t size, StunRequest* req) {
+    request_count_++;
+  }
+
+  void OnResponse(StunMessage* res) {
+    response_ = res;
+    success_ = true;
+  }
+  void OnErrorResponse(StunMessage* res) {
+    response_ = res;
+    failure_ = true;
+  }
+  void OnTimeout() {
+    timeout_ = true;
+  }
+
+ protected:
+  static StunMessage* CreateStunMessage(StunMessageType type,
+                                        StunMessage* req) {
+    StunMessage* msg = new StunMessage();
+    msg->SetType(type);
+    if (req) {
+      msg->SetTransactionID(req->transaction_id());
+    }
+    return msg;
+  }
+  static int TotalDelay(int sends) {
+    int total = 0;
+    for (int i = 0; i < sends; i++) {
+      if (i < 4)
+        total += 100 << i;
+      else
+        total += 1600;
+    }
+    return total;
+  }
+
+  StunRequestManager manager_;
+  int request_count_;
+  StunMessage* response_;
+  bool success_;
+  bool failure_;
+  bool timeout_;
+};
+
+// Forwards results to the test class.
+class StunRequestThunker : public StunRequest {
+ public:
+  StunRequestThunker(StunMessage* msg, StunRequestTest* test)
+      : StunRequest(msg), test_(test) {}
+  explicit StunRequestThunker(StunRequestTest* test) : test_(test) {}
+ private:
+  virtual void OnResponse(StunMessage* res) {
+    test_->OnResponse(res);
+  }
+  virtual void OnErrorResponse(StunMessage* res) {
+    test_->OnErrorResponse(res);
+  }
+  virtual void OnTimeout() {
+    test_->OnTimeout();
+  }
+
+  virtual void Prepare(StunMessage* request) {
+    request->SetType(STUN_BINDING_REQUEST);
+  }
+
+  StunRequestTest* test_;
+};
+
+// Test handling of a normal binding response.
+TEST_F(StunRequestTest, TestSuccess) {
+  StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
+
+  manager_.Send(new StunRequestThunker(req, this));
+  StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
+  EXPECT_TRUE(manager_.CheckResponse(res));
+
+  EXPECT_TRUE(response_ == res);
+  EXPECT_TRUE(success_);
+  EXPECT_FALSE(failure_);
+  EXPECT_FALSE(timeout_);
+  delete res;
+}
+
+// Test handling of an error binding response.
+TEST_F(StunRequestTest, TestError) {
+  StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
+
+  manager_.Send(new StunRequestThunker(req, this));
+  StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req);
+  EXPECT_TRUE(manager_.CheckResponse(res));
+
+  EXPECT_TRUE(response_ == res);
+  EXPECT_FALSE(success_);
+  EXPECT_TRUE(failure_);
+  EXPECT_FALSE(timeout_);
+  delete res;
+}
+
+// Test handling of a binding response with the wrong transaction id.
+TEST_F(StunRequestTest, TestUnexpected) {
+  StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
+
+  manager_.Send(new StunRequestThunker(req, this));
+  StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, NULL);
+  EXPECT_FALSE(manager_.CheckResponse(res));
+
+  EXPECT_TRUE(response_ == NULL);
+  EXPECT_FALSE(success_);
+  EXPECT_FALSE(failure_);
+  EXPECT_FALSE(timeout_);
+  delete res;
+}
+
+// Test that requests are sent at the right times, and that the 9th request
+// (sent at 7900 ms) can be properly replied to.
+TEST_F(StunRequestTest, TestBackoff) {
+  StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
+
+  uint32 start = rtc::Time();
+  manager_.Send(new StunRequestThunker(req, this));
+  StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
+  for (int i = 0; i < 9; ++i) {
+    while (request_count_ == i)
+      rtc::Thread::Current()->ProcessMessages(1);
+    int32 elapsed = rtc::TimeSince(start);
+    LOG(LS_INFO) << "STUN request #" << (i + 1)
+                 << " sent at " << elapsed << " ms";
+    EXPECT_GE(TotalDelay(i + 1), elapsed);
+  }
+  EXPECT_TRUE(manager_.CheckResponse(res));
+
+  EXPECT_TRUE(response_ == res);
+  EXPECT_TRUE(success_);
+  EXPECT_FALSE(failure_);
+  EXPECT_FALSE(timeout_);
+  delete res;
+}
+
+// Test that we timeout properly if no response is received in 9500 ms.
+TEST_F(StunRequestTest, TestTimeout) {
+  StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL);
+  StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req);
+
+  manager_.Send(new StunRequestThunker(req, this));
+  rtc::Thread::Current()->ProcessMessages(10000);  // > STUN timeout
+  EXPECT_FALSE(manager_.CheckResponse(res));
+
+  EXPECT_TRUE(response_ == NULL);
+  EXPECT_FALSE(success_);
+  EXPECT_FALSE(failure_);
+  EXPECT_TRUE(timeout_);
+  delete res;
+}
+
+// Regression test for specific crash where we receive a response with the
+// same id as a request that doesn't have an underlying StunMessage yet.
+TEST_F(StunRequestTest, TestNoEmptyRequest) {
+  StunRequestThunker* request = new StunRequestThunker(this);
+
+  manager_.SendDelayed(request, 100);
+
+  StunMessage dummy_req;
+  dummy_req.SetTransactionID(request->id());
+  StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req);
+
+  EXPECT_TRUE(manager_.CheckResponse(res));
+
+  EXPECT_TRUE(response_ == res);
+  EXPECT_TRUE(success_);
+  EXPECT_FALSE(failure_);
+  EXPECT_FALSE(timeout_);
+  delete res;
+}
diff --git a/p2p/base/stunserver.cc b/p2p/base/stunserver.cc
new file mode 100644
index 0000000..fbc316b
--- /dev/null
+++ b/p2p/base/stunserver.cc
@@ -0,0 +1,99 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/stunserver.h"
+
+#include "webrtc/base/bytebuffer.h"
+#include "webrtc/base/logging.h"
+
+namespace cricket {
+
+StunServer::StunServer(rtc::AsyncUDPSocket* socket) : socket_(socket) {
+  socket_->SignalReadPacket.connect(this, &StunServer::OnPacket);
+}
+
+StunServer::~StunServer() {
+  socket_->SignalReadPacket.disconnect(this);
+}
+
+void StunServer::OnPacket(
+    rtc::AsyncPacketSocket* socket, const char* buf, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time) {
+  // Parse the STUN message; eat any messages that fail to parse.
+  rtc::ByteBuffer bbuf(buf, size);
+  StunMessage msg;
+  if (!msg.Read(&bbuf)) {
+    return;
+  }
+
+  // TODO: If unknown non-optional (<= 0x7fff) attributes are found, send a
+  //       420 "Unknown Attribute" response.
+
+  // Send the message to the appropriate handler function.
+  switch (msg.type()) {
+    case STUN_BINDING_REQUEST:
+      OnBindingRequest(&msg, remote_addr);
+      break;
+
+    default:
+      SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported");
+  }
+}
+
+void StunServer::OnBindingRequest(
+    StunMessage* msg, const rtc::SocketAddress& remote_addr) {
+  StunMessage response;
+  GetStunBindReqponse(msg, remote_addr, &response);
+  SendResponse(response, remote_addr);
+}
+
+void StunServer::SendErrorResponse(
+    const StunMessage& msg, const rtc::SocketAddress& addr,
+    int error_code, const char* error_desc) {
+  StunMessage err_msg;
+  err_msg.SetType(GetStunErrorResponseType(msg.type()));
+  err_msg.SetTransactionID(msg.transaction_id());
+
+  StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
+  err_code->SetCode(error_code);
+  err_code->SetReason(error_desc);
+  err_msg.AddAttribute(err_code);
+
+  SendResponse(err_msg, addr);
+}
+
+void StunServer::SendResponse(
+    const StunMessage& msg, const rtc::SocketAddress& addr) {
+  rtc::ByteBuffer buf;
+  msg.Write(&buf);
+  rtc::PacketOptions options;
+  if (socket_->SendTo(buf.Data(), buf.Length(), addr, options) < 0)
+    LOG_ERR(LS_ERROR) << "sendto";
+}
+
+void StunServer::GetStunBindReqponse(StunMessage* request,
+                                     const rtc::SocketAddress& remote_addr,
+                                     StunMessage* response) const {
+  response->SetType(STUN_BINDING_RESPONSE);
+  response->SetTransactionID(request->transaction_id());
+
+  // Tell the user the address that we received their request from.
+  StunAddressAttribute* mapped_addr;
+  if (!request->IsLegacy()) {
+    mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+  } else {
+    mapped_addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  }
+  mapped_addr->SetAddress(remote_addr);
+  response->AddAttribute(mapped_addr);
+}
+
+}  // namespace cricket
diff --git a/p2p/base/stunserver.h b/p2p/base/stunserver.h
new file mode 100644
index 0000000..a7eeab1
--- /dev/null
+++ b/p2p/base/stunserver.h
@@ -0,0 +1,66 @@
+/*
+ *  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_P2P_BASE_STUNSERVER_H_
+#define WEBRTC_P2P_BASE_STUNSERVER_H_
+
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/asyncudpsocket.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace cricket {
+
+const int STUN_SERVER_PORT = 3478;
+
+class StunServer : public sigslot::has_slots<> {
+ public:
+  // Creates a STUN server, which will listen on the given socket.
+  explicit StunServer(rtc::AsyncUDPSocket* socket);
+  // Removes the STUN server from the socket and deletes the socket.
+  ~StunServer();
+
+ protected:
+  // Slot for AsyncSocket.PacketRead:
+  void OnPacket(
+      rtc::AsyncPacketSocket* socket, const char* buf, size_t size,
+      const rtc::SocketAddress& remote_addr,
+      const rtc::PacketTime& packet_time);
+
+  // Handlers for the different types of STUN/TURN requests:
+  virtual void OnBindingRequest(StunMessage* msg,
+      const rtc::SocketAddress& addr);
+  void OnAllocateRequest(StunMessage* msg,
+      const rtc::SocketAddress& addr);
+  void OnSharedSecretRequest(StunMessage* msg,
+      const rtc::SocketAddress& addr);
+  void OnSendRequest(StunMessage* msg,
+      const rtc::SocketAddress& addr);
+
+  // Sends an error response to the given message back to the user.
+  void SendErrorResponse(
+      const StunMessage& msg, const rtc::SocketAddress& addr,
+      int error_code, const char* error_desc);
+
+  // Sends the given message to the appropriate destination.
+  void SendResponse(const StunMessage& msg,
+       const rtc::SocketAddress& addr);
+
+  // A helper method to compose a STUN binding response.
+  void GetStunBindReqponse(StunMessage* request,
+                           const rtc::SocketAddress& remote_addr,
+                           StunMessage* response) const;
+
+ private:
+  rtc::scoped_ptr<rtc::AsyncUDPSocket> socket_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_STUNSERVER_H_
diff --git a/p2p/base/stunserver_unittest.cc b/p2p/base/stunserver_unittest.cc
new file mode 100644
index 0000000..7266eae
--- /dev/null
+++ b/p2p/base/stunserver_unittest.cc
@@ -0,0 +1,109 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/p2p/base/stunserver.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/testclient.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+using namespace cricket;
+
+static const rtc::SocketAddress server_addr("99.99.99.1", 3478);
+static const rtc::SocketAddress client_addr("1.2.3.4", 1234);
+
+class StunServerTest : public testing::Test {
+ public:
+  StunServerTest()
+    : pss_(new rtc::PhysicalSocketServer),
+      ss_(new rtc::VirtualSocketServer(pss_.get())),
+      worker_(ss_.get()) {
+  }
+  virtual void SetUp() {
+    server_.reset(new StunServer(
+        rtc::AsyncUDPSocket::Create(ss_.get(), server_addr)));
+    client_.reset(new rtc::TestClient(
+        rtc::AsyncUDPSocket::Create(ss_.get(), client_addr)));
+
+    worker_.Start();
+  }
+  void Send(const StunMessage& msg) {
+    rtc::ByteBuffer buf;
+    msg.Write(&buf);
+    Send(buf.Data(), static_cast<int>(buf.Length()));
+  }
+  void Send(const char* buf, int len) {
+    client_->SendTo(buf, len, server_addr);
+  }
+  StunMessage* Receive() {
+    StunMessage* msg = NULL;
+    rtc::TestClient::Packet* packet = client_->NextPacket();
+    if (packet) {
+      rtc::ByteBuffer buf(packet->buf, packet->size);
+      msg = new StunMessage();
+      msg->Read(&buf);
+      delete packet;
+    }
+    return msg;
+  }
+ private:
+  rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> ss_;
+  rtc::Thread worker_;
+  rtc::scoped_ptr<StunServer> server_;
+  rtc::scoped_ptr<rtc::TestClient> client_;
+};
+
+// Disable for TSan v2, see
+// https://code.google.com/p/webrtc/issues/detail?id=2517 for details.
+#if !defined(THREAD_SANITIZER)
+
+TEST_F(StunServerTest, TestGood) {
+  StunMessage req;
+  std::string transaction_id = "0123456789ab";
+  req.SetType(STUN_BINDING_REQUEST);
+  req.SetTransactionID(transaction_id);
+  Send(req);
+
+  StunMessage* msg = Receive();
+  ASSERT_TRUE(msg != NULL);
+  EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type());
+  EXPECT_EQ(req.transaction_id(), msg->transaction_id());
+
+  const StunAddressAttribute* mapped_addr =
+      msg->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+  EXPECT_TRUE(mapped_addr != NULL);
+  EXPECT_EQ(1, mapped_addr->family());
+  EXPECT_EQ(client_addr.port(), mapped_addr->port());
+  if (mapped_addr->ipaddr() != client_addr.ipaddr()) {
+    LOG(LS_WARNING) << "Warning: mapped IP ("
+                    << mapped_addr->ipaddr()
+                    << ") != local IP (" << client_addr.ipaddr()
+                    << ")";
+  }
+
+  delete msg;
+}
+
+#endif // if !defined(THREAD_SANITIZER)
+
+TEST_F(StunServerTest, TestBad) {
+  const char* bad = "this is a completely nonsensical message whose only "
+                    "purpose is to make the parser go 'ack'.  it doesn't "
+                    "look anything like a normal stun message";
+  Send(bad, static_cast<int>(strlen(bad)));
+
+  StunMessage* msg = Receive();
+  ASSERT_TRUE(msg == NULL);
+}
diff --git a/p2p/base/tcpport.cc b/p2p/base/tcpport.cc
new file mode 100644
index 0000000..be3068b
--- /dev/null
+++ b/p2p/base/tcpport.cc
@@ -0,0 +1,321 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/tcpport.h"
+
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+
+namespace cricket {
+
+TCPPort::TCPPort(rtc::Thread* thread,
+                 rtc::PacketSocketFactory* factory,
+                 rtc::Network* network, const rtc::IPAddress& ip,
+                 int min_port, int max_port, const std::string& username,
+                 const std::string& password, bool allow_listen)
+    : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port,
+           username, password),
+      incoming_only_(false),
+      allow_listen_(allow_listen),
+      socket_(NULL),
+      error_(0) {
+  // TODO(mallinath) - Set preference value as per RFC 6544.
+  // http://b/issue?id=7141794
+}
+
+bool TCPPort::Init() {
+  if (allow_listen_) {
+    // Treat failure to create or bind a TCP socket as fatal.  This
+    // should never happen.
+    socket_ = socket_factory()->CreateServerTcpSocket(
+        rtc::SocketAddress(ip(), 0), min_port(), max_port(),
+        false /* ssl */);
+    if (!socket_) {
+      LOG_J(LS_ERROR, this) << "TCP socket creation failed.";
+      return false;
+    }
+    socket_->SignalNewConnection.connect(this, &TCPPort::OnNewConnection);
+    socket_->SignalAddressReady.connect(this, &TCPPort::OnAddressReady);
+  }
+  return true;
+}
+
+TCPPort::~TCPPort() {
+  delete socket_;
+  std::list<Incoming>::iterator it;
+  for (it = incoming_.begin(); it != incoming_.end(); ++it)
+    delete it->socket;
+  incoming_.clear();
+}
+
+Connection* TCPPort::CreateConnection(const Candidate& address,
+                                      CandidateOrigin origin) {
+  // We only support TCP protocols
+  if ((address.protocol() != TCP_PROTOCOL_NAME) &&
+      (address.protocol() != SSLTCP_PROTOCOL_NAME)) {
+    return NULL;
+  }
+
+  if (address.tcptype() == TCPTYPE_ACTIVE_STR ||
+      (address.tcptype().empty() && address.address().port() == 0)) {
+    // It's active only candidate, we should not try to create connections
+    // for these candidates.
+    return NULL;
+  }
+
+  // We can't accept TCP connections incoming on other ports
+  if (origin == ORIGIN_OTHER_PORT)
+    return NULL;
+
+  // Check if we are allowed to make outgoing TCP connections
+  if (incoming_only_ && (origin == ORIGIN_MESSAGE))
+    return NULL;
+
+  // We don't know how to act as an ssl server yet
+  if ((address.protocol() == SSLTCP_PROTOCOL_NAME) &&
+      (origin == ORIGIN_THIS_PORT)) {
+    return NULL;
+  }
+
+  if (!IsCompatibleAddress(address.address())) {
+    return NULL;
+  }
+
+  TCPConnection* conn = NULL;
+  if (rtc::AsyncPacketSocket* socket =
+      GetIncoming(address.address(), true)) {
+    socket->SignalReadPacket.disconnect(this);
+    conn = new TCPConnection(this, address, socket);
+  } else {
+    conn = new TCPConnection(this, address);
+  }
+  AddConnection(conn);
+  return conn;
+}
+
+void TCPPort::PrepareAddress() {
+  if (socket_) {
+    // If socket isn't bound yet the address will be added in
+    // OnAddressReady(). Socket may be in the CLOSED state if Listen()
+    // failed, we still want to add the socket address.
+    LOG(LS_VERBOSE) << "Preparing TCP address, current state: "
+                    << socket_->GetState();
+    if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND ||
+        socket_->GetState() == rtc::AsyncPacketSocket::STATE_CLOSED)
+      AddAddress(socket_->GetLocalAddress(), socket_->GetLocalAddress(),
+                 rtc::SocketAddress(),
+                 TCP_PROTOCOL_NAME, TCPTYPE_PASSIVE_STR, LOCAL_PORT_TYPE,
+                 ICE_TYPE_PREFERENCE_HOST_TCP, 0, true);
+  } else {
+    LOG_J(LS_INFO, this) << "Not listening due to firewall restrictions.";
+    // Note: We still add the address, since otherwise the remote side won't
+    // recognize our incoming TCP connections.
+    AddAddress(rtc::SocketAddress(ip(), 0),
+               rtc::SocketAddress(ip(), 0), rtc::SocketAddress(),
+               TCP_PROTOCOL_NAME, TCPTYPE_ACTIVE_STR, LOCAL_PORT_TYPE,
+               ICE_TYPE_PREFERENCE_HOST_TCP, 0, true);
+  }
+}
+
+int TCPPort::SendTo(const void* data, size_t size,
+                    const rtc::SocketAddress& addr,
+                    const rtc::PacketOptions& options,
+                    bool payload) {
+  rtc::AsyncPacketSocket * socket = NULL;
+  if (TCPConnection * conn = static_cast<TCPConnection*>(GetConnection(addr))) {
+    socket = conn->socket();
+  } else {
+    socket = GetIncoming(addr);
+  }
+  if (!socket) {
+    LOG_J(LS_ERROR, this) << "Attempted to send to an unknown destination, "
+                          << addr.ToSensitiveString();
+    return -1;  // TODO: Set error_
+  }
+
+  int sent = socket->Send(data, size, options);
+  if (sent < 0) {
+    error_ = socket->GetError();
+    LOG_J(LS_ERROR, this) << "TCP send of " << size
+                          << " bytes failed with error " << error_;
+  }
+  return sent;
+}
+
+int TCPPort::GetOption(rtc::Socket::Option opt, int* value) {
+  if (socket_) {
+    return socket_->GetOption(opt, value);
+  } else {
+    return SOCKET_ERROR;
+  }
+}
+
+int TCPPort::SetOption(rtc::Socket::Option opt, int value) {
+  if (socket_) {
+    return socket_->SetOption(opt, value);
+  } else {
+    return SOCKET_ERROR;
+  }
+}
+
+int TCPPort::GetError() {
+  return error_;
+}
+
+void TCPPort::OnNewConnection(rtc::AsyncPacketSocket* socket,
+                              rtc::AsyncPacketSocket* new_socket) {
+  ASSERT(socket == socket_);
+
+  Incoming incoming;
+  incoming.addr = new_socket->GetRemoteAddress();
+  incoming.socket = new_socket;
+  incoming.socket->SignalReadPacket.connect(this, &TCPPort::OnReadPacket);
+  incoming.socket->SignalReadyToSend.connect(this, &TCPPort::OnReadyToSend);
+
+  LOG_J(LS_VERBOSE, this) << "Accepted connection from "
+                          << incoming.addr.ToSensitiveString();
+  incoming_.push_back(incoming);
+}
+
+rtc::AsyncPacketSocket* TCPPort::GetIncoming(
+    const rtc::SocketAddress& addr, bool remove) {
+  rtc::AsyncPacketSocket* socket = NULL;
+  for (std::list<Incoming>::iterator it = incoming_.begin();
+       it != incoming_.end(); ++it) {
+    if (it->addr == addr) {
+      socket = it->socket;
+      if (remove)
+        incoming_.erase(it);
+      break;
+    }
+  }
+  return socket;
+}
+
+void TCPPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
+                           const char* data, size_t size,
+                           const rtc::SocketAddress& remote_addr,
+                           const rtc::PacketTime& packet_time) {
+  Port::OnReadPacket(data, size, remote_addr, PROTO_TCP);
+}
+
+void TCPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
+  Port::OnReadyToSend();
+}
+
+void TCPPort::OnAddressReady(rtc::AsyncPacketSocket* socket,
+                             const rtc::SocketAddress& address) {
+  AddAddress(address, address, rtc::SocketAddress(),
+             TCP_PROTOCOL_NAME, TCPTYPE_PASSIVE_STR, LOCAL_PORT_TYPE,
+             ICE_TYPE_PREFERENCE_HOST_TCP, 0, true);
+}
+
+TCPConnection::TCPConnection(TCPPort* port, const Candidate& candidate,
+                             rtc::AsyncPacketSocket* socket)
+    : Connection(port, 0, candidate), socket_(socket), error_(0) {
+  bool outgoing = (socket_ == NULL);
+  if (outgoing) {
+    // TODO: Handle failures here (unlikely since TCP).
+    int opts = (candidate.protocol() == SSLTCP_PROTOCOL_NAME) ?
+        rtc::PacketSocketFactory::OPT_SSLTCP : 0;
+    socket_ = port->socket_factory()->CreateClientTcpSocket(
+        rtc::SocketAddress(port->ip(), 0),
+        candidate.address(), port->proxy(), port->user_agent(), opts);
+    if (socket_) {
+      LOG_J(LS_VERBOSE, this) << "Connecting from "
+                              << socket_->GetLocalAddress().ToSensitiveString()
+                              << " to "
+                              << candidate.address().ToSensitiveString();
+      set_connected(false);
+      socket_->SignalConnect.connect(this, &TCPConnection::OnConnect);
+    } else {
+      LOG_J(LS_WARNING, this) << "Failed to create connection to "
+                              << candidate.address().ToSensitiveString();
+    }
+  } else {
+    // Incoming connections should match the network address.
+    ASSERT(socket_->GetLocalAddress().ipaddr() == port->ip());
+  }
+
+  if (socket_) {
+    socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket);
+    socket_->SignalReadyToSend.connect(this, &TCPConnection::OnReadyToSend);
+    socket_->SignalClose.connect(this, &TCPConnection::OnClose);
+  }
+}
+
+TCPConnection::~TCPConnection() {
+  delete socket_;
+}
+
+int TCPConnection::Send(const void* data, size_t size,
+                        const rtc::PacketOptions& options) {
+  if (!socket_) {
+    error_ = ENOTCONN;
+    return SOCKET_ERROR;
+  }
+
+  if (write_state() != STATE_WRITABLE) {
+    // TODO: Should STATE_WRITE_TIMEOUT return a non-blocking error?
+    error_ = EWOULDBLOCK;
+    return SOCKET_ERROR;
+  }
+  int sent = socket_->Send(data, size, options);
+  if (sent < 0) {
+    error_ = socket_->GetError();
+  } else {
+    send_rate_tracker_.Update(sent);
+  }
+  return sent;
+}
+
+int TCPConnection::GetError() {
+  return error_;
+}
+
+void TCPConnection::OnConnect(rtc::AsyncPacketSocket* socket) {
+  ASSERT(socket == socket_);
+  // Do not use this connection if the socket bound to a different address than
+  // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
+  // given a binding address, and the platform is expected to pick the
+  // correct local address.
+  if (socket->GetLocalAddress().ipaddr() == port()->ip()) {
+    LOG_J(LS_VERBOSE, this) << "Connection established to "
+                            << socket->GetRemoteAddress().ToSensitiveString();
+    set_connected(true);
+  } else {
+    LOG_J(LS_WARNING, this) << "Dropping connection as TCP socket bound to a "
+                            << "different address from the local candidate.";
+    socket_->Close();
+  }
+}
+
+void TCPConnection::OnClose(rtc::AsyncPacketSocket* socket, int error) {
+  ASSERT(socket == socket_);
+  LOG_J(LS_VERBOSE, this) << "Connection closed with error " << error;
+  set_connected(false);
+  set_write_state(STATE_WRITE_TIMEOUT);
+}
+
+void TCPConnection::OnReadPacket(
+  rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+  const rtc::SocketAddress& remote_addr,
+  const rtc::PacketTime& packet_time) {
+  ASSERT(socket == socket_);
+  Connection::OnReadPacket(data, size, packet_time);
+}
+
+void TCPConnection::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
+  ASSERT(socket == socket_);
+  Connection::OnReadyToSend();
+}
+
+}  // namespace cricket
diff --git a/p2p/base/tcpport.h b/p2p/base/tcpport.h
new file mode 100644
index 0000000..43e4936
--- /dev/null
+++ b/p2p/base/tcpport.h
@@ -0,0 +1,136 @@
+/*
+ *  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_P2P_BASE_TCPPORT_H_
+#define WEBRTC_P2P_BASE_TCPPORT_H_
+
+#include <list>
+#include <string>
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/base/asyncpacketsocket.h"
+
+namespace cricket {
+
+class TCPConnection;
+
+// Communicates using a local TCP port.
+//
+// This class is designed to allow subclasses to take advantage of the
+// connection management provided by this class.  A subclass should take of all
+// packet sending and preparation, but when a packet is received, it should
+// call this TCPPort::OnReadPacket (3 arg) to dispatch to a connection.
+class TCPPort : public Port {
+ public:
+  static TCPPort* Create(rtc::Thread* thread,
+                         rtc::PacketSocketFactory* factory,
+                         rtc::Network* network,
+                         const rtc::IPAddress& ip,
+                         int min_port, int max_port,
+                         const std::string& username,
+                         const std::string& password,
+                         bool allow_listen) {
+    TCPPort* port = new TCPPort(thread, factory, network,
+                                ip, min_port, max_port,
+                                username, password, allow_listen);
+    if (!port->Init()) {
+      delete port;
+      port = NULL;
+    }
+    return port;
+  }
+  virtual ~TCPPort();
+
+  virtual Connection* CreateConnection(const Candidate& address,
+                                       CandidateOrigin origin);
+
+  virtual void PrepareAddress();
+
+  virtual int GetOption(rtc::Socket::Option opt, int* value);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetError();
+
+ protected:
+  TCPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
+          rtc::Network* network, const rtc::IPAddress& ip,
+          int min_port, int max_port, const std::string& username,
+          const std::string& password, bool allow_listen);
+  bool Init();
+
+  // Handles sending using the local TCP socket.
+  virtual int SendTo(const void* data, size_t size,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options,
+                     bool payload);
+
+  // Accepts incoming TCP connection.
+  void OnNewConnection(rtc::AsyncPacketSocket* socket,
+                       rtc::AsyncPacketSocket* new_socket);
+
+ private:
+  struct Incoming {
+    rtc::SocketAddress addr;
+    rtc::AsyncPacketSocket* socket;
+  };
+
+  rtc::AsyncPacketSocket* GetIncoming(
+      const rtc::SocketAddress& addr, bool remove = false);
+
+  // Receives packet signal from the local TCP Socket.
+  void OnReadPacket(rtc::AsyncPacketSocket* socket,
+                    const char* data, size_t size,
+                    const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time);
+
+  void OnReadyToSend(rtc::AsyncPacketSocket* socket);
+
+  void OnAddressReady(rtc::AsyncPacketSocket* socket,
+                      const rtc::SocketAddress& address);
+
+  // TODO: Is this still needed?
+  bool incoming_only_;
+  bool allow_listen_;
+  rtc::AsyncPacketSocket* socket_;
+  int error_;
+  std::list<Incoming> incoming_;
+
+  friend class TCPConnection;
+};
+
+class TCPConnection : public Connection {
+ public:
+  // Connection is outgoing unless socket is specified
+  TCPConnection(TCPPort* port, const Candidate& candidate,
+                rtc::AsyncPacketSocket* socket = 0);
+  virtual ~TCPConnection();
+
+  virtual int Send(const void* data, size_t size,
+                   const rtc::PacketOptions& options);
+  virtual int GetError();
+
+  rtc::AsyncPacketSocket* socket() { return socket_; }
+
+ private:
+  void OnConnect(rtc::AsyncPacketSocket* socket);
+  void OnClose(rtc::AsyncPacketSocket* socket, int error);
+  void OnReadPacket(rtc::AsyncPacketSocket* socket,
+                    const char* data, size_t size,
+                    const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time);
+  void OnReadyToSend(rtc::AsyncPacketSocket* socket);
+
+  rtc::AsyncPacketSocket* socket_;
+  int error_;
+
+  friend class TCPPort;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TCPPORT_H_
diff --git a/p2p/base/testrelayserver.h b/p2p/base/testrelayserver.h
new file mode 100644
index 0000000..87cb9e5
--- /dev/null
+++ b/p2p/base/testrelayserver.h
@@ -0,0 +1,101 @@
+/*
+ *  Copyright 2008 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_P2P_BASE_TESTRELAYSERVER_H_
+#define WEBRTC_P2P_BASE_TESTRELAYSERVER_H_
+
+#include "webrtc/p2p/base/relayserver.h"
+#include "webrtc/base/asynctcpsocket.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/socketadapters.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+// A test relay server. Useful for unit tests.
+class TestRelayServer : public sigslot::has_slots<> {
+ public:
+  TestRelayServer(rtc::Thread* thread,
+                  const rtc::SocketAddress& udp_int_addr,
+                  const rtc::SocketAddress& udp_ext_addr,
+                  const rtc::SocketAddress& tcp_int_addr,
+                  const rtc::SocketAddress& tcp_ext_addr,
+                  const rtc::SocketAddress& ssl_int_addr,
+                  const rtc::SocketAddress& ssl_ext_addr)
+      : server_(thread) {
+    server_.AddInternalSocket(rtc::AsyncUDPSocket::Create(
+        thread->socketserver(), udp_int_addr));
+    server_.AddExternalSocket(rtc::AsyncUDPSocket::Create(
+        thread->socketserver(), udp_ext_addr));
+
+    tcp_int_socket_.reset(CreateListenSocket(thread, tcp_int_addr));
+    tcp_ext_socket_.reset(CreateListenSocket(thread, tcp_ext_addr));
+    ssl_int_socket_.reset(CreateListenSocket(thread, ssl_int_addr));
+    ssl_ext_socket_.reset(CreateListenSocket(thread, ssl_ext_addr));
+  }
+  int GetConnectionCount() const {
+    return server_.GetConnectionCount();
+  }
+  rtc::SocketAddressPair GetConnection(int connection) const {
+    return server_.GetConnection(connection);
+  }
+  bool HasConnection(const rtc::SocketAddress& address) const {
+    return server_.HasConnection(address);
+  }
+
+ private:
+  rtc::AsyncSocket* CreateListenSocket(rtc::Thread* thread,
+      const rtc::SocketAddress& addr) {
+    rtc::AsyncSocket* socket =
+        thread->socketserver()->CreateAsyncSocket(addr.family(), SOCK_STREAM);
+    socket->Bind(addr);
+    socket->Listen(5);
+    socket->SignalReadEvent.connect(this, &TestRelayServer::OnAccept);
+    return socket;
+  }
+  void OnAccept(rtc::AsyncSocket* socket) {
+    bool external = (socket == tcp_ext_socket_.get() ||
+                     socket == ssl_ext_socket_.get());
+    bool ssl = (socket == ssl_int_socket_.get() ||
+                socket == ssl_ext_socket_.get());
+    rtc::AsyncSocket* raw_socket = socket->Accept(NULL);
+    if (raw_socket) {
+      rtc::AsyncTCPSocket* packet_socket = new rtc::AsyncTCPSocket(
+          (!ssl) ? raw_socket :
+          new rtc::AsyncSSLServerSocket(raw_socket), false);
+      if (!external) {
+        packet_socket->SignalClose.connect(this,
+            &TestRelayServer::OnInternalClose);
+        server_.AddInternalSocket(packet_socket);
+      } else {
+        packet_socket->SignalClose.connect(this,
+            &TestRelayServer::OnExternalClose);
+        server_.AddExternalSocket(packet_socket);
+      }
+    }
+  }
+  void OnInternalClose(rtc::AsyncPacketSocket* socket, int error) {
+    server_.RemoveInternalSocket(socket);
+  }
+  void OnExternalClose(rtc::AsyncPacketSocket* socket, int error) {
+    server_.RemoveExternalSocket(socket);
+  }
+ private:
+  cricket::RelayServer server_;
+  rtc::scoped_ptr<rtc::AsyncSocket> tcp_int_socket_;
+  rtc::scoped_ptr<rtc::AsyncSocket> tcp_ext_socket_;
+  rtc::scoped_ptr<rtc::AsyncSocket> ssl_int_socket_;
+  rtc::scoped_ptr<rtc::AsyncSocket> ssl_ext_socket_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TESTRELAYSERVER_H_
diff --git a/p2p/base/teststunserver.h b/p2p/base/teststunserver.h
new file mode 100644
index 0000000..a2a8b6f
--- /dev/null
+++ b/p2p/base/teststunserver.h
@@ -0,0 +1,58 @@
+/*
+ *  Copyright 2008 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_P2P_BASE_TESTSTUNSERVER_H_
+#define WEBRTC_P2P_BASE_TESTSTUNSERVER_H_
+
+#include "webrtc/p2p/base/stunserver.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+// A test STUN server. Useful for unit tests.
+class TestStunServer : StunServer {
+ public:
+  static TestStunServer* Create(rtc::Thread* thread,
+                                const rtc::SocketAddress& addr) {
+    rtc::AsyncSocket* socket =
+        thread->socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
+    rtc::AsyncUDPSocket* udp_socket =
+        rtc::AsyncUDPSocket::Create(socket, addr);
+
+    return new TestStunServer(udp_socket);
+  }
+
+  // Set a fake STUN address to return to the client.
+  void set_fake_stun_addr(const rtc::SocketAddress& addr) {
+    fake_stun_addr_ = addr;
+  }
+
+ private:
+  explicit TestStunServer(rtc::AsyncUDPSocket* socket) : StunServer(socket) {}
+
+  void OnBindingRequest(StunMessage* msg,
+                        const rtc::SocketAddress& remote_addr) OVERRIDE {
+    if (fake_stun_addr_.IsNil()) {
+      StunServer::OnBindingRequest(msg, remote_addr);
+    } else {
+      StunMessage response;
+      GetStunBindReqponse(msg, fake_stun_addr_, &response);
+      SendResponse(response, remote_addr);
+    }
+  }
+
+ private:
+  rtc::SocketAddress fake_stun_addr_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TESTSTUNSERVER_H_
diff --git a/p2p/base/testturnserver.h b/p2p/base/testturnserver.h
new file mode 100644
index 0000000..19f73e7
--- /dev/null
+++ b/p2p/base/testturnserver.h
@@ -0,0 +1,103 @@
+/*
+ *  Copyright 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_P2P_BASE_TESTTURNSERVER_H_
+#define WEBRTC_P2P_BASE_TESTTURNSERVER_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/p2p/base/turnserver.h"
+#include "webrtc/base/asyncudpsocket.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+static const char kTestRealm[] = "example.org";
+static const char kTestSoftware[] = "TestTurnServer";
+
+class TestTurnRedirector : public TurnRedirectInterface {
+ public:
+  explicit TestTurnRedirector(const std::vector<rtc::SocketAddress>& addresses)
+      : alternate_server_addresses_(addresses),
+        iter_(alternate_server_addresses_.begin()) {
+  }
+
+  virtual bool ShouldRedirect(const rtc::SocketAddress&,
+                              rtc::SocketAddress* out) {
+    if (!out || iter_ == alternate_server_addresses_.end()) {
+      return false;
+    }
+    *out = *iter_++;
+    return true;
+  }
+
+ private:
+  const std::vector<rtc::SocketAddress>& alternate_server_addresses_;
+  std::vector<rtc::SocketAddress>::const_iterator iter_;
+};
+
+class TestTurnServer : public TurnAuthInterface {
+ public:
+  TestTurnServer(rtc::Thread* thread,
+                 const rtc::SocketAddress& udp_int_addr,
+                 const rtc::SocketAddress& udp_ext_addr)
+      : server_(thread) {
+    AddInternalSocket(udp_int_addr, cricket::PROTO_UDP);
+    server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(),
+        udp_ext_addr);
+    server_.set_realm(kTestRealm);
+    server_.set_software(kTestSoftware);
+    server_.set_auth_hook(this);
+  }
+
+  void set_enable_otu_nonce(bool enable) {
+    server_.set_enable_otu_nonce(enable);
+  }
+
+  TurnServer* server() { return &server_; }
+
+  void set_redirect_hook(TurnRedirectInterface* redirect_hook) {
+    server_.set_redirect_hook(redirect_hook);
+  }
+
+  void AddInternalSocket(const rtc::SocketAddress& int_addr,
+                         ProtocolType proto) {
+    rtc::Thread* thread = rtc::Thread::Current();
+    if (proto == cricket::PROTO_UDP) {
+      server_.AddInternalSocket(rtc::AsyncUDPSocket::Create(
+          thread->socketserver(), int_addr), proto);
+    } else if (proto == cricket::PROTO_TCP) {
+      // For TCP we need to create a server socket which can listen for incoming
+      // new connections.
+      rtc::AsyncSocket* socket =
+          thread->socketserver()->CreateAsyncSocket(SOCK_STREAM);
+      socket->Bind(int_addr);
+      socket->Listen(5);
+      server_.AddInternalServerSocket(socket, proto);
+    }
+  }
+
+ private:
+  // For this test server, succeed if the password is the same as the username.
+  // Obviously, do not use this in a production environment.
+  virtual bool GetKey(const std::string& username, const std::string& realm,
+                      std::string* key) {
+    return ComputeStunCredentialHash(username, realm, username, key);
+  }
+
+  TurnServer server_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TESTTURNSERVER_H_
diff --git a/p2p/base/transport.cc b/p2p/base/transport.cc
new file mode 100644
index 0000000..05c455e
--- /dev/null
+++ b/p2p/base/transport.cc
@@ -0,0 +1,960 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/transport.h"
+
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/bind.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+
+namespace cricket {
+
+using rtc::Bind;
+
+enum {
+  MSG_ONSIGNALINGREADY = 1,
+  MSG_ONREMOTECANDIDATE,
+  MSG_READSTATE,
+  MSG_WRITESTATE,
+  MSG_REQUESTSIGNALING,
+  MSG_CANDIDATEREADY,
+  MSG_ROUTECHANGE,
+  MSG_CONNECTING,
+  MSG_CANDIDATEALLOCATIONCOMPLETE,
+  MSG_ROLECONFLICT,
+  MSG_COMPLETED,
+  MSG_FAILED,
+};
+
+struct ChannelParams : public rtc::MessageData {
+  ChannelParams() : channel(NULL), candidate(NULL) {}
+  explicit ChannelParams(int component)
+      : component(component), channel(NULL), candidate(NULL) {}
+  explicit ChannelParams(Candidate* candidate)
+      : channel(NULL), candidate(candidate) {
+  }
+
+  ~ChannelParams() {
+    delete candidate;
+  }
+
+  std::string name;
+  int component;
+  TransportChannelImpl* channel;
+  Candidate* candidate;
+};
+
+static std::string IceProtoToString(TransportProtocol proto) {
+  std::string proto_str;
+  switch (proto) {
+    case ICEPROTO_GOOGLE:
+      proto_str = "gice";
+      break;
+    case ICEPROTO_HYBRID:
+      proto_str = "hybrid";
+      break;
+    case ICEPROTO_RFC5245:
+      proto_str = "ice";
+      break;
+    default:
+      ASSERT(false);
+      break;
+  }
+  return proto_str;
+}
+
+static bool VerifyIceParams(const TransportDescription& desc) {
+  // For legacy protocols.
+  if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
+    return true;
+
+  if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
+      desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
+    return false;
+  }
+  if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
+      desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
+    return false;
+  }
+  return true;
+}
+
+bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
+  if (err_desc) {
+    *err_desc = desc;
+  }
+  LOG(LS_ERROR) << desc;
+  return false;
+}
+
+bool IceCredentialsChanged(const std::string& old_ufrag,
+                           const std::string& old_pwd,
+                           const std::string& new_ufrag,
+                           const std::string& new_pwd) {
+  // TODO(jiayl): The standard (RFC 5245 Section 9.1.1.1) says that ICE should
+  // restart when both the ufrag and password are changed, but we do restart
+  // when either ufrag or passwrod is changed to keep compatible with GICE. We
+  // should clean this up when GICE is no longer used.
+  return (old_ufrag != new_ufrag) || (old_pwd != new_pwd);
+}
+
+static bool IceCredentialsChanged(const TransportDescription& old_desc,
+                                  const TransportDescription& new_desc) {
+  return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd,
+                               new_desc.ice_ufrag, new_desc.ice_pwd);
+}
+
+Transport::Transport(rtc::Thread* signaling_thread,
+                     rtc::Thread* worker_thread,
+                     const std::string& content_name,
+                     const std::string& type,
+                     PortAllocator* allocator)
+  : signaling_thread_(signaling_thread),
+    worker_thread_(worker_thread),
+    content_name_(content_name),
+    type_(type),
+    allocator_(allocator),
+    destroyed_(false),
+    readable_(TRANSPORT_STATE_NONE),
+    writable_(TRANSPORT_STATE_NONE),
+    was_writable_(false),
+    connect_requested_(false),
+    ice_role_(ICEROLE_UNKNOWN),
+    tiebreaker_(0),
+    protocol_(ICEPROTO_HYBRID),
+    remote_ice_mode_(ICEMODE_FULL) {
+}
+
+Transport::~Transport() {
+  ASSERT(signaling_thread_->IsCurrent());
+  ASSERT(destroyed_);
+}
+
+void Transport::SetIceRole(IceRole role) {
+  worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
+}
+
+void Transport::SetIdentity(rtc::SSLIdentity* identity) {
+  worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity));
+}
+
+bool Transport::GetIdentity(rtc::SSLIdentity** identity) {
+  // The identity is set on the worker thread, so for safety it must also be
+  // acquired on the worker thread.
+  return worker_thread_->Invoke<bool>(
+      Bind(&Transport::GetIdentity_w, this, identity));
+}
+
+bool Transport::GetRemoteCertificate(rtc::SSLCertificate** cert) {
+  // Channels can be deleted on the worker thread, so for safety the remote
+  // certificate is acquired on the worker thread.
+  return worker_thread_->Invoke<bool>(
+      Bind(&Transport::GetRemoteCertificate_w, this, cert));
+}
+
+bool Transport::GetRemoteCertificate_w(rtc::SSLCertificate** cert) {
+  ASSERT(worker_thread()->IsCurrent());
+  if (channels_.empty())
+    return false;
+
+  ChannelMap::iterator iter = channels_.begin();
+  return iter->second->GetRemoteCertificate(cert);
+}
+
+bool Transport::SetLocalTransportDescription(
+    const TransportDescription& description,
+    ContentAction action,
+    std::string* error_desc) {
+  return worker_thread_->Invoke<bool>(Bind(
+      &Transport::SetLocalTransportDescription_w, this,
+      description, action, error_desc));
+}
+
+bool Transport::SetRemoteTransportDescription(
+    const TransportDescription& description,
+    ContentAction action,
+    std::string* error_desc) {
+  return worker_thread_->Invoke<bool>(Bind(
+      &Transport::SetRemoteTransportDescription_w, this,
+      description, action, error_desc));
+}
+
+TransportChannelImpl* Transport::CreateChannel(int component) {
+  return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
+      &Transport::CreateChannel_w, this, component));
+}
+
+TransportChannelImpl* Transport::CreateChannel_w(int component) {
+  ASSERT(worker_thread()->IsCurrent());
+  TransportChannelImpl *impl;
+  rtc::CritScope cs(&crit_);
+
+  // Create the entry if it does not exist.
+  bool impl_exists = false;
+  if (channels_.find(component) == channels_.end()) {
+    impl = CreateTransportChannel(component);
+    channels_[component] = ChannelMapEntry(impl);
+  } else {
+    impl = channels_[component].get();
+    impl_exists = true;
+  }
+
+  // Increase the ref count.
+  channels_[component].AddRef();
+  destroyed_ = false;
+
+  if (impl_exists) {
+    // If this is an existing channel, we should just return it without
+    // connecting to all the signal again.
+    return impl;
+  }
+
+  // Push down our transport state to the new channel.
+  impl->SetIceRole(ice_role_);
+  impl->SetIceTiebreaker(tiebreaker_);
+  // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
+  // below Apply**Description_w calls can fail.
+  if (local_description_)
+    ApplyLocalTransportDescription_w(impl, NULL);
+  if (remote_description_)
+    ApplyRemoteTransportDescription_w(impl, NULL);
+  if (local_description_ && remote_description_)
+    ApplyNegotiatedTransportDescription_w(impl, NULL);
+
+  impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
+  impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
+  impl->SignalRequestSignaling.connect(
+      this, &Transport::OnChannelRequestSignaling);
+  impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady);
+  impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange);
+  impl->SignalCandidatesAllocationDone.connect(
+      this, &Transport::OnChannelCandidatesAllocationDone);
+  impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
+  impl->SignalConnectionRemoved.connect(
+      this, &Transport::OnChannelConnectionRemoved);
+
+  if (connect_requested_) {
+    impl->Connect();
+    if (channels_.size() == 1) {
+      // If this is the first channel, then indicate that we have started
+      // connecting.
+      signaling_thread()->Post(this, MSG_CONNECTING, NULL);
+    }
+  }
+  return impl;
+}
+
+TransportChannelImpl* Transport::GetChannel(int component) {
+  rtc::CritScope cs(&crit_);
+  ChannelMap::iterator iter = channels_.find(component);
+  return (iter != channels_.end()) ? iter->second.get() : NULL;
+}
+
+bool Transport::HasChannels() {
+  rtc::CritScope cs(&crit_);
+  return !channels_.empty();
+}
+
+void Transport::DestroyChannel(int component) {
+  worker_thread_->Invoke<void>(Bind(
+      &Transport::DestroyChannel_w, this, component));
+}
+
+void Transport::DestroyChannel_w(int component) {
+  ASSERT(worker_thread()->IsCurrent());
+
+  TransportChannelImpl* impl = NULL;
+  {
+    rtc::CritScope cs(&crit_);
+    ChannelMap::iterator iter = channels_.find(component);
+    if (iter == channels_.end())
+      return;
+
+    iter->second.DecRef();
+    if (!iter->second.ref()) {
+      impl = iter->second.get();
+      channels_.erase(iter);
+    }
+  }
+
+  if (connect_requested_ && channels_.empty()) {
+    // We're no longer attempting to connect.
+    signaling_thread()->Post(this, MSG_CONNECTING, NULL);
+  }
+
+  if (impl) {
+    // Check in case the deleted channel was the only non-writable channel.
+    OnChannelWritableState(impl);
+    DestroyTransportChannel(impl);
+  }
+}
+
+void Transport::ConnectChannels() {
+  ASSERT(signaling_thread()->IsCurrent());
+  worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
+}
+
+void Transport::ConnectChannels_w() {
+  ASSERT(worker_thread()->IsCurrent());
+  if (connect_requested_ || channels_.empty())
+    return;
+  connect_requested_ = true;
+  signaling_thread()->Post(
+      this, MSG_CANDIDATEREADY, NULL);
+
+  if (!local_description_) {
+    // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
+    // As Transport must know TD is offer or answer and cricket::Transport
+    // doesn't have the capability to decide it. This should be set by the
+    // Session.
+    // Session must generate local TD before remote candidates pushed when
+    // initiate request initiated by the remote.
+    LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has "
+                 << "been set. Will generate one.";
+    TransportDescription desc(NS_GINGLE_P2P, std::vector<std::string>(),
+                              rtc::CreateRandomString(ICE_UFRAG_LENGTH),
+                              rtc::CreateRandomString(ICE_PWD_LENGTH),
+                              ICEMODE_FULL, CONNECTIONROLE_NONE, NULL,
+                              Candidates());
+    SetLocalTransportDescription_w(desc, CA_OFFER, NULL);
+  }
+
+  CallChannels_w(&TransportChannelImpl::Connect);
+  if (!channels_.empty()) {
+    signaling_thread()->Post(this, MSG_CONNECTING, NULL);
+  }
+}
+
+void Transport::OnConnecting_s() {
+  ASSERT(signaling_thread()->IsCurrent());
+  SignalConnecting(this);
+}
+
+void Transport::DestroyAllChannels() {
+  ASSERT(signaling_thread()->IsCurrent());
+  worker_thread_->Invoke<void>(
+      Bind(&Transport::DestroyAllChannels_w, this));
+  worker_thread()->Clear(this);
+  signaling_thread()->Clear(this);
+  destroyed_ = true;
+}
+
+void Transport::DestroyAllChannels_w() {
+  ASSERT(worker_thread()->IsCurrent());
+  std::vector<TransportChannelImpl*> impls;
+  {
+    rtc::CritScope cs(&crit_);
+    for (ChannelMap::iterator iter = channels_.begin();
+         iter != channels_.end();
+         ++iter) {
+      iter->second.DecRef();
+      if (!iter->second.ref())
+        impls.push_back(iter->second.get());
+      }
+    }
+  channels_.clear();
+
+
+  for (size_t i = 0; i < impls.size(); ++i)
+    DestroyTransportChannel(impls[i]);
+}
+
+void Transport::ResetChannels() {
+  ASSERT(signaling_thread()->IsCurrent());
+  worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this));
+}
+
+void Transport::ResetChannels_w() {
+  ASSERT(worker_thread()->IsCurrent());
+
+  // We are no longer attempting to connect
+  connect_requested_ = false;
+
+  // Clear out the old messages, they aren't relevant
+  rtc::CritScope cs(&crit_);
+  ready_candidates_.clear();
+
+  // Reset all of the channels
+  CallChannels_w(&TransportChannelImpl::Reset);
+}
+
+void Transport::OnSignalingReady() {
+  ASSERT(signaling_thread()->IsCurrent());
+  if (destroyed_) return;
+
+  worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
+
+  // Notify the subclass.
+  OnTransportSignalingReady();
+}
+
+void Transport::CallChannels_w(TransportChannelFunc func) {
+  ASSERT(worker_thread()->IsCurrent());
+  rtc::CritScope cs(&crit_);
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end();
+       ++iter) {
+    ((iter->second.get())->*func)();
+  }
+}
+
+bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) {
+  // No address zero.
+  if (cand.address().IsNil() || cand.address().IsAny()) {
+    *error = "candidate has address of zero";
+    return false;
+  }
+
+  // Disallow all ports below 1024, except for 80 and 443 on public addresses.
+  int port = cand.address().port();
+  if (cand.protocol() == TCP_PROTOCOL_NAME &&
+      (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) {
+    // Expected for active-only candidates per
+    // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
+    // Libjingle clients emit port 0, in "active" mode.
+    return true;
+  }
+  if (port < 1024) {
+    if ((port != 80) && (port != 443)) {
+      *error = "candidate has port below 1024, but not 80 or 443";
+      return false;
+    }
+
+    if (cand.address().IsPrivateIP()) {
+      *error = "candidate has port of 80 or 443 with private IP address";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+bool Transport::GetStats(TransportStats* stats) {
+  ASSERT(signaling_thread()->IsCurrent());
+  return worker_thread_->Invoke<bool>(Bind(
+      &Transport::GetStats_w, this, stats));
+}
+
+bool Transport::GetStats_w(TransportStats* stats) {
+  ASSERT(worker_thread()->IsCurrent());
+  stats->content_name = content_name();
+  stats->channel_stats.clear();
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end();
+       ++iter) {
+    TransportChannelStats substats;
+    substats.component = iter->second->component();
+    if (!iter->second->GetStats(&substats.connection_infos)) {
+      return false;
+    }
+    stats->channel_stats.push_back(substats);
+  }
+  return true;
+}
+
+bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const {
+  return worker_thread_->Invoke<bool>(Bind(
+      &Transport::GetSslRole_w, this, ssl_role));
+}
+
+void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) {
+  for (std::vector<Candidate>::const_iterator iter = candidates.begin();
+       iter != candidates.end();
+       ++iter) {
+    OnRemoteCandidate(*iter);
+  }
+}
+
+void Transport::OnRemoteCandidate(const Candidate& candidate) {
+  ASSERT(signaling_thread()->IsCurrent());
+  if (destroyed_) return;
+
+  if (!HasChannel(candidate.component())) {
+    LOG(LS_WARNING) << "Ignoring candidate for unknown component "
+                    << candidate.component();
+    return;
+  }
+
+  ChannelParams* params = new ChannelParams(new Candidate(candidate));
+  worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params);
+}
+
+void Transport::OnRemoteCandidate_w(const Candidate& candidate) {
+  ASSERT(worker_thread()->IsCurrent());
+  ChannelMap::iterator iter = channels_.find(candidate.component());
+  // It's ok for a channel to go away while this message is in transit.
+  if (iter != channels_.end()) {
+    iter->second->OnCandidate(candidate);
+  }
+}
+
+void Transport::OnChannelReadableState(TransportChannel* channel) {
+  ASSERT(worker_thread()->IsCurrent());
+  signaling_thread()->Post(this, MSG_READSTATE, NULL);
+}
+
+void Transport::OnChannelReadableState_s() {
+  ASSERT(signaling_thread()->IsCurrent());
+  TransportState readable = GetTransportState_s(true);
+  if (readable_ != readable) {
+    readable_ = readable;
+    SignalReadableState(this);
+  }
+}
+
+void Transport::OnChannelWritableState(TransportChannel* channel) {
+  ASSERT(worker_thread()->IsCurrent());
+  signaling_thread()->Post(this, MSG_WRITESTATE, NULL);
+
+  MaybeCompleted_w();
+}
+
+void Transport::OnChannelWritableState_s() {
+  ASSERT(signaling_thread()->IsCurrent());
+  TransportState writable = GetTransportState_s(false);
+  if (writable_ != writable) {
+    was_writable_ = (writable_ == TRANSPORT_STATE_ALL);
+    writable_ = writable;
+    SignalWritableState(this);
+  }
+}
+
+TransportState Transport::GetTransportState_s(bool read) {
+  ASSERT(signaling_thread()->IsCurrent());
+  rtc::CritScope cs(&crit_);
+  bool any = false;
+  bool all = !channels_.empty();
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end();
+       ++iter) {
+    bool b = (read ? iter->second->readable() :
+      iter->second->writable());
+    any = any || b;
+    all = all && b;
+  }
+  if (all) {
+    return TRANSPORT_STATE_ALL;
+  } else if (any) {
+    return TRANSPORT_STATE_SOME;
+  } else {
+    return TRANSPORT_STATE_NONE;
+  }
+}
+
+void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) {
+  ASSERT(worker_thread()->IsCurrent());
+  ChannelParams* params = new ChannelParams(channel->component());
+  signaling_thread()->Post(this, MSG_REQUESTSIGNALING, params);
+}
+
+void Transport::OnChannelRequestSignaling_s(int component) {
+  ASSERT(signaling_thread()->IsCurrent());
+  LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates";
+  // Resetting ICE state for the channel.
+  {
+    rtc::CritScope cs(&crit_);
+    ChannelMap::iterator iter = channels_.find(component);
+    if (iter != channels_.end())
+      iter->second.set_candidates_allocated(false);
+  }
+  SignalRequestSignaling(this);
+}
+
+void Transport::OnChannelCandidateReady(TransportChannelImpl* channel,
+                                        const Candidate& candidate) {
+  ASSERT(worker_thread()->IsCurrent());
+  rtc::CritScope cs(&crit_);
+  ready_candidates_.push_back(candidate);
+
+  // We hold any messages until the client lets us connect.
+  if (connect_requested_) {
+    signaling_thread()->Post(
+        this, MSG_CANDIDATEREADY, NULL);
+  }
+}
+
+void Transport::OnChannelCandidateReady_s() {
+  ASSERT(signaling_thread()->IsCurrent());
+  ASSERT(connect_requested_);
+
+  std::vector<Candidate> candidates;
+  {
+    rtc::CritScope cs(&crit_);
+    candidates.swap(ready_candidates_);
+  }
+
+  // we do the deleting of Candidate* here to keep the new above and
+  // delete below close to each other
+  if (!candidates.empty()) {
+    SignalCandidatesReady(this, candidates);
+  }
+}
+
+void Transport::OnChannelRouteChange(TransportChannel* channel,
+                                     const Candidate& remote_candidate) {
+  ASSERT(worker_thread()->IsCurrent());
+  ChannelParams* params = new ChannelParams(new Candidate(remote_candidate));
+  params->channel = static_cast<cricket::TransportChannelImpl*>(channel);
+  signaling_thread()->Post(this, MSG_ROUTECHANGE, params);
+}
+
+void Transport::OnChannelRouteChange_s(const TransportChannel* channel,
+                                       const Candidate& remote_candidate) {
+  ASSERT(signaling_thread()->IsCurrent());
+  SignalRouteChange(this, remote_candidate.component(), remote_candidate);
+}
+
+void Transport::OnChannelCandidatesAllocationDone(
+    TransportChannelImpl* channel) {
+  ASSERT(worker_thread()->IsCurrent());
+  rtc::CritScope cs(&crit_);
+  ChannelMap::iterator iter = channels_.find(channel->component());
+  ASSERT(iter != channels_.end());
+  LOG(LS_INFO) << "Transport: " << content_name_ << ", component "
+               << channel->component() << " allocation complete";
+  iter->second.set_candidates_allocated(true);
+
+  // If all channels belonging to this Transport got signal, then
+  // forward this signal to upper layer.
+  // Can this signal arrive before all transport channels are created?
+  for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
+    if (!iter->second.candidates_allocated())
+      return;
+  }
+  signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE);
+
+  MaybeCompleted_w();
+}
+
+void Transport::OnChannelCandidatesAllocationDone_s() {
+  ASSERT(signaling_thread()->IsCurrent());
+  LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
+  SignalCandidatesAllocationDone(this);
+}
+
+void Transport::OnRoleConflict(TransportChannelImpl* channel) {
+  signaling_thread_->Post(this, MSG_ROLECONFLICT);
+}
+
+void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
+  ASSERT(worker_thread()->IsCurrent());
+  MaybeCompleted_w();
+
+  // Check if the state is now Failed.
+  // Failed is only available in the Controlling ICE role.
+  if (channel->GetIceRole() != ICEROLE_CONTROLLING) {
+    return;
+  }
+
+  ChannelMap::iterator iter = channels_.find(channel->component());
+  ASSERT(iter != channels_.end());
+  // Failed can only occur after candidate allocation has stopped.
+  if (!iter->second.candidates_allocated()) {
+    return;
+  }
+
+  size_t connections = channel->GetConnectionCount();
+  if (connections == 0) {
+    // A Transport has failed if any of its channels have no remaining
+    // connections.
+    signaling_thread_->Post(this, MSG_FAILED);
+  }
+}
+
+void Transport::MaybeCompleted_w() {
+  ASSERT(worker_thread()->IsCurrent());
+
+  // A Transport's ICE process is completed if all of its channels are writable,
+  // have finished allocating candidates, and have pruned all but one of their
+  // connections.
+  ChannelMap::const_iterator iter;
+  for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
+    const TransportChannelImpl* channel = iter->second.get();
+    if (!(channel->writable() &&
+          channel->GetConnectionCount() == 1 &&
+          channel->GetIceRole() == ICEROLE_CONTROLLING &&
+          iter->second.candidates_allocated())) {
+      return;
+    }
+  }
+
+  signaling_thread_->Post(this, MSG_COMPLETED);
+}
+
+void Transport::SetIceRole_w(IceRole role) {
+  rtc::CritScope cs(&crit_);
+  ice_role_ = role;
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end(); ++iter) {
+    iter->second->SetIceRole(ice_role_);
+  }
+}
+
+void Transport::SetRemoteIceMode_w(IceMode mode) {
+  rtc::CritScope cs(&crit_);
+  remote_ice_mode_ = mode;
+  // Shouldn't channels be created after this method executed?
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end(); ++iter) {
+    iter->second->SetRemoteIceMode(remote_ice_mode_);
+  }
+}
+
+bool Transport::SetLocalTransportDescription_w(
+    const TransportDescription& desc,
+    ContentAction action,
+    std::string* error_desc) {
+  bool ret = true;
+  rtc::CritScope cs(&crit_);
+
+  if (!VerifyIceParams(desc)) {
+    return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
+                                   error_desc);
+  }
+
+  if (local_description_ && IceCredentialsChanged(*local_description_, desc)) {
+    IceRole new_ice_role = (action == CA_OFFER) ? ICEROLE_CONTROLLING
+                                                : ICEROLE_CONTROLLED;
+
+    // It must be called before ApplyLocalTransportDescription_w, which may
+    // trigger an ICE restart and depends on the new ICE role.
+    SetIceRole_w(new_ice_role);
+  }
+
+  local_description_.reset(new TransportDescription(desc));
+
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end(); ++iter) {
+    ret &= ApplyLocalTransportDescription_w(iter->second.get(), error_desc);
+  }
+  if (!ret)
+    return false;
+
+  // If PRANSWER/ANSWER is set, we should decide transport protocol type.
+  if (action == CA_PRANSWER || action == CA_ANSWER) {
+    ret &= NegotiateTransportDescription_w(action, error_desc);
+  }
+  return ret;
+}
+
+bool Transport::SetRemoteTransportDescription_w(
+    const TransportDescription& desc,
+    ContentAction action,
+    std::string* error_desc) {
+  bool ret = true;
+  rtc::CritScope cs(&crit_);
+
+  if (!VerifyIceParams(desc)) {
+    return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
+                                   error_desc);
+  }
+
+  remote_description_.reset(new TransportDescription(desc));
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end(); ++iter) {
+    ret &= ApplyRemoteTransportDescription_w(iter->second.get(), error_desc);
+  }
+
+  // If PRANSWER/ANSWER is set, we should decide transport protocol type.
+  if (action == CA_PRANSWER || action == CA_ANSWER) {
+    ret = NegotiateTransportDescription_w(CA_OFFER, error_desc);
+  }
+  return ret;
+}
+
+bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch,
+                                                 std::string* error_desc) {
+  // If existing protocol_type is HYBRID, we may have not chosen the final
+  // protocol type, so update the channel protocol type from the
+  // local description. Otherwise, skip updating the protocol type.
+  // We check for HYBRID to avoid accidental changes; in the case of a
+  // session renegotiation, the new offer will have the google-ice ICE option,
+  // so we need to make sure we don't switch back from ICE mode to HYBRID
+  // when this happens.
+  // There are some other ways we could have solved this, but this is the
+  // simplest. The ultimate solution will be to get rid of GICE altogether.
+  IceProtocolType protocol_type;
+  if (ch->GetIceProtocolType(&protocol_type) &&
+      protocol_type == ICEPROTO_HYBRID) {
+    ch->SetIceProtocolType(
+        TransportProtocolFromDescription(local_description()));
+  }
+  ch->SetIceCredentials(local_description_->ice_ufrag,
+                        local_description_->ice_pwd);
+  return true;
+}
+
+bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
+                                                  std::string* error_desc) {
+  ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
+                              remote_description_->ice_pwd);
+  return true;
+}
+
+bool Transport::ApplyNegotiatedTransportDescription_w(
+    TransportChannelImpl* channel, std::string* error_desc) {
+  channel->SetIceProtocolType(protocol_);
+  channel->SetRemoteIceMode(remote_ice_mode_);
+  return true;
+}
+
+bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
+                                                std::string* error_desc) {
+  // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
+  // P2PTransport.
+  const TransportDescription* offer;
+  const TransportDescription* answer;
+
+  if (local_role == CA_OFFER) {
+    offer = local_description_.get();
+    answer = remote_description_.get();
+  } else {
+    offer = remote_description_.get();
+    answer = local_description_.get();
+  }
+
+  TransportProtocol offer_proto = TransportProtocolFromDescription(offer);
+  TransportProtocol answer_proto = TransportProtocolFromDescription(answer);
+
+  // If offered protocol is gice/ice, then we expect to receive matching
+  // protocol in answer, anything else is treated as an error.
+  // HYBRID is not an option when offered specific protocol.
+  // If offered protocol is HYBRID and answered protocol is HYBRID then
+  // gice is preferred protocol.
+  // TODO(mallinath) - Answer from local or remote should't have both ice
+  // and gice support. It should always pick which protocol it wants to use.
+  // Once WebRTC stops supporting gice (for backward compatibility), HYBRID in
+  // answer must be treated as error.
+  if ((offer_proto == ICEPROTO_GOOGLE || offer_proto == ICEPROTO_RFC5245) &&
+      (offer_proto != answer_proto)) {
+    std::ostringstream desc;
+    desc << "Offer and answer protocol mismatch: "
+         << IceProtoToString(offer_proto)
+         << " vs "
+         << IceProtoToString(answer_proto);
+    return BadTransportDescription(desc.str(), error_desc);
+  }
+  protocol_ = answer_proto == ICEPROTO_HYBRID ? ICEPROTO_GOOGLE : answer_proto;
+
+  // If transport is in ICEROLE_CONTROLLED and remote end point supports only
+  // ice_lite, this local end point should take CONTROLLING role.
+  if (ice_role_ == ICEROLE_CONTROLLED &&
+      remote_description_->ice_mode == ICEMODE_LITE) {
+    SetIceRole_w(ICEROLE_CONTROLLING);
+  }
+
+  // Update remote ice_mode to all existing channels.
+  remote_ice_mode_ = remote_description_->ice_mode;
+
+  // Now that we have negotiated everything, push it downward.
+  // Note that we cache the result so that if we have race conditions
+  // between future SetRemote/SetLocal invocations and new channel
+  // creation, we have the negotiation state saved until a new
+  // negotiation happens.
+  for (ChannelMap::iterator iter = channels_.begin();
+       iter != channels_.end();
+       ++iter) {
+    if (!ApplyNegotiatedTransportDescription_w(iter->second.get(), error_desc))
+      return false;
+  }
+  return true;
+}
+
+void Transport::OnMessage(rtc::Message* msg) {
+  switch (msg->message_id) {
+    case MSG_ONSIGNALINGREADY:
+      CallChannels_w(&TransportChannelImpl::OnSignalingReady);
+      break;
+    case MSG_ONREMOTECANDIDATE: {
+        ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
+        OnRemoteCandidate_w(*params->candidate);
+        delete params;
+      }
+      break;
+    case MSG_CONNECTING:
+      OnConnecting_s();
+      break;
+    case MSG_READSTATE:
+      OnChannelReadableState_s();
+      break;
+    case MSG_WRITESTATE:
+      OnChannelWritableState_s();
+      break;
+    case MSG_REQUESTSIGNALING: {
+        ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
+        OnChannelRequestSignaling_s(params->component);
+        delete params;
+      }
+      break;
+    case MSG_CANDIDATEREADY:
+      OnChannelCandidateReady_s();
+      break;
+    case MSG_ROUTECHANGE: {
+        ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
+        OnChannelRouteChange_s(params->channel, *params->candidate);
+        delete params;
+      }
+      break;
+    case MSG_CANDIDATEALLOCATIONCOMPLETE:
+      OnChannelCandidatesAllocationDone_s();
+      break;
+    case MSG_ROLECONFLICT:
+      SignalRoleConflict();
+      break;
+    case MSG_COMPLETED:
+      SignalCompleted(this);
+      break;
+    case MSG_FAILED:
+      SignalFailed(this);
+      break;
+  }
+}
+
+bool TransportParser::ParseAddress(const buzz::XmlElement* elem,
+                                   const buzz::QName& address_name,
+                                   const buzz::QName& port_name,
+                                   rtc::SocketAddress* address,
+                                   ParseError* error) {
+  if (!elem->HasAttr(address_name))
+    return BadParse("address does not have " + address_name.LocalPart(), error);
+  if (!elem->HasAttr(port_name))
+    return BadParse("address does not have " + port_name.LocalPart(), error);
+
+  address->SetIP(elem->Attr(address_name));
+  std::istringstream ist(elem->Attr(port_name));
+  int port = 0;
+  ist >> port;
+  address->SetPort(port);
+
+  return true;
+}
+
+// We're GICE if the namespace is NS_GOOGLE_P2P, or if NS_JINGLE_ICE_UDP is
+// used and the GICE ice-option is set.
+TransportProtocol TransportProtocolFromDescription(
+    const TransportDescription* desc) {
+  ASSERT(desc != NULL);
+  if (desc->transport_type == NS_JINGLE_ICE_UDP) {
+    return (desc->HasOption(ICE_OPTION_GICE)) ?
+        ICEPROTO_HYBRID : ICEPROTO_RFC5245;
+  }
+  return ICEPROTO_GOOGLE;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/transport.h b/p2p/base/transport.h
new file mode 100644
index 0000000..ab772fe
--- /dev/null
+++ b/p2p/base/transport.h
@@ -0,0 +1,513 @@
+/*
+ *  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.
+ */
+
+// A Transport manages a set of named channels of the same type.
+//
+// Subclasses choose the appropriate class to instantiate for each channel;
+// however, this base class keeps track of the channels by name, watches their
+// state changes (in order to update the manager's state), and forwards
+// requests to begin connecting or to reset to each of the channels.
+//
+// On Threading:  Transport performs work on both the signaling and worker
+// threads.  For subclasses, the rule is that all signaling related calls will
+// be made on the signaling thread and all channel related calls (including
+// signaling for a channel) will be made on the worker thread.  When
+// information needs to be sent between the two threads, this class should do
+// the work (e.g., OnRemoteCandidate).
+//
+// Note: Subclasses must call DestroyChannels() in their own constructors.
+// It is not possible to do so here because the subclass constructor will
+// already have run.
+
+#ifndef WEBRTC_P2P_BASE_TRANSPORT_H_
+#define WEBRTC_P2P_BASE_TRANSPORT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/sessiondescription.h"
+#include "webrtc/p2p/base/transportinfo.h"
+#include "webrtc/base/criticalsection.h"
+#include "webrtc/base/messagequeue.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/sslstreamadapter.h"
+
+namespace rtc {
+class Thread;
+}
+
+namespace buzz {
+class QName;
+class XmlElement;
+}
+
+namespace cricket {
+
+struct ParseError;
+struct WriteError;
+class CandidateTranslator;
+class PortAllocator;
+class SessionManager;
+class Session;
+class TransportChannel;
+class TransportChannelImpl;
+
+typedef std::vector<buzz::XmlElement*> XmlElements;
+typedef std::vector<Candidate> Candidates;
+
+// Used to parse and serialize (write) transport candidates.  For
+// convenience of old code, Transports will implement TransportParser.
+// Parse/Write seems better than Serialize/Deserialize or
+// Create/Translate.
+class TransportParser {
+ public:
+  // The incoming Translator value may be null, in which case
+  // ParseCandidates should return false if there are candidates to
+  // parse (indicating a failure to parse).  If the Translator is null
+  // and there are no candidates to parse, then return true,
+  // indicating a successful parse of 0 candidates.
+
+  // Parse or write a transport description, including ICE credentials and
+  // any DTLS fingerprint. Since only Jingle has transport descriptions, these
+  // functions are only used when serializing to Jingle.
+  virtual bool ParseTransportDescription(const buzz::XmlElement* elem,
+                                         const CandidateTranslator* translator,
+                                         TransportDescription* tdesc,
+                                         ParseError* error) = 0;
+  virtual bool WriteTransportDescription(const TransportDescription& tdesc,
+                                         const CandidateTranslator* translator,
+                                         buzz::XmlElement** tdesc_elem,
+                                         WriteError* error) = 0;
+
+
+  // Parse a single candidate. This must be used when parsing Gingle
+  // candidates, since there is no enclosing transport description.
+  virtual bool ParseGingleCandidate(const buzz::XmlElement* elem,
+                                    const CandidateTranslator* translator,
+                                    Candidate* candidates,
+                                    ParseError* error) = 0;
+  virtual bool WriteGingleCandidate(const Candidate& candidate,
+                                    const CandidateTranslator* translator,
+                                    buzz::XmlElement** candidate_elem,
+                                    WriteError* error) = 0;
+
+  // Helper function to parse an element describing an address.  This
+  // retrieves the IP and port from the given element and verifies
+  // that they look like plausible values.
+  bool ParseAddress(const buzz::XmlElement* elem,
+                    const buzz::QName& address_name,
+                    const buzz::QName& port_name,
+                    rtc::SocketAddress* address,
+                    ParseError* error);
+
+  virtual ~TransportParser() {}
+};
+
+// For "writable" and "readable", we need to differentiate between
+// none, all, and some.
+enum TransportState {
+  TRANSPORT_STATE_NONE = 0,
+  TRANSPORT_STATE_SOME,
+  TRANSPORT_STATE_ALL
+};
+
+// Stats that we can return about the connections for a transport channel.
+// TODO(hta): Rename to ConnectionStats
+struct ConnectionInfo {
+  ConnectionInfo()
+      : best_connection(false),
+        writable(false),
+        readable(false),
+        timeout(false),
+        new_connection(false),
+        rtt(0),
+        sent_total_bytes(0),
+        sent_bytes_second(0),
+        recv_total_bytes(0),
+        recv_bytes_second(0),
+        key(NULL) {}
+
+  bool best_connection;        // Is this the best connection we have?
+  bool writable;               // Has this connection received a STUN response?
+  bool readable;               // Has this connection received a STUN request?
+  bool timeout;                // Has this connection timed out?
+  bool new_connection;         // Is this a newly created connection?
+  size_t rtt;                  // The STUN RTT for this connection.
+  size_t sent_total_bytes;     // Total bytes sent on this connection.
+  size_t sent_bytes_second;    // Bps over the last measurement interval.
+  size_t recv_total_bytes;     // Total bytes received on this connection.
+  size_t recv_bytes_second;    // Bps over the last measurement interval.
+  Candidate local_candidate;   // The local candidate for this connection.
+  Candidate remote_candidate;  // The remote candidate for this connection.
+  void* key;                   // A static value that identifies this conn.
+};
+
+// Information about all the connections of a channel.
+typedef std::vector<ConnectionInfo> ConnectionInfos;
+
+// Information about a specific channel
+struct TransportChannelStats {
+  int component;
+  ConnectionInfos connection_infos;
+};
+
+// Information about all the channels of a transport.
+// TODO(hta): Consider if a simple vector is as good as a map.
+typedef std::vector<TransportChannelStats> TransportChannelStatsList;
+
+// Information about the stats of a transport.
+struct TransportStats {
+  std::string content_name;
+  TransportChannelStatsList channel_stats;
+};
+
+bool BadTransportDescription(const std::string& desc, std::string* err_desc);
+
+bool IceCredentialsChanged(const std::string& old_ufrag,
+                           const std::string& old_pwd,
+                           const std::string& new_ufrag,
+                           const std::string& new_pwd);
+
+class Transport : public rtc::MessageHandler,
+                  public sigslot::has_slots<> {
+ public:
+  Transport(rtc::Thread* signaling_thread,
+            rtc::Thread* worker_thread,
+            const std::string& content_name,
+            const std::string& type,
+            PortAllocator* allocator);
+  virtual ~Transport();
+
+  // Returns the signaling thread. The app talks to Transport on this thread.
+  rtc::Thread* signaling_thread() { return signaling_thread_; }
+  // Returns the worker thread. The actual networking is done on this thread.
+  rtc::Thread* worker_thread() { return worker_thread_; }
+
+  // Returns the content_name of this transport.
+  const std::string& content_name() const { return content_name_; }
+  // Returns the type of this transport.
+  const std::string& type() const { return type_; }
+
+  // Returns the port allocator object for this transport.
+  PortAllocator* port_allocator() { return allocator_; }
+
+  // Returns the readable and states of this manager.  These bits are the ORs
+  // of the corresponding bits on the managed channels.  Each time one of these
+  // states changes, a signal is raised.
+  // TODO: Replace uses of readable() and writable() with
+  // any_channels_readable() and any_channels_writable().
+  bool readable() const { return any_channels_readable(); }
+  bool writable() const { return any_channels_writable(); }
+  bool was_writable() const { return was_writable_; }
+  bool any_channels_readable() const {
+    return (readable_ == TRANSPORT_STATE_SOME ||
+            readable_ == TRANSPORT_STATE_ALL);
+  }
+  bool any_channels_writable() const {
+    return (writable_ == TRANSPORT_STATE_SOME ||
+            writable_ == TRANSPORT_STATE_ALL);
+  }
+  bool all_channels_readable() const {
+    return (readable_ == TRANSPORT_STATE_ALL);
+  }
+  bool all_channels_writable() const {
+    return (writable_ == TRANSPORT_STATE_ALL);
+  }
+  sigslot::signal1<Transport*> SignalReadableState;
+  sigslot::signal1<Transport*> SignalWritableState;
+  sigslot::signal1<Transport*> SignalCompleted;
+  sigslot::signal1<Transport*> SignalFailed;
+
+  // Returns whether the client has requested the channels to connect.
+  bool connect_requested() const { return connect_requested_; }
+
+  void SetIceRole(IceRole role);
+  IceRole ice_role() const { return ice_role_; }
+
+  void SetIceTiebreaker(uint64 IceTiebreaker) { tiebreaker_ = IceTiebreaker; }
+  uint64 IceTiebreaker() { return tiebreaker_; }
+
+  // Must be called before applying local session description.
+  void SetIdentity(rtc::SSLIdentity* identity);
+
+  // Get a copy of the local identity provided by SetIdentity.
+  bool GetIdentity(rtc::SSLIdentity** identity);
+
+  // Get a copy of the remote certificate in use by the specified channel.
+  bool GetRemoteCertificate(rtc::SSLCertificate** cert);
+
+  TransportProtocol protocol() const { return protocol_; }
+
+  // Create, destroy, and lookup the channels of this type by their components.
+  TransportChannelImpl* CreateChannel(int component);
+  // Note: GetChannel may lead to race conditions, since the mutex is not held
+  // after the pointer is returned.
+  TransportChannelImpl* GetChannel(int component);
+  // Note: HasChannel does not lead to race conditions, unlike GetChannel.
+  bool HasChannel(int component) {
+    return (NULL != GetChannel(component));
+  }
+  bool HasChannels();
+  void DestroyChannel(int component);
+
+  // Set the local TransportDescription to be used by TransportChannels.
+  // This should be called before ConnectChannels().
+  bool SetLocalTransportDescription(const TransportDescription& description,
+                                    ContentAction action,
+                                    std::string* error_desc);
+
+  // Set the remote TransportDescription to be used by TransportChannels.
+  bool SetRemoteTransportDescription(const TransportDescription& description,
+                                     ContentAction action,
+                                     std::string* error_desc);
+
+  // Tells all current and future channels to start connecting.  When the first
+  // channel begins connecting, the following signal is raised.
+  void ConnectChannels();
+  sigslot::signal1<Transport*> SignalConnecting;
+
+  // Resets all of the channels back to their initial state.  They are no
+  // longer connecting.
+  void ResetChannels();
+
+  // Destroys every channel created so far.
+  void DestroyAllChannels();
+
+  bool GetStats(TransportStats* stats);
+
+  // Before any stanza is sent, the manager will request signaling.  Once
+  // signaling is available, the client should call OnSignalingReady.  Once
+  // this occurs, the transport (or its channels) can send any waiting stanzas.
+  // OnSignalingReady invokes OnTransportSignalingReady and then forwards this
+  // signal to each channel.
+  sigslot::signal1<Transport*> SignalRequestSignaling;
+  void OnSignalingReady();
+
+  // Handles sending of ready candidates and receiving of remote candidates.
+  sigslot::signal2<Transport*,
+                   const std::vector<Candidate>&> SignalCandidatesReady;
+
+  sigslot::signal1<Transport*> SignalCandidatesAllocationDone;
+  void OnRemoteCandidates(const std::vector<Candidate>& candidates);
+
+  // If candidate is not acceptable, returns false and sets error.
+  // Call this before calling OnRemoteCandidates.
+  virtual bool VerifyCandidate(const Candidate& candidate,
+                               std::string* error);
+
+  // Signals when the best connection for a channel changes.
+  sigslot::signal3<Transport*,
+                   int,  // component
+                   const Candidate&> SignalRouteChange;
+
+  // A transport message has generated an transport-specific error.  The
+  // stanza that caused the error is available in session_msg.  If false is
+  // returned, the error is considered unrecoverable, and the session is
+  // terminated.
+  // TODO(juberti): Remove these obsolete functions once Session no longer
+  // references them.
+  virtual void OnTransportError(const buzz::XmlElement* error) {}
+  sigslot::signal6<Transport*, const buzz::XmlElement*, const buzz::QName&,
+                   const std::string&, const std::string&,
+                   const buzz::XmlElement*>
+      SignalTransportError;
+
+  // Forwards the signal from TransportChannel to BaseSession.
+  sigslot::signal0<> SignalRoleConflict;
+
+  virtual bool GetSslRole(rtc::SSLRole* ssl_role) const;
+
+ protected:
+  // These are called by Create/DestroyChannel above in order to create or
+  // destroy the appropriate type of channel.
+  virtual TransportChannelImpl* CreateTransportChannel(int component) = 0;
+  virtual void DestroyTransportChannel(TransportChannelImpl* channel) = 0;
+
+  // Informs the subclass that we received the signaling ready message.
+  virtual void OnTransportSignalingReady() {}
+
+  // The current local transport description, for use by derived classes
+  // when performing transport description negotiation.
+  const TransportDescription* local_description() const {
+    return local_description_.get();
+  }
+
+  // The current remote transport description, for use by derived classes
+  // when performing transport description negotiation.
+  const TransportDescription* remote_description() const {
+    return remote_description_.get();
+  }
+
+  virtual void SetIdentity_w(rtc::SSLIdentity* identity) {}
+
+  virtual bool GetIdentity_w(rtc::SSLIdentity** identity) {
+    return false;
+  }
+
+  // Pushes down the transport parameters from the local description, such
+  // as the ICE ufrag and pwd.
+  // Derived classes can override, but must call the base as well.
+  virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
+                                                std::string* error_desc);
+
+  // Pushes down remote ice credentials from the remote description to the
+  // transport channel.
+  virtual bool ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
+                                                 std::string* error_desc);
+
+  // Negotiates the transport parameters based on the current local and remote
+  // transport description, such at the version of ICE to use, and whether DTLS
+  // should be activated.
+  // Derived classes can negotiate their specific parameters here, but must call
+  // the base as well.
+  virtual bool NegotiateTransportDescription_w(ContentAction local_role,
+                                               std::string* error_desc);
+
+  // Pushes down the transport parameters obtained via negotiation.
+  // Derived classes can set their specific parameters here, but must call the
+  // base as well.
+  virtual bool ApplyNegotiatedTransportDescription_w(
+      TransportChannelImpl* channel, std::string* error_desc);
+
+  virtual bool GetSslRole_w(rtc::SSLRole* ssl_role) const {
+    return false;
+  }
+
+ private:
+  struct ChannelMapEntry {
+    ChannelMapEntry() : impl_(NULL), candidates_allocated_(false), ref_(0) {}
+    explicit ChannelMapEntry(TransportChannelImpl *impl)
+        : impl_(impl),
+          candidates_allocated_(false),
+          ref_(0) {
+    }
+
+    void AddRef() { ++ref_; }
+    void DecRef() {
+      ASSERT(ref_ > 0);
+      --ref_;
+    }
+    int ref() const { return ref_; }
+
+    TransportChannelImpl* get() const { return impl_; }
+    TransportChannelImpl* operator->() const  { return impl_; }
+    void set_candidates_allocated(bool status) {
+      candidates_allocated_ = status;
+    }
+    bool candidates_allocated() const { return candidates_allocated_; }
+
+  private:
+    TransportChannelImpl *impl_;
+    bool candidates_allocated_;
+    int ref_;
+  };
+
+  // Candidate component => ChannelMapEntry
+  typedef std::map<int, ChannelMapEntry> ChannelMap;
+
+  // Called when the state of a channel changes.
+  void OnChannelReadableState(TransportChannel* channel);
+  void OnChannelWritableState(TransportChannel* channel);
+
+  // Called when a channel requests signaling.
+  void OnChannelRequestSignaling(TransportChannelImpl* channel);
+
+  // Called when a candidate is ready from remote peer.
+  void OnRemoteCandidate(const Candidate& candidate);
+  // Called when a candidate is ready from channel.
+  void OnChannelCandidateReady(TransportChannelImpl* channel,
+                               const Candidate& candidate);
+  void OnChannelRouteChange(TransportChannel* channel,
+                            const Candidate& remote_candidate);
+  void OnChannelCandidatesAllocationDone(TransportChannelImpl* channel);
+  // Called when there is ICE role change.
+  void OnRoleConflict(TransportChannelImpl* channel);
+  // Called when the channel removes a connection.
+  void OnChannelConnectionRemoved(TransportChannelImpl* channel);
+
+  // Dispatches messages to the appropriate handler (below).
+  void OnMessage(rtc::Message* msg);
+
+  // These are versions of the above methods that are called only on a
+  // particular thread (s = signaling, w = worker).  The above methods post or
+  // send a message to invoke this version.
+  TransportChannelImpl* CreateChannel_w(int component);
+  void DestroyChannel_w(int component);
+  void ConnectChannels_w();
+  void ResetChannels_w();
+  void DestroyAllChannels_w();
+  void OnRemoteCandidate_w(const Candidate& candidate);
+  void OnChannelReadableState_s();
+  void OnChannelWritableState_s();
+  void OnChannelRequestSignaling_s(int component);
+  void OnConnecting_s();
+  void OnChannelRouteChange_s(const TransportChannel* channel,
+                              const Candidate& remote_candidate);
+  void OnChannelCandidatesAllocationDone_s();
+
+  // Helper function that invokes the given function on every channel.
+  typedef void (TransportChannelImpl::* TransportChannelFunc)();
+  void CallChannels_w(TransportChannelFunc func);
+
+  // Computes the OR of the channel's read or write state (argument picks).
+  TransportState GetTransportState_s(bool read);
+
+  void OnChannelCandidateReady_s();
+
+  void SetIceRole_w(IceRole role);
+  void SetRemoteIceMode_w(IceMode mode);
+  bool SetLocalTransportDescription_w(const TransportDescription& desc,
+                                      ContentAction action,
+                                      std::string* error_desc);
+  bool SetRemoteTransportDescription_w(const TransportDescription& desc,
+                                       ContentAction action,
+                                       std::string* error_desc);
+  bool GetStats_w(TransportStats* infos);
+  bool GetRemoteCertificate_w(rtc::SSLCertificate** cert);
+
+  // Sends SignalCompleted if we are now in that state.
+  void MaybeCompleted_w();
+
+  rtc::Thread* signaling_thread_;
+  rtc::Thread* worker_thread_;
+  std::string content_name_;
+  std::string type_;
+  PortAllocator* allocator_;
+  bool destroyed_;
+  TransportState readable_;
+  TransportState writable_;
+  bool was_writable_;
+  bool connect_requested_;
+  IceRole ice_role_;
+  uint64 tiebreaker_;
+  TransportProtocol protocol_;
+  IceMode remote_ice_mode_;
+  rtc::scoped_ptr<TransportDescription> local_description_;
+  rtc::scoped_ptr<TransportDescription> remote_description_;
+
+  ChannelMap channels_;
+  // Buffers the ready_candidates so that SignalCanidatesReady can
+  // provide them in multiples.
+  std::vector<Candidate> ready_candidates_;
+  // Protects changes to channels and messages
+  rtc::CriticalSection crit_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Transport);
+};
+
+// Extract a TransportProtocol from a TransportDescription.
+TransportProtocol TransportProtocolFromDescription(
+    const TransportDescription* desc);
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TRANSPORT_H_
diff --git a/p2p/base/transport_unittest.cc b/p2p/base/transport_unittest.cc
new file mode 100644
index 0000000..abcf32c
--- /dev/null
+++ b/p2p/base/transport_unittest.cc
@@ -0,0 +1,438 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/p2p/base/constants.h"
+#include "webrtc/p2p/base/fakesession.h"
+#include "webrtc/p2p/base/p2ptransport.h"
+#include "webrtc/p2p/base/parsing.h"
+#include "webrtc/p2p/base/rawtransport.h"
+#include "webrtc/p2p/base/sessionmessages.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/base/fakesslidentity.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/thread.h"
+
+using cricket::Candidate;
+using cricket::Candidates;
+using cricket::Transport;
+using cricket::FakeTransport;
+using cricket::TransportChannel;
+using cricket::FakeTransportChannel;
+using cricket::IceRole;
+using cricket::TransportDescription;
+using cricket::WriteError;
+using cricket::ParseError;
+using rtc::SocketAddress;
+
+static const char kIceUfrag1[] = "TESTICEUFRAG0001";
+static const char kIcePwd1[] = "TESTICEPWD00000000000001";
+
+static const char kIceUfrag2[] = "TESTICEUFRAG0002";
+static const char kIcePwd2[] = "TESTICEPWD00000000000002";
+
+class TransportTest : public testing::Test,
+                      public sigslot::has_slots<> {
+ public:
+  TransportTest()
+      : thread_(rtc::Thread::Current()),
+        transport_(new FakeTransport(
+            thread_, thread_, "test content name", NULL)),
+        channel_(NULL),
+        connecting_signalled_(false),
+        completed_(false),
+        failed_(false) {
+    transport_->SignalConnecting.connect(this, &TransportTest::OnConnecting);
+    transport_->SignalCompleted.connect(this, &TransportTest::OnCompleted);
+    transport_->SignalFailed.connect(this, &TransportTest::OnFailed);
+  }
+  ~TransportTest() {
+    transport_->DestroyAllChannels();
+  }
+  bool SetupChannel() {
+    channel_ = CreateChannel(1);
+    return (channel_ != NULL);
+  }
+  FakeTransportChannel* CreateChannel(int component) {
+    return static_cast<FakeTransportChannel*>(
+        transport_->CreateChannel(component));
+  }
+  void DestroyChannel() {
+    transport_->DestroyChannel(1);
+    channel_ = NULL;
+  }
+
+ protected:
+  void OnConnecting(Transport* transport) {
+    connecting_signalled_ = true;
+  }
+  void OnCompleted(Transport* transport) {
+    completed_ = true;
+  }
+  void OnFailed(Transport* transport) {
+    failed_ = true;
+  }
+
+  rtc::Thread* thread_;
+  rtc::scoped_ptr<FakeTransport> transport_;
+  FakeTransportChannel* channel_;
+  bool connecting_signalled_;
+  bool completed_;
+  bool failed_;
+};
+
+class FakeCandidateTranslator : public cricket::CandidateTranslator {
+ public:
+  void AddMapping(int component, const std::string& channel_name) {
+    name_to_component[channel_name] = component;
+    component_to_name[component] = channel_name;
+  }
+
+  bool GetChannelNameFromComponent(
+      int component, std::string* channel_name) const {
+    if (component_to_name.find(component) == component_to_name.end()) {
+      return false;
+    }
+    *channel_name = component_to_name.find(component)->second;
+    return true;
+  }
+  bool GetComponentFromChannelName(
+      const std::string& channel_name, int* component) const {
+    if (name_to_component.find(channel_name) == name_to_component.end()) {
+      return false;
+    }
+    *component = name_to_component.find(channel_name)->second;
+    return true;
+  }
+
+  std::map<std::string, int> name_to_component;
+  std::map<int, std::string> component_to_name;
+};
+
+// Test that calling ConnectChannels triggers an OnConnecting signal.
+TEST_F(TransportTest, TestConnectChannelsDoesSignal) {
+  EXPECT_TRUE(SetupChannel());
+  transport_->ConnectChannels();
+  EXPECT_FALSE(connecting_signalled_);
+
+  EXPECT_TRUE_WAIT(connecting_signalled_, 100);
+}
+
+// Test that DestroyAllChannels kills any pending OnConnecting signals.
+TEST_F(TransportTest, TestDestroyAllClearsPosts) {
+  EXPECT_TRUE(transport_->CreateChannel(1) != NULL);
+
+  transport_->ConnectChannels();
+  transport_->DestroyAllChannels();
+
+  thread_->ProcessMessages(0);
+  EXPECT_FALSE(connecting_signalled_);
+}
+
+// This test verifies channels are created with proper ICE
+// role, tiebreaker and remote ice mode and credentials after offer and
+// answer negotiations.
+TEST_F(TransportTest, TestChannelIceParameters) {
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  transport_->SetIceTiebreaker(99U);
+  cricket::TransportDescription local_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
+                                                       cricket::CA_OFFER,
+                                                       NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
+  EXPECT_TRUE(SetupChannel());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
+  EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode());
+  EXPECT_EQ(kIceUfrag1, channel_->ice_ufrag());
+  EXPECT_EQ(kIcePwd1, channel_->ice_pwd());
+
+  cricket::TransportDescription remote_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
+                                                        cricket::CA_ANSWER,
+                                                        NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
+  EXPECT_EQ(99U, channel_->IceTiebreaker());
+  EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode());
+  // Changing the transport role from CONTROLLING to CONTROLLED.
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel_->GetIceRole());
+  EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode());
+  EXPECT_EQ(kIceUfrag1, channel_->remote_ice_ufrag());
+  EXPECT_EQ(kIcePwd1, channel_->remote_ice_pwd());
+}
+
+// Verifies that IceCredentialsChanged returns true when either ufrag or pwd
+// changed, and false in other cases.
+TEST_F(TransportTest, TestIceCredentialsChanged) {
+  EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u2", "p2"));
+  EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u2", "p1"));
+  EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u1", "p2"));
+  EXPECT_FALSE(cricket::IceCredentialsChanged("u1", "p1", "u1", "p1"));
+}
+
+// This test verifies that the callee's ICE role changes from controlled to
+// controlling when the callee triggers an ICE restart.
+TEST_F(TransportTest, TestIceControlledToControllingOnIceRestart) {
+  EXPECT_TRUE(SetupChannel());
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLED);
+
+  cricket::TransportDescription desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetRemoteTransportDescription(desc,
+                                                        cricket::CA_OFFER,
+                                                        NULL));
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(desc,
+                                                       cricket::CA_ANSWER,
+                                                       NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLED, transport_->ice_role());
+
+  cricket::TransportDescription new_local_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag2, kIcePwd2);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(new_local_desc,
+                                                       cricket::CA_OFFER,
+                                                       NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
+}
+
+// This test verifies that the caller's ICE role changes from controlling to
+// controlled when the callee triggers an ICE restart.
+TEST_F(TransportTest, TestIceControllingToControlledOnIceRestart) {
+  EXPECT_TRUE(SetupChannel());
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+
+  cricket::TransportDescription desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(desc,
+                                                       cricket::CA_OFFER,
+                                                       NULL));
+  ASSERT_TRUE(transport_->SetRemoteTransportDescription(desc,
+                                                        cricket::CA_ANSWER,
+                                                        NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
+
+  cricket::TransportDescription new_local_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag2, kIcePwd2);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(new_local_desc,
+                                                       cricket::CA_ANSWER,
+                                                       NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLED, transport_->ice_role());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel_->GetIceRole());
+}
+
+// This test verifies that the caller's ICE role is still controlling after the
+// callee triggers ICE restart if the callee's ICE mode is LITE.
+TEST_F(TransportTest, TestIceControllingOnIceRestartIfRemoteIsIceLite) {
+  EXPECT_TRUE(SetupChannel());
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+
+  cricket::TransportDescription desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(desc,
+                                                       cricket::CA_OFFER,
+                                                       NULL));
+
+  cricket::TransportDescription remote_desc(
+      cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(),
+      kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE,
+      cricket::CONNECTIONROLE_NONE, NULL, cricket::Candidates());
+  ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
+                                                        cricket::CA_ANSWER,
+                                                        NULL));
+
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
+
+  cricket::TransportDescription new_local_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag2, kIcePwd2);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(new_local_desc,
+                                                       cricket::CA_ANSWER,
+                                                       NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
+}
+
+// This test verifies that the Completed and Failed states can be reached.
+TEST_F(TransportTest, TestChannelCompletedAndFailed) {
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  cricket::TransportDescription local_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
+                                                       cricket::CA_OFFER,
+                                                       NULL));
+  EXPECT_TRUE(SetupChannel());
+
+  cricket::TransportDescription remote_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
+                                                        cricket::CA_ANSWER,
+                                                        NULL));
+
+  channel_->SetConnectionCount(2);
+  channel_->SignalCandidatesAllocationDone(channel_);
+  channel_->SetWritable(true);
+  EXPECT_TRUE_WAIT(transport_->all_channels_writable(), 100);
+  // ICE is not yet completed because there is still more than one connection.
+  EXPECT_FALSE(completed_);
+  EXPECT_FALSE(failed_);
+
+  // When the connection count drops to 1, SignalCompleted should be emitted,
+  // and completed() should be true.
+  channel_->SetConnectionCount(1);
+  EXPECT_TRUE_WAIT(completed_, 100);
+  completed_ = false;
+
+  // When the connection count drops to 0, SignalFailed should be emitted, and
+  // completed() should be false.
+  channel_->SetConnectionCount(0);
+  EXPECT_TRUE_WAIT(failed_, 100);
+  EXPECT_FALSE(completed_);
+}
+
+// Tests channel role is reversed after receiving ice-lite from remote.
+TEST_F(TransportTest, TestSetRemoteIceLiteInOffer) {
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  cricket::TransportDescription remote_desc(
+      cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(),
+      kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE,
+      cricket::CONNECTIONROLE_ACTPASS, NULL, cricket::Candidates());
+  ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
+                                                        cricket::CA_OFFER,
+                                                        NULL));
+  cricket::TransportDescription local_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
+                                                       cricket::CA_ANSWER,
+                                                       NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
+  EXPECT_TRUE(SetupChannel());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
+  EXPECT_EQ(cricket::ICEMODE_LITE, channel_->remote_ice_mode());
+}
+
+// Tests ice-lite in remote answer.
+TEST_F(TransportTest, TestSetRemoteIceLiteInAnswer) {
+  transport_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  cricket::TransportDescription local_desc(
+      cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+  ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
+                                                       cricket::CA_OFFER,
+                                                       NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
+  EXPECT_TRUE(SetupChannel());
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
+  // Channels will be created in ICEFULL_MODE.
+  EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode());
+  cricket::TransportDescription remote_desc(
+      cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(),
+      kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE,
+      cricket::CONNECTIONROLE_NONE, NULL, cricket::Candidates());
+  ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
+                                                        cricket::CA_ANSWER,
+                                                        NULL));
+  EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
+  // After receiving remote description with ICEMODE_LITE, channel should
+  // have mode set to ICEMODE_LITE.
+  EXPECT_EQ(cricket::ICEMODE_LITE, channel_->remote_ice_mode());
+}
+
+// Tests that we can properly serialize/deserialize candidates.
+TEST_F(TransportTest, TestP2PTransportWriteAndParseCandidate) {
+  Candidate test_candidate(
+      "", 1, "udp",
+      rtc::SocketAddress("2001:db8:fefe::1", 9999),
+      738197504, "abcdef", "ghijkl", "foo", "testnet", 50, "");
+  Candidate test_candidate2(
+      "", 2, "tcp",
+      rtc::SocketAddress("192.168.7.1", 9999),
+      1107296256, "mnopqr", "stuvwx", "bar", "testnet2", 100, "");
+  rtc::SocketAddress host_address("www.google.com", 24601);
+  host_address.SetResolvedIP(rtc::IPAddress(0x0A000001));
+  Candidate test_candidate3(
+      "", 3, "spdy", host_address, 1476395008, "yzabcd",
+      "efghij", "baz", "testnet3", 150, "");
+  WriteError write_error;
+  ParseError parse_error;
+  rtc::scoped_ptr<buzz::XmlElement> elem;
+  cricket::Candidate parsed_candidate;
+  cricket::P2PTransportParser parser;
+
+  FakeCandidateTranslator translator;
+  translator.AddMapping(1, "test");
+  translator.AddMapping(2, "test2");
+  translator.AddMapping(3, "test3");
+
+  EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate, &translator,
+                                          elem.accept(), &write_error));
+  EXPECT_EQ("", write_error.text);
+  EXPECT_EQ("test", elem->Attr(buzz::QN_NAME));
+  EXPECT_EQ("udp", elem->Attr(cricket::QN_PROTOCOL));
+  EXPECT_EQ("2001:db8:fefe::1", elem->Attr(cricket::QN_ADDRESS));
+  EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT));
+  EXPECT_EQ("0.34", elem->Attr(cricket::QN_PREFERENCE));
+  EXPECT_EQ("abcdef", elem->Attr(cricket::QN_USERNAME));
+  EXPECT_EQ("ghijkl", elem->Attr(cricket::QN_PASSWORD));
+  EXPECT_EQ("foo", elem->Attr(cricket::QN_TYPE));
+  EXPECT_EQ("testnet", elem->Attr(cricket::QN_NETWORK));
+  EXPECT_EQ("50", elem->Attr(cricket::QN_GENERATION));
+
+  EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator,
+                                          &parsed_candidate, &parse_error));
+  EXPECT_TRUE(test_candidate.IsEquivalent(parsed_candidate));
+
+  EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate2, &translator,
+                                          elem.accept(), &write_error));
+  EXPECT_EQ("test2", elem->Attr(buzz::QN_NAME));
+  EXPECT_EQ("tcp", elem->Attr(cricket::QN_PROTOCOL));
+  EXPECT_EQ("192.168.7.1", elem->Attr(cricket::QN_ADDRESS));
+  EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT));
+  EXPECT_EQ("0.51", elem->Attr(cricket::QN_PREFERENCE));
+  EXPECT_EQ("mnopqr", elem->Attr(cricket::QN_USERNAME));
+  EXPECT_EQ("stuvwx", elem->Attr(cricket::QN_PASSWORD));
+  EXPECT_EQ("bar", elem->Attr(cricket::QN_TYPE));
+  EXPECT_EQ("testnet2", elem->Attr(cricket::QN_NETWORK));
+  EXPECT_EQ("100", elem->Attr(cricket::QN_GENERATION));
+
+  EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator,
+                                          &parsed_candidate, &parse_error));
+  EXPECT_TRUE(test_candidate2.IsEquivalent(parsed_candidate));
+
+  // Check that an ip is preferred over hostname.
+  EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate3, &translator,
+                                          elem.accept(), &write_error));
+  EXPECT_EQ("test3", elem->Attr(cricket::QN_NAME));
+  EXPECT_EQ("spdy", elem->Attr(cricket::QN_PROTOCOL));
+  EXPECT_EQ("10.0.0.1", elem->Attr(cricket::QN_ADDRESS));
+  EXPECT_EQ("24601", elem->Attr(cricket::QN_PORT));
+  EXPECT_EQ("0.69", elem->Attr(cricket::QN_PREFERENCE));
+  EXPECT_EQ("yzabcd", elem->Attr(cricket::QN_USERNAME));
+  EXPECT_EQ("efghij", elem->Attr(cricket::QN_PASSWORD));
+  EXPECT_EQ("baz", elem->Attr(cricket::QN_TYPE));
+  EXPECT_EQ("testnet3", elem->Attr(cricket::QN_NETWORK));
+  EXPECT_EQ("150", elem->Attr(cricket::QN_GENERATION));
+
+  EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator,
+                                          &parsed_candidate, &parse_error));
+  EXPECT_TRUE(test_candidate3.IsEquivalent(parsed_candidate));
+}
+
+TEST_F(TransportTest, TestGetStats) {
+  EXPECT_TRUE(SetupChannel());
+  cricket::TransportStats stats;
+  EXPECT_TRUE(transport_->GetStats(&stats));
+  // Note that this tests the behavior of a FakeTransportChannel.
+  ASSERT_EQ(1U, stats.channel_stats.size());
+  EXPECT_EQ(1, stats.channel_stats[0].component);
+  transport_->ConnectChannels();
+  EXPECT_TRUE(transport_->GetStats(&stats));
+  ASSERT_EQ(1U, stats.channel_stats.size());
+  EXPECT_EQ(1, stats.channel_stats[0].component);
+}
diff --git a/p2p/base/transportchannel.cc b/p2p/base/transportchannel.cc
new file mode 100644
index 0000000..16ae27d
--- /dev/null
+++ b/p2p/base/transportchannel.cc
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <sstream>
+#include "webrtc/p2p/base/transportchannel.h"
+
+namespace cricket {
+
+std::string TransportChannel::ToString() const {
+  const char READABLE_ABBREV[2] = { '_', 'R' };
+  const char WRITABLE_ABBREV[2] = { '_', 'W' };
+  std::stringstream ss;
+  ss << "Channel[" << content_name_
+     << "|" << component_
+     << "|" << READABLE_ABBREV[readable_] << WRITABLE_ABBREV[writable_] << "]";
+  return ss.str();
+}
+
+void TransportChannel::set_readable(bool readable) {
+  if (readable_ != readable) {
+    readable_ = readable;
+    SignalReadableState(this);
+  }
+}
+
+void TransportChannel::set_writable(bool writable) {
+  if (writable_ != writable) {
+    writable_ = writable;
+    if (writable_) {
+      SignalReadyToSend(this);
+    }
+    SignalWritableState(this);
+  }
+}
+
+}  // namespace cricket
diff --git a/p2p/base/transportchannel.h b/p2p/base/transportchannel.h
new file mode 100644
index 0000000..f91c4a8
--- /dev/null
+++ b/p2p/base/transportchannel.h
@@ -0,0 +1,143 @@
+/*
+ *  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_P2P_BASE_TRANSPORTCHANNEL_H_
+#define WEBRTC_P2P_BASE_TRANSPORTCHANNEL_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportdescription.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/dscp.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/socket.h"
+#include "webrtc/base/sslidentity.h"
+#include "webrtc/base/sslstreamadapter.h"
+
+namespace cricket {
+
+class Candidate;
+
+// Flags for SendPacket/SignalReadPacket.
+enum PacketFlags {
+  PF_NORMAL       = 0x00,  // A normal packet.
+  PF_SRTP_BYPASS  = 0x01,  // An encrypted SRTP packet; bypass any additional
+                           // crypto provided by the transport (e.g. DTLS)
+};
+
+// A TransportChannel represents one logical stream of packets that are sent
+// between the two sides of a session.
+class TransportChannel : public sigslot::has_slots<> {
+ public:
+  explicit TransportChannel(const std::string& content_name, int component)
+      : content_name_(content_name),
+        component_(component),
+        readable_(false), writable_(false) {}
+  virtual ~TransportChannel() {}
+
+  // TODO(mallinath) - Remove this API, as it's no longer useful.
+  // Returns the session id of this channel.
+  virtual const std::string SessionId() const { return std::string(); }
+
+  const std::string& content_name() const { return content_name_; }
+  int component() const { return component_; }
+
+  // Returns the readable and states of this channel.  Each time one of these
+  // states changes, a signal is raised.  These states are aggregated by the
+  // TransportManager.
+  bool readable() const { return readable_; }
+  bool writable() const { return writable_; }
+  sigslot::signal1<TransportChannel*> SignalReadableState;
+  sigslot::signal1<TransportChannel*> SignalWritableState;
+  // Emitted when the TransportChannel's ability to send has changed.
+  sigslot::signal1<TransportChannel*> SignalReadyToSend;
+
+  // Attempts to send the given packet.  The return value is < 0 on failure.
+  // TODO: Remove the default argument once channel code is updated.
+  virtual int SendPacket(const char* data, size_t len,
+                         const rtc::PacketOptions& options,
+                         int flags = 0) = 0;
+
+  // Sets a socket option on this channel.  Note that not all options are
+  // supported by all transport types.
+  virtual int SetOption(rtc::Socket::Option opt, int value) = 0;
+
+  // Returns the most recent error that occurred on this channel.
+  virtual int GetError() = 0;
+
+  // Returns the current stats for this connection.
+  virtual bool GetStats(ConnectionInfos* infos) = 0;
+
+  // Is DTLS active?
+  virtual bool IsDtlsActive() const = 0;
+
+  // Default implementation.
+  virtual bool GetSslRole(rtc::SSLRole* role) const = 0;
+
+  // Sets up the ciphers to use for DTLS-SRTP.
+  virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) = 0;
+
+  // Finds out which DTLS-SRTP cipher was negotiated
+  virtual bool GetSrtpCipher(std::string* cipher) = 0;
+
+  // Gets a copy of the local SSL identity, owned by the caller.
+  virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const = 0;
+
+  // Gets a copy of the remote side's SSL certificate, owned by the caller.
+  virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const = 0;
+
+  // Allows key material to be extracted for external encryption.
+  virtual bool ExportKeyingMaterial(const std::string& label,
+      const uint8* context,
+      size_t context_len,
+      bool use_context,
+      uint8* result,
+      size_t result_len) = 0;
+
+  // Signalled each time a packet is received on this channel.
+  sigslot::signal5<TransportChannel*, const char*,
+                   size_t, const rtc::PacketTime&, int> SignalReadPacket;
+
+  // This signal occurs when there is a change in the way that packets are
+  // being routed, i.e. to a different remote location. The candidate
+  // indicates where and how we are currently sending media.
+  sigslot::signal2<TransportChannel*, const Candidate&> SignalRouteChange;
+
+  // Invoked when the channel is being destroyed.
+  sigslot::signal1<TransportChannel*> SignalDestroyed;
+
+  // Debugging description of this transport channel.
+  std::string ToString() const;
+
+ protected:
+  // Sets the readable state, signaling if necessary.
+  void set_readable(bool readable);
+
+  // Sets the writable state, signaling if necessary.
+  void set_writable(bool writable);
+
+
+ private:
+  // Used mostly for debugging.
+  std::string content_name_;
+  int component_;
+  bool readable_;
+  bool writable_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(TransportChannel);
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TRANSPORTCHANNEL_H_
diff --git a/p2p/base/transportchannelimpl.h b/p2p/base/transportchannelimpl.h
new file mode 100644
index 0000000..060df7f
--- /dev/null
+++ b/p2p/base/transportchannelimpl.h
@@ -0,0 +1,111 @@
+/*
+ *  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_P2P_BASE_TRANSPORTCHANNELIMPL_H_
+#define WEBRTC_P2P_BASE_TRANSPORTCHANNELIMPL_H_
+
+#include <string>
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannel.h"
+
+namespace buzz { class XmlElement; }
+
+namespace cricket {
+
+class Candidate;
+
+// Base class for real implementations of TransportChannel.  This includes some
+// methods called only by Transport, which do not need to be exposed to the
+// client.
+class TransportChannelImpl : public TransportChannel {
+ public:
+  explicit TransportChannelImpl(const std::string& content_name, int component)
+      : TransportChannel(content_name, component) {}
+
+  // Returns the transport that created this channel.
+  virtual Transport* GetTransport() = 0;
+
+  // For ICE channels.
+  virtual IceRole GetIceRole() const = 0;
+  virtual void SetIceRole(IceRole role) = 0;
+  virtual void SetIceTiebreaker(uint64 tiebreaker) = 0;
+  virtual size_t GetConnectionCount() const = 0;
+  // To toggle G-ICE/ICE.
+  virtual bool GetIceProtocolType(IceProtocolType* type) const = 0;
+  virtual void SetIceProtocolType(IceProtocolType type) = 0;
+  // SetIceCredentials only need to be implemented by the ICE
+  // transport channels. Non-ICE transport channels can just ignore.
+  // The ufrag and pwd should be set before the Connect() is called.
+  virtual void SetIceCredentials(const std::string& ice_ufrag,
+                                 const std::string& ice_pwd)  = 0;
+  // SetRemoteIceCredentials only need to be implemented by the ICE
+  // transport channels. Non-ICE transport channels can just ignore.
+  virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
+                                       const std::string& ice_pwd) = 0;
+
+  // SetRemoteIceMode must be implemented only by the ICE transport channels.
+  virtual void SetRemoteIceMode(IceMode mode) = 0;
+
+  // Begins the process of attempting to make a connection to the other client.
+  virtual void Connect() = 0;
+
+  // Resets this channel back to the initial state (i.e., not connecting).
+  virtual void Reset() = 0;
+
+  // Allows an individual channel to request signaling and be notified when it
+  // is ready.  This is useful if the individual named channels have need to
+  // send their own transport-info stanzas.
+  sigslot::signal1<TransportChannelImpl*> SignalRequestSignaling;
+  virtual void OnSignalingReady() = 0;
+
+  // Handles sending and receiving of candidates.  The Transport
+  // receives the candidates and may forward them to the relevant
+  // channel.
+  //
+  // Note: Since candidates are delivered asynchronously to the
+  // channel, they cannot return an error if the message is invalid.
+  // It is assumed that the Transport will have checked validity
+  // before forwarding.
+  sigslot::signal2<TransportChannelImpl*,
+                   const Candidate&> SignalCandidateReady;
+  virtual void OnCandidate(const Candidate& candidate) = 0;
+
+  // DTLS methods
+  // Set DTLS local identity.  The identity object is not copied, but the caller
+  // retains ownership and must delete it after this TransportChannelImpl is
+  // destroyed.
+  // TODO(bemasc): Fix the ownership semantics of this method.
+  virtual bool SetLocalIdentity(rtc::SSLIdentity* identity) = 0;
+
+  // Set DTLS Remote fingerprint. Must be after local identity set.
+  virtual bool SetRemoteFingerprint(const std::string& digest_alg,
+    const uint8* digest,
+    size_t digest_len) = 0;
+
+  virtual bool SetSslRole(rtc::SSLRole role) = 0;
+
+  // TransportChannel is forwarding this signal from PortAllocatorSession.
+  sigslot::signal1<TransportChannelImpl*> SignalCandidatesAllocationDone;
+
+  // Invoked when there is conflict in the ICE role between local and remote
+  // agents.
+  sigslot::signal1<TransportChannelImpl*> SignalRoleConflict;
+
+  // Emitted whenever the number of connections available to the transport
+  // channel decreases.
+  sigslot::signal1<TransportChannelImpl*> SignalConnectionRemoved;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(TransportChannelImpl);
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TRANSPORTCHANNELIMPL_H_
diff --git a/p2p/base/transportchannelproxy.cc b/p2p/base/transportchannelproxy.cc
new file mode 100644
index 0000000..b5e0957
--- /dev/null
+++ b/p2p/base/transportchannelproxy.cc
@@ -0,0 +1,249 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/p2p/base/transportchannelproxy.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+enum {
+  MSG_UPDATESTATE,
+};
+
+TransportChannelProxy::TransportChannelProxy(const std::string& content_name,
+                                             const std::string& name,
+                                             int component)
+    : TransportChannel(content_name, component),
+      name_(name),
+      impl_(NULL) {
+  worker_thread_ = rtc::Thread::Current();
+}
+
+TransportChannelProxy::~TransportChannelProxy() {
+  // Clearing any pending signal.
+  worker_thread_->Clear(this);
+  if (impl_)
+    impl_->GetTransport()->DestroyChannel(impl_->component());
+}
+
+void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+
+  if (impl == impl_) {
+    // Ignore if the |impl| has already been set.
+    LOG(LS_WARNING) << "Ignored TransportChannelProxy::SetImplementation call "
+                    << "with a same impl as the existing one.";
+    return;
+  }
+
+  // Destroy any existing impl_.
+  if (impl_) {
+    impl_->GetTransport()->DestroyChannel(impl_->component());
+  }
+
+  // Adopt the supplied impl, and connect to its signals.
+  impl_ = impl;
+
+  if (impl_) {
+    impl_->SignalReadableState.connect(
+        this, &TransportChannelProxy::OnReadableState);
+    impl_->SignalWritableState.connect(
+        this, &TransportChannelProxy::OnWritableState);
+    impl_->SignalReadPacket.connect(
+        this, &TransportChannelProxy::OnReadPacket);
+    impl_->SignalReadyToSend.connect(
+        this, &TransportChannelProxy::OnReadyToSend);
+    impl_->SignalRouteChange.connect(
+        this, &TransportChannelProxy::OnRouteChange);
+    for (OptionList::iterator it = pending_options_.begin();
+         it != pending_options_.end();
+         ++it) {
+      impl_->SetOption(it->first, it->second);
+    }
+
+    // Push down the SRTP ciphers, if any were set.
+    if (!pending_srtp_ciphers_.empty()) {
+      impl_->SetSrtpCiphers(pending_srtp_ciphers_);
+    }
+    pending_options_.clear();
+  }
+
+  // Post ourselves a message to see if we need to fire state callbacks.
+  worker_thread_->Post(this, MSG_UPDATESTATE);
+}
+
+int TransportChannelProxy::SendPacket(const char* data, size_t len,
+                                      const rtc::PacketOptions& options,
+                                      int flags) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  // Fail if we don't have an impl yet.
+  if (!impl_) {
+    return -1;
+  }
+  return impl_->SendPacket(data, len, options, flags);
+}
+
+int TransportChannelProxy::SetOption(rtc::Socket::Option opt, int value) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    pending_options_.push_back(OptionPair(opt, value));
+    return 0;
+  }
+  return impl_->SetOption(opt, value);
+}
+
+int TransportChannelProxy::GetError() {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return 0;
+  }
+  return impl_->GetError();
+}
+
+bool TransportChannelProxy::GetStats(ConnectionInfos* infos) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->GetStats(infos);
+}
+
+bool TransportChannelProxy::IsDtlsActive() const {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->IsDtlsActive();
+}
+
+bool TransportChannelProxy::GetSslRole(rtc::SSLRole* role) const {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->GetSslRole(role);
+}
+
+bool TransportChannelProxy::SetSslRole(rtc::SSLRole role) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->SetSslRole(role);
+}
+
+bool TransportChannelProxy::SetSrtpCiphers(const std::vector<std::string>&
+                                           ciphers) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  pending_srtp_ciphers_ = ciphers;  // Cache so we can send later, but always
+                                    // set so it stays consistent.
+  if (impl_) {
+    return impl_->SetSrtpCiphers(ciphers);
+  }
+  return true;
+}
+
+bool TransportChannelProxy::GetSrtpCipher(std::string* cipher) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->GetSrtpCipher(cipher);
+}
+
+bool TransportChannelProxy::GetLocalIdentity(
+    rtc::SSLIdentity** identity) const {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->GetLocalIdentity(identity);
+}
+
+bool TransportChannelProxy::GetRemoteCertificate(
+    rtc::SSLCertificate** cert) const {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->GetRemoteCertificate(cert);
+}
+
+bool TransportChannelProxy::ExportKeyingMaterial(const std::string& label,
+                                                 const uint8* context,
+                                                 size_t context_len,
+                                                 bool use_context,
+                                                 uint8* result,
+                                                 size_t result_len) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return false;
+  }
+  return impl_->ExportKeyingMaterial(label, context, context_len, use_context,
+                                     result, result_len);
+}
+
+IceRole TransportChannelProxy::GetIceRole() const {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (!impl_) {
+    return ICEROLE_UNKNOWN;
+  }
+  return impl_->GetIceRole();
+}
+
+void TransportChannelProxy::OnReadableState(TransportChannel* channel) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == impl_);
+  set_readable(impl_->readable());
+  // Note: SignalReadableState fired by set_readable.
+}
+
+void TransportChannelProxy::OnWritableState(TransportChannel* channel) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == impl_);
+  set_writable(impl_->writable());
+  // Note: SignalWritableState fired by set_readable.
+}
+
+void TransportChannelProxy::OnReadPacket(
+    TransportChannel* channel, const char* data, size_t size,
+    const rtc::PacketTime& packet_time, int flags) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == impl_);
+  SignalReadPacket(this, data, size, packet_time, flags);
+}
+
+void TransportChannelProxy::OnReadyToSend(TransportChannel* channel) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == impl_);
+  SignalReadyToSend(this);
+}
+
+void TransportChannelProxy::OnRouteChange(TransportChannel* channel,
+                                          const Candidate& candidate) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  ASSERT(channel == impl_);
+  SignalRouteChange(this, candidate);
+}
+
+void TransportChannelProxy::OnMessage(rtc::Message* msg) {
+  ASSERT(rtc::Thread::Current() == worker_thread_);
+  if (msg->message_id == MSG_UPDATESTATE) {
+     // If impl_ is already readable or writable, push up those signals.
+     set_readable(impl_ ? impl_->readable() : false);
+     set_writable(impl_ ? impl_->writable() : false);
+  }
+}
+
+}  // namespace cricket
diff --git a/p2p/base/transportchannelproxy.h b/p2p/base/transportchannelproxy.h
new file mode 100644
index 0000000..cfd07f8
--- /dev/null
+++ b/p2p/base/transportchannelproxy.h
@@ -0,0 +1,95 @@
+/*
+ *  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_P2P_BASE_TRANSPORTCHANNELPROXY_H_
+#define WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "webrtc/p2p/base/transportchannel.h"
+#include "webrtc/base/messagehandler.h"
+
+namespace rtc {
+class Thread;
+}
+
+namespace cricket {
+
+class TransportChannelImpl;
+
+// Proxies calls between the client and the transport channel implementation.
+// This is needed because clients are allowed to create channels before the
+// network negotiation is complete.  Hence, we create a proxy up front, and
+// when negotiation completes, connect the proxy to the implementaiton.
+class TransportChannelProxy : public TransportChannel,
+                              public rtc::MessageHandler {
+ public:
+  TransportChannelProxy(const std::string& content_name,
+                        const std::string& name,
+                        int component);
+  virtual ~TransportChannelProxy();
+
+  const std::string& name() const { return name_; }
+  TransportChannelImpl* impl() { return impl_; }
+
+  // Sets the implementation to which we will proxy.
+  void SetImplementation(TransportChannelImpl* impl);
+
+  // Implementation of the TransportChannel interface.  These simply forward to
+  // the implementation.
+  virtual int SendPacket(const char* data, size_t len,
+                         const rtc::PacketOptions& options,
+                         int flags);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetError();
+  virtual IceRole GetIceRole() const;
+  virtual bool GetStats(ConnectionInfos* infos);
+  virtual bool IsDtlsActive() const;
+  virtual bool GetSslRole(rtc::SSLRole* role) const;
+  virtual bool SetSslRole(rtc::SSLRole role);
+  virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers);
+  virtual bool GetSrtpCipher(std::string* cipher);
+  virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const;
+  virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const;
+  virtual bool ExportKeyingMaterial(const std::string& label,
+                            const uint8* context,
+                            size_t context_len,
+                            bool use_context,
+                            uint8* result,
+                            size_t result_len);
+
+ private:
+  // Catch signals from the implementation channel.  These just forward to the
+  // client (after updating our state to match).
+  void OnReadableState(TransportChannel* channel);
+  void OnWritableState(TransportChannel* channel);
+  void OnReadPacket(TransportChannel* channel, const char* data, size_t size,
+                    const rtc::PacketTime& packet_time, int flags);
+  void OnReadyToSend(TransportChannel* channel);
+  void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
+
+  void OnMessage(rtc::Message* message);
+
+  typedef std::pair<rtc::Socket::Option, int> OptionPair;
+  typedef std::vector<OptionPair> OptionList;
+  std::string name_;
+  rtc::Thread* worker_thread_;
+  TransportChannelImpl* impl_;
+  OptionList pending_options_;
+  std::vector<std::string> pending_srtp_ciphers_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(TransportChannelProxy);
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_
diff --git a/p2p/base/transportdescription.cc b/p2p/base/transportdescription.cc
new file mode 100644
index 0000000..01c6a8f
--- /dev/null
+++ b/p2p/base/transportdescription.cc
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 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/p2p/base/transportdescription.h"
+
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/base/stringutils.h"
+
+namespace cricket {
+
+bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role) {
+  const char* const roles[] = {
+      CONNECTIONROLE_ACTIVE_STR,
+      CONNECTIONROLE_PASSIVE_STR,
+      CONNECTIONROLE_ACTPASS_STR,
+      CONNECTIONROLE_HOLDCONN_STR
+  };
+
+  for (size_t i = 0; i < ARRAY_SIZE(roles); ++i) {
+    if (_stricmp(roles[i], role_str.c_str()) == 0) {
+      *role = static_cast<ConnectionRole>(CONNECTIONROLE_ACTIVE + i);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str) {
+  switch (role) {
+    case cricket::CONNECTIONROLE_ACTIVE:
+      *role_str = cricket::CONNECTIONROLE_ACTIVE_STR;
+      break;
+    case cricket::CONNECTIONROLE_ACTPASS:
+      *role_str = cricket::CONNECTIONROLE_ACTPASS_STR;
+      break;
+    case cricket::CONNECTIONROLE_PASSIVE:
+      *role_str = cricket::CONNECTIONROLE_PASSIVE_STR;
+      break;
+    case cricket::CONNECTIONROLE_HOLDCONN:
+      *role_str = cricket::CONNECTIONROLE_HOLDCONN_STR;
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/transportdescription.h b/p2p/base/transportdescription.h
new file mode 100644
index 0000000..5ab1cd6
--- /dev/null
+++ b/p2p/base/transportdescription.h
@@ -0,0 +1,171 @@
+/*
+ *  Copyright 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_P2P_BASE_TRANSPORTDESCRIPTION_H_
+#define WEBRTC_P2P_BASE_TRANSPORTDESCRIPTION_H_
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sslfingerprint.h"
+
+namespace cricket {
+
+// SEC_ENABLED and SEC_REQUIRED should only be used if the session
+// was negotiated over TLS, to protect the inline crypto material
+// exchange.
+// SEC_DISABLED: No crypto in outgoing offer, ignore any supplied crypto.
+// SEC_ENABLED:  Crypto in outgoing offer and answer (if supplied in offer).
+// SEC_REQUIRED: Crypto in outgoing offer and answer. Fail any offer with absent
+//               or unsupported crypto.
+enum SecurePolicy {
+  SEC_DISABLED,
+  SEC_ENABLED,
+  SEC_REQUIRED
+};
+
+// The transport protocol we've elected to use.
+enum TransportProtocol {
+  ICEPROTO_GOOGLE,  // Google version of ICE protocol.
+  ICEPROTO_HYBRID,  // ICE, but can fall back to the Google version.
+  ICEPROTO_RFC5245  // Standard RFC 5245 version of ICE.
+};
+// The old name for TransportProtocol.
+// TODO(juberti): remove this.
+typedef TransportProtocol IceProtocolType;
+
+// Whether our side of the call is driving the negotiation, or the other side.
+enum IceRole {
+  ICEROLE_CONTROLLING = 0,
+  ICEROLE_CONTROLLED,
+  ICEROLE_UNKNOWN
+};
+
+// ICE RFC 5245 implementation type.
+enum IceMode {
+  ICEMODE_FULL,  // As defined in http://tools.ietf.org/html/rfc5245#section-4.1
+  ICEMODE_LITE   // As defined in http://tools.ietf.org/html/rfc5245#section-4.2
+};
+
+// RFC 4145 - http://tools.ietf.org/html/rfc4145#section-4
+// 'active':  The endpoint will initiate an outgoing connection.
+// 'passive': The endpoint will accept an incoming connection.
+// 'actpass': The endpoint is willing to accept an incoming
+//            connection or to initiate an outgoing connection.
+enum ConnectionRole {
+  CONNECTIONROLE_NONE = 0,
+  CONNECTIONROLE_ACTIVE,
+  CONNECTIONROLE_PASSIVE,
+  CONNECTIONROLE_ACTPASS,
+  CONNECTIONROLE_HOLDCONN,
+};
+
+extern const char CONNECTIONROLE_ACTIVE_STR[];
+extern const char CONNECTIONROLE_PASSIVE_STR[];
+extern const char CONNECTIONROLE_ACTPASS_STR[];
+extern const char CONNECTIONROLE_HOLDCONN_STR[];
+
+bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role);
+bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str);
+
+typedef std::vector<Candidate> Candidates;
+
+struct TransportDescription {
+  TransportDescription()
+      : ice_mode(ICEMODE_FULL),
+        connection_role(CONNECTIONROLE_NONE) {}
+
+  TransportDescription(const std::string& transport_type,
+                       const std::vector<std::string>& transport_options,
+                       const std::string& ice_ufrag,
+                       const std::string& ice_pwd,
+                       IceMode ice_mode,
+                       ConnectionRole role,
+                       const rtc::SSLFingerprint* identity_fingerprint,
+                       const Candidates& candidates)
+      : transport_type(transport_type),
+        transport_options(transport_options),
+        ice_ufrag(ice_ufrag),
+        ice_pwd(ice_pwd),
+        ice_mode(ice_mode),
+        connection_role(role),
+        identity_fingerprint(CopyFingerprint(identity_fingerprint)),
+        candidates(candidates) {}
+  TransportDescription(const std::string& transport_type,
+                       const std::string& ice_ufrag,
+                       const std::string& ice_pwd)
+      : transport_type(transport_type),
+        ice_ufrag(ice_ufrag),
+        ice_pwd(ice_pwd),
+        ice_mode(ICEMODE_FULL),
+        connection_role(CONNECTIONROLE_NONE) {}
+  TransportDescription(const TransportDescription& from)
+      : transport_type(from.transport_type),
+        transport_options(from.transport_options),
+        ice_ufrag(from.ice_ufrag),
+        ice_pwd(from.ice_pwd),
+        ice_mode(from.ice_mode),
+        connection_role(from.connection_role),
+        identity_fingerprint(CopyFingerprint(from.identity_fingerprint.get())),
+        candidates(from.candidates) {}
+
+  TransportDescription& operator=(const TransportDescription& from) {
+    // Self-assignment
+    if (this == &from)
+      return *this;
+
+    transport_type = from.transport_type;
+    transport_options = from.transport_options;
+    ice_ufrag = from.ice_ufrag;
+    ice_pwd = from.ice_pwd;
+    ice_mode = from.ice_mode;
+    connection_role = from.connection_role;
+
+    identity_fingerprint.reset(CopyFingerprint(
+        from.identity_fingerprint.get()));
+    candidates = from.candidates;
+    return *this;
+  }
+
+  bool HasOption(const std::string& option) const {
+    return (std::find(transport_options.begin(), transport_options.end(),
+                      option) != transport_options.end());
+  }
+  void AddOption(const std::string& option) {
+    transport_options.push_back(option);
+  }
+  bool secure() const { return identity_fingerprint != NULL; }
+
+  static rtc::SSLFingerprint* CopyFingerprint(
+      const rtc::SSLFingerprint* from) {
+    if (!from)
+      return NULL;
+
+    return new rtc::SSLFingerprint(*from);
+  }
+
+  std::string transport_type;  // xmlns of <transport>
+  std::vector<std::string> transport_options;
+  std::string ice_ufrag;
+  std::string ice_pwd;
+  IceMode ice_mode;
+  ConnectionRole connection_role;
+
+  rtc::scoped_ptr<rtc::SSLFingerprint> identity_fingerprint;
+  Candidates candidates;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TRANSPORTDESCRIPTION_H_
diff --git a/p2p/base/transportdescriptionfactory.cc b/p2p/base/transportdescriptionfactory.cc
new file mode 100644
index 0000000..619c9d1
--- /dev/null
+++ b/p2p/base/transportdescriptionfactory.cc
@@ -0,0 +1,160 @@
+/*
+ *  Copyright 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/p2p/base/transportdescriptionfactory.h"
+
+#include "webrtc/p2p/base/transportdescription.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/messagedigest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sslfingerprint.h"
+
+namespace cricket {
+
+static TransportProtocol kDefaultProtocol = ICEPROTO_GOOGLE;
+
+TransportDescriptionFactory::TransportDescriptionFactory()
+    : protocol_(kDefaultProtocol),
+      secure_(SEC_DISABLED),
+      identity_(NULL) {
+}
+
+TransportDescription* TransportDescriptionFactory::CreateOffer(
+    const TransportOptions& options,
+    const TransportDescription* current_description) const {
+  rtc::scoped_ptr<TransportDescription> desc(new TransportDescription());
+
+  // Set the transport type depending on the selected protocol.
+  if (protocol_ == ICEPROTO_RFC5245) {
+    desc->transport_type = NS_JINGLE_ICE_UDP;
+  } else if (protocol_ == ICEPROTO_HYBRID) {
+    desc->transport_type = NS_JINGLE_ICE_UDP;
+    desc->AddOption(ICE_OPTION_GICE);
+  } else if (protocol_ == ICEPROTO_GOOGLE) {
+    desc->transport_type = NS_GINGLE_P2P;
+  }
+
+  // Generate the ICE credentials if we don't already have them.
+  if (!current_description || options.ice_restart) {
+    desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
+    desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
+  } else {
+    desc->ice_ufrag = current_description->ice_ufrag;
+    desc->ice_pwd = current_description->ice_pwd;
+  }
+
+  // If we are trying to establish a secure transport, add a fingerprint.
+  if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
+    // Fail if we can't create the fingerprint.
+    // If we are the initiator set role to "actpass".
+    if (!SetSecurityInfo(desc.get(), CONNECTIONROLE_ACTPASS)) {
+      return NULL;
+    }
+  }
+
+  return desc.release();
+}
+
+TransportDescription* TransportDescriptionFactory::CreateAnswer(
+    const TransportDescription* offer,
+    const TransportOptions& options,
+    const TransportDescription* current_description) const {
+  // A NULL offer is treated as a GICE transport description.
+  // TODO(juberti): Figure out why we get NULL offers, and fix this upstream.
+  rtc::scoped_ptr<TransportDescription> desc(new TransportDescription());
+
+  // Figure out which ICE variant to negotiate; prefer RFC 5245 ICE, but fall
+  // back to G-ICE if needed. Note that we never create a hybrid answer, since
+  // we know what the other side can support already.
+  if (offer && offer->transport_type == NS_JINGLE_ICE_UDP &&
+      (protocol_ == ICEPROTO_RFC5245 || protocol_ == ICEPROTO_HYBRID)) {
+    // Offer is ICE or hybrid, we support ICE or hybrid: use ICE.
+    desc->transport_type = NS_JINGLE_ICE_UDP;
+  } else if (offer && offer->transport_type == NS_JINGLE_ICE_UDP &&
+             offer->HasOption(ICE_OPTION_GICE) &&
+             protocol_ == ICEPROTO_GOOGLE) {
+    desc->transport_type = NS_GINGLE_P2P;
+    // Offer is hybrid, we support GICE: use GICE.
+  } else if ((!offer || offer->transport_type == NS_GINGLE_P2P) &&
+             (protocol_ == ICEPROTO_HYBRID || protocol_ == ICEPROTO_GOOGLE)) {
+    // Offer is GICE, we support hybrid or GICE: use GICE.
+    desc->transport_type = NS_GINGLE_P2P;
+  } else {
+    // Mismatch.
+    LOG(LS_WARNING) << "Failed to create TransportDescription answer "
+                       "because of incompatible transport types";
+    return NULL;
+  }
+
+  // Generate the ICE credentials if we don't already have them or ice is
+  // being restarted.
+  if (!current_description || options.ice_restart) {
+    desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
+    desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
+  } else {
+    desc->ice_ufrag = current_description->ice_ufrag;
+    desc->ice_pwd = current_description->ice_pwd;
+  }
+
+  // Negotiate security params.
+  if (offer && offer->identity_fingerprint.get()) {
+    // The offer supports DTLS, so answer with DTLS, as long as we support it.
+    if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
+      // Fail if we can't create the fingerprint.
+      // Setting DTLS role to active.
+      ConnectionRole role = (options.prefer_passive_role) ?
+          CONNECTIONROLE_PASSIVE : CONNECTIONROLE_ACTIVE;
+
+      if (!SetSecurityInfo(desc.get(), role)) {
+        return NULL;
+      }
+    }
+  } else if (secure_ == SEC_REQUIRED) {
+    // We require DTLS, but the other side didn't offer it. Fail.
+    LOG(LS_WARNING) << "Failed to create TransportDescription answer "
+                       "because of incompatible security settings";
+    return NULL;
+  }
+
+  return desc.release();
+}
+
+bool TransportDescriptionFactory::SetSecurityInfo(
+    TransportDescription* desc, ConnectionRole role) const {
+  if (!identity_) {
+    LOG(LS_ERROR) << "Cannot create identity digest with no identity";
+    return false;
+  }
+
+  // This digest algorithm is used to produce the a=fingerprint lines in SDP.
+  // RFC 4572 Section 5 requires that those lines use the same hash function as
+  // the certificate's signature.
+  std::string digest_alg;
+  if (!identity_->certificate().GetSignatureDigestAlgorithm(&digest_alg)) {
+    LOG(LS_ERROR) << "Failed to retrieve the certificate's digest algorithm";
+    return false;
+  }
+
+  desc->identity_fingerprint.reset(
+      rtc::SSLFingerprint::Create(digest_alg, identity_));
+  if (!desc->identity_fingerprint.get()) {
+    LOG(LS_ERROR) << "Failed to create identity fingerprint, alg="
+                  << digest_alg;
+    return false;
+  }
+
+  // Assign security role.
+  desc->connection_role = role;
+  return true;
+}
+
+}  // namespace cricket
+
diff --git a/p2p/base/transportdescriptionfactory.h b/p2p/base/transportdescriptionfactory.h
new file mode 100644
index 0000000..a137f72
--- /dev/null
+++ b/p2p/base/transportdescriptionfactory.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 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_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_
+#define WEBRTC_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_
+
+#include "webrtc/p2p/base/transportdescription.h"
+
+namespace rtc {
+class SSLIdentity;
+}
+
+namespace cricket {
+
+struct TransportOptions {
+  TransportOptions() : ice_restart(false), prefer_passive_role(false) {}
+  bool ice_restart;
+  bool prefer_passive_role;
+};
+
+// Creates transport descriptions according to the supplied configuration.
+// When creating answers, performs the appropriate negotiation
+// of the various fields to determine the proper result.
+class TransportDescriptionFactory {
+ public:
+  // Default ctor; use methods below to set configuration.
+  TransportDescriptionFactory();
+  SecurePolicy secure() const { return secure_; }
+  // The identity to use when setting up DTLS.
+  rtc::SSLIdentity* identity() const { return identity_; }
+
+  // Specifies the transport protocol to be use.
+  void set_protocol(TransportProtocol protocol) { protocol_ = protocol; }
+  // Specifies the transport security policy to use.
+  void set_secure(SecurePolicy s) { secure_ = s; }
+  // Specifies the identity to use (only used when secure is not SEC_DISABLED).
+  void set_identity(rtc::SSLIdentity* identity) { identity_ = identity; }
+
+  // Creates a transport description suitable for use in an offer.
+  TransportDescription* CreateOffer(const TransportOptions& options,
+      const TransportDescription* current_description) const;
+  // Create a transport description that is a response to an offer.
+  TransportDescription* CreateAnswer(
+      const TransportDescription* offer,
+      const TransportOptions& options,
+      const TransportDescription* current_description) const;
+
+ private:
+  bool SetSecurityInfo(TransportDescription* description,
+                       ConnectionRole role) const;
+
+  TransportProtocol protocol_;
+  SecurePolicy secure_;
+  rtc::SSLIdentity* identity_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_
diff --git a/p2p/base/transportdescriptionfactory_unittest.cc b/p2p/base/transportdescriptionfactory_unittest.cc
new file mode 100644
index 0000000..22816a2
--- /dev/null
+++ b/p2p/base/transportdescriptionfactory_unittest.cc
@@ -0,0 +1,365 @@
+/*
+ *  Copyright 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 <string>
+#include <vector>
+
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/transportdescription.h"
+#include "webrtc/p2p/base/transportdescriptionfactory.h"
+#include "webrtc/base/fakesslidentity.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/ssladapter.h"
+
+using rtc::scoped_ptr;
+using cricket::TransportDescriptionFactory;
+using cricket::TransportDescription;
+using cricket::TransportOptions;
+
+class TransportDescriptionFactoryTest : public testing::Test {
+ public:
+  TransportDescriptionFactoryTest()
+      : id1_(new rtc::FakeSSLIdentity("User1")),
+        id2_(new rtc::FakeSSLIdentity("User2")) {
+  }
+
+  void CheckDesc(const TransportDescription* desc, const std::string& type,
+                 const std::string& opt, const std::string& ice_ufrag,
+                 const std::string& ice_pwd, const std::string& dtls_alg) {
+    ASSERT_TRUE(desc != NULL);
+    EXPECT_EQ(type, desc->transport_type);
+    EXPECT_EQ(!opt.empty(), desc->HasOption(opt));
+    if (ice_ufrag.empty() && ice_pwd.empty()) {
+      EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
+                desc->ice_ufrag.size());
+      EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
+                desc->ice_pwd.size());
+    } else {
+      EXPECT_EQ(ice_ufrag, desc->ice_ufrag);
+      EXPECT_EQ(ice_pwd, desc->ice_pwd);
+    }
+    if (dtls_alg.empty()) {
+      EXPECT_TRUE(desc->identity_fingerprint.get() == NULL);
+    } else {
+      ASSERT_TRUE(desc->identity_fingerprint.get() != NULL);
+      EXPECT_EQ(desc->identity_fingerprint->algorithm, dtls_alg);
+      EXPECT_GT(desc->identity_fingerprint->digest.length(), 0U);
+    }
+  }
+
+  // This test ice restart by doing two offer answer exchanges. On the second
+  // exchange ice is restarted. The test verifies that the ufrag and password
+  // in the offer and answer is changed.
+  // If |dtls| is true, the test verifies that the finger print is not changed.
+  void TestIceRestart(bool dtls) {
+    if (dtls) {
+      f1_.set_secure(cricket::SEC_ENABLED);
+      f2_.set_secure(cricket::SEC_ENABLED);
+      f1_.set_identity(id1_.get());
+      f2_.set_identity(id2_.get());
+    } else {
+      f1_.set_secure(cricket::SEC_DISABLED);
+      f2_.set_secure(cricket::SEC_DISABLED);
+    }
+
+    cricket::TransportOptions options;
+    // The initial offer / answer exchange.
+    rtc::scoped_ptr<TransportDescription> offer(f1_.CreateOffer(
+        options, NULL));
+    rtc::scoped_ptr<TransportDescription> answer(
+        f2_.CreateAnswer(offer.get(),
+                         options, NULL));
+
+    // Create an updated offer where we restart ice.
+    options.ice_restart = true;
+    rtc::scoped_ptr<TransportDescription> restart_offer(f1_.CreateOffer(
+        options, offer.get()));
+
+    VerifyUfragAndPasswordChanged(dtls, offer.get(), restart_offer.get());
+
+    // Create a new answer. The transport ufrag and password is changed since
+    // |options.ice_restart == true|
+    rtc::scoped_ptr<TransportDescription> restart_answer(
+        f2_.CreateAnswer(restart_offer.get(), options, answer.get()));
+    ASSERT_TRUE(restart_answer.get() != NULL);
+
+    VerifyUfragAndPasswordChanged(dtls, answer.get(), restart_answer.get());
+  }
+
+  void VerifyUfragAndPasswordChanged(bool dtls,
+                                     const TransportDescription* org_desc,
+                                     const TransportDescription* restart_desc) {
+    EXPECT_NE(org_desc->ice_pwd, restart_desc->ice_pwd);
+    EXPECT_NE(org_desc->ice_ufrag, restart_desc->ice_ufrag);
+    EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
+              restart_desc->ice_ufrag.size());
+    EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
+              restart_desc->ice_pwd.size());
+    // If DTLS is enabled, make sure the finger print is unchanged.
+    if (dtls) {
+      EXPECT_FALSE(
+          org_desc->identity_fingerprint->GetRfc4572Fingerprint().empty());
+      EXPECT_EQ(org_desc->identity_fingerprint->GetRfc4572Fingerprint(),
+                restart_desc->identity_fingerprint->GetRfc4572Fingerprint());
+    }
+  }
+
+ protected:
+  TransportDescriptionFactory f1_;
+  TransportDescriptionFactory f2_;
+  scoped_ptr<rtc::SSLIdentity> id1_;
+  scoped_ptr<rtc::SSLIdentity> id2_;
+};
+
+// Test that in the default case, we generate the expected G-ICE offer.
+TEST_F(TransportDescriptionFactoryTest, TestOfferGice) {
+  f1_.set_protocol(cricket::ICEPROTO_GOOGLE);
+  scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", "");
+}
+
+// Test generating a hybrid offer.
+TEST_F(TransportDescriptionFactoryTest, TestOfferHybrid) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "google-ice", "", "", "");
+}
+
+// Test generating an ICE-only offer.
+TEST_F(TransportDescriptionFactoryTest, TestOfferIce) {
+  f1_.set_protocol(cricket::ICEPROTO_RFC5245);
+  scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", "");
+}
+
+// Test generating a hybrid offer with DTLS.
+TEST_F(TransportDescriptionFactoryTest, TestOfferHybridDtls) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f1_.set_secure(cricket::SEC_ENABLED);
+  f1_.set_identity(id1_.get());
+  std::string digest_alg;
+  ASSERT_TRUE(id1_->certificate().GetSignatureDigestAlgorithm(&digest_alg));
+  scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "google-ice", "", "",
+            digest_alg);
+  // Ensure it also works with SEC_REQUIRED.
+  f1_.set_secure(cricket::SEC_REQUIRED);
+  desc.reset(f1_.CreateOffer(TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "google-ice", "", "",
+            digest_alg);
+}
+
+// Test generating a hybrid offer with DTLS fails with no identity.
+TEST_F(TransportDescriptionFactoryTest, TestOfferHybridDtlsWithNoIdentity) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f1_.set_secure(cricket::SEC_ENABLED);
+  scoped_ptr<TransportDescription> desc(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  ASSERT_TRUE(desc.get() == NULL);
+}
+
+// Test updating a hybrid offer with DTLS to pick ICE.
+// The ICE credentials should stay the same in the new offer.
+TEST_F(TransportDescriptionFactoryTest, TestOfferHybridDtlsReofferIceDtls) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f1_.set_secure(cricket::SEC_ENABLED);
+  f1_.set_identity(id1_.get());
+  std::string digest_alg;
+  ASSERT_TRUE(id1_->certificate().GetSignatureDigestAlgorithm(&digest_alg));
+  scoped_ptr<TransportDescription> old_desc(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  ASSERT_TRUE(old_desc.get() != NULL);
+  f1_.set_protocol(cricket::ICEPROTO_RFC5245);
+  scoped_ptr<TransportDescription> desc(
+      f1_.CreateOffer(TransportOptions(), old_desc.get()));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "",
+            old_desc->ice_ufrag, old_desc->ice_pwd, digest_alg);
+}
+
+// Test that we can answer a GICE offer with GICE.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerGiceToGice) {
+  f1_.set_protocol(cricket::ICEPROTO_GOOGLE);
+  f2_.set_protocol(cricket::ICEPROTO_GOOGLE);
+  scoped_ptr<TransportDescription> offer(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(f2_.CreateAnswer(
+      offer.get(), TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", "");
+  // Should get the same result when answering as hybrid.
+  f2_.set_protocol(cricket::ICEPROTO_HYBRID);
+  desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
+                              NULL));
+  CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", "");
+}
+
+// Test that we can answer a hybrid offer with GICE.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerGiceToHybrid) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f2_.set_protocol(cricket::ICEPROTO_GOOGLE);
+  scoped_ptr<TransportDescription> offer(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", "");
+}
+
+// Test that we can answer a hybrid offer with ICE.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToHybrid) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f2_.set_protocol(cricket::ICEPROTO_RFC5245);
+  scoped_ptr<TransportDescription> offer(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", "");
+  // Should get the same result when answering as hybrid.
+  f2_.set_protocol(cricket::ICEPROTO_HYBRID);
+  desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
+                              NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", "");
+}
+
+// Test that we can answer an ICE offer with ICE.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToIce) {
+  f1_.set_protocol(cricket::ICEPROTO_RFC5245);
+  f2_.set_protocol(cricket::ICEPROTO_RFC5245);
+  scoped_ptr<TransportDescription> offer(f1_.CreateOffer(
+      TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(f2_.CreateAnswer(
+      offer.get(), TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", "");
+  // Should get the same result when answering as hybrid.
+  f2_.set_protocol(cricket::ICEPROTO_HYBRID);
+  desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
+                              NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", "");
+}
+
+// Test that we can't answer a GICE offer with ICE.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToGice) {
+  f1_.set_protocol(cricket::ICEPROTO_GOOGLE);
+  f2_.set_protocol(cricket::ICEPROTO_RFC5245);
+  scoped_ptr<TransportDescription> offer(
+      f1_.CreateOffer(TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
+  ASSERT_TRUE(desc.get() == NULL);
+}
+
+// Test that we can't answer an ICE offer with GICE.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerGiceToIce) {
+  f1_.set_protocol(cricket::ICEPROTO_RFC5245);
+  f2_.set_protocol(cricket::ICEPROTO_GOOGLE);
+  scoped_ptr<TransportDescription> offer(
+      f1_.CreateOffer(TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(f2_.CreateAnswer(
+      offer.get(), TransportOptions(), NULL));
+  ASSERT_TRUE(desc.get() == NULL);
+}
+
+// Test that we can update an answer properly; ICE credentials shouldn't change.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToIceReanswer) {
+  f1_.set_protocol(cricket::ICEPROTO_RFC5245);
+  f2_.set_protocol(cricket::ICEPROTO_RFC5245);
+  scoped_ptr<TransportDescription> offer(
+      f1_.CreateOffer(TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> old_desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
+  ASSERT_TRUE(old_desc.get() != NULL);
+  scoped_ptr<TransportDescription> desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(),
+                       old_desc.get()));
+  ASSERT_TRUE(desc.get() != NULL);
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "",
+            old_desc->ice_ufrag, old_desc->ice_pwd, "");
+}
+
+// Test that we handle answering an offer with DTLS with no DTLS.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerHybridToHybridDtls) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f1_.set_secure(cricket::SEC_ENABLED);
+  f1_.set_identity(id1_.get());
+  f2_.set_protocol(cricket::ICEPROTO_HYBRID);
+  scoped_ptr<TransportDescription> offer(
+      f1_.CreateOffer(TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", "");
+}
+
+// Test that we handle answering an offer without DTLS if we have DTLS enabled,
+// but fail if we require DTLS.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerHybridDtlsToHybrid) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f2_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f2_.set_secure(cricket::SEC_ENABLED);
+  f2_.set_identity(id2_.get());
+  scoped_ptr<TransportDescription> offer(
+      f1_.CreateOffer(TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", "");
+  f2_.set_secure(cricket::SEC_REQUIRED);
+  desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
+                              NULL));
+  ASSERT_TRUE(desc.get() == NULL);
+}
+
+// Test that we handle answering an DTLS offer with DTLS, both if we have
+// DTLS enabled and required.
+TEST_F(TransportDescriptionFactoryTest, TestAnswerHybridDtlsToHybridDtls) {
+  f1_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f1_.set_secure(cricket::SEC_ENABLED);
+  f1_.set_identity(id1_.get());
+
+  f2_.set_protocol(cricket::ICEPROTO_HYBRID);
+  f2_.set_secure(cricket::SEC_ENABLED);
+  f2_.set_identity(id2_.get());
+  // f2_ produces the answer that is being checked in this test, so the
+  // answer must contain fingerprint lines with id2_'s digest algorithm.
+  std::string digest_alg2;
+  ASSERT_TRUE(id2_->certificate().GetSignatureDigestAlgorithm(&digest_alg2));
+
+  scoped_ptr<TransportDescription> offer(
+      f1_.CreateOffer(TransportOptions(), NULL));
+  ASSERT_TRUE(offer.get() != NULL);
+  scoped_ptr<TransportDescription> desc(
+      f2_.CreateAnswer(offer.get(), TransportOptions(), NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", digest_alg2);
+  f2_.set_secure(cricket::SEC_REQUIRED);
+  desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(),
+                              NULL));
+  CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", digest_alg2);
+}
+
+// Test that ice ufrag and password is changed in an updated offer and answer
+// if |TransportDescriptionOptions::ice_restart| is true.
+TEST_F(TransportDescriptionFactoryTest, TestIceRestart) {
+  TestIceRestart(false);
+}
+
+// Test that ice ufrag and password is changed in an updated offer and answer
+// if |TransportDescriptionOptions::ice_restart| is true and DTLS is enabled.
+TEST_F(TransportDescriptionFactoryTest, TestIceRestartWithDtls) {
+  TestIceRestart(true);
+}
diff --git a/p2p/base/transportinfo.h b/p2p/base/transportinfo.h
new file mode 100644
index 0000000..3fbf204
--- /dev/null
+++ b/p2p/base/transportinfo.h
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 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_P2P_BASE_TRANSPORTINFO_H_
+#define WEBRTC_P2P_BASE_TRANSPORTINFO_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/transportdescription.h"
+#include "webrtc/base/helpers.h"
+
+namespace cricket {
+
+// A TransportInfo is NOT a transport-info message.  It is comparable
+// to a "ContentInfo". A transport-infos message is basically just a
+// collection of TransportInfos.
+struct TransportInfo {
+  TransportInfo() {}
+
+  TransportInfo(const std::string& content_name,
+                const TransportDescription& description)
+      : content_name(content_name),
+        description(description) {}
+
+  std::string content_name;
+  TransportDescription description;
+};
+
+typedef std::vector<TransportInfo> TransportInfos;
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TRANSPORTINFO_H_
diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc
new file mode 100644
index 0000000..e7626fe
--- /dev/null
+++ b/p2p/base/turnport.cc
@@ -0,0 +1,1196 @@
+/*
+ *  Copyright 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/p2p/base/turnport.h"
+
+#include <functional>
+
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/byteorder.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/nethelpers.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/stringencode.h"
+
+namespace cricket {
+
+// TODO(juberti): Move to stun.h when relay messages have been renamed.
+static const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST;
+
+// TODO(juberti): Extract to turnmessage.h
+static const int TURN_DEFAULT_PORT = 3478;
+static const int TURN_CHANNEL_NUMBER_START = 0x4000;
+static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000;  // 5 minutes
+
+static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
+
+// Retry at most twice (i.e. three different ALLOCATE requests) on
+// STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766.
+static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2;
+
+inline bool IsTurnChannelData(uint16 msg_type) {
+  return ((msg_type & 0xC000) == 0x4000);  // MSB are 0b01
+}
+
+static int GetRelayPreference(cricket::ProtocolType proto, bool secure) {
+  int relay_preference = ICE_TYPE_PREFERENCE_RELAY;
+  if (proto == cricket::PROTO_TCP) {
+    relay_preference -= 1;
+    if (secure)
+      relay_preference -= 1;
+  }
+
+  ASSERT(relay_preference >= 0);
+  return relay_preference;
+}
+
+class TurnAllocateRequest : public StunRequest {
+ public:
+  explicit TurnAllocateRequest(TurnPort* port);
+  virtual void Prepare(StunMessage* request);
+  virtual void OnResponse(StunMessage* response);
+  virtual void OnErrorResponse(StunMessage* response);
+  virtual void OnTimeout();
+
+ private:
+  // Handles authentication challenge from the server.
+  void OnAuthChallenge(StunMessage* response, int code);
+  void OnTryAlternate(StunMessage* response, int code);
+  void OnUnknownAttribute(StunMessage* response);
+
+  TurnPort* port_;
+};
+
+class TurnRefreshRequest : public StunRequest {
+ public:
+  explicit TurnRefreshRequest(TurnPort* port);
+  virtual void Prepare(StunMessage* request);
+  virtual void OnResponse(StunMessage* response);
+  virtual void OnErrorResponse(StunMessage* response);
+  virtual void OnTimeout();
+
+ private:
+  TurnPort* port_;
+};
+
+class TurnCreatePermissionRequest : public StunRequest,
+                                    public sigslot::has_slots<> {
+ public:
+  TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry,
+                              const rtc::SocketAddress& ext_addr);
+  virtual void Prepare(StunMessage* request);
+  virtual void OnResponse(StunMessage* response);
+  virtual void OnErrorResponse(StunMessage* response);
+  virtual void OnTimeout();
+
+ private:
+  void OnEntryDestroyed(TurnEntry* entry);
+
+  TurnPort* port_;
+  TurnEntry* entry_;
+  rtc::SocketAddress ext_addr_;
+};
+
+class TurnChannelBindRequest : public StunRequest,
+                               public sigslot::has_slots<> {
+ public:
+  TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id,
+                         const rtc::SocketAddress& ext_addr);
+  virtual void Prepare(StunMessage* request);
+  virtual void OnResponse(StunMessage* response);
+  virtual void OnErrorResponse(StunMessage* response);
+  virtual void OnTimeout();
+
+ private:
+  void OnEntryDestroyed(TurnEntry* entry);
+
+  TurnPort* port_;
+  TurnEntry* entry_;
+  int channel_id_;
+  rtc::SocketAddress ext_addr_;
+};
+
+// Manages a "connection" to a remote destination. We will attempt to bring up
+// a channel for this remote destination to reduce the overhead of sending data.
+class TurnEntry : public sigslot::has_slots<> {
+ public:
+  enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
+  TurnEntry(TurnPort* port, int channel_id,
+            const rtc::SocketAddress& ext_addr);
+
+  TurnPort* port() { return port_; }
+
+  int channel_id() const { return channel_id_; }
+  const rtc::SocketAddress& address() const { return ext_addr_; }
+  BindState state() const { return state_; }
+
+  // Helper methods to send permission and channel bind requests.
+  void SendCreatePermissionRequest();
+  void SendChannelBindRequest(int delay);
+  // Sends a packet to the given destination address.
+  // This will wrap the packet in STUN if necessary.
+  int Send(const void* data, size_t size, bool payload,
+           const rtc::PacketOptions& options);
+
+  void OnCreatePermissionSuccess();
+  void OnCreatePermissionError(StunMessage* response, int code);
+  void OnChannelBindSuccess();
+  void OnChannelBindError(StunMessage* response, int code);
+  // Signal sent when TurnEntry is destroyed.
+  sigslot::signal1<TurnEntry*> SignalDestroyed;
+
+ private:
+  TurnPort* port_;
+  int channel_id_;
+  rtc::SocketAddress ext_addr_;
+  BindState state_;
+};
+
+TurnPort::TurnPort(rtc::Thread* thread,
+                   rtc::PacketSocketFactory* factory,
+                   rtc::Network* network,
+                   rtc::AsyncPacketSocket* socket,
+                   const std::string& username,
+                   const std::string& password,
+                   const ProtocolAddress& server_address,
+                   const RelayCredentials& credentials,
+                   int server_priority)
+    : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
+           username, password),
+      server_address_(server_address),
+      credentials_(credentials),
+      socket_(socket),
+      resolver_(NULL),
+      error_(0),
+      request_manager_(thread),
+      next_channel_number_(TURN_CHANNEL_NUMBER_START),
+      connected_(false),
+      server_priority_(server_priority),
+      allocate_mismatch_retries_(0) {
+  request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
+}
+
+TurnPort::TurnPort(rtc::Thread* thread,
+                   rtc::PacketSocketFactory* factory,
+                   rtc::Network* network,
+                   const rtc::IPAddress& ip,
+                   int min_port, int max_port,
+                   const std::string& username,
+                   const std::string& password,
+                   const ProtocolAddress& server_address,
+                   const RelayCredentials& credentials,
+                   int server_priority)
+    : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port,
+           username, password),
+      server_address_(server_address),
+      credentials_(credentials),
+      socket_(NULL),
+      resolver_(NULL),
+      error_(0),
+      request_manager_(thread),
+      next_channel_number_(TURN_CHANNEL_NUMBER_START),
+      connected_(false),
+      server_priority_(server_priority),
+      allocate_mismatch_retries_(0) {
+  request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
+}
+
+TurnPort::~TurnPort() {
+  // TODO(juberti): Should this even be necessary?
+  while (!entries_.empty()) {
+    DestroyEntry(entries_.front()->address());
+  }
+  if (resolver_) {
+    resolver_->Destroy(false);
+  }
+  if (!SharedSocket()) {
+    delete socket_;
+  }
+}
+
+void TurnPort::PrepareAddress() {
+  if (credentials_.username.empty() ||
+      credentials_.password.empty()) {
+    LOG(LS_ERROR) << "Allocation can't be started without setting the"
+                  << " TURN server credentials for the user.";
+    OnAllocateError();
+    return;
+  }
+
+  if (!server_address_.address.port()) {
+    // We will set default TURN port, if no port is set in the address.
+    server_address_.address.SetPort(TURN_DEFAULT_PORT);
+  }
+
+  if (server_address_.address.IsUnresolved()) {
+    ResolveTurnAddress(server_address_.address);
+  } else {
+    // If protocol family of server address doesn't match with local, return.
+    if (!IsCompatibleAddress(server_address_.address)) {
+      LOG(LS_ERROR) << "Server IP address family does not match with "
+                    << "local host address family type";
+      OnAllocateError();
+      return;
+    }
+
+    // Insert the current address to prevent redirection pingpong.
+    attempted_server_addresses_.insert(server_address_.address);
+
+    LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
+                         << ProtoToString(server_address_.proto) << " @ "
+                         << server_address_.address.ToSensitiveString();
+    if (!CreateTurnClientSocket()) {
+      OnAllocateError();
+    } else if (server_address_.proto == PROTO_UDP) {
+      // If its UDP, send AllocateRequest now.
+      // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
+      SendRequest(new TurnAllocateRequest(this), 0);
+    }
+  }
+}
+
+bool TurnPort::CreateTurnClientSocket() {
+  ASSERT(!socket_ || SharedSocket());
+
+  if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
+    socket_ = socket_factory()->CreateUdpSocket(
+        rtc::SocketAddress(ip(), 0), min_port(), max_port());
+  } else if (server_address_.proto == PROTO_TCP) {
+    ASSERT(!SharedSocket());
+    int opts = rtc::PacketSocketFactory::OPT_STUN;
+    // If secure bit is enabled in server address, use TLS over TCP.
+    if (server_address_.secure) {
+      opts |= rtc::PacketSocketFactory::OPT_TLS;
+    }
+    socket_ = socket_factory()->CreateClientTcpSocket(
+        rtc::SocketAddress(ip(), 0), server_address_.address,
+        proxy(), user_agent(), opts);
+  }
+
+  if (!socket_) {
+    error_ = SOCKET_ERROR;
+    return false;
+  }
+
+  // Apply options if any.
+  for (SocketOptionsMap::iterator iter = socket_options_.begin();
+       iter != socket_options_.end(); ++iter) {
+    socket_->SetOption(iter->first, iter->second);
+  }
+
+  if (!SharedSocket()) {
+    // If socket is shared, AllocationSequence will receive the packet.
+    socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
+  }
+
+  socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
+
+  if (server_address_.proto == PROTO_TCP) {
+    socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
+    socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
+  }
+  return true;
+}
+
+void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
+  ASSERT(server_address_.proto == PROTO_TCP);
+  // Do not use this port if the socket bound to a different address than
+  // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
+  // given a binding address, and the platform is expected to pick the
+  // correct local address.
+  if (socket->GetLocalAddress().ipaddr() != ip()) {
+    LOG(LS_WARNING) << "Socket is bound to a different address then the "
+                    << "local port. Discarding TURN port.";
+    OnAllocateError();
+    return;
+  }
+
+  if (server_address_.address.IsUnresolved()) {
+    server_address_.address = socket_->GetRemoteAddress();
+  }
+
+  LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
+               << " using tcp.";
+  SendRequest(new TurnAllocateRequest(this), 0);
+}
+
+void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
+  LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
+  if (!connected_) {
+    OnAllocateError();
+  }
+}
+
+void TurnPort::OnAllocateMismatch() {
+  if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
+    LOG_J(LS_WARNING, this) << "Giving up on the port after "
+                            << allocate_mismatch_retries_
+                            << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
+    OnAllocateError();
+    return;
+  }
+
+  LOG_J(LS_INFO, this) << "Allocating a new socket after "
+                       << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
+                       << allocate_mismatch_retries_ + 1;
+  if (SharedSocket()) {
+    ResetSharedSocket();
+  } else {
+    delete socket_;
+  }
+  socket_ = NULL;
+
+  PrepareAddress();
+  ++allocate_mismatch_retries_;
+}
+
+Connection* TurnPort::CreateConnection(const Candidate& address,
+                                       CandidateOrigin origin) {
+  // TURN-UDP can only connect to UDP candidates.
+  if (address.protocol() != UDP_PROTOCOL_NAME) {
+    return NULL;
+  }
+
+  if (!IsCompatibleAddress(address.address())) {
+    return NULL;
+  }
+
+  // Create an entry, if needed, so we can get our permissions set up correctly.
+  CreateEntry(address.address());
+
+  // A TURN port will have two candiates, STUN and TURN. STUN may not
+  // present in all cases. If present stun candidate will be added first
+  // and TURN candidate later.
+  for (size_t index = 0; index < Candidates().size(); ++index) {
+    if (Candidates()[index].type() == RELAY_PORT_TYPE) {
+      ProxyConnection* conn = new ProxyConnection(this, index, address);
+      conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
+      AddConnection(conn);
+      return conn;
+    }
+  }
+  return NULL;
+}
+
+int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
+  if (!socket_) {
+    // If socket is not created yet, these options will be applied during socket
+    // creation.
+    socket_options_[opt] = value;
+    return 0;
+  }
+  return socket_->SetOption(opt, value);
+}
+
+int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
+  if (!socket_) {
+    SocketOptionsMap::const_iterator it = socket_options_.find(opt);
+    if (it == socket_options_.end()) {
+      return -1;
+    }
+    *value = it->second;
+    return 0;
+  }
+
+  return socket_->GetOption(opt, value);
+}
+
+int TurnPort::GetError() {
+  return error_;
+}
+
+int TurnPort::SendTo(const void* data, size_t size,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options,
+                     bool payload) {
+  // Try to find an entry for this specific address; we should have one.
+  TurnEntry* entry = FindEntry(addr);
+  ASSERT(entry != NULL);
+  if (!entry) {
+    return 0;
+  }
+
+  if (!connected()) {
+    error_ = EWOULDBLOCK;
+    return SOCKET_ERROR;
+  }
+
+  // Send the actual contents to the server using the usual mechanism.
+  int sent = entry->Send(data, size, payload, options);
+  if (sent <= 0) {
+    return SOCKET_ERROR;
+  }
+
+  // The caller of the function is expecting the number of user data bytes,
+  // rather than the size of the packet.
+  return static_cast<int>(size);
+}
+
+void TurnPort::OnReadPacket(
+    rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time) {
+  ASSERT(socket == socket_);
+  ASSERT(remote_addr == server_address_.address);
+
+  // The message must be at least the size of a channel header.
+  if (size < TURN_CHANNEL_HEADER_SIZE) {
+    LOG_J(LS_WARNING, this) << "Received TURN message that was too short";
+    return;
+  }
+
+  // Check the message type, to see if is a Channel Data message.
+  // The message will either be channel data, a TURN data indication, or
+  // a response to a previous request.
+  uint16 msg_type = rtc::GetBE16(data);
+  if (IsTurnChannelData(msg_type)) {
+    HandleChannelData(msg_type, data, size, packet_time);
+  } else if (msg_type == TURN_DATA_INDICATION) {
+    HandleDataIndication(data, size, packet_time);
+  } else {
+    // This must be a response for one of our requests.
+    // Check success responses, but not errors, for MESSAGE-INTEGRITY.
+    if (IsStunSuccessResponseType(msg_type) &&
+        !StunMessage::ValidateMessageIntegrity(data, size, hash())) {
+      LOG_J(LS_WARNING, this) << "Received TURN message with invalid "
+                              << "message integrity, msg_type=" << msg_type;
+      return;
+    }
+    request_manager_.CheckResponse(data, size);
+  }
+}
+
+void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
+  if (connected_) {
+    Port::OnReadyToSend();
+  }
+}
+
+
+// Update current server address port with the alternate server address port.
+bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
+  // Check if we have seen this address before and reject if we did.
+  AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
+  if (iter != attempted_server_addresses_.end()) {
+    LOG_J(LS_WARNING, this) << "Redirection to ["
+                            << address.ToSensitiveString()
+                            << "] ignored, allocation failed.";
+    return false;
+  }
+
+  // If protocol family of server address doesn't match with local, return.
+  if (!IsCompatibleAddress(address)) {
+    LOG(LS_WARNING) << "Server IP address family does not match with "
+                    << "local host address family type";
+    return false;
+  }
+
+  LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
+                       << server_address_.address.ToSensitiveString()
+                       << "] to TURN server ["
+                       << address.ToSensitiveString()
+                       << "]";
+  server_address_ = ProtocolAddress(address, server_address_.proto,
+                                    server_address_.secure);
+
+  // Insert the current address to prevent redirection pingpong.
+  attempted_server_addresses_.insert(server_address_.address);
+  return true;
+}
+
+void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
+  if (resolver_)
+    return;
+
+  resolver_ = socket_factory()->CreateAsyncResolver();
+  resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
+  resolver_->Start(address);
+}
+
+void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
+  ASSERT(resolver == resolver_);
+  // If DNS resolve is failed when trying to connect to the server using TCP,
+  // one of the reason could be due to DNS queries blocked by firewall.
+  // In such cases we will try to connect to the server with hostname, assuming
+  // socket layer will resolve the hostname through a HTTP proxy (if any).
+  if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) {
+    if (!CreateTurnClientSocket()) {
+      OnAllocateError();
+    }
+    return;
+  }
+
+  // Copy the original server address in |resolved_address|. For TLS based
+  // sockets we need hostname along with resolved address.
+  rtc::SocketAddress resolved_address = server_address_.address;
+  if (resolver_->GetError() != 0 ||
+      !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
+    LOG_J(LS_WARNING, this) << "TURN host lookup received error "
+                            << resolver_->GetError();
+    error_ = resolver_->GetError();
+    OnAllocateError();
+    return;
+  }
+  // Signal needs both resolved and unresolved address. After signal is sent
+  // we can copy resolved address back into |server_address_|.
+  SignalResolvedServerAddress(this, server_address_.address,
+                              resolved_address);
+  server_address_.address = resolved_address;
+  PrepareAddress();
+}
+
+void TurnPort::OnSendStunPacket(const void* data, size_t size,
+                                StunRequest* request) {
+  rtc::PacketOptions options(DefaultDscpValue());
+  if (Send(data, size, options) < 0) {
+    LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
+                          << socket_->GetError();
+  }
+}
+
+void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
+  // STUN Port will discover STUN candidate, as it's supplied with first TURN
+  // server address.
+  // Why not using this address? - P2PTransportChannel will start creating
+  // connections after first candidate, which means it could start creating the
+  // connections before TURN candidate added. For that to handle, we need to
+  // supply STUN candidate from this port to UDPPort, and TurnPort should have
+  // handle to UDPPort to pass back the address.
+}
+
+void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
+                                 const rtc::SocketAddress& stun_address) {
+  connected_ = true;
+
+  rtc::SocketAddress related_address = stun_address;
+    if (!(candidate_filter() & CF_REFLEXIVE)) {
+    // If candidate filter only allows relay type of address, empty raddr to
+    // avoid local address leakage.
+    related_address = rtc::EmptySocketAddressWithFamily(stun_address.family());
+  }
+
+  // For relayed candidate, Base is the candidate itself.
+  AddAddress(address,          // Candidate address.
+             address,          // Base address.
+             related_address,  // Related address.
+             UDP_PROTOCOL_NAME,
+             "",  // TCP canddiate type, empty for turn candidates.
+             RELAY_PORT_TYPE,
+             GetRelayPreference(server_address_.proto, server_address_.secure),
+             server_priority_,
+             true);
+}
+
+void TurnPort::OnAllocateError() {
+  // We will send SignalPortError asynchronously as this can be sent during
+  // port initialization. This way it will not be blocking other port
+  // creation.
+  thread()->Post(this, MSG_ERROR);
+}
+
+void TurnPort::OnMessage(rtc::Message* message) {
+  if (message->message_id == MSG_ERROR) {
+    SignalPortError(this);
+    return;
+  } else if (message->message_id == MSG_ALLOCATE_MISMATCH) {
+    OnAllocateMismatch();
+    return;
+  }
+
+  Port::OnMessage(message);
+}
+
+void TurnPort::OnAllocateRequestTimeout() {
+  OnAllocateError();
+}
+
+void TurnPort::HandleDataIndication(const char* data, size_t size,
+                                    const rtc::PacketTime& packet_time) {
+  // Read in the message, and process according to RFC5766, Section 10.4.
+  rtc::ByteBuffer buf(data, size);
+  TurnMessage msg;
+  if (!msg.Read(&buf)) {
+    LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
+    return;
+  }
+
+  // Check mandatory attributes.
+  const StunAddressAttribute* addr_attr =
+      msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
+  if (!addr_attr) {
+    LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute "
+                            << "in data indication.";
+    return;
+  }
+
+  const StunByteStringAttribute* data_attr =
+      msg.GetByteString(STUN_ATTR_DATA);
+  if (!data_attr) {
+    LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in "
+                            << "data indication.";
+    return;
+  }
+
+  // Verify that the data came from somewhere we think we have a permission for.
+  rtc::SocketAddress ext_addr(addr_attr->GetAddress());
+  if (!HasPermission(ext_addr.ipaddr())) {
+    LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid "
+                            << "peer address, addr="
+                            << ext_addr.ToSensitiveString();
+    return;
+  }
+
+  DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr,
+                 PROTO_UDP, packet_time);
+}
+
+void TurnPort::HandleChannelData(int channel_id, const char* data,
+                                 size_t size,
+                                 const rtc::PacketTime& packet_time) {
+  // Read the message, and process according to RFC5766, Section 11.6.
+  //    0                   1                   2                   3
+  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //   |         Channel Number        |            Length             |
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //   |                                                               |
+  //   /                       Application Data                        /
+  //   /                                                               /
+  //   |                                                               |
+  //   |                               +-------------------------------+
+  //   |                               |
+  //   +-------------------------------+
+
+  // Extract header fields from the message.
+  uint16 len = rtc::GetBE16(data + 2);
+  if (len > size - TURN_CHANNEL_HEADER_SIZE) {
+    LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
+                            << "incorrect length, len=" << len;
+    return;
+  }
+  // Allowing messages larger than |len|, as ChannelData can be padded.
+
+  TurnEntry* entry = FindEntry(channel_id);
+  if (!entry) {
+    LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid "
+                            << "channel, channel_id=" << channel_id;
+    return;
+  }
+
+  DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(),
+                 PROTO_UDP, packet_time);
+}
+
+void TurnPort::DispatchPacket(const char* data, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    ProtocolType proto, const rtc::PacketTime& packet_time) {
+  if (Connection* conn = GetConnection(remote_addr)) {
+    conn->OnReadPacket(data, size, packet_time);
+  } else {
+    Port::OnReadPacket(data, size, remote_addr, proto);
+  }
+}
+
+bool TurnPort::ScheduleRefresh(int lifetime) {
+  // Lifetime is in seconds; we schedule a refresh for one minute less.
+  if (lifetime < 2 * 60) {
+    LOG_J(LS_WARNING, this) << "Received response with lifetime that was "
+                            << "too short, lifetime=" << lifetime;
+    return false;
+  }
+
+  SendRequest(new TurnRefreshRequest(this), (lifetime - 60) * 1000);
+  return true;
+}
+
+void TurnPort::SendRequest(StunRequest* req, int delay) {
+  request_manager_.SendDelayed(req, delay);
+}
+
+void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
+  // If we've gotten the necessary data from the server, add it to our request.
+  VERIFY(!hash_.empty());
+  VERIFY(msg->AddAttribute(new StunByteStringAttribute(
+      STUN_ATTR_USERNAME, credentials_.username)));
+  VERIFY(msg->AddAttribute(new StunByteStringAttribute(
+      STUN_ATTR_REALM, realm_)));
+  VERIFY(msg->AddAttribute(new StunByteStringAttribute(
+      STUN_ATTR_NONCE, nonce_)));
+  VERIFY(msg->AddMessageIntegrity(hash()));
+}
+
+int TurnPort::Send(const void* data, size_t len,
+                   const rtc::PacketOptions& options) {
+  return socket_->SendTo(data, len, server_address_.address, options);
+}
+
+void TurnPort::UpdateHash() {
+  VERIFY(ComputeStunCredentialHash(credentials_.username, realm_,
+                                   credentials_.password, &hash_));
+}
+
+bool TurnPort::UpdateNonce(StunMessage* response) {
+  // When stale nonce error received, we should update
+  // hash and store realm and nonce.
+  // Check the mandatory attributes.
+  const StunByteStringAttribute* realm_attr =
+      response->GetByteString(STUN_ATTR_REALM);
+  if (!realm_attr) {
+    LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in "
+                  << "stale nonce error response.";
+    return false;
+  }
+  set_realm(realm_attr->GetString());
+
+  const StunByteStringAttribute* nonce_attr =
+      response->GetByteString(STUN_ATTR_NONCE);
+  if (!nonce_attr) {
+    LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in "
+                  << "stale nonce error response.";
+    return false;
+  }
+  set_nonce(nonce_attr->GetString());
+  return true;
+}
+
+static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
+  return e->address().ipaddr() == ipaddr;
+}
+bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
+  return (std::find_if(entries_.begin(), entries_.end(),
+      std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
+}
+
+static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
+  return e->address() == addr;
+}
+TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
+  EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
+      std::bind2nd(std::ptr_fun(MatchesAddress), addr));
+  return (it != entries_.end()) ? *it : NULL;
+}
+
+static bool MatchesChannelId(TurnEntry* e, int id) {
+  return e->channel_id() == id;
+}
+TurnEntry* TurnPort::FindEntry(int channel_id) const {
+  EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
+      std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id));
+  return (it != entries_.end()) ? *it : NULL;
+}
+
+TurnEntry* TurnPort::CreateEntry(const rtc::SocketAddress& addr) {
+  ASSERT(FindEntry(addr) == NULL);
+  TurnEntry* entry = new TurnEntry(this, next_channel_number_++, addr);
+  entries_.push_back(entry);
+  return entry;
+}
+
+void TurnPort::DestroyEntry(const rtc::SocketAddress& addr) {
+  TurnEntry* entry = FindEntry(addr);
+  ASSERT(entry != NULL);
+  entry->SignalDestroyed(entry);
+  entries_.remove(entry);
+  delete entry;
+}
+
+void TurnPort::OnConnectionDestroyed(Connection* conn) {
+  // Destroying TurnEntry for the connection, which is already destroyed.
+  DestroyEntry(conn->remote_candidate().address());
+}
+
+TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
+    : StunRequest(new TurnMessage()),
+      port_(port) {
+}
+
+void TurnAllocateRequest::Prepare(StunMessage* request) {
+  // Create the request as indicated in RFC 5766, Section 6.1.
+  request->SetType(TURN_ALLOCATE_REQUEST);
+  StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32(
+      STUN_ATTR_REQUESTED_TRANSPORT);
+  transport_attr->SetValue(IPPROTO_UDP << 24);
+  VERIFY(request->AddAttribute(transport_attr));
+  if (!port_->hash().empty()) {
+    port_->AddRequestAuthInfo(request);
+  }
+}
+
+void TurnAllocateRequest::OnResponse(StunMessage* response) {
+  // Check mandatory attributes as indicated in RFC5766, Section 6.3.
+  const StunAddressAttribute* mapped_attr =
+      response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+  if (!mapped_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS "
+                             << "attribute in allocate success response";
+    return;
+  }
+  // Using XOR-Mapped-Address for stun.
+  port_->OnStunAddress(mapped_attr->GetAddress());
+
+  const StunAddressAttribute* relayed_attr =
+      response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS);
+  if (!relayed_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS "
+                             << "attribute in allocate success response";
+    return;
+  }
+
+  const StunUInt32Attribute* lifetime_attr =
+      response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
+  if (!lifetime_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
+                             << "allocate success response";
+    return;
+  }
+  // Notify the port the allocate succeeded, and schedule a refresh request.
+  port_->OnAllocateSuccess(relayed_attr->GetAddress(),
+                           mapped_attr->GetAddress());
+  port_->ScheduleRefresh(lifetime_attr->value());
+}
+
+void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
+  // Process error response according to RFC5766, Section 6.4.
+  const StunErrorCodeAttribute* error_code = response->GetErrorCode();
+  switch (error_code->code()) {
+    case STUN_ERROR_UNAUTHORIZED:       // Unauthrorized.
+      OnAuthChallenge(response, error_code->code());
+      break;
+    case STUN_ERROR_TRY_ALTERNATE:
+      OnTryAlternate(response, error_code->code());
+      break;
+    case STUN_ERROR_ALLOCATION_MISMATCH:
+      // We must handle this error async because trying to delete the socket in
+      // OnErrorResponse will cause a deadlock on the socket.
+      port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH);
+      break;
+    default:
+      LOG_J(LS_WARNING, port_) << "Allocate response error, code="
+                               << error_code->code();
+      port_->OnAllocateError();
+  }
+}
+
+void TurnAllocateRequest::OnTimeout() {
+  LOG_J(LS_WARNING, port_) << "Allocate request timeout";
+  port_->OnAllocateRequestTimeout();
+}
+
+void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
+  // If we failed to authenticate even after we sent our credentials, fail hard.
+  if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
+    LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server "
+                             << "after challenge.";
+    port_->OnAllocateError();
+    return;
+  }
+
+  // Check the mandatory attributes.
+  const StunByteStringAttribute* realm_attr =
+      response->GetByteString(STUN_ATTR_REALM);
+  if (!realm_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in "
+                             << "allocate unauthorized response.";
+    return;
+  }
+  port_->set_realm(realm_attr->GetString());
+
+  const StunByteStringAttribute* nonce_attr =
+      response->GetByteString(STUN_ATTR_NONCE);
+  if (!nonce_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in "
+                             << "allocate unauthorized response.";
+    return;
+  }
+  port_->set_nonce(nonce_attr->GetString());
+
+  // Send another allocate request, with the received realm and nonce values.
+  port_->SendRequest(new TurnAllocateRequest(port_), 0);
+}
+
+void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
+  // TODO(guoweis): Currently, we only support UDP redirect
+  if (port_->server_address().proto != PROTO_UDP) {
+    LOG_J(LS_WARNING, port_) << "Receiving 300 Alternate Server on non-UDP "
+                         << "allocating request from ["
+                         << port_->server_address().address.ToSensitiveString()
+                         << "], failed as currently not supported";
+    port_->OnAllocateError();
+    return;
+  }
+
+  // According to RFC 5389 section 11, there are use cases where
+  // authentication of response is not possible, we're not validating
+  // message integrity.
+
+  // Get the alternate server address attribute value.
+  const StunAddressAttribute* alternate_server_attr =
+      response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
+  if (!alternate_server_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
+                             << "attribute in try alternate error response";
+    port_->OnAllocateError();
+    return;
+  }
+  if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
+    port_->OnAllocateError();
+    return;
+  }
+
+  // Check the attributes.
+  const StunByteStringAttribute* realm_attr =
+      response->GetByteString(STUN_ATTR_REALM);
+  if (realm_attr) {
+    LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
+                          << "try alternate error response.";
+    port_->set_realm(realm_attr->GetString());
+  }
+
+  const StunByteStringAttribute* nonce_attr =
+      response->GetByteString(STUN_ATTR_NONCE);
+  if (nonce_attr) {
+    LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
+                          << "try alternate error response.";
+    port_->set_nonce(nonce_attr->GetString());
+  }
+
+  // Send another allocate request to alternate server,
+  // with the received realm and nonce values.
+  port_->SendRequest(new TurnAllocateRequest(port_), 0);
+}
+
+TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
+    : StunRequest(new TurnMessage()),
+      port_(port) {
+}
+
+void TurnRefreshRequest::Prepare(StunMessage* request) {
+  // Create the request as indicated in RFC 5766, Section 7.1.
+  // No attributes need to be included.
+  request->SetType(TURN_REFRESH_REQUEST);
+  port_->AddRequestAuthInfo(request);
+}
+
+void TurnRefreshRequest::OnResponse(StunMessage* response) {
+  // Check mandatory attributes as indicated in RFC5766, Section 7.3.
+  const StunUInt32Attribute* lifetime_attr =
+      response->GetUInt32(STUN_ATTR_TURN_LIFETIME);
+  if (!lifetime_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in "
+                             << "refresh success response.";
+    return;
+  }
+
+  // Schedule a refresh based on the returned lifetime value.
+  port_->ScheduleRefresh(lifetime_attr->value());
+}
+
+void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
+  const StunErrorCodeAttribute* error_code = response->GetErrorCode();
+  LOG_J(LS_WARNING, port_) << "Refresh response error, code="
+                           << error_code->code();
+
+  if (error_code->code() == STUN_ERROR_STALE_NONCE) {
+    if (port_->UpdateNonce(response)) {
+      // Send RefreshRequest immediately.
+      port_->SendRequest(new TurnRefreshRequest(port_), 0);
+    }
+  }
+}
+
+void TurnRefreshRequest::OnTimeout() {
+}
+
+TurnCreatePermissionRequest::TurnCreatePermissionRequest(
+    TurnPort* port, TurnEntry* entry,
+    const rtc::SocketAddress& ext_addr)
+    : StunRequest(new TurnMessage()),
+      port_(port),
+      entry_(entry),
+      ext_addr_(ext_addr) {
+  entry_->SignalDestroyed.connect(
+      this, &TurnCreatePermissionRequest::OnEntryDestroyed);
+}
+
+void TurnCreatePermissionRequest::Prepare(StunMessage* request) {
+  // Create the request as indicated in RFC5766, Section 9.1.
+  request->SetType(TURN_CREATE_PERMISSION_REQUEST);
+  VERIFY(request->AddAttribute(new StunXorAddressAttribute(
+      STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
+  port_->AddRequestAuthInfo(request);
+}
+
+void TurnCreatePermissionRequest::OnResponse(StunMessage* response) {
+  if (entry_) {
+    entry_->OnCreatePermissionSuccess();
+  }
+}
+
+void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) {
+  if (entry_) {
+    const StunErrorCodeAttribute* error_code = response->GetErrorCode();
+    entry_->OnCreatePermissionError(response, error_code->code());
+  }
+}
+
+void TurnCreatePermissionRequest::OnTimeout() {
+  LOG_J(LS_WARNING, port_) << "Create permission timeout";
+}
+
+void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
+  ASSERT(entry_ == entry);
+  entry_ = NULL;
+}
+
+TurnChannelBindRequest::TurnChannelBindRequest(
+    TurnPort* port, TurnEntry* entry,
+    int channel_id, const rtc::SocketAddress& ext_addr)
+    : StunRequest(new TurnMessage()),
+      port_(port),
+      entry_(entry),
+      channel_id_(channel_id),
+      ext_addr_(ext_addr) {
+  entry_->SignalDestroyed.connect(
+      this, &TurnChannelBindRequest::OnEntryDestroyed);
+}
+
+void TurnChannelBindRequest::Prepare(StunMessage* request) {
+  // Create the request as indicated in RFC5766, Section 11.1.
+  request->SetType(TURN_CHANNEL_BIND_REQUEST);
+  VERIFY(request->AddAttribute(new StunUInt32Attribute(
+      STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16)));
+  VERIFY(request->AddAttribute(new StunXorAddressAttribute(
+      STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
+  port_->AddRequestAuthInfo(request);
+}
+
+void TurnChannelBindRequest::OnResponse(StunMessage* response) {
+  if (entry_) {
+    entry_->OnChannelBindSuccess();
+    // Refresh the channel binding just under the permission timeout
+    // threshold. The channel binding has a longer lifetime, but
+    // this is the easiest way to keep both the channel and the
+    // permission from expiring.
+    entry_->SendChannelBindRequest(TURN_PERMISSION_TIMEOUT - 60 * 1000);
+  }
+}
+
+void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) {
+  if (entry_) {
+    const StunErrorCodeAttribute* error_code = response->GetErrorCode();
+    entry_->OnChannelBindError(response, error_code->code());
+  }
+}
+
+void TurnChannelBindRequest::OnTimeout() {
+  LOG_J(LS_WARNING, port_) << "Channel bind timeout";
+}
+
+void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
+  ASSERT(entry_ == entry);
+  entry_ = NULL;
+}
+
+TurnEntry::TurnEntry(TurnPort* port, int channel_id,
+                     const rtc::SocketAddress& ext_addr)
+    : port_(port),
+      channel_id_(channel_id),
+      ext_addr_(ext_addr),
+      state_(STATE_UNBOUND) {
+  // Creating permission for |ext_addr_|.
+  SendCreatePermissionRequest();
+}
+
+void TurnEntry::SendCreatePermissionRequest() {
+  port_->SendRequest(new TurnCreatePermissionRequest(
+      port_, this, ext_addr_), 0);
+}
+
+void TurnEntry::SendChannelBindRequest(int delay) {
+  port_->SendRequest(new TurnChannelBindRequest(
+      port_, this, channel_id_, ext_addr_), delay);
+}
+
+int TurnEntry::Send(const void* data, size_t size, bool payload,
+                    const rtc::PacketOptions& options) {
+  rtc::ByteBuffer buf;
+  if (state_ != STATE_BOUND) {
+    // If we haven't bound the channel yet, we have to use a Send Indication.
+    TurnMessage msg;
+    msg.SetType(TURN_SEND_INDICATION);
+    msg.SetTransactionID(
+        rtc::CreateRandomString(kStunTransactionIdLength));
+    VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
+        STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
+    VERIFY(msg.AddAttribute(new StunByteStringAttribute(
+        STUN_ATTR_DATA, data, size)));
+    VERIFY(msg.Write(&buf));
+
+    // If we're sending real data, request a channel bind that we can use later.
+    if (state_ == STATE_UNBOUND && payload) {
+      SendChannelBindRequest(0);
+      state_ = STATE_BINDING;
+    }
+  } else {
+    // If the channel is bound, we can send the data as a Channel Message.
+    buf.WriteUInt16(channel_id_);
+    buf.WriteUInt16(static_cast<uint16>(size));
+    buf.WriteBytes(reinterpret_cast<const char*>(data), size);
+  }
+  return port_->Send(buf.Data(), buf.Length(), options);
+}
+
+void TurnEntry::OnCreatePermissionSuccess() {
+  LOG_J(LS_INFO, port_) << "Create permission for "
+                        << ext_addr_.ToSensitiveString()
+                        << " succeeded";
+  // For success result code will be 0.
+  port_->SignalCreatePermissionResult(port_, ext_addr_, 0);
+}
+
+void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
+  LOG_J(LS_WARNING, port_) << "Create permission for "
+                           << ext_addr_.ToSensitiveString()
+                           << " failed, code=" << code;
+  if (code == STUN_ERROR_STALE_NONCE) {
+    if (port_->UpdateNonce(response)) {
+      SendCreatePermissionRequest();
+    }
+  } else {
+    // Send signal with error code.
+    port_->SignalCreatePermissionResult(port_, ext_addr_, code);
+  }
+}
+
+void TurnEntry::OnChannelBindSuccess() {
+  LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
+                        << " succeeded";
+  ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND);
+  state_ = STATE_BOUND;
+}
+
+void TurnEntry::OnChannelBindError(StunMessage* response, int code) {
+  // TODO(mallinath) - Implement handling of error response for channel
+  // bind request as per http://tools.ietf.org/html/rfc5766#section-11.3
+  LOG_J(LS_WARNING, port_) << "Channel bind for "
+                           << ext_addr_.ToSensitiveString()
+                           << " failed, code=" << code;
+  if (code == STUN_ERROR_STALE_NONCE) {
+    if (port_->UpdateNonce(response)) {
+      // Send channel bind request with fresh nonce.
+      SendChannelBindRequest(0);
+    }
+  }
+}
+
+}  // namespace cricket
diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h
new file mode 100644
index 0000000..17fad17
--- /dev/null
+++ b/p2p/base/turnport.h
@@ -0,0 +1,237 @@
+/*
+ *  Copyright 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_P2P_BASE_TURNPORT_H_
+#define WEBRTC_P2P_BASE_TURNPORT_H_
+
+#include <stdio.h>
+#include <list>
+#include <set>
+#include <string>
+
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/client/basicportallocator.h"
+#include "webrtc/base/asyncpacketsocket.h"
+
+namespace rtc {
+class AsyncResolver;
+class SignalThread;
+}
+
+namespace cricket {
+
+extern const char TURN_PORT_TYPE[];
+class TurnAllocateRequest;
+class TurnEntry;
+
+class TurnPort : public Port {
+ public:
+  static TurnPort* Create(rtc::Thread* thread,
+                          rtc::PacketSocketFactory* factory,
+                          rtc::Network* network,
+                          rtc::AsyncPacketSocket* socket,
+                          const std::string& username,  // ice username.
+                          const std::string& password,  // ice password.
+                          const ProtocolAddress& server_address,
+                          const RelayCredentials& credentials,
+                          int server_priority) {
+    return new TurnPort(thread, factory, network, socket,
+                        username, password, server_address,
+                        credentials, server_priority);
+  }
+
+  static TurnPort* Create(rtc::Thread* thread,
+                          rtc::PacketSocketFactory* factory,
+                          rtc::Network* network,
+                          const rtc::IPAddress& ip,
+                          int min_port, int max_port,
+                          const std::string& username,  // ice username.
+                          const std::string& password,  // ice password.
+                          const ProtocolAddress& server_address,
+                          const RelayCredentials& credentials,
+                          int server_priority) {
+    return new TurnPort(thread, factory, network, ip, min_port, max_port,
+                        username, password, server_address, credentials,
+                        server_priority);
+  }
+
+  virtual ~TurnPort();
+
+  const ProtocolAddress& server_address() const { return server_address_; }
+
+  bool connected() const { return connected_; }
+  const RelayCredentials& credentials() const { return credentials_; }
+
+  virtual void PrepareAddress();
+  virtual Connection* CreateConnection(
+      const Candidate& c, PortInterface::CandidateOrigin origin);
+  virtual int SendTo(const void* data, size_t size,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options,
+                     bool payload);
+  virtual int SetOption(rtc::Socket::Option opt, int value);
+  virtual int GetOption(rtc::Socket::Option opt, int* value);
+  virtual int GetError();
+
+  virtual bool HandleIncomingPacket(
+      rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+      const rtc::SocketAddress& remote_addr,
+      const rtc::PacketTime& packet_time) {
+    OnReadPacket(socket, data, size, remote_addr, packet_time);
+    return true;
+  }
+  virtual void OnReadPacket(rtc::AsyncPacketSocket* socket,
+                            const char* data, size_t size,
+                            const rtc::SocketAddress& remote_addr,
+                            const rtc::PacketTime& packet_time);
+
+  virtual void OnReadyToSend(rtc::AsyncPacketSocket* socket);
+
+  void OnSocketConnect(rtc::AsyncPacketSocket* socket);
+  void OnSocketClose(rtc::AsyncPacketSocket* socket, int error);
+
+
+  const std::string& hash() const { return hash_; }
+  const std::string& nonce() const { return nonce_; }
+
+  int error() const { return error_; }
+
+  void OnAllocateMismatch();
+
+  rtc::AsyncPacketSocket* socket() const {
+    return socket_;
+  }
+
+  // Signal with resolved server address.
+  // Parameters are port, server address and resolved server address.
+  // This signal will be sent only if server address is resolved successfully.
+  sigslot::signal3<TurnPort*,
+                   const rtc::SocketAddress&,
+                   const rtc::SocketAddress&> SignalResolvedServerAddress;
+
+  // This signal is only for testing purpose.
+  sigslot::signal3<TurnPort*, const rtc::SocketAddress&, int>
+      SignalCreatePermissionResult;
+
+ protected:
+  TurnPort(rtc::Thread* thread,
+           rtc::PacketSocketFactory* factory,
+           rtc::Network* network,
+           rtc::AsyncPacketSocket* socket,
+           const std::string& username,
+           const std::string& password,
+           const ProtocolAddress& server_address,
+           const RelayCredentials& credentials,
+           int server_priority);
+
+  TurnPort(rtc::Thread* thread,
+           rtc::PacketSocketFactory* factory,
+           rtc::Network* network,
+           const rtc::IPAddress& ip,
+           int min_port, int max_port,
+           const std::string& username,
+           const std::string& password,
+           const ProtocolAddress& server_address,
+           const RelayCredentials& credentials,
+           int server_priority);
+
+ private:
+  enum {
+    MSG_ERROR = MSG_FIRST_AVAILABLE,
+    MSG_ALLOCATE_MISMATCH
+  };
+
+  typedef std::list<TurnEntry*> EntryList;
+  typedef std::map<rtc::Socket::Option, int> SocketOptionsMap;
+  typedef std::set<rtc::SocketAddress> AttemptedServerSet;
+
+  virtual void OnMessage(rtc::Message* pmsg);
+
+  bool CreateTurnClientSocket();
+
+  void set_nonce(const std::string& nonce) { nonce_ = nonce; }
+  void set_realm(const std::string& realm) {
+    if (realm != realm_) {
+      realm_ = realm;
+      UpdateHash();
+    }
+  }
+
+  bool SetAlternateServer(const rtc::SocketAddress& address);
+  void ResolveTurnAddress(const rtc::SocketAddress& address);
+  void OnResolveResult(rtc::AsyncResolverInterface* resolver);
+
+  void AddRequestAuthInfo(StunMessage* msg);
+  void OnSendStunPacket(const void* data, size_t size, StunRequest* request);
+  // Stun address from allocate success response.
+  // Currently used only for testing.
+  void OnStunAddress(const rtc::SocketAddress& address);
+  void OnAllocateSuccess(const rtc::SocketAddress& address,
+                         const rtc::SocketAddress& stun_address);
+  void OnAllocateError();
+  void OnAllocateRequestTimeout();
+
+  void HandleDataIndication(const char* data, size_t size,
+                            const rtc::PacketTime& packet_time);
+  void HandleChannelData(int channel_id, const char* data, size_t size,
+                         const rtc::PacketTime& packet_time);
+  void DispatchPacket(const char* data, size_t size,
+      const rtc::SocketAddress& remote_addr,
+      ProtocolType proto, const rtc::PacketTime& packet_time);
+
+  bool ScheduleRefresh(int lifetime);
+  void SendRequest(StunRequest* request, int delay);
+  int Send(const void* data, size_t size,
+           const rtc::PacketOptions& options);
+  void UpdateHash();
+  bool UpdateNonce(StunMessage* response);
+
+  bool HasPermission(const rtc::IPAddress& ipaddr) const;
+  TurnEntry* FindEntry(const rtc::SocketAddress& address) const;
+  TurnEntry* FindEntry(int channel_id) const;
+  TurnEntry* CreateEntry(const rtc::SocketAddress& address);
+  void DestroyEntry(const rtc::SocketAddress& address);
+  void OnConnectionDestroyed(Connection* conn);
+
+  ProtocolAddress server_address_;
+  RelayCredentials credentials_;
+  AttemptedServerSet attempted_server_addresses_;
+
+  rtc::AsyncPacketSocket* socket_;
+  SocketOptionsMap socket_options_;
+  rtc::AsyncResolverInterface* resolver_;
+  int error_;
+
+  StunRequestManager request_manager_;
+  std::string realm_;       // From 401/438 response message.
+  std::string nonce_;       // From 401/438 response message.
+  std::string hash_;        // Digest of username:realm:password
+
+  int next_channel_number_;
+  EntryList entries_;
+
+  bool connected_;
+  // By default the value will be set to 0. This value will be used in
+  // calculating the candidate priority.
+  int server_priority_;
+
+  // The number of retries made due to allocate mismatch error.
+  size_t allocate_mismatch_retries_;
+
+  friend class TurnEntry;
+  friend class TurnAllocateRequest;
+  friend class TurnRefreshRequest;
+  friend class TurnCreatePermissionRequest;
+  friend class TurnChannelBindRequest;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TURNPORT_H_
diff --git a/p2p/base/turnport_unittest.cc b/p2p/base/turnport_unittest.cc
new file mode 100644
index 0000000..4b524d5
--- /dev/null
+++ b/p2p/base/turnport_unittest.cc
@@ -0,0 +1,668 @@
+/*
+ *  Copyright 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.
+ */
+#if defined(WEBRTC_POSIX)
+#include <dirent.h>
+#endif
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/tcpport.h"
+#include "webrtc/p2p/base/testturnserver.h"
+#include "webrtc/p2p/base/turnport.h"
+#include "webrtc/p2p/base/udpport.h"
+#include "webrtc/base/asynctcpsocket.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/base/dscp.h"
+#include "webrtc/base/firewallsocketserver.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+using rtc::SocketAddress;
+using cricket::Connection;
+using cricket::Port;
+using cricket::PortInterface;
+using cricket::TurnPort;
+using cricket::UDPPort;
+
+static const SocketAddress kLocalAddr1("11.11.11.11", 0);
+static const SocketAddress kLocalAddr2("22.22.22.22", 0);
+static const SocketAddress kLocalIPv6Addr(
+    "2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
+static const SocketAddress kTurnUdpIntAddr("99.99.99.3",
+                                           cricket::TURN_SERVER_PORT);
+static const SocketAddress kTurnTcpIntAddr("99.99.99.4",
+                                           cricket::TURN_SERVER_PORT);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
+static const SocketAddress kTurnAlternateUdpIntAddr(
+    "99.99.99.6", cricket::TURN_SERVER_PORT);
+static const SocketAddress kTurnUdpIPv6IntAddr(
+    "2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT);
+static const SocketAddress kTurnUdpIPv6ExtAddr(
+  "2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0);
+
+static const char kIceUfrag1[] = "TESTICEUFRAG0001";
+static const char kIceUfrag2[] = "TESTICEUFRAG0002";
+static const char kIcePwd1[] = "TESTICEPWD00000000000001";
+static const char kIcePwd2[] = "TESTICEPWD00000000000002";
+static const char kTurnUsername[] = "test";
+static const char kTurnPassword[] = "test";
+static const unsigned int kTimeout = 1000;
+
+static const cricket::ProtocolAddress kTurnUdpProtoAddr(
+    kTurnUdpIntAddr, cricket::PROTO_UDP);
+static const cricket::ProtocolAddress kTurnTcpProtoAddr(
+    kTurnTcpIntAddr, cricket::PROTO_TCP);
+static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr(
+    kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+
+static const unsigned int MSG_TESTFINISH = 0;
+
+#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
+static int GetFDCount() {
+  struct dirent *dp;
+  int fd_count = 0;
+  DIR *dir = opendir("/proc/self/fd/");
+  while ((dp = readdir(dir)) != NULL) {
+    if (dp->d_name[0] == '.')
+      continue;
+    ++fd_count;
+  }
+  closedir(dir);
+  return fd_count;
+}
+#endif
+
+class TurnPortTest : public testing::Test,
+                     public sigslot::has_slots<>,
+                     public rtc::MessageHandler {
+ public:
+  TurnPortTest()
+      : main_(rtc::Thread::Current()),
+        pss_(new rtc::PhysicalSocketServer),
+        ss_(new rtc::VirtualSocketServer(pss_.get())),
+        ss_scope_(ss_.get()),
+        network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32),
+        socket_factory_(rtc::Thread::Current()),
+        turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr),
+        turn_ready_(false),
+        turn_error_(false),
+        turn_unknown_address_(false),
+        turn_create_permission_success_(false),
+        udp_ready_(false),
+        test_finish_(false) {
+    network_.AddIP(rtc::IPAddress(INADDR_ANY));
+  }
+
+  virtual void OnMessage(rtc::Message* msg) {
+    ASSERT(msg->message_id == MSG_TESTFINISH);
+    if (msg->message_id == MSG_TESTFINISH)
+      test_finish_ = true;
+  }
+
+  void OnTurnPortComplete(Port* port) {
+    turn_ready_ = true;
+  }
+  void OnTurnPortError(Port* port) {
+    turn_error_ = true;
+  }
+  void OnTurnUnknownAddress(PortInterface* port, const SocketAddress& addr,
+                            cricket::ProtocolType proto,
+                            cricket::IceMessage* msg, const std::string& rf,
+                            bool /*port_muxed*/) {
+    turn_unknown_address_ = true;
+  }
+  void OnTurnCreatePermissionResult(TurnPort* port, const SocketAddress& addr,
+                                     int code) {
+    // Ignoring the address.
+    if (code == 0) {
+      turn_create_permission_success_ = true;
+    }
+  }
+  void OnTurnReadPacket(Connection* conn, const char* data, size_t size,
+                        const rtc::PacketTime& packet_time) {
+    turn_packets_.push_back(rtc::Buffer(data, size));
+  }
+  void OnUdpPortComplete(Port* port) {
+    udp_ready_ = true;
+  }
+  void OnUdpReadPacket(Connection* conn, const char* data, size_t size,
+                       const rtc::PacketTime& packet_time) {
+    udp_packets_.push_back(rtc::Buffer(data, size));
+  }
+  void OnSocketReadPacket(rtc::AsyncPacketSocket* socket,
+                          const char* data, size_t size,
+                          const rtc::SocketAddress& remote_addr,
+                          const rtc::PacketTime& packet_time) {
+    turn_port_->HandleIncomingPacket(socket, data, size, remote_addr,
+                                     packet_time);
+  }
+  rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) {
+    rtc::AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_STREAM);
+    EXPECT_GE(socket->Bind(addr), 0);
+    EXPECT_GE(socket->Listen(5), 0);
+    return socket;
+  }
+
+  void CreateTurnPort(const std::string& username,
+                      const std::string& password,
+                      const cricket::ProtocolAddress& server_address) {
+    CreateTurnPort(kLocalAddr1, username, password, server_address);
+  }
+  void CreateTurnPort(const rtc::SocketAddress& local_address,
+                      const std::string& username,
+                      const std::string& password,
+                      const cricket::ProtocolAddress& server_address) {
+    cricket::RelayCredentials credentials(username, password);
+    turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_,
+                                 local_address.ipaddr(), 0, 0,
+                                 kIceUfrag1, kIcePwd1,
+                                 server_address, credentials, 0));
+    // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be
+    // in Hybrid mode. Protocol type is necessary to send correct type STUN ping
+    // messages.
+    // This TURN port will be the controlling.
+    turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+    turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+    ConnectSignals();
+  }
+
+  void CreateSharedTurnPort(const std::string& username,
+                            const std::string& password,
+                            const cricket::ProtocolAddress& server_address) {
+    ASSERT(server_address.proto == cricket::PROTO_UDP);
+
+    if (!socket_) {
+      socket_.reset(socket_factory_.CreateUdpSocket(
+          rtc::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0));
+      ASSERT_TRUE(socket_ != NULL);
+      socket_->SignalReadPacket.connect(
+          this, &TurnPortTest::OnSocketReadPacket);
+    }
+
+    cricket::RelayCredentials credentials(username, password);
+    turn_port_.reset(cricket::TurnPort::Create(
+        main_, &socket_factory_, &network_, socket_.get(),
+        kIceUfrag1, kIcePwd1, server_address, credentials, 0));
+    // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be
+    // in Hybrid mode. Protocol type is necessary to send correct type STUN ping
+    // messages.
+    // This TURN port will be the controlling.
+    turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+    turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+    ConnectSignals();
+  }
+
+  void ConnectSignals() {
+    turn_port_->SignalPortComplete.connect(this,
+        &TurnPortTest::OnTurnPortComplete);
+    turn_port_->SignalPortError.connect(this,
+        &TurnPortTest::OnTurnPortError);
+    turn_port_->SignalUnknownAddress.connect(this,
+        &TurnPortTest::OnTurnUnknownAddress);
+    turn_port_->SignalCreatePermissionResult.connect(this,
+        &TurnPortTest::OnTurnCreatePermissionResult);
+  }
+  void CreateUdpPort() {
+    udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_,
+                                    kLocalAddr2.ipaddr(), 0, 0,
+                                    kIceUfrag2, kIcePwd2));
+    // Set protocol type to RFC5245, as turn port is also in same mode.
+    // UDP port will be controlled.
+    udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+    udp_port_->SetIceRole(cricket::ICEROLE_CONTROLLED);
+    udp_port_->SignalPortComplete.connect(
+        this, &TurnPortTest::OnUdpPortComplete);
+  }
+
+  void TestTurnConnection() {
+    // Create ports and prepare addresses.
+    ASSERT_TRUE(turn_port_ != NULL);
+    turn_port_->PrepareAddress();
+    ASSERT_TRUE_WAIT(turn_ready_, kTimeout);
+    CreateUdpPort();
+    udp_port_->PrepareAddress();
+    ASSERT_TRUE_WAIT(udp_ready_, kTimeout);
+
+    // Send ping from UDP to TURN.
+    Connection* conn1 = udp_port_->CreateConnection(
+                    turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
+    ASSERT_TRUE(conn1 != NULL);
+    conn1->Ping(0);
+    WAIT(!turn_unknown_address_, kTimeout);
+    EXPECT_FALSE(turn_unknown_address_);
+    EXPECT_EQ(Connection::STATE_READ_INIT, conn1->read_state());
+    EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state());
+
+    // Send ping from TURN to UDP.
+    Connection* conn2 = turn_port_->CreateConnection(
+                    udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
+    ASSERT_TRUE(conn2 != NULL);
+    ASSERT_TRUE_WAIT(turn_create_permission_success_, kTimeout);
+    conn2->Ping(0);
+
+    EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout);
+    EXPECT_EQ(Connection::STATE_READABLE, conn1->read_state());
+    EXPECT_EQ(Connection::STATE_READ_INIT, conn2->read_state());
+    EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state());
+
+    // Send another ping from UDP to TURN.
+    conn1->Ping(0);
+    EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout);
+    EXPECT_EQ(Connection::STATE_READABLE, conn2->read_state());
+  }
+
+  void TestTurnSendData() {
+    turn_port_->PrepareAddress();
+    EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+    CreateUdpPort();
+    udp_port_->PrepareAddress();
+    EXPECT_TRUE_WAIT(udp_ready_, kTimeout);
+    // Create connections and send pings.
+    Connection* conn1 = turn_port_->CreateConnection(
+        udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
+    Connection* conn2 = udp_port_->CreateConnection(
+        turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE);
+    ASSERT_TRUE(conn1 != NULL);
+    ASSERT_TRUE(conn2 != NULL);
+    conn1->SignalReadPacket.connect(static_cast<TurnPortTest*>(this),
+                                    &TurnPortTest::OnTurnReadPacket);
+    conn2->SignalReadPacket.connect(static_cast<TurnPortTest*>(this),
+                                    &TurnPortTest::OnUdpReadPacket);
+    conn1->Ping(0);
+    EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout);
+    conn2->Ping(0);
+    EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout);
+
+    // Send some data.
+    size_t num_packets = 256;
+    for (size_t i = 0; i < num_packets; ++i) {
+      unsigned char buf[256] = { 0 };
+      for (size_t j = 0; j < i + 1; ++j) {
+        buf[j] = 0xFF - static_cast<unsigned char>(j);
+      }
+      conn1->Send(buf, i + 1, options);
+      conn2->Send(buf, i + 1, options);
+      main_->ProcessMessages(0);
+    }
+
+    // Check the data.
+    ASSERT_EQ_WAIT(num_packets, turn_packets_.size(), kTimeout);
+    ASSERT_EQ_WAIT(num_packets, udp_packets_.size(), kTimeout);
+    for (size_t i = 0; i < num_packets; ++i) {
+      EXPECT_EQ(i + 1, turn_packets_[i].length());
+      EXPECT_EQ(i + 1, udp_packets_[i].length());
+      EXPECT_EQ(turn_packets_[i], udp_packets_[i]);
+    }
+  }
+
+ protected:
+  rtc::Thread* main_;
+  rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> ss_;
+  rtc::SocketServerScope ss_scope_;
+  rtc::Network network_;
+  rtc::BasicPacketSocketFactory socket_factory_;
+  rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_;
+  cricket::TestTurnServer turn_server_;
+  rtc::scoped_ptr<TurnPort> turn_port_;
+  rtc::scoped_ptr<UDPPort> udp_port_;
+  bool turn_ready_;
+  bool turn_error_;
+  bool turn_unknown_address_;
+  bool turn_create_permission_success_;
+  bool udp_ready_;
+  bool test_finish_;
+  std::vector<rtc::Buffer> turn_packets_;
+  std::vector<rtc::Buffer> udp_packets_;
+  rtc::PacketOptions options;
+};
+
+// Do a normal TURN allocation.
+TEST_F(TurnPortTest, TestTurnAllocate) {
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10*1024));
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  ASSERT_EQ(1U, turn_port_->Candidates().size());
+  EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
+            turn_port_->Candidates()[0].address().ipaddr());
+  EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
+}
+
+// Testing a normal UDP allocation using TCP connection.
+TEST_F(TurnPortTest, TestTurnTcpAllocate) {
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
+  EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10*1024));
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  ASSERT_EQ(1U, turn_port_->Candidates().size());
+  EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
+            turn_port_->Candidates()[0].address().ipaddr());
+  EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
+}
+
+// Testing turn port will attempt to create TCP socket on address resolution
+// failure.
+TEST_F(TurnPortTest, DISABLED_TestTurnTcpOnAddressResolveFailure) {
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+  CreateTurnPort(kTurnUsername, kTurnPassword, cricket::ProtocolAddress(
+      rtc::SocketAddress("www.webrtc-blah-blah.com", 3478),
+      cricket::PROTO_TCP));
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+  // As VSS doesn't provide a DNS resolution, name resolve will fail. TurnPort
+  // will proceed in creating a TCP socket which will fail as there is no
+  // server on the above domain and error will be set to SOCKET_ERROR.
+  EXPECT_EQ(SOCKET_ERROR, turn_port_->error());
+}
+
+// In case of UDP on address resolve failure, TurnPort will not create socket
+// and return allocate failure.
+TEST_F(TurnPortTest, DISABLED_TestTurnUdpOnAdressResolveFailure) {
+  CreateTurnPort(kTurnUsername, kTurnPassword, cricket::ProtocolAddress(
+      rtc::SocketAddress("www.webrtc-blah-blah.com", 3478),
+      cricket::PROTO_UDP));
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+  // Error from turn port will not be socket error.
+  EXPECT_NE(SOCKET_ERROR, turn_port_->error());
+}
+
+// Try to do a TURN allocation with an invalid password.
+TEST_F(TurnPortTest, TestTurnAllocateBadPassword) {
+  CreateTurnPort(kTurnUsername, "bad", kTurnUdpProtoAddr);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+  ASSERT_EQ(0U, turn_port_->Candidates().size());
+}
+
+// Tests that a new local address is created after
+// STUN_ERROR_ALLOCATION_MISMATCH.
+TEST_F(TurnPortTest, TestTurnAllocateMismatch) {
+  // Do a normal allocation first.
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress());
+
+  // Forces the socket server to assign the same port.
+  ss_->SetNextPortForTesting(first_addr.port());
+
+  turn_ready_ = false;
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  turn_port_->PrepareAddress();
+
+  // Verifies that the new port has the same address.
+  EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress());
+
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+
+  // Verifies that the new port has a different address now.
+  EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress());
+}
+
+// Tests that a shared-socket-TurnPort creates its own socket after
+// STUN_ERROR_ALLOCATION_MISMATCH.
+TEST_F(TurnPortTest, TestSharedSocketAllocateMismatch) {
+  // Do a normal allocation first.
+  CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress());
+
+  turn_ready_ = false;
+  CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+
+  // Verifies that the new port has the same address.
+  EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress());
+  EXPECT_TRUE(turn_port_->SharedSocket());
+
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+
+  // Verifies that the new port has a different address now.
+  EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress());
+  EXPECT_FALSE(turn_port_->SharedSocket());
+}
+
+TEST_F(TurnPortTest, TestTurnTcpAllocateMismatch) {
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
+
+  // Do a normal allocation first.
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress());
+
+  // Forces the socket server to assign the same port.
+  ss_->SetNextPortForTesting(first_addr.port());
+
+  turn_ready_ = false;
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
+  turn_port_->PrepareAddress();
+
+  // Verifies that the new port has the same address.
+  EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress());
+
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+
+  // Verifies that the new port has a different address now.
+  EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress());
+}
+
+// Do a TURN allocation and try to send a packet to it from the outside.
+// The packet should be dropped. Then, try to send a packet from TURN to the
+// outside. It should reach its destination. Finally, try again from the
+// outside. It should now work as well.
+TEST_F(TurnPortTest, TestTurnConnection) {
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  TestTurnConnection();
+}
+
+// Similar to above, except that this test will use the shared socket.
+TEST_F(TurnPortTest, TestTurnConnectionUsingSharedSocket) {
+  CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  TestTurnConnection();
+}
+
+// Test that we can establish a TCP connection with TURN server.
+TEST_F(TurnPortTest, TestTurnTcpConnection) {
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
+  TestTurnConnection();
+}
+
+// Test that we fail to create a connection when we want to use TLS over TCP.
+// This test should be removed once we have TLS support.
+TEST_F(TurnPortTest, TestTurnTlsTcpConnectionFails) {
+  cricket::ProtocolAddress secure_addr(kTurnTcpProtoAddr.address,
+                                       kTurnTcpProtoAddr.proto,
+                                       true);
+  CreateTurnPort(kTurnUsername, kTurnPassword, secure_addr);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+  ASSERT_EQ(0U, turn_port_->Candidates().size());
+}
+
+// Test try-alternate-server feature.
+TEST_F(TurnPortTest, TestTurnAlternateServer) {
+  std::vector<rtc::SocketAddress> redirect_addresses;
+  redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
+
+  cricket::TestTurnRedirector redirector(redirect_addresses);
+  turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
+                                 cricket::PROTO_UDP);
+  turn_server_.set_redirect_hook(&redirector);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+
+  // Retrieve the address before we run the state machine.
+  const SocketAddress old_addr = turn_port_->server_address().address;
+
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  // Retrieve the address again, the turn port's address should be
+  // changed.
+  const SocketAddress new_addr = turn_port_->server_address().address;
+  EXPECT_NE(old_addr, new_addr);
+  ASSERT_EQ(1U, turn_port_->Candidates().size());
+  EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
+            turn_port_->Candidates()[0].address().ipaddr());
+  EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
+}
+
+// Test that we fail when we redirect to an address different from
+// current IP family.
+TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6) {
+  std::vector<rtc::SocketAddress> redirect_addresses;
+  redirect_addresses.push_back(kTurnUdpIPv6IntAddr);
+
+  cricket::TestTurnRedirector redirector(redirect_addresses);
+  turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
+                                 cricket::PROTO_UDP);
+  turn_server_.set_redirect_hook(&redirector);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+}
+
+// Test that we fail to handle alternate-server response over TCP protocol.
+TEST_F(TurnPortTest, TestTurnAlternateServerTcp) {
+  std::vector<rtc::SocketAddress> redirect_addresses;
+  redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
+
+  cricket::TestTurnRedirector redirector(redirect_addresses);
+  turn_server_.set_redirect_hook(&redirector);
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
+
+  turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, cricket::PROTO_TCP);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+}
+
+// Test try-alternate-server catches the case of pingpong.
+TEST_F(TurnPortTest, TestTurnAlternateServerPingPong) {
+  std::vector<rtc::SocketAddress> redirect_addresses;
+  redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
+  redirect_addresses.push_back(kTurnUdpIntAddr);
+
+  cricket::TestTurnRedirector redirector(redirect_addresses);
+
+  turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
+                                 cricket::PROTO_UDP);
+  turn_server_.set_redirect_hook(&redirector);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+  ASSERT_EQ(0U, turn_port_->Candidates().size());
+  rtc::SocketAddress address;
+  // Verify that we have exhausted all alternate servers instead of
+  // failure caused by other errors.
+  EXPECT_FALSE(redirector.ShouldRedirect(address, &address));
+}
+
+// Test try-alternate-server catch the case of repeated server.
+TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetition) {
+  std::vector<rtc::SocketAddress> redirect_addresses;
+  redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
+  redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
+
+  cricket::TestTurnRedirector redirector(redirect_addresses);
+
+  turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
+                                 cricket::PROTO_UDP);
+  turn_server_.set_redirect_hook(&redirector);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_error_, kTimeout);
+  ASSERT_EQ(0U, turn_port_->Candidates().size());
+}
+
+
+// Run TurnConnectionTest with one-time-use nonce feature.
+// Here server will send a 438 STALE_NONCE error message for
+// every TURN transaction.
+TEST_F(TurnPortTest, TestTurnConnectionUsingOTUNonce) {
+  turn_server_.set_enable_otu_nonce(true);
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  TestTurnConnection();
+}
+
+// Do a TURN allocation, establish a UDP connection, and send some data.
+TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) {
+  // Create ports and prepare addresses.
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+  TestTurnSendData();
+}
+
+// Do a TURN allocation, establish a TCP connection, and send some data.
+TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) {
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+  // Create ports and prepare addresses.
+  CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
+  TestTurnSendData();
+}
+
+// Test TURN fails to make a connection from IPv6 address to a server which has
+// IPv4 address.
+TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv4) {
+  turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+  CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+                 kTurnUdpProtoAddr);
+  turn_port_->PrepareAddress();
+  ASSERT_TRUE_WAIT(turn_error_, kTimeout);
+  EXPECT_TRUE(turn_port_->Candidates().empty());
+}
+
+// Test TURN make a connection from IPv6 address to a server which has
+// IPv6 intenal address. But in this test external address is a IPv4 address,
+// hence allocated address will be a IPv4 address.
+TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) {
+  turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+  CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+                 kTurnUdpIPv6ProtoAddr);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  ASSERT_EQ(1U, turn_port_->Candidates().size());
+  EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
+            turn_port_->Candidates()[0].address().ipaddr());
+  EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
+}
+
+// This test verifies any FD's are not leaked after TurnPort is destroyed.
+// https://code.google.com/p/webrtc/issues/detail?id=2651
+#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
+TEST_F(TurnPortTest, TestResolverShutdown) {
+  turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+  int last_fd_count = GetFDCount();
+  // Need to supply unresolved address to kick off resolver.
+  CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+                 cricket::ProtocolAddress(rtc::SocketAddress(
+                    "stun.l.google.com", 3478), cricket::PROTO_UDP));
+  turn_port_->PrepareAddress();
+  ASSERT_TRUE_WAIT(turn_error_, kTimeout);
+  EXPECT_TRUE(turn_port_->Candidates().empty());
+  turn_port_.reset();
+  rtc::Thread::Current()->Post(this, MSG_TESTFINISH);
+  // Waiting for above message to be processed.
+  ASSERT_TRUE_WAIT(test_finish_, kTimeout);
+  EXPECT_EQ(last_fd_count, GetFDCount());
+}
+#endif
diff --git a/p2p/base/turnserver.cc b/p2p/base/turnserver.cc
new file mode 100644
index 0000000..8605e98
--- /dev/null
+++ b/p2p/base/turnserver.cc
@@ -0,0 +1,1011 @@
+/*
+ *  Copyright 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/p2p/base/turnserver.h"
+
+#include "webrtc/p2p/base/asyncstuntcpsocket.h"
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/packetsocketfactory.h"
+#include "webrtc/p2p/base/stun.h"
+#include "webrtc/base/bytebuffer.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/messagedigest.h"
+#include "webrtc/base/socketadapters.h"
+#include "webrtc/base/stringencode.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+// TODO(juberti): Move this all to a future turnmessage.h
+//static const int IPPROTO_UDP = 17;
+static const int kNonceTimeout = 60 * 60 * 1000;              // 60 minutes
+static const int kDefaultAllocationTimeout = 10 * 60 * 1000;  // 10 minutes
+static const int kPermissionTimeout = 5 * 60 * 1000;          //  5 minutes
+static const int kChannelTimeout = 10 * 60 * 1000;            // 10 minutes
+
+static const int kMinChannelNumber = 0x4000;
+static const int kMaxChannelNumber = 0x7FFF;
+
+static const size_t kNonceKeySize = 16;
+static const size_t kNonceSize = 40;
+
+static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
+
+// TODO(mallinath) - Move these to a common place.
+inline bool IsTurnChannelData(uint16 msg_type) {
+  // The first two bits of a channel data message are 0b01.
+  return ((msg_type & 0xC000) == 0x4000);
+}
+
+// IDs used for posted messages for TurnServer::Allocation.
+enum {
+  MSG_ALLOCATION_TIMEOUT,
+};
+
+// Encapsulates a TURN allocation.
+// The object is created when an allocation request is received, and then
+// handles TURN messages (via HandleTurnMessage) and channel data messages
+// (via HandleChannelData) for this allocation when received by the server.
+// The object self-deletes and informs the server if its lifetime timer expires.
+class TurnServer::Allocation : public rtc::MessageHandler,
+                               public sigslot::has_slots<> {
+ public:
+  Allocation(TurnServer* server_,
+             rtc::Thread* thread, const Connection& conn,
+             rtc::AsyncPacketSocket* server_socket,
+             const std::string& key);
+  virtual ~Allocation();
+
+  Connection* conn() { return &conn_; }
+  const std::string& key() const { return key_; }
+  const std::string& transaction_id() const { return transaction_id_; }
+  const std::string& username() const { return username_; }
+  const std::string& last_nonce() const { return last_nonce_; }
+  void set_last_nonce(const std::string& nonce) { last_nonce_ = nonce; }
+
+  std::string ToString() const;
+
+  void HandleTurnMessage(const TurnMessage* msg);
+  void HandleChannelData(const char* data, size_t size);
+
+  sigslot::signal1<Allocation*> SignalDestroyed;
+
+ private:
+  typedef std::list<Permission*> PermissionList;
+  typedef std::list<Channel*> ChannelList;
+
+  void HandleAllocateRequest(const TurnMessage* msg);
+  void HandleRefreshRequest(const TurnMessage* msg);
+  void HandleSendIndication(const TurnMessage* msg);
+  void HandleCreatePermissionRequest(const TurnMessage* msg);
+  void HandleChannelBindRequest(const TurnMessage* msg);
+
+  void OnExternalPacket(rtc::AsyncPacketSocket* socket,
+                        const char* data, size_t size,
+                        const rtc::SocketAddress& addr,
+                        const rtc::PacketTime& packet_time);
+
+  static int ComputeLifetime(const TurnMessage* msg);
+  bool HasPermission(const rtc::IPAddress& addr);
+  void AddPermission(const rtc::IPAddress& addr);
+  Permission* FindPermission(const rtc::IPAddress& addr) const;
+  Channel* FindChannel(int channel_id) const;
+  Channel* FindChannel(const rtc::SocketAddress& addr) const;
+
+  void SendResponse(TurnMessage* msg);
+  void SendBadRequestResponse(const TurnMessage* req);
+  void SendErrorResponse(const TurnMessage* req, int code,
+                         const std::string& reason);
+  void SendExternal(const void* data, size_t size,
+                    const rtc::SocketAddress& peer);
+
+  void OnPermissionDestroyed(Permission* perm);
+  void OnChannelDestroyed(Channel* channel);
+  virtual void OnMessage(rtc::Message* msg);
+
+  TurnServer* server_;
+  rtc::Thread* thread_;
+  Connection conn_;
+  rtc::scoped_ptr<rtc::AsyncPacketSocket> external_socket_;
+  std::string key_;
+  std::string transaction_id_;
+  std::string username_;
+  std::string last_nonce_;
+  PermissionList perms_;
+  ChannelList channels_;
+};
+
+// Encapsulates a TURN permission.
+// The object is created when a create permission request is received by an
+// allocation, and self-deletes when its lifetime timer expires.
+class TurnServer::Permission : public rtc::MessageHandler {
+ public:
+  Permission(rtc::Thread* thread, const rtc::IPAddress& peer);
+  ~Permission();
+
+  const rtc::IPAddress& peer() const { return peer_; }
+  void Refresh();
+
+  sigslot::signal1<Permission*> SignalDestroyed;
+
+ private:
+  virtual void OnMessage(rtc::Message* msg);
+
+  rtc::Thread* thread_;
+  rtc::IPAddress peer_;
+};
+
+// Encapsulates a TURN channel binding.
+// The object is created when a channel bind request is received by an
+// allocation, and self-deletes when its lifetime timer expires.
+class TurnServer::Channel : public rtc::MessageHandler {
+ public:
+  Channel(rtc::Thread* thread, int id,
+                     const rtc::SocketAddress& peer);
+  ~Channel();
+
+  int id() const { return id_; }
+  const rtc::SocketAddress& peer() const { return peer_; }
+  void Refresh();
+
+  sigslot::signal1<Channel*> SignalDestroyed;
+
+ private:
+  virtual void OnMessage(rtc::Message* msg);
+
+  rtc::Thread* thread_;
+  int id_;
+  rtc::SocketAddress peer_;
+};
+
+static bool InitResponse(const StunMessage* req, StunMessage* resp) {
+  int resp_type = (req) ? GetStunSuccessResponseType(req->type()) : -1;
+  if (resp_type == -1)
+    return false;
+  resp->SetType(resp_type);
+  resp->SetTransactionID(req->transaction_id());
+  return true;
+}
+
+static bool InitErrorResponse(const StunMessage* req, int code,
+                              const std::string& reason, StunMessage* resp) {
+  int resp_type = (req) ? GetStunErrorResponseType(req->type()) : -1;
+  if (resp_type == -1)
+    return false;
+  resp->SetType(resp_type);
+  resp->SetTransactionID(req->transaction_id());
+  VERIFY(resp->AddAttribute(new cricket::StunErrorCodeAttribute(
+      STUN_ATTR_ERROR_CODE, code, reason)));
+  return true;
+}
+
+TurnServer::TurnServer(rtc::Thread* thread)
+    : thread_(thread),
+      nonce_key_(rtc::CreateRandomString(kNonceKeySize)),
+      auth_hook_(NULL),
+      redirect_hook_(NULL),
+      enable_otu_nonce_(false) {
+}
+
+TurnServer::~TurnServer() {
+  for (AllocationMap::iterator it = allocations_.begin();
+       it != allocations_.end(); ++it) {
+    delete it->second;
+  }
+
+  for (InternalSocketMap::iterator it = server_sockets_.begin();
+       it != server_sockets_.end(); ++it) {
+    rtc::AsyncPacketSocket* socket = it->first;
+    delete socket;
+  }
+
+  for (ServerSocketMap::iterator it = server_listen_sockets_.begin();
+       it != server_listen_sockets_.end(); ++it) {
+    rtc::AsyncSocket* socket = it->first;
+    delete socket;
+  }
+}
+
+void TurnServer::AddInternalSocket(rtc::AsyncPacketSocket* socket,
+                                   ProtocolType proto) {
+  ASSERT(server_sockets_.end() == server_sockets_.find(socket));
+  server_sockets_[socket] = proto;
+  socket->SignalReadPacket.connect(this, &TurnServer::OnInternalPacket);
+}
+
+void TurnServer::AddInternalServerSocket(rtc::AsyncSocket* socket,
+                                         ProtocolType proto) {
+  ASSERT(server_listen_sockets_.end() ==
+      server_listen_sockets_.find(socket));
+  server_listen_sockets_[socket] = proto;
+  socket->SignalReadEvent.connect(this, &TurnServer::OnNewInternalConnection);
+}
+
+void TurnServer::SetExternalSocketFactory(
+    rtc::PacketSocketFactory* factory,
+    const rtc::SocketAddress& external_addr) {
+  external_socket_factory_.reset(factory);
+  external_addr_ = external_addr;
+}
+
+void TurnServer::OnNewInternalConnection(rtc::AsyncSocket* socket) {
+  ASSERT(server_listen_sockets_.find(socket) != server_listen_sockets_.end());
+  AcceptConnection(socket);
+}
+
+void TurnServer::AcceptConnection(rtc::AsyncSocket* server_socket) {
+  // Check if someone is trying to connect to us.
+  rtc::SocketAddress accept_addr;
+  rtc::AsyncSocket* accepted_socket = server_socket->Accept(&accept_addr);
+  if (accepted_socket != NULL) {
+    ProtocolType proto = server_listen_sockets_[server_socket];
+    cricket::AsyncStunTCPSocket* tcp_socket =
+        new cricket::AsyncStunTCPSocket(accepted_socket, false);
+
+    tcp_socket->SignalClose.connect(this, &TurnServer::OnInternalSocketClose);
+    // Finally add the socket so it can start communicating with the client.
+    AddInternalSocket(tcp_socket, proto);
+  }
+}
+
+void TurnServer::OnInternalSocketClose(rtc::AsyncPacketSocket* socket,
+                                       int err) {
+  DestroyInternalSocket(socket);
+}
+
+void TurnServer::OnInternalPacket(rtc::AsyncPacketSocket* socket,
+                                  const char* data, size_t size,
+                                  const rtc::SocketAddress& addr,
+                                  const rtc::PacketTime& packet_time) {
+  // Fail if the packet is too small to even contain a channel header.
+  if (size < TURN_CHANNEL_HEADER_SIZE) {
+   return;
+  }
+  InternalSocketMap::iterator iter = server_sockets_.find(socket);
+  ASSERT(iter != server_sockets_.end());
+  Connection conn(addr, iter->second, socket);
+  uint16 msg_type = rtc::GetBE16(data);
+  if (!IsTurnChannelData(msg_type)) {
+    // This is a STUN message.
+    HandleStunMessage(&conn, data, size);
+  } else {
+    // This is a channel message; let the allocation handle it.
+    Allocation* allocation = FindAllocation(&conn);
+    if (allocation) {
+      allocation->HandleChannelData(data, size);
+    }
+  }
+}
+
+void TurnServer::HandleStunMessage(Connection* conn, const char* data,
+                                   size_t size) {
+  TurnMessage msg;
+  rtc::ByteBuffer buf(data, size);
+  if (!msg.Read(&buf) || (buf.Length() > 0)) {
+    LOG(LS_WARNING) << "Received invalid STUN message";
+    return;
+  }
+
+  // If it's a STUN binding request, handle that specially.
+  if (msg.type() == STUN_BINDING_REQUEST) {
+    HandleBindingRequest(conn, &msg);
+    return;
+  }
+
+  if (redirect_hook_ != NULL && msg.type() == STUN_ALLOCATE_REQUEST) {
+    rtc::SocketAddress address;
+    if (redirect_hook_->ShouldRedirect(conn->src(), &address)) {
+      SendErrorResponseWithAlternateServer(
+          conn, &msg, address);
+      return;
+    }
+  }
+
+  // Look up the key that we'll use to validate the M-I. If we have an
+  // existing allocation, the key will already be cached.
+  Allocation* allocation = FindAllocation(conn);
+  std::string key;
+  if (!allocation) {
+    GetKey(&msg, &key);
+  } else {
+    key = allocation->key();
+  }
+
+  // Ensure the message is authorized; only needed for requests.
+  if (IsStunRequestType(msg.type())) {
+    if (!CheckAuthorization(conn, &msg, data, size, key)) {
+      return;
+    }
+  }
+
+  if (!allocation && msg.type() == STUN_ALLOCATE_REQUEST) {
+    HandleAllocateRequest(conn, &msg, key);
+  } else if (allocation &&
+             (msg.type() != STUN_ALLOCATE_REQUEST ||
+              msg.transaction_id() == allocation->transaction_id())) {
+    // This is a non-allocate request, or a retransmit of an allocate.
+    // Check that the username matches the previous username used.
+    if (IsStunRequestType(msg.type()) &&
+        msg.GetByteString(STUN_ATTR_USERNAME)->GetString() !=
+            allocation->username()) {
+      SendErrorResponse(conn, &msg, STUN_ERROR_WRONG_CREDENTIALS,
+                        STUN_ERROR_REASON_WRONG_CREDENTIALS);
+      return;
+    }
+    allocation->HandleTurnMessage(&msg);
+  } else {
+    // Allocation mismatch.
+    SendErrorResponse(conn, &msg, STUN_ERROR_ALLOCATION_MISMATCH,
+                      STUN_ERROR_REASON_ALLOCATION_MISMATCH);
+  }
+}
+
+bool TurnServer::GetKey(const StunMessage* msg, std::string* key) {
+  const StunByteStringAttribute* username_attr =
+      msg->GetByteString(STUN_ATTR_USERNAME);
+  if (!username_attr) {
+    return false;
+  }
+
+  std::string username = username_attr->GetString();
+  return (auth_hook_ != NULL && auth_hook_->GetKey(username, realm_, key));
+}
+
+bool TurnServer::CheckAuthorization(Connection* conn,
+                                    const StunMessage* msg,
+                                    const char* data, size_t size,
+                                    const std::string& key) {
+  // RFC 5389, 10.2.2.
+  ASSERT(IsStunRequestType(msg->type()));
+  const StunByteStringAttribute* mi_attr =
+      msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
+  const StunByteStringAttribute* username_attr =
+      msg->GetByteString(STUN_ATTR_USERNAME);
+  const StunByteStringAttribute* realm_attr =
+      msg->GetByteString(STUN_ATTR_REALM);
+  const StunByteStringAttribute* nonce_attr =
+      msg->GetByteString(STUN_ATTR_NONCE);
+
+  // Fail if no M-I.
+  if (!mi_attr) {
+    SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED,
+                                       STUN_ERROR_REASON_UNAUTHORIZED);
+    return false;
+  }
+
+  // Fail if there is M-I but no username, nonce, or realm.
+  if (!username_attr || !realm_attr || !nonce_attr) {
+    SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST,
+                      STUN_ERROR_REASON_BAD_REQUEST);
+    return false;
+  }
+
+  // Fail if bad nonce.
+  if (!ValidateNonce(nonce_attr->GetString())) {
+    SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
+                                       STUN_ERROR_REASON_STALE_NONCE);
+    return false;
+  }
+
+  // Fail if bad username or M-I.
+  // We need |data| and |size| for the call to ValidateMessageIntegrity.
+  if (key.empty() || !StunMessage::ValidateMessageIntegrity(data, size, key)) {
+    SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED,
+                                       STUN_ERROR_REASON_UNAUTHORIZED);
+    return false;
+  }
+
+  // Fail if one-time-use nonce feature is enabled.
+  Allocation* allocation = FindAllocation(conn);
+  if (enable_otu_nonce_ && allocation &&
+      allocation->last_nonce() == nonce_attr->GetString()) {
+    SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
+                                       STUN_ERROR_REASON_STALE_NONCE);
+    return false;
+  }
+
+  if (allocation) {
+    allocation->set_last_nonce(nonce_attr->GetString());
+  }
+  // Success.
+  return true;
+}
+
+void TurnServer::HandleBindingRequest(Connection* conn,
+                                      const StunMessage* req) {
+  StunMessage response;
+  InitResponse(req, &response);
+
+  // Tell the user the address that we received their request from.
+  StunAddressAttribute* mapped_addr_attr;
+  mapped_addr_attr = new StunXorAddressAttribute(
+      STUN_ATTR_XOR_MAPPED_ADDRESS, conn->src());
+  VERIFY(response.AddAttribute(mapped_addr_attr));
+
+  SendStun(conn, &response);
+}
+
+void TurnServer::HandleAllocateRequest(Connection* conn,
+                                       const TurnMessage* msg,
+                                       const std::string& key) {
+  // Check the parameters in the request.
+  const StunUInt32Attribute* transport_attr =
+      msg->GetUInt32(STUN_ATTR_REQUESTED_TRANSPORT);
+  if (!transport_attr) {
+    SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST,
+                      STUN_ERROR_REASON_BAD_REQUEST);
+    return;
+  }
+
+  // Only UDP is supported right now.
+  int proto = transport_attr->value() >> 24;
+  if (proto != IPPROTO_UDP) {
+    SendErrorResponse(conn, msg, STUN_ERROR_UNSUPPORTED_PROTOCOL,
+                      STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL);
+    return;
+  }
+
+  // Create the allocation and let it send the success response.
+  // If the actual socket allocation fails, send an internal error.
+  Allocation* alloc = CreateAllocation(conn, proto, key);
+  if (alloc) {
+    alloc->HandleTurnMessage(msg);
+  } else {
+    SendErrorResponse(conn, msg, STUN_ERROR_SERVER_ERROR,
+                      "Failed to allocate socket");
+  }
+}
+
+std::string TurnServer::GenerateNonce() const {
+  // Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now))
+  uint32 now = rtc::Time();
+  std::string input(reinterpret_cast<const char*>(&now), sizeof(now));
+  std::string nonce = rtc::hex_encode(input.c_str(), input.size());
+  nonce += rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_, input);
+  ASSERT(nonce.size() == kNonceSize);
+  return nonce;
+}
+
+bool TurnServer::ValidateNonce(const std::string& nonce) const {
+  // Check the size.
+  if (nonce.size() != kNonceSize) {
+    return false;
+  }
+
+  // Decode the timestamp.
+  uint32 then;
+  char* p = reinterpret_cast<char*>(&then);
+  size_t len = rtc::hex_decode(p, sizeof(then),
+      nonce.substr(0, sizeof(then) * 2));
+  if (len != sizeof(then)) {
+    return false;
+  }
+
+  // Verify the HMAC.
+  if (nonce.substr(sizeof(then) * 2) != rtc::ComputeHmac(
+      rtc::DIGEST_MD5, nonce_key_, std::string(p, sizeof(then)))) {
+    return false;
+  }
+
+  // Validate the timestamp.
+  return rtc::TimeSince(then) < kNonceTimeout;
+}
+
+TurnServer::Allocation* TurnServer::FindAllocation(Connection* conn) {
+  AllocationMap::const_iterator it = allocations_.find(*conn);
+  return (it != allocations_.end()) ? it->second : NULL;
+}
+
+TurnServer::Allocation* TurnServer::CreateAllocation(Connection* conn,
+                                                     int proto,
+                                                     const std::string& key) {
+  rtc::AsyncPacketSocket* external_socket = (external_socket_factory_) ?
+      external_socket_factory_->CreateUdpSocket(external_addr_, 0, 0) : NULL;
+  if (!external_socket) {
+    return NULL;
+  }
+
+  // The Allocation takes ownership of the socket.
+  Allocation* allocation = new Allocation(this,
+      thread_, *conn, external_socket, key);
+  allocation->SignalDestroyed.connect(this, &TurnServer::OnAllocationDestroyed);
+  allocations_[*conn] = allocation;
+  return allocation;
+}
+
+void TurnServer::SendErrorResponse(Connection* conn,
+                                   const StunMessage* req,
+                                   int code, const std::string& reason) {
+  TurnMessage resp;
+  InitErrorResponse(req, code, reason, &resp);
+  LOG(LS_INFO) << "Sending error response, type=" << resp.type()
+               << ", code=" << code << ", reason=" << reason;
+  SendStun(conn, &resp);
+}
+
+void TurnServer::SendErrorResponseWithRealmAndNonce(
+    Connection* conn, const StunMessage* msg,
+    int code, const std::string& reason) {
+  TurnMessage resp;
+  InitErrorResponse(msg, code, reason, &resp);
+  VERIFY(resp.AddAttribute(new StunByteStringAttribute(
+      STUN_ATTR_NONCE, GenerateNonce())));
+  VERIFY(resp.AddAttribute(new StunByteStringAttribute(
+      STUN_ATTR_REALM, realm_)));
+  SendStun(conn, &resp);
+}
+
+void TurnServer::SendErrorResponseWithAlternateServer(
+    Connection* conn, const StunMessage* msg,
+    const rtc::SocketAddress& addr) {
+  TurnMessage resp;
+  InitErrorResponse(msg, STUN_ERROR_TRY_ALTERNATE,
+                    STUN_ERROR_REASON_TRY_ALTERNATE_SERVER, &resp);
+  VERIFY(resp.AddAttribute(new StunAddressAttribute(
+      STUN_ATTR_ALTERNATE_SERVER, addr)));
+  SendStun(conn, &resp);
+}
+
+void TurnServer::SendStun(Connection* conn, StunMessage* msg) {
+  rtc::ByteBuffer buf;
+  // Add a SOFTWARE attribute if one is set.
+  if (!software_.empty()) {
+    VERIFY(msg->AddAttribute(
+        new StunByteStringAttribute(STUN_ATTR_SOFTWARE, software_)));
+  }
+  msg->Write(&buf);
+  Send(conn, buf);
+}
+
+void TurnServer::Send(Connection* conn,
+                      const rtc::ByteBuffer& buf) {
+  rtc::PacketOptions options;
+  conn->socket()->SendTo(buf.Data(), buf.Length(), conn->src(), options);
+}
+
+void TurnServer::OnAllocationDestroyed(Allocation* allocation) {
+  // Removing the internal socket if the connection is not udp.
+  rtc::AsyncPacketSocket* socket = allocation->conn()->socket();
+  InternalSocketMap::iterator iter = server_sockets_.find(socket);
+  ASSERT(iter != server_sockets_.end());
+  // Skip if the socket serving this allocation is UDP, as this will be shared
+  // by all allocations.
+  if (iter->second != cricket::PROTO_UDP) {
+    DestroyInternalSocket(socket);
+  }
+
+  AllocationMap::iterator it = allocations_.find(*(allocation->conn()));
+  if (it != allocations_.end())
+    allocations_.erase(it);
+}
+
+void TurnServer::DestroyInternalSocket(rtc::AsyncPacketSocket* socket) {
+  InternalSocketMap::iterator iter = server_sockets_.find(socket);
+  if (iter != server_sockets_.end()) {
+    rtc::AsyncPacketSocket* socket = iter->first;
+    // We must destroy the socket async to avoid invalidating the sigslot
+    // callback list iterator inside a sigslot callback.
+    rtc::Thread::Current()->Dispose(socket);
+    server_sockets_.erase(iter);
+  }
+}
+
+TurnServer::Connection::Connection(const rtc::SocketAddress& src,
+                                   ProtocolType proto,
+                                   rtc::AsyncPacketSocket* socket)
+    : src_(src),
+      dst_(socket->GetRemoteAddress()),
+      proto_(proto),
+      socket_(socket) {
+}
+
+bool TurnServer::Connection::operator==(const Connection& c) const {
+  return src_ == c.src_ && dst_ == c.dst_ && proto_ == c.proto_;
+}
+
+bool TurnServer::Connection::operator<(const Connection& c) const {
+  return src_ < c.src_ || dst_ < c.dst_ || proto_ < c.proto_;
+}
+
+std::string TurnServer::Connection::ToString() const {
+  const char* const kProtos[] = {
+      "unknown", "udp", "tcp", "ssltcp"
+  };
+  std::ostringstream ost;
+  ost << src_.ToString() << "-" << dst_.ToString() << ":"<< kProtos[proto_];
+  return ost.str();
+}
+
+TurnServer::Allocation::Allocation(TurnServer* server,
+                                   rtc::Thread* thread,
+                                   const Connection& conn,
+                                   rtc::AsyncPacketSocket* socket,
+                                   const std::string& key)
+    : server_(server),
+      thread_(thread),
+      conn_(conn),
+      external_socket_(socket),
+      key_(key) {
+  external_socket_->SignalReadPacket.connect(
+      this, &TurnServer::Allocation::OnExternalPacket);
+}
+
+TurnServer::Allocation::~Allocation() {
+  for (ChannelList::iterator it = channels_.begin();
+       it != channels_.end(); ++it) {
+    delete *it;
+  }
+  for (PermissionList::iterator it = perms_.begin();
+       it != perms_.end(); ++it) {
+    delete *it;
+  }
+  thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+  LOG_J(LS_INFO, this) << "Allocation destroyed";
+}
+
+std::string TurnServer::Allocation::ToString() const {
+  std::ostringstream ost;
+  ost << "Alloc[" << conn_.ToString() << "]";
+  return ost.str();
+}
+
+void TurnServer::Allocation::HandleTurnMessage(const TurnMessage* msg) {
+  ASSERT(msg != NULL);
+  switch (msg->type()) {
+    case STUN_ALLOCATE_REQUEST:
+      HandleAllocateRequest(msg);
+      break;
+    case TURN_REFRESH_REQUEST:
+      HandleRefreshRequest(msg);
+      break;
+    case TURN_SEND_INDICATION:
+      HandleSendIndication(msg);
+      break;
+    case TURN_CREATE_PERMISSION_REQUEST:
+      HandleCreatePermissionRequest(msg);
+      break;
+    case TURN_CHANNEL_BIND_REQUEST:
+      HandleChannelBindRequest(msg);
+      break;
+    default:
+      // Not sure what to do with this, just eat it.
+      LOG_J(LS_WARNING, this) << "Invalid TURN message type received: "
+                              << msg->type();
+  }
+}
+
+void TurnServer::Allocation::HandleAllocateRequest(const TurnMessage* msg) {
+  // Copy the important info from the allocate request.
+  transaction_id_ = msg->transaction_id();
+  const StunByteStringAttribute* username_attr =
+      msg->GetByteString(STUN_ATTR_USERNAME);
+  ASSERT(username_attr != NULL);
+  username_ = username_attr->GetString();
+
+  // Figure out the lifetime and start the allocation timer.
+  int lifetime_secs = ComputeLifetime(msg);
+  thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT);
+
+  LOG_J(LS_INFO, this) << "Created allocation, lifetime=" << lifetime_secs;
+
+  // We've already validated all the important bits; just send a response here.
+  TurnMessage response;
+  InitResponse(msg, &response);
+
+  StunAddressAttribute* mapped_addr_attr =
+      new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, conn_.src());
+  StunAddressAttribute* relayed_addr_attr =
+      new StunXorAddressAttribute(STUN_ATTR_XOR_RELAYED_ADDRESS,
+          external_socket_->GetLocalAddress());
+  StunUInt32Attribute* lifetime_attr =
+      new StunUInt32Attribute(STUN_ATTR_LIFETIME, lifetime_secs);
+  VERIFY(response.AddAttribute(mapped_addr_attr));
+  VERIFY(response.AddAttribute(relayed_addr_attr));
+  VERIFY(response.AddAttribute(lifetime_attr));
+
+  SendResponse(&response);
+}
+
+void TurnServer::Allocation::HandleRefreshRequest(const TurnMessage* msg) {
+  // Figure out the new lifetime.
+  int lifetime_secs = ComputeLifetime(msg);
+
+  // Reset the expiration timer.
+  thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+  thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT);
+
+  LOG_J(LS_INFO, this) << "Refreshed allocation, lifetime=" << lifetime_secs;
+
+  // Send a success response with a LIFETIME attribute.
+  TurnMessage response;
+  InitResponse(msg, &response);
+
+  StunUInt32Attribute* lifetime_attr =
+      new StunUInt32Attribute(STUN_ATTR_LIFETIME, lifetime_secs);
+  VERIFY(response.AddAttribute(lifetime_attr));
+
+  SendResponse(&response);
+}
+
+void TurnServer::Allocation::HandleSendIndication(const TurnMessage* msg) {
+  // Check mandatory attributes.
+  const StunByteStringAttribute* data_attr = msg->GetByteString(STUN_ATTR_DATA);
+  const StunAddressAttribute* peer_attr =
+      msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
+  if (!data_attr || !peer_attr) {
+    LOG_J(LS_WARNING, this) << "Received invalid send indication";
+    return;
+  }
+
+  // If a permission exists, send the data on to the peer.
+  if (HasPermission(peer_attr->GetAddress().ipaddr())) {
+    SendExternal(data_attr->bytes(), data_attr->length(),
+                 peer_attr->GetAddress());
+  } else {
+    LOG_J(LS_WARNING, this) << "Received send indication without permission"
+                            << "peer=" << peer_attr->GetAddress();
+  }
+}
+
+void TurnServer::Allocation::HandleCreatePermissionRequest(
+    const TurnMessage* msg) {
+  // Check mandatory attributes.
+  const StunAddressAttribute* peer_attr =
+      msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
+  if (!peer_attr) {
+    SendBadRequestResponse(msg);
+    return;
+  }
+
+  // Add this permission.
+  AddPermission(peer_attr->GetAddress().ipaddr());
+
+  LOG_J(LS_INFO, this) << "Created permission, peer="
+                       << peer_attr->GetAddress();
+
+  // Send a success response.
+  TurnMessage response;
+  InitResponse(msg, &response);
+  SendResponse(&response);
+}
+
+void TurnServer::Allocation::HandleChannelBindRequest(const TurnMessage* msg) {
+  // Check mandatory attributes.
+  const StunUInt32Attribute* channel_attr =
+      msg->GetUInt32(STUN_ATTR_CHANNEL_NUMBER);
+  const StunAddressAttribute* peer_attr =
+      msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
+  if (!channel_attr || !peer_attr) {
+    SendBadRequestResponse(msg);
+    return;
+  }
+
+  // Check that channel id is valid.
+  int channel_id = channel_attr->value() >> 16;
+  if (channel_id < kMinChannelNumber || channel_id > kMaxChannelNumber) {
+    SendBadRequestResponse(msg);
+    return;
+  }
+
+  // Check that this channel id isn't bound to another transport address, and
+  // that this transport address isn't bound to another channel id.
+  Channel* channel1 = FindChannel(channel_id);
+  Channel* channel2 = FindChannel(peer_attr->GetAddress());
+  if (channel1 != channel2) {
+    SendBadRequestResponse(msg);
+    return;
+  }
+
+  // Add or refresh this channel.
+  if (!channel1) {
+    channel1 = new Channel(thread_, channel_id, peer_attr->GetAddress());
+    channel1->SignalDestroyed.connect(this,
+        &TurnServer::Allocation::OnChannelDestroyed);
+    channels_.push_back(channel1);
+  } else {
+    channel1->Refresh();
+  }
+
+  // Channel binds also refresh permissions.
+  AddPermission(peer_attr->GetAddress().ipaddr());
+
+  LOG_J(LS_INFO, this) << "Bound channel, id=" << channel_id
+                       << ", peer=" << peer_attr->GetAddress();
+
+  // Send a success response.
+  TurnMessage response;
+  InitResponse(msg, &response);
+  SendResponse(&response);
+}
+
+void TurnServer::Allocation::HandleChannelData(const char* data, size_t size) {
+  // Extract the channel number from the data.
+  uint16 channel_id = rtc::GetBE16(data);
+  Channel* channel = FindChannel(channel_id);
+  if (channel) {
+    // Send the data to the peer address.
+    SendExternal(data + TURN_CHANNEL_HEADER_SIZE,
+                 size - TURN_CHANNEL_HEADER_SIZE, channel->peer());
+  } else {
+    LOG_J(LS_WARNING, this) << "Received channel data for invalid channel, id="
+                            << channel_id;
+  }
+}
+
+void TurnServer::Allocation::OnExternalPacket(
+    rtc::AsyncPacketSocket* socket,
+    const char* data, size_t size,
+    const rtc::SocketAddress& addr,
+    const rtc::PacketTime& packet_time) {
+  ASSERT(external_socket_.get() == socket);
+  Channel* channel = FindChannel(addr);
+  if (channel) {
+    // There is a channel bound to this address. Send as a channel message.
+    rtc::ByteBuffer buf;
+    buf.WriteUInt16(channel->id());
+    buf.WriteUInt16(static_cast<uint16>(size));
+    buf.WriteBytes(data, size);
+    server_->Send(&conn_, buf);
+  } else if (HasPermission(addr.ipaddr())) {
+    // No channel, but a permission exists. Send as a data indication.
+    TurnMessage msg;
+    msg.SetType(TURN_DATA_INDICATION);
+    msg.SetTransactionID(
+        rtc::CreateRandomString(kStunTransactionIdLength));
+    VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
+        STUN_ATTR_XOR_PEER_ADDRESS, addr)));
+    VERIFY(msg.AddAttribute(new StunByteStringAttribute(
+        STUN_ATTR_DATA, data, size)));
+    server_->SendStun(&conn_, &msg);
+  } else {
+    LOG_J(LS_WARNING, this) << "Received external packet without permission, "
+                            << "peer=" << addr;
+  }
+}
+
+int TurnServer::Allocation::ComputeLifetime(const TurnMessage* msg) {
+  // Return the smaller of our default lifetime and the requested lifetime.
+  uint32 lifetime = kDefaultAllocationTimeout / 1000;  // convert to seconds
+  const StunUInt32Attribute* lifetime_attr = msg->GetUInt32(STUN_ATTR_LIFETIME);
+  if (lifetime_attr && lifetime_attr->value() < lifetime) {
+    lifetime = lifetime_attr->value();
+  }
+  return lifetime;
+}
+
+bool TurnServer::Allocation::HasPermission(const rtc::IPAddress& addr) {
+  return (FindPermission(addr) != NULL);
+}
+
+void TurnServer::Allocation::AddPermission(const rtc::IPAddress& addr) {
+  Permission* perm = FindPermission(addr);
+  if (!perm) {
+    perm = new Permission(thread_, addr);
+    perm->SignalDestroyed.connect(
+        this, &TurnServer::Allocation::OnPermissionDestroyed);
+    perms_.push_back(perm);
+  } else {
+    perm->Refresh();
+  }
+}
+
+TurnServer::Permission* TurnServer::Allocation::FindPermission(
+    const rtc::IPAddress& addr) const {
+  for (PermissionList::const_iterator it = perms_.begin();
+       it != perms_.end(); ++it) {
+    if ((*it)->peer() == addr)
+      return *it;
+  }
+  return NULL;
+}
+
+TurnServer::Channel* TurnServer::Allocation::FindChannel(int channel_id) const {
+  for (ChannelList::const_iterator it = channels_.begin();
+       it != channels_.end(); ++it) {
+    if ((*it)->id() == channel_id)
+      return *it;
+  }
+  return NULL;
+}
+
+TurnServer::Channel* TurnServer::Allocation::FindChannel(
+    const rtc::SocketAddress& addr) const {
+  for (ChannelList::const_iterator it = channels_.begin();
+       it != channels_.end(); ++it) {
+    if ((*it)->peer() == addr)
+      return *it;
+  }
+  return NULL;
+}
+
+void TurnServer::Allocation::SendResponse(TurnMessage* msg) {
+  // Success responses always have M-I.
+  msg->AddMessageIntegrity(key_);
+  server_->SendStun(&conn_, msg);
+}
+
+void TurnServer::Allocation::SendBadRequestResponse(const TurnMessage* req) {
+  SendErrorResponse(req, STUN_ERROR_BAD_REQUEST, STUN_ERROR_REASON_BAD_REQUEST);
+}
+
+void TurnServer::Allocation::SendErrorResponse(const TurnMessage* req, int code,
+                                       const std::string& reason) {
+  server_->SendErrorResponse(&conn_, req, code, reason);
+}
+
+void TurnServer::Allocation::SendExternal(const void* data, size_t size,
+                                  const rtc::SocketAddress& peer) {
+  rtc::PacketOptions options;
+  external_socket_->SendTo(data, size, peer, options);
+}
+
+void TurnServer::Allocation::OnMessage(rtc::Message* msg) {
+  ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT);
+  SignalDestroyed(this);
+  delete this;
+}
+
+void TurnServer::Allocation::OnPermissionDestroyed(Permission* perm) {
+  PermissionList::iterator it = std::find(perms_.begin(), perms_.end(), perm);
+  ASSERT(it != perms_.end());
+  perms_.erase(it);
+}
+
+void TurnServer::Allocation::OnChannelDestroyed(Channel* channel) {
+  ChannelList::iterator it =
+      std::find(channels_.begin(), channels_.end(), channel);
+  ASSERT(it != channels_.end());
+  channels_.erase(it);
+}
+
+TurnServer::Permission::Permission(rtc::Thread* thread,
+                                   const rtc::IPAddress& peer)
+    : thread_(thread), peer_(peer) {
+  Refresh();
+}
+
+TurnServer::Permission::~Permission() {
+  thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+}
+
+void TurnServer::Permission::Refresh() {
+  thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+  thread_->PostDelayed(kPermissionTimeout, this, MSG_ALLOCATION_TIMEOUT);
+}
+
+void TurnServer::Permission::OnMessage(rtc::Message* msg) {
+  ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT);
+  SignalDestroyed(this);
+  delete this;
+}
+
+TurnServer::Channel::Channel(rtc::Thread* thread, int id,
+                             const rtc::SocketAddress& peer)
+    : thread_(thread), id_(id), peer_(peer) {
+  Refresh();
+}
+
+TurnServer::Channel::~Channel() {
+  thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+}
+
+void TurnServer::Channel::Refresh() {
+  thread_->Clear(this, MSG_ALLOCATION_TIMEOUT);
+  thread_->PostDelayed(kChannelTimeout, this, MSG_ALLOCATION_TIMEOUT);
+}
+
+void TurnServer::Channel::OnMessage(rtc::Message* msg) {
+  ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT);
+  SignalDestroyed(this);
+  delete this;
+}
+
+}  // namespace cricket
diff --git a/p2p/base/turnserver.h b/p2p/base/turnserver.h
new file mode 100644
index 0000000..670b618
--- /dev/null
+++ b/p2p/base/turnserver.h
@@ -0,0 +1,190 @@
+/*
+ *  Copyright 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_P2P_BASE_TURNSERVER_H_
+#define WEBRTC_P2P_BASE_TURNSERVER_H_
+
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+
+#include "webrtc/p2p/base/portinterface.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/messagequeue.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace rtc {
+class ByteBuffer;
+class PacketSocketFactory;
+class Thread;
+}
+
+namespace cricket {
+
+class StunMessage;
+class TurnMessage;
+
+// The default server port for TURN, as specified in RFC5766.
+const int TURN_SERVER_PORT = 3478;
+
+// An interface through which the MD5 credential hash can be retrieved.
+class TurnAuthInterface {
+ public:
+  // Gets HA1 for the specified user and realm.
+  // HA1 = MD5(A1) = MD5(username:realm:password).
+  // Return true if the given username and realm are valid, or false if not.
+  virtual bool GetKey(const std::string& username, const std::string& realm,
+                      std::string* key) = 0;
+};
+
+// An interface enables Turn Server to control redirection behavior.
+class TurnRedirectInterface {
+ public:
+  virtual bool ShouldRedirect(const rtc::SocketAddress& address,
+                              rtc::SocketAddress* out) = 0;
+  virtual ~TurnRedirectInterface() {}
+};
+
+// The core TURN server class. Give it a socket to listen on via
+// AddInternalServerSocket, and a factory to create external sockets via
+// SetExternalSocketFactory, and it's ready to go.
+// Not yet wired up: TCP support.
+class TurnServer : public sigslot::has_slots<> {
+ public:
+  explicit TurnServer(rtc::Thread* thread);
+  ~TurnServer();
+
+  // Gets/sets the realm value to use for the server.
+  const std::string& realm() const { return realm_; }
+  void set_realm(const std::string& realm) { realm_ = realm; }
+
+  // Gets/sets the value for the SOFTWARE attribute for TURN messages.
+  const std::string& software() const { return software_; }
+  void set_software(const std::string& software) { software_ = software; }
+
+  // Sets the authentication callback; does not take ownership.
+  void set_auth_hook(TurnAuthInterface* auth_hook) { auth_hook_ = auth_hook; }
+
+  void set_redirect_hook(TurnRedirectInterface* redirect_hook) {
+    redirect_hook_ = redirect_hook;
+  }
+
+  void set_enable_otu_nonce(bool enable) { enable_otu_nonce_ = enable; }
+
+  // Starts listening for packets from internal clients.
+  void AddInternalSocket(rtc::AsyncPacketSocket* socket,
+                         ProtocolType proto);
+  // Starts listening for the connections on this socket. When someone tries
+  // to connect, the connection will be accepted and a new internal socket
+  // will be added.
+  void AddInternalServerSocket(rtc::AsyncSocket* socket,
+                               ProtocolType proto);
+  // Specifies the factory to use for creating external sockets.
+  void SetExternalSocketFactory(rtc::PacketSocketFactory* factory,
+                                const rtc::SocketAddress& address);
+
+ private:
+  // Encapsulates the client's connection to the server.
+  class Connection {
+   public:
+    Connection() : proto_(PROTO_UDP), socket_(NULL) {}
+    Connection(const rtc::SocketAddress& src,
+               ProtocolType proto,
+               rtc::AsyncPacketSocket* socket);
+    const rtc::SocketAddress& src() const { return src_; }
+    rtc::AsyncPacketSocket* socket() { return socket_; }
+    bool operator==(const Connection& t) const;
+    bool operator<(const Connection& t) const;
+    std::string ToString() const;
+
+   private:
+    rtc::SocketAddress src_;
+    rtc::SocketAddress dst_;
+    cricket::ProtocolType proto_;
+    rtc::AsyncPacketSocket* socket_;
+  };
+  class Allocation;
+  class Permission;
+  class Channel;
+  typedef std::map<Connection, Allocation*> AllocationMap;
+
+  void OnInternalPacket(rtc::AsyncPacketSocket* socket, const char* data,
+                        size_t size, const rtc::SocketAddress& address,
+                        const rtc::PacketTime& packet_time);
+
+  void OnNewInternalConnection(rtc::AsyncSocket* socket);
+
+  // Accept connections on this server socket.
+  void AcceptConnection(rtc::AsyncSocket* server_socket);
+  void OnInternalSocketClose(rtc::AsyncPacketSocket* socket, int err);
+
+  void HandleStunMessage(Connection* conn, const char* data, size_t size);
+  void HandleBindingRequest(Connection* conn, const StunMessage* msg);
+  void HandleAllocateRequest(Connection* conn, const TurnMessage* msg,
+                             const std::string& key);
+
+  bool GetKey(const StunMessage* msg, std::string* key);
+  bool CheckAuthorization(Connection* conn, const StunMessage* msg,
+                          const char* data, size_t size,
+                          const std::string& key);
+  std::string GenerateNonce() const;
+  bool ValidateNonce(const std::string& nonce) const;
+
+  Allocation* FindAllocation(Connection* conn);
+  Allocation* CreateAllocation(Connection* conn, int proto,
+                               const std::string& key);
+
+  void SendErrorResponse(Connection* conn, const StunMessage* req,
+                         int code, const std::string& reason);
+
+  void SendErrorResponseWithRealmAndNonce(Connection* conn,
+                                          const StunMessage* req,
+                                          int code,
+                                          const std::string& reason);
+
+  void SendErrorResponseWithAlternateServer(Connection* conn,
+                                            const StunMessage* req,
+                                            const rtc::SocketAddress& addr);
+
+  void SendStun(Connection* conn, StunMessage* msg);
+  void Send(Connection* conn, const rtc::ByteBuffer& buf);
+
+  void OnAllocationDestroyed(Allocation* allocation);
+  void DestroyInternalSocket(rtc::AsyncPacketSocket* socket);
+
+  typedef std::map<rtc::AsyncPacketSocket*,
+                   ProtocolType> InternalSocketMap;
+  typedef std::map<rtc::AsyncSocket*,
+                   ProtocolType> ServerSocketMap;
+
+  rtc::Thread* thread_;
+  std::string nonce_key_;
+  std::string realm_;
+  std::string software_;
+  TurnAuthInterface* auth_hook_;
+  TurnRedirectInterface* redirect_hook_;
+  // otu - one-time-use. Server will respond with 438 if it's
+  // sees the same nonce in next transaction.
+  bool enable_otu_nonce_;
+
+  InternalSocketMap server_sockets_;
+  ServerSocketMap server_listen_sockets_;
+  rtc::scoped_ptr<rtc::PacketSocketFactory>
+      external_socket_factory_;
+  rtc::SocketAddress external_addr_;
+
+  AllocationMap allocations_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_BASE_TURNSERVER_H_
diff --git a/p2p/base/udpport.h b/p2p/base/udpport.h
new file mode 100644
index 0000000..9f86864
--- /dev/null
+++ b/p2p/base/udpport.h
@@ -0,0 +1,17 @@
+/*
+ *  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_P2P_BASE_UDPPORT_H_
+#define WEBRTC_P2P_BASE_UDPPORT_H_
+
+// StunPort will be handling UDPPort functionality.
+#include "webrtc/p2p/base/stunport.h"
+
+#endif  // WEBRTC_P2P_BASE_UDPPORT_H_
diff --git a/p2p/client/autoportallocator.h b/p2p/client/autoportallocator.h
new file mode 100644
index 0000000..5df1f0d
--- /dev/null
+++ b/p2p/client/autoportallocator.h
@@ -0,0 +1,52 @@
+/*
+ *  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.
+ */
+
+#ifndef WEBRTC_P2P_CLIENT_AUTOPORTALLOCATOR_H_
+#define WEBRTC_P2P_CLIENT_AUTOPORTALLOCATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/client/httpportallocator.h"
+#include "webrtc/libjingle/xmpp/jingleinfotask.h"
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "webrtc/base/sigslot.h"
+
+// This class sets the relay and stun servers using XmppClient.
+// It enables the client to traverse Proxy and NAT.
+class AutoPortAllocator : public cricket::HttpPortAllocator {
+ public:
+  AutoPortAllocator(rtc::NetworkManager* network_manager,
+                    const std::string& user_agent)
+      : cricket::HttpPortAllocator(network_manager, user_agent) {
+  }
+
+  // Creates and initiates a task to get relay token from XmppClient and set
+  // it appropriately.
+  void SetXmppClient(buzz::XmppClient* client) {
+    // The JingleInfoTask is freed by the task-runner.
+    buzz::JingleInfoTask* jit = new buzz::JingleInfoTask(client);
+    jit->SignalJingleInfo.connect(this, &AutoPortAllocator::OnJingleInfo);
+    jit->Start();
+    jit->RefreshJingleInfoNow();
+  }
+
+ private:
+  void OnJingleInfo(
+      const std::string& token,
+      const std::vector<std::string>& relay_hosts,
+      const std::vector<rtc::SocketAddress>& stun_hosts) {
+    SetRelayToken(token);
+    SetStunHosts(stun_hosts);
+    SetRelayHosts(relay_hosts);
+  }
+};
+
+#endif  // WEBRTC_P2P_CLIENT_AUTOPORTALLOCATOR_H_
diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc
new file mode 100644
index 0000000..5013a57
--- /dev/null
+++ b/p2p/client/basicportallocator.cc
@@ -0,0 +1,1190 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/client/basicportallocator.h"
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/p2p/base/stunport.h"
+#include "webrtc/p2p/base/tcpport.h"
+#include "webrtc/p2p/base/turnport.h"
+#include "webrtc/p2p/base/udpport.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+
+using rtc::CreateRandomId;
+using rtc::CreateRandomString;
+
+namespace {
+
+enum {
+  MSG_CONFIG_START,
+  MSG_CONFIG_READY,
+  MSG_ALLOCATE,
+  MSG_ALLOCATION_PHASE,
+  MSG_SHAKE,
+  MSG_SEQUENCEOBJECTS_CREATED,
+  MSG_CONFIG_STOP,
+};
+
+const int PHASE_UDP = 0;
+const int PHASE_RELAY = 1;
+const int PHASE_TCP = 2;
+const int PHASE_SSLTCP = 3;
+
+const int kNumPhases = 4;
+
+const int SHAKE_MIN_DELAY = 45 * 1000;  // 45 seconds
+const int SHAKE_MAX_DELAY = 90 * 1000;  // 90 seconds
+
+int ShakeDelay() {
+  int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1;
+  return SHAKE_MIN_DELAY + CreateRandomId() % range;
+}
+
+}  // namespace
+
+namespace cricket {
+
+const uint32 DISABLE_ALL_PHASES =
+  PORTALLOCATOR_DISABLE_UDP
+  | PORTALLOCATOR_DISABLE_TCP
+  | PORTALLOCATOR_DISABLE_STUN
+  | PORTALLOCATOR_DISABLE_RELAY;
+
+// Performs the allocation of ports, in a sequenced (timed) manner, for a given
+// network and IP address.
+class AllocationSequence : public rtc::MessageHandler,
+                           public sigslot::has_slots<> {
+ public:
+  enum State {
+    kInit,       // Initial state.
+    kRunning,    // Started allocating ports.
+    kStopped,    // Stopped from running.
+    kCompleted,  // All ports are allocated.
+
+    // kInit --> kRunning --> {kCompleted|kStopped}
+  };
+
+  AllocationSequence(BasicPortAllocatorSession* session,
+                     rtc::Network* network,
+                     PortConfiguration* config,
+                     uint32 flags);
+  ~AllocationSequence();
+  bool Init();
+  void Clear();
+
+  State state() const { return state_; }
+
+  // Disables the phases for a new sequence that this one already covers for an
+  // equivalent network setup.
+  void DisableEquivalentPhases(rtc::Network* network,
+      PortConfiguration* config, uint32* flags);
+
+  // Starts and stops the sequence.  When started, it will continue allocating
+  // new ports on its own timed schedule.
+  void Start();
+  void Stop();
+
+  // MessageHandler
+  void OnMessage(rtc::Message* msg);
+
+  void EnableProtocol(ProtocolType proto);
+  bool ProtocolEnabled(ProtocolType proto) const;
+
+  // Signal from AllocationSequence, when it's done with allocating ports.
+  // This signal is useful, when port allocation fails which doesn't result
+  // in any candidates. Using this signal BasicPortAllocatorSession can send
+  // its candidate discovery conclusion signal. Without this signal,
+  // BasicPortAllocatorSession doesn't have any event to trigger signal. This
+  // can also be achieved by starting timer in BPAS.
+  sigslot::signal1<AllocationSequence*> SignalPortAllocationComplete;
+
+ private:
+  typedef std::vector<ProtocolType> ProtocolList;
+
+  bool IsFlagSet(uint32 flag) {
+    return ((flags_ & flag) != 0);
+  }
+  void CreateUDPPorts();
+  void CreateTCPPorts();
+  void CreateStunPorts();
+  void CreateRelayPorts();
+  void CreateGturnPort(const RelayServerConfig& config);
+  void CreateTurnPort(const RelayServerConfig& config);
+
+  void OnReadPacket(rtc::AsyncPacketSocket* socket,
+                    const char* data, size_t size,
+                    const rtc::SocketAddress& remote_addr,
+                    const rtc::PacketTime& packet_time);
+
+  void OnPortDestroyed(PortInterface* port);
+
+  BasicPortAllocatorSession* session_;
+  rtc::Network* network_;
+  rtc::IPAddress ip_;
+  PortConfiguration* config_;
+  State state_;
+  uint32 flags_;
+  ProtocolList protocols_;
+  rtc::scoped_ptr<rtc::AsyncPacketSocket> udp_socket_;
+  // There will be only one udp port per AllocationSequence.
+  UDPPort* udp_port_;
+  std::vector<TurnPort*> turn_ports_;
+  int phase_;
+};
+
+// BasicPortAllocator
+BasicPortAllocator::BasicPortAllocator(
+    rtc::NetworkManager* network_manager,
+    rtc::PacketSocketFactory* socket_factory)
+    : network_manager_(network_manager),
+      socket_factory_(socket_factory) {
+  ASSERT(socket_factory_ != NULL);
+  Construct();
+}
+
+BasicPortAllocator::BasicPortAllocator(
+    rtc::NetworkManager* network_manager)
+    : network_manager_(network_manager),
+      socket_factory_(NULL) {
+  Construct();
+}
+
+BasicPortAllocator::BasicPortAllocator(
+    rtc::NetworkManager* network_manager,
+    rtc::PacketSocketFactory* socket_factory,
+    const ServerAddresses& stun_servers)
+    : network_manager_(network_manager),
+      socket_factory_(socket_factory),
+      stun_servers_(stun_servers) {
+  ASSERT(socket_factory_ != NULL);
+  Construct();
+}
+
+BasicPortAllocator::BasicPortAllocator(
+    rtc::NetworkManager* network_manager,
+    const ServerAddresses& stun_servers,
+    const rtc::SocketAddress& relay_address_udp,
+    const rtc::SocketAddress& relay_address_tcp,
+    const rtc::SocketAddress& relay_address_ssl)
+    : network_manager_(network_manager),
+      socket_factory_(NULL),
+      stun_servers_(stun_servers) {
+
+  RelayServerConfig config(RELAY_GTURN);
+  if (!relay_address_udp.IsNil())
+    config.ports.push_back(ProtocolAddress(relay_address_udp, PROTO_UDP));
+  if (!relay_address_tcp.IsNil())
+    config.ports.push_back(ProtocolAddress(relay_address_tcp, PROTO_TCP));
+  if (!relay_address_ssl.IsNil())
+    config.ports.push_back(ProtocolAddress(relay_address_ssl, PROTO_SSLTCP));
+
+  if (!config.ports.empty())
+    AddRelay(config);
+
+  Construct();
+}
+
+void BasicPortAllocator::Construct() {
+  allow_tcp_listen_ = true;
+}
+
+BasicPortAllocator::~BasicPortAllocator() {
+}
+
+PortAllocatorSession *BasicPortAllocator::CreateSessionInternal(
+    const std::string& content_name, int component,
+    const std::string& ice_ufrag, const std::string& ice_pwd) {
+  return new BasicPortAllocatorSession(
+      this, content_name, component, ice_ufrag, ice_pwd);
+}
+
+
+// BasicPortAllocatorSession
+BasicPortAllocatorSession::BasicPortAllocatorSession(
+    BasicPortAllocator *allocator,
+    const std::string& content_name,
+    int component,
+    const std::string& ice_ufrag,
+    const std::string& ice_pwd)
+    : PortAllocatorSession(content_name, component,
+                           ice_ufrag, ice_pwd, allocator->flags()),
+      allocator_(allocator), network_thread_(NULL),
+      socket_factory_(allocator->socket_factory()),
+      allocation_started_(false),
+      network_manager_started_(false),
+      running_(false),
+      allocation_sequences_created_(false) {
+  allocator_->network_manager()->SignalNetworksChanged.connect(
+      this, &BasicPortAllocatorSession::OnNetworksChanged);
+  allocator_->network_manager()->StartUpdating();
+}
+
+BasicPortAllocatorSession::~BasicPortAllocatorSession() {
+  allocator_->network_manager()->StopUpdating();
+  if (network_thread_ != NULL)
+    network_thread_->Clear(this);
+
+  for (uint32 i = 0; i < sequences_.size(); ++i) {
+    // AllocationSequence should clear it's map entry for turn ports before
+    // ports are destroyed.
+    sequences_[i]->Clear();
+  }
+
+  std::vector<PortData>::iterator it;
+  for (it = ports_.begin(); it != ports_.end(); it++)
+    delete it->port();
+
+  for (uint32 i = 0; i < configs_.size(); ++i)
+    delete configs_[i];
+
+  for (uint32 i = 0; i < sequences_.size(); ++i)
+    delete sequences_[i];
+}
+
+void BasicPortAllocatorSession::StartGettingPorts() {
+  network_thread_ = rtc::Thread::Current();
+  if (!socket_factory_) {
+    owned_socket_factory_.reset(
+        new rtc::BasicPacketSocketFactory(network_thread_));
+    socket_factory_ = owned_socket_factory_.get();
+  }
+
+  running_ = true;
+  network_thread_->Post(this, MSG_CONFIG_START);
+
+  if (flags() & PORTALLOCATOR_ENABLE_SHAKER)
+    network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
+}
+
+void BasicPortAllocatorSession::StopGettingPorts() {
+  ASSERT(rtc::Thread::Current() == network_thread_);
+  running_ = false;
+  network_thread_->Clear(this, MSG_ALLOCATE);
+  for (uint32 i = 0; i < sequences_.size(); ++i)
+    sequences_[i]->Stop();
+  network_thread_->Post(this, MSG_CONFIG_STOP);
+}
+
+void BasicPortAllocatorSession::OnMessage(rtc::Message *message) {
+  switch (message->message_id) {
+  case MSG_CONFIG_START:
+    ASSERT(rtc::Thread::Current() == network_thread_);
+    GetPortConfigurations();
+    break;
+
+  case MSG_CONFIG_READY:
+    ASSERT(rtc::Thread::Current() == network_thread_);
+    OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
+    break;
+
+  case MSG_ALLOCATE:
+    ASSERT(rtc::Thread::Current() == network_thread_);
+    OnAllocate();
+    break;
+
+  case MSG_SHAKE:
+    ASSERT(rtc::Thread::Current() == network_thread_);
+    OnShake();
+    break;
+  case MSG_SEQUENCEOBJECTS_CREATED:
+    ASSERT(rtc::Thread::Current() == network_thread_);
+    OnAllocationSequenceObjectsCreated();
+    break;
+  case MSG_CONFIG_STOP:
+    ASSERT(rtc::Thread::Current() == network_thread_);
+    OnConfigStop();
+    break;
+  default:
+    ASSERT(false);
+  }
+}
+
+void BasicPortAllocatorSession::GetPortConfigurations() {
+  PortConfiguration* config = new PortConfiguration(allocator_->stun_servers(),
+                                                    username(),
+                                                    password());
+
+  for (size_t i = 0; i < allocator_->relays().size(); ++i) {
+    config->AddRelay(allocator_->relays()[i]);
+  }
+  ConfigReady(config);
+}
+
+void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
+  network_thread_->Post(this, MSG_CONFIG_READY, config);
+}
+
+// Adds a configuration to the list.
+void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
+  if (config)
+    configs_.push_back(config);
+
+  AllocatePorts();
+}
+
+void BasicPortAllocatorSession::OnConfigStop() {
+  ASSERT(rtc::Thread::Current() == network_thread_);
+
+  // If any of the allocated ports have not completed the candidates allocation,
+  // mark those as error. Since session doesn't need any new candidates
+  // at this stage of the allocation, it's safe to discard any new candidates.
+  bool send_signal = false;
+  for (std::vector<PortData>::iterator it = ports_.begin();
+       it != ports_.end(); ++it) {
+    if (!it->complete()) {
+      // Updating port state to error, which didn't finish allocating candidates
+      // yet.
+      it->set_error();
+      send_signal = true;
+    }
+  }
+
+  // Did we stop any running sequences?
+  for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
+       it != sequences_.end() && !send_signal; ++it) {
+    if ((*it)->state() == AllocationSequence::kStopped) {
+      send_signal = true;
+    }
+  }
+
+  // If we stopped anything that was running, send a done signal now.
+  if (send_signal) {
+    MaybeSignalCandidatesAllocationDone();
+  }
+}
+
+void BasicPortAllocatorSession::AllocatePorts() {
+  ASSERT(rtc::Thread::Current() == network_thread_);
+  network_thread_->Post(this, MSG_ALLOCATE);
+}
+
+void BasicPortAllocatorSession::OnAllocate() {
+  if (network_manager_started_)
+    DoAllocate();
+
+  allocation_started_ = true;
+}
+
+// For each network, see if we have a sequence that covers it already.  If not,
+// create a new sequence to create the appropriate ports.
+void BasicPortAllocatorSession::DoAllocate() {
+  bool done_signal_needed = false;
+  std::vector<rtc::Network*> networks;
+  allocator_->network_manager()->GetNetworks(&networks);
+  if (networks.empty()) {
+    LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated";
+    done_signal_needed = true;
+  } else {
+    for (uint32 i = 0; i < networks.size(); ++i) {
+      PortConfiguration* config = NULL;
+      if (configs_.size() > 0)
+        config = configs_.back();
+
+      uint32 sequence_flags = flags();
+      if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
+        // If all the ports are disabled we should just fire the allocation
+        // done event and return.
+        done_signal_needed = true;
+        break;
+      }
+
+      // Disables phases that are not specified in this config.
+      if (!config || config->StunServers().empty()) {
+        // No STUN ports specified in this config.
+        sequence_flags |= PORTALLOCATOR_DISABLE_STUN;
+      }
+      if (!config || config->relays.empty()) {
+        // No relay ports specified in this config.
+        sequence_flags |= PORTALLOCATOR_DISABLE_RELAY;
+      }
+
+      if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) &&
+#ifdef USE_WEBRTC_DEV_BRANCH
+          networks[i]->GetBestIP().family() == AF_INET6) {
+#else  // USE_WEBRTC_DEV_BRANCH
+          networks[i]->ip().family() == AF_INET6) {
+#endif  // USE_WEBRTC_DEV_BRANCH
+        // Skip IPv6 networks unless the flag's been set.
+        continue;
+      }
+
+      // Disable phases that would only create ports equivalent to
+      // ones that we have already made.
+      DisableEquivalentPhases(networks[i], config, &sequence_flags);
+
+      if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) {
+        // New AllocationSequence would have nothing to do, so don't make it.
+        continue;
+      }
+
+      AllocationSequence* sequence =
+          new AllocationSequence(this, networks[i], config, sequence_flags);
+      if (!sequence->Init()) {
+        delete sequence;
+        continue;
+      }
+      done_signal_needed = true;
+      sequence->SignalPortAllocationComplete.connect(
+          this, &BasicPortAllocatorSession::OnPortAllocationComplete);
+      if (running_)
+        sequence->Start();
+      sequences_.push_back(sequence);
+    }
+  }
+  if (done_signal_needed) {
+    network_thread_->Post(this, MSG_SEQUENCEOBJECTS_CREATED);
+  }
+}
+
+void BasicPortAllocatorSession::OnNetworksChanged() {
+  network_manager_started_ = true;
+  if (allocation_started_)
+    DoAllocate();
+}
+
+void BasicPortAllocatorSession::DisableEquivalentPhases(
+    rtc::Network* network, PortConfiguration* config, uint32* flags) {
+  for (uint32 i = 0; i < sequences_.size() &&
+      (*flags & DISABLE_ALL_PHASES) != DISABLE_ALL_PHASES; ++i) {
+    sequences_[i]->DisableEquivalentPhases(network, config, flags);
+  }
+}
+
+void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
+                                                 AllocationSequence * seq,
+                                                 bool prepare_address) {
+  if (!port)
+    return;
+
+  LOG(LS_INFO) << "Adding allocated port for " << content_name();
+  port->set_content_name(content_name());
+  port->set_component(component_);
+  port->set_generation(generation());
+  if (allocator_->proxy().type != rtc::PROXY_NONE)
+    port->set_proxy(allocator_->user_agent(), allocator_->proxy());
+  port->set_send_retransmit_count_attribute((allocator_->flags() &
+      PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
+
+  // Push down the candidate_filter to individual port.
+  port->set_candidate_filter(allocator_->candidate_filter());
+
+  PortData data(port, seq);
+  ports_.push_back(data);
+
+  port->SignalCandidateReady.connect(
+      this, &BasicPortAllocatorSession::OnCandidateReady);
+  port->SignalPortComplete.connect(this,
+      &BasicPortAllocatorSession::OnPortComplete);
+  port->SignalDestroyed.connect(this,
+      &BasicPortAllocatorSession::OnPortDestroyed);
+  port->SignalPortError.connect(
+      this, &BasicPortAllocatorSession::OnPortError);
+  LOG_J(LS_INFO, port) << "Added port to allocator";
+
+  if (prepare_address)
+    port->PrepareAddress();
+}
+
+void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() {
+  allocation_sequences_created_ = true;
+  // Send candidate allocation complete signal if we have no sequences.
+  MaybeSignalCandidatesAllocationDone();
+}
+
+void BasicPortAllocatorSession::OnCandidateReady(
+    Port* port, const Candidate& c) {
+  ASSERT(rtc::Thread::Current() == network_thread_);
+  PortData* data = FindPort(port);
+  ASSERT(data != NULL);
+  // Discarding any candidate signal if port allocation status is
+  // already in completed state.
+  if (data->complete())
+    return;
+
+  // Send candidates whose protocol is enabled.
+  std::vector<Candidate> candidates;
+  ProtocolType pvalue;
+  bool candidate_allowed_to_send = CheckCandidateFilter(c);
+  if (StringToProto(c.protocol().c_str(), &pvalue) &&
+      data->sequence()->ProtocolEnabled(pvalue) &&
+      candidate_allowed_to_send) {
+    candidates.push_back(c);
+  }
+
+  if (!candidates.empty()) {
+    SignalCandidatesReady(this, candidates);
+  }
+
+  // Moving to READY state as we have atleast one candidate from the port.
+  // Since this port has atleast one candidate we should forward this port
+  // to listners, to allow connections from this port.
+  // Also we should make sure that candidate gathered from this port is allowed
+  // to send outside.
+  if (!data->ready() && candidate_allowed_to_send) {
+    data->set_ready();
+    SignalPortReady(this, port);
+  }
+}
+
+void BasicPortAllocatorSession::OnPortComplete(Port* port) {
+  ASSERT(rtc::Thread::Current() == network_thread_);
+  PortData* data = FindPort(port);
+  ASSERT(data != NULL);
+
+  // Ignore any late signals.
+  if (data->complete())
+    return;
+
+  // Moving to COMPLETE state.
+  data->set_complete();
+  // Send candidate allocation complete signal if this was the last port.
+  MaybeSignalCandidatesAllocationDone();
+}
+
+void BasicPortAllocatorSession::OnPortError(Port* port) {
+  ASSERT(rtc::Thread::Current() == network_thread_);
+  PortData* data = FindPort(port);
+  ASSERT(data != NULL);
+  // We might have already given up on this port and stopped it.
+  if (data->complete())
+    return;
+
+  // SignalAddressError is currently sent from StunPort/TurnPort.
+  // But this signal itself is generic.
+  data->set_error();
+  // Send candidate allocation complete signal if this was the last port.
+  MaybeSignalCandidatesAllocationDone();
+}
+
+void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq,
+                                                  ProtocolType proto) {
+  std::vector<Candidate> candidates;
+  for (std::vector<PortData>::iterator it = ports_.begin();
+       it != ports_.end(); ++it) {
+    if (it->sequence() != seq)
+      continue;
+
+    const std::vector<Candidate>& potentials = it->port()->Candidates();
+    for (size_t i = 0; i < potentials.size(); ++i) {
+      if (!CheckCandidateFilter(potentials[i]))
+        continue;
+      ProtocolType pvalue;
+      if (!StringToProto(potentials[i].protocol().c_str(), &pvalue))
+        continue;
+      if (pvalue == proto) {
+        candidates.push_back(potentials[i]);
+      }
+    }
+  }
+
+  if (!candidates.empty()) {
+    SignalCandidatesReady(this, candidates);
+  }
+}
+
+bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) {
+  uint32 filter = allocator_->candidate_filter();
+  bool allowed = false;
+  if (filter & CF_RELAY) {
+    allowed |= (c.type() == RELAY_PORT_TYPE);
+  }
+
+  if (filter & CF_REFLEXIVE) {
+    // We allow host candidates if the filter allows server-reflexive candidates
+    // and the candidate is a public IP. Because we don't generate
+    // server-reflexive candidates if they have the same IP as the host
+    // candidate (i.e. when the host candidate is a public IP), filtering to
+    // only server-reflexive candidates won't work right when the host
+    // candidates have public IPs.
+    allowed |= (c.type() == STUN_PORT_TYPE) ||
+               (c.type() == LOCAL_PORT_TYPE && !c.address().IsPrivateIP());
+  }
+
+  if (filter & CF_HOST) {
+    allowed |= (c.type() == LOCAL_PORT_TYPE);
+  }
+
+  return allowed;
+}
+
+void BasicPortAllocatorSession::OnPortAllocationComplete(
+    AllocationSequence* seq) {
+  // Send candidate allocation complete signal if all ports are done.
+  MaybeSignalCandidatesAllocationDone();
+}
+
+void BasicPortAllocatorSession::MaybeSignalCandidatesAllocationDone() {
+  // Send signal only if all required AllocationSequence objects
+  // are created.
+  if (!allocation_sequences_created_)
+    return;
+
+  // Check that all port allocation sequences are complete.
+  for (std::vector<AllocationSequence*>::iterator it = sequences_.begin();
+       it != sequences_.end(); ++it) {
+    if ((*it)->state() == AllocationSequence::kRunning)
+      return;
+  }
+
+  // If all allocated ports are in complete state, session must have got all
+  // expected candidates. Session will trigger candidates allocation complete
+  // signal.
+  for (std::vector<PortData>::iterator it = ports_.begin();
+       it != ports_.end(); ++it) {
+    if (!it->complete())
+      return;
+  }
+  LOG(LS_INFO) << "All candidates gathered for " << content_name_ << ":"
+               << component_ << ":" << generation();
+  SignalCandidatesAllocationDone(this);
+}
+
+void BasicPortAllocatorSession::OnPortDestroyed(
+    PortInterface* port) {
+  ASSERT(rtc::Thread::Current() == network_thread_);
+  for (std::vector<PortData>::iterator iter = ports_.begin();
+       iter != ports_.end(); ++iter) {
+    if (port == iter->port()) {
+      ports_.erase(iter);
+      LOG_J(LS_INFO, port) << "Removed port from allocator ("
+                           << static_cast<int>(ports_.size()) << " remaining)";
+      return;
+    }
+  }
+  ASSERT(false);
+}
+
+void BasicPortAllocatorSession::OnShake() {
+  LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<";
+
+  std::vector<Port*> ports;
+  std::vector<Connection*> connections;
+
+  for (size_t i = 0; i < ports_.size(); ++i) {
+    if (ports_[i].ready())
+      ports.push_back(ports_[i].port());
+  }
+
+  for (size_t i = 0; i < ports.size(); ++i) {
+    Port::AddressMap::const_iterator iter;
+    for (iter = ports[i]->connections().begin();
+         iter != ports[i]->connections().end();
+         ++iter) {
+      connections.push_back(iter->second);
+    }
+  }
+
+  LOG(INFO) << ">>>>> Destroying " << ports.size() << " ports and "
+            << connections.size() << " connections";
+
+  for (size_t i = 0; i < connections.size(); ++i)
+    connections[i]->Destroy();
+
+  if (running_ || (ports.size() > 0) || (connections.size() > 0))
+    network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE);
+}
+
+BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort(
+    Port* port) {
+  for (std::vector<PortData>::iterator it = ports_.begin();
+       it != ports_.end(); ++it) {
+    if (it->port() == port) {
+      return &*it;
+    }
+  }
+  return NULL;
+}
+
+// AllocationSequence
+
+AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
+                                       rtc::Network* network,
+                                       PortConfiguration* config,
+                                       uint32 flags)
+    : session_(session),
+      network_(network),
+
+#ifdef USE_WEBRTC_DEV_BRANCH
+      ip_(network->GetBestIP()),
+#else  // USE_WEBRTC_DEV_BRANCH
+      ip_(network->ip()),
+#endif  // USE_WEBRTC_DEV_BRANCH
+      config_(config),
+      state_(kInit),
+      flags_(flags),
+      udp_socket_(),
+      udp_port_(NULL),
+      phase_(0) {
+}
+
+bool AllocationSequence::Init() {
+  if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
+      !IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_UFRAG)) {
+    LOG(LS_ERROR) << "Shared socket option can't be set without "
+                  << "shared ufrag.";
+    ASSERT(false);
+    return false;
+  }
+
+  if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
+    udp_socket_.reset(session_->socket_factory()->CreateUdpSocket(
+        rtc::SocketAddress(ip_, 0), session_->allocator()->min_port(),
+        session_->allocator()->max_port()));
+    if (udp_socket_) {
+      udp_socket_->SignalReadPacket.connect(
+          this, &AllocationSequence::OnReadPacket);
+    }
+    // Continuing if |udp_socket_| is NULL, as local TCP and RelayPort using TCP
+    // are next available options to setup a communication channel.
+  }
+  return true;
+}
+
+void AllocationSequence::Clear() {
+  udp_port_ = NULL;
+  turn_ports_.clear();
+}
+
+AllocationSequence::~AllocationSequence() {
+  session_->network_thread()->Clear(this);
+}
+
+void AllocationSequence::DisableEquivalentPhases(rtc::Network* network,
+    PortConfiguration* config, uint32* flags) {
+#ifdef USE_WEBRTC_DEV_BRANCH
+  if (!((network == network_) && (ip_ == network->GetBestIP()))) {
+#else  // USE_WEBRTC_DEV_BRANCH
+  if (!((network == network_) && (ip_ == network->ip()))) {
+#endif  // USE_WEBRTC_DEV_BRANCH
+    // Different network setup; nothing is equivalent.
+    return;
+  }
+
+  // Else turn off the stuff that we've already got covered.
+
+  // Every config implicitly specifies local, so turn that off right away.
+  *flags |= PORTALLOCATOR_DISABLE_UDP;
+  *flags |= PORTALLOCATOR_DISABLE_TCP;
+
+  if (config_ && config) {
+    if (config_->StunServers() == config->StunServers()) {
+      // Already got this STUN servers covered.
+      *flags |= PORTALLOCATOR_DISABLE_STUN;
+    }
+    if (!config_->relays.empty()) {
+      // Already got relays covered.
+      // NOTE: This will even skip a _different_ set of relay servers if we
+      // were to be given one, but that never happens in our codebase. Should
+      // probably get rid of the list in PortConfiguration and just keep a
+      // single relay server in each one.
+      *flags |= PORTALLOCATOR_DISABLE_RELAY;
+    }
+  }
+}
+
+void AllocationSequence::Start() {
+  state_ = kRunning;
+  session_->network_thread()->Post(this, MSG_ALLOCATION_PHASE);
+}
+
+void AllocationSequence::Stop() {
+  // If the port is completed, don't set it to stopped.
+  if (state_ == kRunning) {
+    state_ = kStopped;
+    session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
+  }
+}
+
+void AllocationSequence::OnMessage(rtc::Message* msg) {
+  ASSERT(rtc::Thread::Current() == session_->network_thread());
+  ASSERT(msg->message_id == MSG_ALLOCATION_PHASE);
+
+  const char* const PHASE_NAMES[kNumPhases] = {
+    "Udp", "Relay", "Tcp", "SslTcp"
+  };
+
+  // Perform all of the phases in the current step.
+  LOG_J(LS_INFO, network_) << "Allocation Phase="
+                           << PHASE_NAMES[phase_];
+
+  switch (phase_) {
+    case PHASE_UDP:
+      CreateUDPPorts();
+      CreateStunPorts();
+      EnableProtocol(PROTO_UDP);
+      break;
+
+    case PHASE_RELAY:
+      CreateRelayPorts();
+      break;
+
+    case PHASE_TCP:
+      CreateTCPPorts();
+      EnableProtocol(PROTO_TCP);
+      break;
+
+    case PHASE_SSLTCP:
+      state_ = kCompleted;
+      EnableProtocol(PROTO_SSLTCP);
+      break;
+
+    default:
+      ASSERT(false);
+  }
+
+  if (state() == kRunning) {
+    ++phase_;
+    session_->network_thread()->PostDelayed(
+        session_->allocator()->step_delay(),
+        this, MSG_ALLOCATION_PHASE);
+  } else {
+    // If all phases in AllocationSequence are completed, no allocation
+    // steps needed further. Canceling  pending signal.
+    session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
+    SignalPortAllocationComplete(this);
+  }
+}
+
+void AllocationSequence::EnableProtocol(ProtocolType proto) {
+  if (!ProtocolEnabled(proto)) {
+    protocols_.push_back(proto);
+    session_->OnProtocolEnabled(this, proto);
+  }
+}
+
+bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const {
+  for (ProtocolList::const_iterator it = protocols_.begin();
+       it != protocols_.end(); ++it) {
+    if (*it == proto)
+      return true;
+  }
+  return false;
+}
+
+void AllocationSequence::CreateUDPPorts() {
+  if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP)) {
+    LOG(LS_VERBOSE) << "AllocationSequence: UDP ports disabled, skipping.";
+    return;
+  }
+
+  // TODO(mallinath) - Remove UDPPort creating socket after shared socket
+  // is enabled completely.
+  UDPPort* port = NULL;
+  if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
+    port = UDPPort::Create(session_->network_thread(),
+                           session_->socket_factory(), network_,
+                           udp_socket_.get(),
+                           session_->username(), session_->password());
+  } else {
+    port = UDPPort::Create(session_->network_thread(),
+                           session_->socket_factory(),
+                           network_, ip_,
+                           session_->allocator()->min_port(),
+                           session_->allocator()->max_port(),
+                           session_->username(), session_->password());
+  }
+
+  if (port) {
+    // If shared socket is enabled, STUN candidate will be allocated by the
+    // UDPPort.
+    if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
+      udp_port_ = port;
+
+      // If STUN is not disabled, setting stun server address to port.
+      if (!IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
+        // If config has stun_servers, use it to get server reflexive candidate
+        // otherwise use first TURN server which supports UDP.
+        if (config_ && !config_->StunServers().empty()) {
+          LOG(LS_INFO) << "AllocationSequence: UDPPort will be handling the "
+                       <<  "STUN candidate generation.";
+          port->set_server_addresses(config_->StunServers());
+        } else if (config_ &&
+                   config_->SupportsProtocol(RELAY_TURN, PROTO_UDP)) {
+          port->set_server_addresses(config_->GetRelayServerAddresses(
+              RELAY_TURN, PROTO_UDP));
+          LOG(LS_INFO) << "AllocationSequence: TURN Server address will be "
+                       << " used for generating STUN candidate.";
+        }
+      }
+    }
+
+    session_->AddAllocatedPort(port, this, true);
+    port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
+  }
+}
+
+void AllocationSequence::CreateTCPPorts() {
+  if (IsFlagSet(PORTALLOCATOR_DISABLE_TCP)) {
+    LOG(LS_VERBOSE) << "AllocationSequence: TCP ports disabled, skipping.";
+    return;
+  }
+
+  Port* port = TCPPort::Create(session_->network_thread(),
+                               session_->socket_factory(),
+                               network_, ip_,
+                               session_->allocator()->min_port(),
+                               session_->allocator()->max_port(),
+                               session_->username(), session_->password(),
+                               session_->allocator()->allow_tcp_listen());
+  if (port) {
+    session_->AddAllocatedPort(port, this, true);
+    // Since TCPPort is not created using shared socket, |port| will not be
+    // added to the dequeue.
+  }
+}
+
+void AllocationSequence::CreateStunPorts() {
+  if (IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
+    LOG(LS_VERBOSE) << "AllocationSequence: STUN ports disabled, skipping.";
+    return;
+  }
+
+  if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
+    return;
+  }
+
+  // If BasicPortAllocatorSession::OnAllocate left STUN ports enabled then we
+  // ought to have an address for them here.
+  ASSERT(config_ && !config_->StunServers().empty());
+  if (!(config_ && !config_->StunServers().empty())) {
+    LOG(LS_WARNING)
+        << "AllocationSequence: No STUN server configured, skipping.";
+    return;
+  }
+
+  StunPort* port = StunPort::Create(session_->network_thread(),
+                                session_->socket_factory(),
+                                network_, ip_,
+                                session_->allocator()->min_port(),
+                                session_->allocator()->max_port(),
+                                session_->username(), session_->password(),
+                                config_->StunServers());
+  if (port) {
+    session_->AddAllocatedPort(port, this, true);
+    // Since StunPort is not created using shared socket, |port| will not be
+    // added to the dequeue.
+  }
+}
+
+void AllocationSequence::CreateRelayPorts() {
+  if (IsFlagSet(PORTALLOCATOR_DISABLE_RELAY)) {
+     LOG(LS_VERBOSE) << "AllocationSequence: Relay ports disabled, skipping.";
+     return;
+  }
+
+  // If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we
+  // ought to have a relay list for them here.
+  ASSERT(config_ && !config_->relays.empty());
+  if (!(config_ && !config_->relays.empty())) {
+    LOG(LS_WARNING)
+        << "AllocationSequence: No relay server configured, skipping.";
+    return;
+  }
+
+  PortConfiguration::RelayList::const_iterator relay;
+  for (relay = config_->relays.begin();
+       relay != config_->relays.end(); ++relay) {
+    if (relay->type == RELAY_GTURN) {
+      CreateGturnPort(*relay);
+    } else if (relay->type == RELAY_TURN) {
+      CreateTurnPort(*relay);
+    } else {
+      ASSERT(false);
+    }
+  }
+}
+
+void AllocationSequence::CreateGturnPort(const RelayServerConfig& config) {
+  // TODO(mallinath) - Rename RelayPort to GTurnPort.
+  RelayPort* port = RelayPort::Create(session_->network_thread(),
+                                      session_->socket_factory(),
+                                      network_, ip_,
+                                      session_->allocator()->min_port(),
+                                      session_->allocator()->max_port(),
+                                      config_->username, config_->password);
+  if (port) {
+    // Since RelayPort is not created using shared socket, |port| will not be
+    // added to the dequeue.
+    // Note: We must add the allocated port before we add addresses because
+    //       the latter will create candidates that need name and preference
+    //       settings.  However, we also can't prepare the address (normally
+    //       done by AddAllocatedPort) until we have these addresses.  So we
+    //       wait to do that until below.
+    session_->AddAllocatedPort(port, this, false);
+
+    // Add the addresses of this protocol.
+    PortList::const_iterator relay_port;
+    for (relay_port = config.ports.begin();
+         relay_port != config.ports.end();
+         ++relay_port) {
+      port->AddServerAddress(*relay_port);
+      port->AddExternalAddress(*relay_port);
+    }
+    // Start fetching an address for this port.
+    port->PrepareAddress();
+  }
+}
+
+void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
+  PortList::const_iterator relay_port;
+  for (relay_port = config.ports.begin();
+       relay_port != config.ports.end(); ++relay_port) {
+    TurnPort* port = NULL;
+    // Shared socket mode must be enabled only for UDP based ports. Hence
+    // don't pass shared socket for ports which will create TCP sockets.
+    // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled
+    // due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537
+    if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
+        relay_port->proto == PROTO_UDP) {
+      port = TurnPort::Create(session_->network_thread(),
+                              session_->socket_factory(),
+                              network_, udp_socket_.get(),
+                              session_->username(), session_->password(),
+                              *relay_port, config.credentials, config.priority);
+
+      turn_ports_.push_back(port);
+      // Listen to the port destroyed signal, to allow AllocationSequence to
+      // remove entrt from it's map.
+      port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
+    } else {
+      port = TurnPort::Create(session_->network_thread(),
+                              session_->socket_factory(),
+                              network_, ip_,
+                              session_->allocator()->min_port(),
+                              session_->allocator()->max_port(),
+                              session_->username(),
+                              session_->password(),
+                              *relay_port, config.credentials, config.priority);
+    }
+    ASSERT(port != NULL);
+    session_->AddAllocatedPort(port, this, true);
+  }
+}
+
+void AllocationSequence::OnReadPacket(
+    rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time) {
+  ASSERT(socket == udp_socket_.get());
+
+  bool turn_port_found = false;
+
+  // Try to find the TurnPort that matches the remote address. Note that the
+  // message could be a STUN binding response if the TURN server is also used as
+  // a STUN server. We don't want to parse every message here to check if it is
+  // a STUN binding response, so we pass the message to TurnPort regardless of
+  // the message type. The TurnPort will just ignore the message since it will
+  // not find any request by transaction ID.
+  for (std::vector<TurnPort*>::const_iterator it = turn_ports_.begin();
+       it != turn_ports_.end(); ++it) {
+    TurnPort* port = *it;
+    if (port->server_address().address == remote_addr) {
+      port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time);
+      turn_port_found = true;
+      break;
+    }
+  }
+
+  if (udp_port_) {
+    const ServerAddresses& stun_servers = udp_port_->server_addresses();
+
+    // Pass the packet to the UdpPort if there is no matching TurnPort, or if
+    // the TURN server is also a STUN server.
+    if (!turn_port_found ||
+        stun_servers.find(remote_addr) != stun_servers.end()) {
+      udp_port_->HandleIncomingPacket(
+          socket, data, size, remote_addr, packet_time);
+    }
+  }
+}
+
+void AllocationSequence::OnPortDestroyed(PortInterface* port) {
+  if (udp_port_ == port) {
+    udp_port_ = NULL;
+    return;
+  }
+
+  turn_ports_.erase(std::find(turn_ports_.begin(), turn_ports_.end(), port));
+}
+
+// PortConfiguration
+PortConfiguration::PortConfiguration(
+    const rtc::SocketAddress& stun_address,
+    const std::string& username,
+    const std::string& password)
+    : stun_address(stun_address), username(username), password(password) {
+  if (!stun_address.IsNil())
+    stun_servers.insert(stun_address);
+}
+
+PortConfiguration::PortConfiguration(const ServerAddresses& stun_servers,
+                                     const std::string& username,
+                                     const std::string& password)
+    : stun_servers(stun_servers),
+      username(username),
+      password(password) {
+  if (!stun_servers.empty())
+    stun_address = *(stun_servers.begin());
+}
+
+ServerAddresses PortConfiguration::StunServers() {
+  if (!stun_address.IsNil() &&
+      stun_servers.find(stun_address) == stun_servers.end()) {
+    stun_servers.insert(stun_address);
+  }
+  return stun_servers;
+}
+
+void PortConfiguration::AddRelay(const RelayServerConfig& config) {
+  relays.push_back(config);
+}
+
+bool PortConfiguration::SupportsProtocol(
+    const RelayServerConfig& relay, ProtocolType type) const {
+  PortList::const_iterator relay_port;
+  for (relay_port = relay.ports.begin();
+        relay_port != relay.ports.end();
+        ++relay_port) {
+    if (relay_port->proto == type)
+      return true;
+  }
+  return false;
+}
+
+bool PortConfiguration::SupportsProtocol(RelayType turn_type,
+                                         ProtocolType type) const {
+  for (size_t i = 0; i < relays.size(); ++i) {
+    if (relays[i].type == turn_type &&
+        SupportsProtocol(relays[i], type))
+      return true;
+  }
+  return false;
+}
+
+ServerAddresses PortConfiguration::GetRelayServerAddresses(
+    RelayType turn_type, ProtocolType type) const {
+  ServerAddresses servers;
+  for (size_t i = 0; i < relays.size(); ++i) {
+    if (relays[i].type == turn_type && SupportsProtocol(relays[i], type)) {
+      servers.insert(relays[i].ports.front().address);
+    }
+  }
+  return servers;
+}
+
+}  // namespace cricket
diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h
new file mode 100644
index 0000000..96468d3
--- /dev/null
+++ b/p2p/client/basicportallocator.h
@@ -0,0 +1,241 @@
+/*
+ *  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_P2P_CLIENT_BASICPORTALLOCATOR_H_
+#define WEBRTC_P2P_CLIENT_BASICPORTALLOCATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/base/messagequeue.h"
+#include "webrtc/base/network.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+struct RelayCredentials {
+  RelayCredentials() {}
+  RelayCredentials(const std::string& username,
+                   const std::string& password)
+      : username(username),
+        password(password) {
+  }
+
+  std::string username;
+  std::string password;
+};
+
+typedef std::vector<ProtocolAddress> PortList;
+struct RelayServerConfig {
+  RelayServerConfig(RelayType type) : type(type), priority(0) {}
+
+  RelayType type;
+  PortList ports;
+  RelayCredentials credentials;
+  int priority;
+};
+
+class BasicPortAllocator : public PortAllocator {
+ public:
+  BasicPortAllocator(rtc::NetworkManager* network_manager,
+                     rtc::PacketSocketFactory* socket_factory);
+  explicit BasicPortAllocator(rtc::NetworkManager* network_manager);
+  BasicPortAllocator(rtc::NetworkManager* network_manager,
+                     rtc::PacketSocketFactory* socket_factory,
+                     const ServerAddresses& stun_servers);
+  BasicPortAllocator(rtc::NetworkManager* network_manager,
+                     const ServerAddresses& stun_servers,
+                     const rtc::SocketAddress& relay_server_udp,
+                     const rtc::SocketAddress& relay_server_tcp,
+                     const rtc::SocketAddress& relay_server_ssl);
+  virtual ~BasicPortAllocator();
+
+  rtc::NetworkManager* network_manager() { return network_manager_; }
+
+  // If socket_factory() is set to NULL each PortAllocatorSession
+  // creates its own socket factory.
+  rtc::PacketSocketFactory* socket_factory() { return socket_factory_; }
+
+  const ServerAddresses& stun_servers() const {
+    return stun_servers_;
+  }
+
+  const std::vector<RelayServerConfig>& relays() const {
+    return relays_;
+  }
+  virtual void AddRelay(const RelayServerConfig& relay) {
+    relays_.push_back(relay);
+  }
+
+  virtual PortAllocatorSession* CreateSessionInternal(
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd);
+
+ private:
+  void Construct();
+
+  rtc::NetworkManager* network_manager_;
+  rtc::PacketSocketFactory* socket_factory_;
+  const ServerAddresses stun_servers_;
+  std::vector<RelayServerConfig> relays_;
+  bool allow_tcp_listen_;
+};
+
+struct PortConfiguration;
+class AllocationSequence;
+
+class BasicPortAllocatorSession : public PortAllocatorSession,
+                                  public rtc::MessageHandler {
+ public:
+  BasicPortAllocatorSession(BasicPortAllocator* allocator,
+                            const std::string& content_name,
+                            int component,
+                            const std::string& ice_ufrag,
+                            const std::string& ice_pwd);
+  ~BasicPortAllocatorSession();
+
+  virtual BasicPortAllocator* allocator() { return allocator_; }
+  rtc::Thread* network_thread() { return network_thread_; }
+  rtc::PacketSocketFactory* socket_factory() { return socket_factory_; }
+
+  virtual void StartGettingPorts();
+  virtual void StopGettingPorts();
+  virtual bool IsGettingPorts() { return running_; }
+
+ protected:
+  // Starts the process of getting the port configurations.
+  virtual void GetPortConfigurations();
+
+  // Adds a port configuration that is now ready.  Once we have one for each
+  // network (or a timeout occurs), we will start allocating ports.
+  virtual void ConfigReady(PortConfiguration* config);
+
+  // MessageHandler.  Can be overriden if message IDs do not conflict.
+  virtual void OnMessage(rtc::Message *message);
+
+ private:
+  class PortData {
+   public:
+    PortData() : port_(NULL), sequence_(NULL), state_(STATE_INIT) {}
+    PortData(Port* port, AllocationSequence* seq)
+    : port_(port), sequence_(seq), state_(STATE_INIT) {
+    }
+
+    Port* port() { return port_; }
+    AllocationSequence* sequence() { return sequence_; }
+    bool ready() const { return state_ == STATE_READY; }
+    bool complete() const {
+      // Returns true if candidate allocation has completed one way or another.
+      return ((state_ == STATE_COMPLETE) || (state_ == STATE_ERROR));
+    }
+
+    void set_ready() { ASSERT(state_ == STATE_INIT); state_ = STATE_READY; }
+    void set_complete() {
+      state_ = STATE_COMPLETE;
+    }
+    void set_error() {
+      ASSERT(state_ == STATE_INIT || state_ == STATE_READY);
+      state_ = STATE_ERROR;
+    }
+
+   private:
+    enum State {
+      STATE_INIT,      // No candidates allocated yet.
+      STATE_READY,     // At least one candidate is ready for process.
+      STATE_COMPLETE,  // All candidates allocated and ready for process.
+      STATE_ERROR      // Error in gathering candidates.
+    };
+    Port* port_;
+    AllocationSequence* sequence_;
+    State state_;
+  };
+
+  void OnConfigReady(PortConfiguration* config);
+  void OnConfigStop();
+  void AllocatePorts();
+  void OnAllocate();
+  void DoAllocate();
+  void OnNetworksChanged();
+  void OnAllocationSequenceObjectsCreated();
+  void DisableEquivalentPhases(rtc::Network* network,
+                               PortConfiguration* config, uint32* flags);
+  void AddAllocatedPort(Port* port, AllocationSequence* seq,
+                        bool prepare_address);
+  void OnCandidateReady(Port* port, const Candidate& c);
+  void OnPortComplete(Port* port);
+  void OnPortError(Port* port);
+  void OnProtocolEnabled(AllocationSequence* seq, ProtocolType proto);
+  void OnPortDestroyed(PortInterface* port);
+  void OnShake();
+  void MaybeSignalCandidatesAllocationDone();
+  void OnPortAllocationComplete(AllocationSequence* seq);
+  PortData* FindPort(Port* port);
+
+  bool CheckCandidateFilter(const Candidate& c);
+
+  BasicPortAllocator* allocator_;
+  rtc::Thread* network_thread_;
+  rtc::scoped_ptr<rtc::PacketSocketFactory> owned_socket_factory_;
+  rtc::PacketSocketFactory* socket_factory_;
+  bool allocation_started_;
+  bool network_manager_started_;
+  bool running_;  // set when StartGetAllPorts is called
+  bool allocation_sequences_created_;
+  std::vector<PortConfiguration*> configs_;
+  std::vector<AllocationSequence*> sequences_;
+  std::vector<PortData> ports_;
+
+  friend class AllocationSequence;
+};
+
+// Records configuration information useful in creating ports.
+struct PortConfiguration : public rtc::MessageData {
+  // TODO(jiayl): remove |stun_address| when Chrome is updated.
+  rtc::SocketAddress stun_address;
+  ServerAddresses stun_servers;
+  std::string username;
+  std::string password;
+
+  typedef std::vector<RelayServerConfig> RelayList;
+  RelayList relays;
+
+  // TODO(jiayl): remove this ctor when Chrome is updated.
+  PortConfiguration(const rtc::SocketAddress& stun_address,
+                    const std::string& username,
+                    const std::string& password);
+
+  PortConfiguration(const ServerAddresses& stun_servers,
+                    const std::string& username,
+                    const std::string& password);
+
+  // TODO(jiayl): remove when |stun_address| is removed.
+  ServerAddresses StunServers();
+
+  // Adds another relay server, with the given ports and modifier, to the list.
+  void AddRelay(const RelayServerConfig& config);
+
+  // Determines whether the given relay server supports the given protocol.
+  bool SupportsProtocol(const RelayServerConfig& relay,
+                        ProtocolType type) const;
+  bool SupportsProtocol(RelayType turn_type, ProtocolType type) const;
+  // Helper method returns the server addresses for the matching RelayType and
+  // Protocol type.
+  ServerAddresses GetRelayServerAddresses(
+      RelayType turn_type, ProtocolType type) const;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_CLIENT_BASICPORTALLOCATOR_H_
diff --git a/p2p/client/connectivitychecker.cc b/p2p/client/connectivitychecker.cc
new file mode 100644
index 0000000..6e3598e
--- /dev/null
+++ b/p2p/client/connectivitychecker.cc
@@ -0,0 +1,573 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/p2p/client/connectivitychecker.h"
+
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/p2p/base/stunport.h"
+#include "webrtc/base/asynchttprequest.h"
+#include "webrtc/base/autodetectproxy.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/httpcommon-inl.h"
+#include "webrtc/base/httpcommon.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/proxydetect.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+static const char kDefaultStunHostname[] = "stun.l.google.com";
+static const int kDefaultStunPort = 19302;
+
+// Default maximum time in milliseconds we will wait for connections.
+static const uint32 kDefaultTimeoutMs = 3000;
+
+enum {
+  MSG_START = 1,
+  MSG_STOP = 2,
+  MSG_TIMEOUT = 3,
+  MSG_SIGNAL_RESULTS = 4
+};
+
+class TestHttpPortAllocator : public HttpPortAllocator {
+ public:
+  TestHttpPortAllocator(rtc::NetworkManager* network_manager,
+                        const std::string& user_agent,
+                        const std::string& relay_token) :
+      HttpPortAllocator(network_manager, user_agent) {
+    SetRelayToken(relay_token);
+  }
+  PortAllocatorSession* CreateSessionInternal(
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd) {
+    return new TestHttpPortAllocatorSession(this, content_name, component,
+                                            ice_ufrag, ice_pwd,
+                                            stun_hosts(), relay_hosts(),
+                                            relay_token(), user_agent());
+  }
+};
+
+void TestHttpPortAllocatorSession::ConfigReady(PortConfiguration* config) {
+  SignalConfigReady(username(), password(), config, proxy_);
+  delete config;
+}
+
+void TestHttpPortAllocatorSession::OnRequestDone(
+    rtc::SignalThread* data) {
+  rtc::AsyncHttpRequest* request =
+      static_cast<rtc::AsyncHttpRequest*>(data);
+
+  // Tell the checker that the request is complete.
+  SignalRequestDone(request);
+
+  // Pass on the response to super class.
+  HttpPortAllocatorSession::OnRequestDone(data);
+}
+
+ConnectivityChecker::ConnectivityChecker(
+    rtc::Thread* worker,
+    const std::string& jid,
+    const std::string& session_id,
+    const std::string& user_agent,
+    const std::string& relay_token,
+    const std::string& connection)
+    : worker_(worker),
+      jid_(jid),
+      session_id_(session_id),
+      user_agent_(user_agent),
+      relay_token_(relay_token),
+      connection_(connection),
+      proxy_detect_(NULL),
+      timeout_ms_(kDefaultTimeoutMs),
+      stun_address_(kDefaultStunHostname, kDefaultStunPort),
+      started_(false) {
+}
+
+ConnectivityChecker::~ConnectivityChecker() {
+  if (started_) {
+    // We try to clear the TIMEOUT below. But worker may still handle it and
+    // cause SignalCheckDone to happen on main-thread. So we finally clear any
+    // pending SIGNAL_RESULTS.
+    worker_->Clear(this, MSG_TIMEOUT);
+    worker_->Send(this, MSG_STOP);
+    nics_.clear();
+    main_->Clear(this, MSG_SIGNAL_RESULTS);
+  }
+}
+
+bool ConnectivityChecker::Initialize() {
+  network_manager_.reset(CreateNetworkManager());
+  socket_factory_.reset(CreateSocketFactory(worker_));
+  port_allocator_.reset(CreatePortAllocator(network_manager_.get(),
+                                            user_agent_, relay_token_));
+  uint32 new_allocator_flags = port_allocator_->flags();
+  new_allocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG;
+  port_allocator_->set_flags(new_allocator_flags);
+  return true;
+}
+
+void ConnectivityChecker::Start() {
+  main_ = rtc::Thread::Current();
+  worker_->Post(this, MSG_START);
+  started_ = true;
+}
+
+void ConnectivityChecker::CleanUp() {
+  ASSERT(worker_ == rtc::Thread::Current());
+  if (proxy_detect_) {
+    proxy_detect_->Release();
+    proxy_detect_ = NULL;
+  }
+
+  for (uint32 i = 0; i < sessions_.size(); ++i) {
+    delete sessions_[i];
+  }
+  sessions_.clear();
+  for (uint32 i = 0; i < ports_.size(); ++i) {
+    delete ports_[i];
+  }
+  ports_.clear();
+}
+
+bool ConnectivityChecker::AddNic(const rtc::IPAddress& ip,
+                                 const rtc::SocketAddress& proxy_addr) {
+  NicMap::iterator i = nics_.find(NicId(ip, proxy_addr));
+  if (i != nics_.end()) {
+    // Already have it.
+    return false;
+  }
+  uint32 now = rtc::Time();
+  NicInfo info;
+  info.ip = ip;
+  info.proxy_info = GetProxyInfo();
+  info.stun.start_time_ms = now;
+  nics_.insert(std::pair<NicId, NicInfo>(NicId(ip, proxy_addr), info));
+  return true;
+}
+
+void ConnectivityChecker::SetProxyInfo(const rtc::ProxyInfo& proxy_info) {
+  port_allocator_->set_proxy(user_agent_, proxy_info);
+  AllocatePorts();
+}
+
+rtc::ProxyInfo ConnectivityChecker::GetProxyInfo() const {
+  rtc::ProxyInfo proxy_info;
+  if (proxy_detect_) {
+    proxy_info = proxy_detect_->proxy();
+  }
+  return proxy_info;
+}
+
+void ConnectivityChecker::CheckNetworks() {
+  network_manager_->SignalNetworksChanged.connect(
+      this, &ConnectivityChecker::OnNetworksChanged);
+  network_manager_->StartUpdating();
+}
+
+void ConnectivityChecker::OnMessage(rtc::Message *msg) {
+  switch (msg->message_id) {
+    case MSG_START:
+      ASSERT(worker_ == rtc::Thread::Current());
+      worker_->PostDelayed(timeout_ms_, this, MSG_TIMEOUT);
+      CheckNetworks();
+      break;
+    case MSG_STOP:
+      // We're being stopped, free resources.
+      CleanUp();
+      break;
+    case MSG_TIMEOUT:
+      // We need to signal results on the main thread.
+      main_->Post(this, MSG_SIGNAL_RESULTS);
+      break;
+    case MSG_SIGNAL_RESULTS:
+      ASSERT(main_ == rtc::Thread::Current());
+      SignalCheckDone(this);
+      break;
+    default:
+      LOG(LS_ERROR) << "Unknown message: " << msg->message_id;
+  }
+}
+
+void ConnectivityChecker::OnProxyDetect(rtc::SignalThread* thread) {
+  ASSERT(worker_ == rtc::Thread::Current());
+  if (proxy_detect_->proxy().type != rtc::PROXY_NONE) {
+    SetProxyInfo(proxy_detect_->proxy());
+  }
+}
+
+void ConnectivityChecker::OnRequestDone(rtc::AsyncHttpRequest* request) {
+  ASSERT(worker_ == rtc::Thread::Current());
+  // Since we don't know what nic were actually used for the http request,
+  // for now, just use the first one.
+  std::vector<rtc::Network*> networks;
+  network_manager_->GetNetworks(&networks);
+  if (networks.empty()) {
+    LOG(LS_ERROR) << "No networks while registering http start.";
+    return;
+  }
+  rtc::ProxyInfo proxy_info = request->proxy();
+  NicMap::iterator i =
+#ifdef USE_WEBRTC_DEV_BRANCH
+      nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address));
+#else  // USE_WEBRTC_DEV_BRANCH
+      nics_.find(NicId(networks[0]->ip(), proxy_info.address));
+#endif  // USE_WEBRTC_DEV_BRANCH
+  if (i != nics_.end()) {
+    int port = request->port();
+    uint32 now = rtc::Time();
+    NicInfo* nic_info = &i->second;
+    if (port == rtc::HTTP_DEFAULT_PORT) {
+      nic_info->http.rtt = now - nic_info->http.start_time_ms;
+    } else if (port == rtc::HTTP_SECURE_PORT) {
+      nic_info->https.rtt = now - nic_info->https.start_time_ms;
+    } else {
+      LOG(LS_ERROR) << "Got response with unknown port: " << port;
+    }
+  } else {
+    LOG(LS_ERROR) << "No nic info found while receiving response.";
+  }
+}
+
+void ConnectivityChecker::OnConfigReady(
+    const std::string& username, const std::string& password,
+    const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) {
+  ASSERT(worker_ == rtc::Thread::Current());
+
+  // Since we send requests on both HTTP and HTTPS we will get two
+  // configs per nic. Results from the second will overwrite the
+  // result from the first.
+  // TODO: Handle multiple pings on one nic.
+  CreateRelayPorts(username, password, config, proxy_info);
+}
+
+void ConnectivityChecker::OnRelayPortComplete(Port* port) {
+  ASSERT(worker_ == rtc::Thread::Current());
+  RelayPort* relay_port = reinterpret_cast<RelayPort*>(port);
+  const ProtocolAddress* address = relay_port->ServerAddress(0);
+#ifdef USE_WEBRTC_DEV_BRANCH
+  rtc::IPAddress ip = port->Network()->GetBestIP();
+#else  // USE_WEBRTC_DEV_BRANCH
+  rtc::IPAddress ip = port->Network()->ip();
+#endif  // USE_WEBRTC_DEV_BRANCH
+  NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
+  if (i != nics_.end()) {
+    // We have it already, add the new information.
+    NicInfo* nic_info = &i->second;
+    ConnectInfo* connect_info = NULL;
+    if (address) {
+      switch (address->proto) {
+        case PROTO_UDP:
+          connect_info = &nic_info->udp;
+          break;
+        case PROTO_TCP:
+          connect_info = &nic_info->tcp;
+          break;
+        case PROTO_SSLTCP:
+          connect_info = &nic_info->ssltcp;
+          break;
+        default:
+          LOG(LS_ERROR) << " relay address with bad protocol added";
+      }
+      if (connect_info) {
+        connect_info->rtt =
+            rtc::TimeSince(connect_info->start_time_ms);
+      }
+    }
+  } else {
+    LOG(LS_ERROR) << " got relay address for non-existing nic";
+  }
+}
+
+void ConnectivityChecker::OnStunPortComplete(Port* port) {
+  ASSERT(worker_ == rtc::Thread::Current());
+  const std::vector<Candidate> candidates = port->Candidates();
+  Candidate c = candidates[0];
+#ifdef USE_WEBRTC_DEV_BRANCH
+  rtc::IPAddress ip = port->Network()->GetBestIP();
+#else  // USE_WEBRTC_DEV_BRANCH
+  rtc::IPAddress ip = port->Network()->ip();
+#endif  // USE_WEBRTC_DEV_BRANCH
+  NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
+  if (i != nics_.end()) {
+    // We have it already, add the new information.
+    uint32 now = rtc::Time();
+    NicInfo* nic_info = &i->second;
+    nic_info->external_address = c.address();
+
+    nic_info->stun_server_addresses =
+        static_cast<StunPort*>(port)->server_addresses();
+    nic_info->stun.rtt = now - nic_info->stun.start_time_ms;
+  } else {
+    LOG(LS_ERROR) << "Got stun address for non-existing nic";
+  }
+}
+
+void ConnectivityChecker::OnStunPortError(Port* port) {
+  ASSERT(worker_ == rtc::Thread::Current());
+  LOG(LS_ERROR) << "Stun address error.";
+#ifdef USE_WEBRTC_DEV_BRANCH
+  rtc::IPAddress ip = port->Network()->GetBestIP();
+#else  // USE_WEBRTC_DEV_BRANCH
+  rtc::IPAddress ip = port->Network()->ip();
+#endif  // USE_WEBRTC_DEV_BRANCH
+  NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address));
+  if (i != nics_.end()) {
+    // We have it already, add the new information.
+    NicInfo* nic_info = &i->second;
+
+    nic_info->stun_server_addresses =
+        static_cast<StunPort*>(port)->server_addresses();
+  }
+}
+
+void ConnectivityChecker::OnRelayPortError(Port* port) {
+  ASSERT(worker_ == rtc::Thread::Current());
+  LOG(LS_ERROR) << "Relay address error.";
+}
+
+void ConnectivityChecker::OnNetworksChanged() {
+  ASSERT(worker_ == rtc::Thread::Current());
+  std::vector<rtc::Network*> networks;
+  network_manager_->GetNetworks(&networks);
+  if (networks.empty()) {
+    LOG(LS_ERROR) << "Machine has no networks; nothing to do";
+    return;
+  }
+  AllocatePorts();
+}
+
+HttpPortAllocator* ConnectivityChecker::CreatePortAllocator(
+    rtc::NetworkManager* network_manager,
+    const std::string& user_agent,
+    const std::string& relay_token) {
+  return new TestHttpPortAllocator(network_manager, user_agent, relay_token);
+}
+
+StunPort* ConnectivityChecker::CreateStunPort(
+    const std::string& username, const std::string& password,
+    const PortConfiguration* config, rtc::Network* network) {
+  return StunPort::Create(worker_,
+                          socket_factory_.get(),
+                          network,
+#ifdef USE_WEBRTC_DEV_BRANCH
+                          network->GetBestIP(),
+#else  // USE_WEBRTC_DEV_BRANCH
+                          network->ip(),
+#endif  // USE_WEBRTC_DEV_BRANCH
+                          0,
+                          0,
+                          username,
+                          password,
+                          config->stun_servers);
+}
+
+RelayPort* ConnectivityChecker::CreateRelayPort(
+    const std::string& username, const std::string& password,
+    const PortConfiguration* config, rtc::Network* network) {
+  return RelayPort::Create(worker_,
+                           socket_factory_.get(),
+                           network,
+#ifdef USE_WEBRTC_DEV_BRANCH
+                           network->GetBestIP(),
+#else  // USE_WEBRTC_DEV_BRANCH
+                           network->ip(),
+#endif  // USE_WEBRTC_DEV_BRANCH
+                           port_allocator_->min_port(),
+                           port_allocator_->max_port(),
+                           username,
+                           password);
+}
+
+void ConnectivityChecker::CreateRelayPorts(
+    const std::string& username, const std::string& password,
+    const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) {
+  PortConfiguration::RelayList::const_iterator relay;
+  std::vector<rtc::Network*> networks;
+  network_manager_->GetNetworks(&networks);
+  if (networks.empty()) {
+    LOG(LS_ERROR) << "Machine has no networks; no relay ports created.";
+    return;
+  }
+  for (relay = config->relays.begin();
+       relay != config->relays.end(); ++relay) {
+    for (uint32 i = 0; i < networks.size(); ++i) {
+      NicMap::iterator iter =
+#ifdef USE_WEBRTC_DEV_BRANCH
+          nics_.find(NicId(networks[i]->GetBestIP(), proxy_info.address));
+#else  // USE_WEBRTC_DEV_BRANCH
+          nics_.find(NicId(networks[i]->ip(), proxy_info.address));
+#endif  // USE_WEBRTC_DEV_BRANCH
+      if (iter != nics_.end()) {
+        // TODO: Now setting the same start time for all protocols.
+        // This might affect accuracy, but since we are mainly looking for
+        // connect failures or number that stick out, this is good enough.
+        uint32 now = rtc::Time();
+        NicInfo* nic_info = &iter->second;
+        nic_info->udp.start_time_ms = now;
+        nic_info->tcp.start_time_ms = now;
+        nic_info->ssltcp.start_time_ms = now;
+
+        // Add the addresses of this protocol.
+        PortList::const_iterator relay_port;
+        for (relay_port = relay->ports.begin();
+             relay_port != relay->ports.end();
+             ++relay_port) {
+          RelayPort* port = CreateRelayPort(username, password,
+                                            config, networks[i]);
+          port->AddServerAddress(*relay_port);
+          port->AddExternalAddress(*relay_port);
+
+          nic_info->media_server_address = port->ServerAddress(0)->address;
+
+          // Listen to network events.
+          port->SignalPortComplete.connect(
+              this, &ConnectivityChecker::OnRelayPortComplete);
+          port->SignalPortError.connect(
+              this, &ConnectivityChecker::OnRelayPortError);
+
+          port->set_proxy(user_agent_, proxy_info);
+
+          // Start fetching an address for this port.
+          port->PrepareAddress();
+          ports_.push_back(port);
+        }
+      } else {
+        LOG(LS_ERROR) << "Failed to find nic info when creating relay ports.";
+      }
+    }
+  }
+}
+
+void ConnectivityChecker::AllocatePorts() {
+  const std::string username = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
+  const std::string password = rtc::CreateRandomString(ICE_PWD_LENGTH);
+  ServerAddresses stun_servers;
+  stun_servers.insert(stun_address_);
+  PortConfiguration config(stun_servers, username, password);
+  std::vector<rtc::Network*> networks;
+  network_manager_->GetNetworks(&networks);
+  if (networks.empty()) {
+    LOG(LS_ERROR) << "Machine has no networks; no ports will be allocated";
+    return;
+  }
+  rtc::ProxyInfo proxy_info = GetProxyInfo();
+  bool allocate_relay_ports = false;
+  for (uint32 i = 0; i < networks.size(); ++i) {
+#ifdef USE_WEBRTC_DEV_BRANCH
+    if (AddNic(networks[i]->GetBestIP(), proxy_info.address)) {
+#else  // USE_WEBRTC_DEV_BRANCH
+    if (AddNic(networks[i]->ip(), proxy_info.address)) {
+#endif  // USE_WEBRTC_DEV_BRANCH
+      Port* port = CreateStunPort(username, password, &config, networks[i]);
+      if (port) {
+
+        // Listen to network events.
+        port->SignalPortComplete.connect(
+            this, &ConnectivityChecker::OnStunPortComplete);
+        port->SignalPortError.connect(
+            this, &ConnectivityChecker::OnStunPortError);
+
+        port->set_proxy(user_agent_, proxy_info);
+        port->PrepareAddress();
+        ports_.push_back(port);
+        allocate_relay_ports = true;
+      }
+    }
+  }
+
+  // If any new ip/proxy combinations were added, send a relay allocate.
+  if (allocate_relay_ports) {
+    AllocateRelayPorts();
+  }
+
+  // Initiate proxy detection.
+  InitiateProxyDetection();
+}
+
+void ConnectivityChecker::InitiateProxyDetection() {
+  // Only start if we haven't been started before.
+  if (!proxy_detect_) {
+    proxy_detect_ = new rtc::AutoDetectProxy(user_agent_);
+    rtc::Url<char> host_url("/", "relay.google.com",
+                                  rtc::HTTP_DEFAULT_PORT);
+    host_url.set_secure(true);
+    proxy_detect_->set_server_url(host_url.url());
+    proxy_detect_->SignalWorkDone.connect(
+        this, &ConnectivityChecker::OnProxyDetect);
+    proxy_detect_->Start();
+  }
+}
+
+void ConnectivityChecker::AllocateRelayPorts() {
+  // Currently we are using the 'default' nic for http(s) requests.
+  TestHttpPortAllocatorSession* allocator_session =
+      reinterpret_cast<TestHttpPortAllocatorSession*>(
+          port_allocator_->CreateSessionInternal(
+              "connectivity checker test content",
+              ICE_CANDIDATE_COMPONENT_RTP,
+              rtc::CreateRandomString(ICE_UFRAG_LENGTH),
+              rtc::CreateRandomString(ICE_PWD_LENGTH)));
+  allocator_session->set_proxy(port_allocator_->proxy());
+  allocator_session->SignalConfigReady.connect(
+      this, &ConnectivityChecker::OnConfigReady);
+  allocator_session->SignalRequestDone.connect(
+      this, &ConnectivityChecker::OnRequestDone);
+
+  // Try both http and https.
+  RegisterHttpStart(rtc::HTTP_SECURE_PORT);
+  allocator_session->SendSessionRequest("relay.l.google.com",
+                                        rtc::HTTP_SECURE_PORT);
+  RegisterHttpStart(rtc::HTTP_DEFAULT_PORT);
+  allocator_session->SendSessionRequest("relay.l.google.com",
+                                        rtc::HTTP_DEFAULT_PORT);
+
+  sessions_.push_back(allocator_session);
+}
+
+void ConnectivityChecker::RegisterHttpStart(int port) {
+  // Since we don't know what nic were actually used for the http request,
+  // for now, just use the first one.
+  std::vector<rtc::Network*> networks;
+  network_manager_->GetNetworks(&networks);
+  if (networks.empty()) {
+    LOG(LS_ERROR) << "No networks while registering http start.";
+    return;
+  }
+  rtc::ProxyInfo proxy_info = GetProxyInfo();
+  NicMap::iterator i =
+#ifdef USE_WEBRTC_DEV_BRANCH
+      nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address));
+#else  // USE_WEBRTC_DEV_BRANCH
+      nics_.find(NicId(networks[0]->ip(), proxy_info.address));
+#endif  // USE_WEBRTC_DEV_BRANCH
+  if (i != nics_.end()) {
+    uint32 now = rtc::Time();
+    NicInfo* nic_info = &i->second;
+    if (port == rtc::HTTP_DEFAULT_PORT) {
+      nic_info->http.start_time_ms = now;
+    } else if (port == rtc::HTTP_SECURE_PORT) {
+      nic_info->https.start_time_ms = now;
+    } else {
+      LOG(LS_ERROR) << "Registering start time for unknown port: " << port;
+    }
+  } else {
+    LOG(LS_ERROR) << "Error, no nic info found while registering http start.";
+  }
+}
+
+}  // namespace rtc
diff --git a/p2p/client/connectivitychecker.h b/p2p/client/connectivitychecker.h
new file mode 100644
index 0000000..427749e
--- /dev/null
+++ b/p2p/client/connectivitychecker.h
@@ -0,0 +1,281 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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_P2P_CLIENT_CONNECTIVITYCHECKER_H_
+#define WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_
+
+#include <map>
+#include <string>
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/client/httpportallocator.h"
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/messagehandler.h"
+#include "webrtc/base/network.h"
+#include "webrtc/base/proxyinfo.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace rtc {
+class AsyncHttpRequest;
+class AutoDetectProxy;
+class BasicPacketSocketFactory;
+class NetworkManager;
+class PacketSocketFactory;
+class SignalThread;
+class TestHttpPortAllocatorSession;
+class Thread;
+}
+
+namespace cricket {
+class HttpPortAllocator;
+class Port;
+class PortAllocatorSession;
+struct PortConfiguration;
+class RelayPort;
+class StunPort;
+
+// Contains details about a discovered firewall that are of interest
+// when debugging call failures.
+struct FirewallInfo {
+  std::string brand;
+  std::string model;
+
+  // TODO: List of current port mappings.
+};
+
+// Contains details about a specific connect attempt.
+struct ConnectInfo {
+  ConnectInfo()
+      : rtt(-1), error(0) {}
+  // Time when the connection was initiated. Needed for calculating
+  // the round trip time.
+  uint32 start_time_ms;
+  // Round trip time in milliseconds or -1 for failed connection.
+  int32 rtt;
+  // Error code representing low level errors like socket errors.
+  int error;
+};
+
+// Identifier for a network interface and proxy address pair.
+struct NicId {
+  NicId(const rtc::IPAddress& ip,
+        const rtc::SocketAddress& proxy_address)
+      : ip(ip),
+        proxy_address(proxy_address) {
+  }
+  rtc::IPAddress ip;
+  rtc::SocketAddress proxy_address;
+};
+
+// Comparator implementation identifying unique network interface and
+// proxy address pairs.
+class NicIdComparator {
+ public:
+  int compare(const NicId &first, const NicId &second) const {
+    if (first.ip == second.ip) {
+      // Compare proxy address.
+      if (first.proxy_address == second.proxy_address) {
+        return 0;
+      } else {
+        return first.proxy_address < second.proxy_address? -1 : 1;
+      }
+    }
+    return first.ip < second.ip ? -1 : 1;
+  }
+
+  bool operator()(const NicId &first, const NicId &second) const {
+    return (compare(first, second) < 0);
+  }
+};
+
+// Contains information of a network interface and proxy address pair.
+struct NicInfo {
+  NicInfo() {}
+  rtc::IPAddress ip;
+  rtc::ProxyInfo proxy_info;
+  rtc::SocketAddress external_address;
+  ServerAddresses stun_server_addresses;
+  rtc::SocketAddress media_server_address;
+  ConnectInfo stun;
+  ConnectInfo http;
+  ConnectInfo https;
+  ConnectInfo udp;
+  ConnectInfo tcp;
+  ConnectInfo ssltcp;
+  FirewallInfo firewall;
+};
+
+// Holds the result of the connectivity check.
+class NicMap : public std::map<NicId, NicInfo, NicIdComparator> {
+};
+
+class TestHttpPortAllocatorSession : public HttpPortAllocatorSession {
+ public:
+  TestHttpPortAllocatorSession(
+      HttpPortAllocator* allocator,
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd,
+      const std::vector<rtc::SocketAddress>& stun_hosts,
+      const std::vector<std::string>& relay_hosts,
+      const std::string& relay_token,
+      const std::string& user_agent)
+      : HttpPortAllocatorSession(
+          allocator, content_name, component, ice_ufrag, ice_pwd, stun_hosts,
+          relay_hosts, relay_token, user_agent) {
+  }
+  void set_proxy(const rtc::ProxyInfo& proxy) {
+    proxy_ = proxy;
+  }
+
+  void ConfigReady(PortConfiguration* config);
+
+  void OnRequestDone(rtc::SignalThread* data);
+
+  sigslot::signal4<const std::string&, const std::string&,
+                   const PortConfiguration*,
+                   const rtc::ProxyInfo&> SignalConfigReady;
+  sigslot::signal1<rtc::AsyncHttpRequest*> SignalRequestDone;
+
+ private:
+  rtc::ProxyInfo proxy_;
+};
+
+// Runs a request/response check on all network interface and proxy
+// address combinations. The check is considered done either when all
+// checks has been successful or when the check times out.
+class ConnectivityChecker
+    : public rtc::MessageHandler, public sigslot::has_slots<> {
+ public:
+  ConnectivityChecker(rtc::Thread* worker,
+                      const std::string& jid,
+                      const std::string& session_id,
+                      const std::string& user_agent,
+                      const std::string& relay_token,
+                      const std::string& connection);
+  virtual ~ConnectivityChecker();
+
+  // Virtual for gMock.
+  virtual bool Initialize();
+  virtual void Start();
+
+  // MessageHandler implementation.
+  virtual void OnMessage(rtc::Message *msg);
+
+  // Instruct checker to stop and wait until that's done.
+  // Virtual for gMock.
+  virtual void Stop() {
+    worker_->Stop();
+  }
+
+  const NicMap& GetResults() const {
+    return nics_;
+  }
+
+  void set_timeout_ms(uint32 timeout) {
+    timeout_ms_ = timeout;
+  }
+
+  void set_stun_address(const rtc::SocketAddress& stun_address) {
+    stun_address_ = stun_address;
+  }
+
+  const std::string& connection() const {
+    return connection_;
+  }
+
+  const std::string& jid() const {
+    return jid_;
+  }
+
+  const std::string& session_id() const {
+    return session_id_;
+  }
+
+  // Context: Main Thread. Signalled when the connectivity check is complete.
+  sigslot::signal1<ConnectivityChecker*> SignalCheckDone;
+
+ protected:
+  // Can be overridden for test.
+  virtual rtc::NetworkManager* CreateNetworkManager() {
+    return new rtc::BasicNetworkManager();
+  }
+  virtual rtc::BasicPacketSocketFactory* CreateSocketFactory(
+      rtc::Thread* thread) {
+    return new rtc::BasicPacketSocketFactory(thread);
+  }
+  virtual HttpPortAllocator* CreatePortAllocator(
+      rtc::NetworkManager* network_manager,
+      const std::string& user_agent,
+      const std::string& relay_token);
+  virtual StunPort* CreateStunPort(
+      const std::string& username, const std::string& password,
+      const PortConfiguration* config, rtc::Network* network);
+  virtual RelayPort* CreateRelayPort(
+      const std::string& username, const std::string& password,
+      const PortConfiguration* config, rtc::Network* network);
+  virtual void InitiateProxyDetection();
+  virtual void SetProxyInfo(const rtc::ProxyInfo& info);
+  virtual rtc::ProxyInfo GetProxyInfo() const;
+
+  rtc::Thread* worker() {
+    return worker_;
+  }
+
+ private:
+  bool AddNic(const rtc::IPAddress& ip,
+              const rtc::SocketAddress& proxy_address);
+  void AllocatePorts();
+  void AllocateRelayPorts();
+  void CheckNetworks();
+  void CreateRelayPorts(
+      const std::string& username, const std::string& password,
+      const PortConfiguration* config, const rtc::ProxyInfo& proxy_info);
+
+  // Must be called by the worker thread.
+  void CleanUp();
+
+  void OnRequestDone(rtc::AsyncHttpRequest* request);
+  void OnRelayPortComplete(Port* port);
+  void OnStunPortComplete(Port* port);
+  void OnRelayPortError(Port* port);
+  void OnStunPortError(Port* port);
+  void OnNetworksChanged();
+  void OnProxyDetect(rtc::SignalThread* thread);
+  void OnConfigReady(
+      const std::string& username, const std::string& password,
+      const PortConfiguration* config, const rtc::ProxyInfo& proxy);
+  void OnConfigWithProxyReady(const PortConfiguration*);
+  void RegisterHttpStart(int port);
+  rtc::Thread* worker_;
+  std::string jid_;
+  std::string session_id_;
+  std::string user_agent_;
+  std::string relay_token_;
+  std::string connection_;
+  rtc::AutoDetectProxy* proxy_detect_;
+  rtc::scoped_ptr<rtc::NetworkManager> network_manager_;
+  rtc::scoped_ptr<rtc::BasicPacketSocketFactory> socket_factory_;
+  rtc::scoped_ptr<HttpPortAllocator> port_allocator_;
+  NicMap nics_;
+  std::vector<Port*> ports_;
+  std::vector<PortAllocatorSession*> sessions_;
+  uint32 timeout_ms_;
+  rtc::SocketAddress stun_address_;
+  rtc::Thread* main_;
+  bool started_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_
diff --git a/p2p/client/connectivitychecker_unittest.cc b/p2p/client/connectivitychecker_unittest.cc
new file mode 100644
index 0000000..838dc88
--- /dev/null
+++ b/p2p/client/connectivitychecker_unittest.cc
@@ -0,0 +1,375 @@
+/*
+ *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <string>
+
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/relayport.h"
+#include "webrtc/p2p/base/stunport.h"
+#include "webrtc/p2p/client/connectivitychecker.h"
+#include "webrtc/p2p/client/httpportallocator.h"
+#include "webrtc/base/asynchttprequest.h"
+#include "webrtc/base/fakenetwork.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace cricket {
+
+static const rtc::SocketAddress kClientAddr1("11.11.11.11", 0);
+static const rtc::SocketAddress kClientAddr2("22.22.22.22", 0);
+static const rtc::SocketAddress kExternalAddr("33.33.33.33", 3333);
+static const rtc::SocketAddress kStunAddr("44.44.44.44", 4444);
+static const rtc::SocketAddress kRelayAddr("55.55.55.55", 5555);
+static const rtc::SocketAddress kProxyAddr("66.66.66.66", 6666);
+static const rtc::ProxyType kProxyType = rtc::PROXY_HTTPS;
+static const char kRelayHost[] = "relay.google.com";
+static const char kRelayToken[] =
+    "CAESFwoOb2phQGdvb2dsZS5jb20Q043h47MmGhBTB1rbfIXkhuarDCZe+xF6";
+static const char kBrowserAgent[] = "browser_test";
+static const char kJid[] = "a.b@c";
+static const char kUserName[] = "testuser";
+static const char kPassword[] = "testpassword";
+static const char kMagicCookie[] = "testcookie";
+static const char kRelayUdpPort[] = "4444";
+static const char kRelayTcpPort[] = "5555";
+static const char kRelaySsltcpPort[] = "6666";
+static const char kSessionId[] = "testsession";
+static const char kConnection[] = "testconnection";
+static const int kMinPort = 1000;
+static const int kMaxPort = 2000;
+
+// Fake implementation to mock away real network usage.
+class FakeRelayPort : public RelayPort {
+ public:
+  FakeRelayPort(rtc::Thread* thread,
+                rtc::PacketSocketFactory* factory,
+                rtc::Network* network, const rtc::IPAddress& ip,
+                int min_port, int max_port,
+                const std::string& username, const std::string& password)
+      : RelayPort(thread, factory, network, ip, min_port, max_port,
+                  username, password) {
+  }
+
+  // Just signal that we are done.
+  virtual void PrepareAddress() {
+    SignalPortComplete(this);
+  }
+};
+
+// Fake implementation to mock away real network usage.
+class FakeStunPort : public StunPort {
+ public:
+  FakeStunPort(rtc::Thread* thread,
+               rtc::PacketSocketFactory* factory,
+               rtc::Network* network,
+               const rtc::IPAddress& ip,
+               int min_port, int max_port,
+               const std::string& username, const std::string& password,
+               const ServerAddresses& server_addr)
+      : StunPort(thread, factory, network, ip, min_port, max_port,
+                 username, password, server_addr) {
+  }
+
+  // Just set external address and signal that we are done.
+  virtual void PrepareAddress() {
+    AddAddress(kExternalAddr, kExternalAddr, rtc::SocketAddress(), "udp", "",
+               STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, 0, true);
+    SignalPortComplete(this);
+  }
+};
+
+// Fake implementation to mock away real network usage by responding
+// to http requests immediately.
+class FakeHttpPortAllocatorSession : public TestHttpPortAllocatorSession {
+ public:
+  FakeHttpPortAllocatorSession(
+      HttpPortAllocator* allocator,
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag, const std::string& ice_pwd,
+      const std::vector<rtc::SocketAddress>& stun_hosts,
+      const std::vector<std::string>& relay_hosts,
+      const std::string& relay_token,
+      const std::string& agent)
+      : TestHttpPortAllocatorSession(allocator,
+                                     content_name,
+                                     component,
+                                     ice_ufrag,
+                                     ice_pwd,
+                                     stun_hosts,
+                                     relay_hosts,
+                                     relay_token,
+                                     agent) {
+  }
+  virtual void SendSessionRequest(const std::string& host, int port) {
+    FakeReceiveSessionResponse(host, port);
+  }
+
+  // Pass results to the real implementation.
+  void FakeReceiveSessionResponse(const std::string& host, int port) {
+    rtc::AsyncHttpRequest* response = CreateAsyncHttpResponse(port);
+    TestHttpPortAllocatorSession::OnRequestDone(response);
+    response->Destroy(true);
+  }
+
+ private:
+  // Helper method for creating a response to a relay session request.
+  rtc::AsyncHttpRequest* CreateAsyncHttpResponse(int port) {
+    rtc::AsyncHttpRequest* request =
+        new rtc::AsyncHttpRequest(kBrowserAgent);
+    std::stringstream ss;
+    ss << "username=" << kUserName << std::endl
+       << "password=" << kPassword << std::endl
+       << "magic_cookie=" << kMagicCookie << std::endl
+       << "relay.ip=" << kRelayAddr.ipaddr().ToString() << std::endl
+       << "relay.udp_port=" << kRelayUdpPort << std::endl
+       << "relay.tcp_port=" << kRelayTcpPort << std::endl
+       << "relay.ssltcp_port=" << kRelaySsltcpPort << std::endl;
+    request->response().document.reset(
+        new rtc::MemoryStream(ss.str().c_str()));
+    request->response().set_success();
+    request->set_port(port);
+    request->set_secure(port == rtc::HTTP_SECURE_PORT);
+    return request;
+  }
+};
+
+// Fake implementation for creating fake http sessions.
+class FakeHttpPortAllocator : public HttpPortAllocator {
+ public:
+  FakeHttpPortAllocator(rtc::NetworkManager* network_manager,
+                        const std::string& user_agent)
+      : HttpPortAllocator(network_manager, user_agent) {
+  }
+
+  virtual PortAllocatorSession* CreateSessionInternal(
+      const std::string& content_name, int component,
+      const std::string& ice_ufrag, const std::string& ice_pwd) {
+    std::vector<rtc::SocketAddress> stun_hosts;
+    stun_hosts.push_back(kStunAddr);
+    std::vector<std::string> relay_hosts;
+    relay_hosts.push_back(kRelayHost);
+    return new FakeHttpPortAllocatorSession(this,
+                                            content_name,
+                                            component,
+                                            ice_ufrag,
+                                            ice_pwd,
+                                            stun_hosts,
+                                            relay_hosts,
+                                            kRelayToken,
+                                            kBrowserAgent);
+  }
+};
+
+class ConnectivityCheckerForTest : public ConnectivityChecker {
+ public:
+  ConnectivityCheckerForTest(rtc::Thread* worker,
+                             const std::string& jid,
+                             const std::string& session_id,
+                             const std::string& user_agent,
+                             const std::string& relay_token,
+                             const std::string& connection)
+      : ConnectivityChecker(worker,
+                            jid,
+                            session_id,
+                            user_agent,
+                            relay_token,
+                            connection),
+        proxy_initiated_(false) {
+  }
+
+  rtc::FakeNetworkManager* network_manager() const {
+    return network_manager_;
+  }
+
+  FakeHttpPortAllocator* port_allocator() const {
+    return fake_port_allocator_;
+  }
+
+ protected:
+  // Overridden methods for faking a real network.
+  virtual rtc::NetworkManager* CreateNetworkManager() {
+    network_manager_ = new rtc::FakeNetworkManager();
+    return network_manager_;
+  }
+  virtual rtc::BasicPacketSocketFactory* CreateSocketFactory(
+      rtc::Thread* thread) {
+    // Create socket factory, for simplicity, let it run on the current thread.
+    socket_factory_ =
+        new rtc::BasicPacketSocketFactory(rtc::Thread::Current());
+    return socket_factory_;
+  }
+  virtual HttpPortAllocator* CreatePortAllocator(
+      rtc::NetworkManager* network_manager,
+      const std::string& user_agent,
+      const std::string& relay_token) {
+    fake_port_allocator_ =
+        new FakeHttpPortAllocator(network_manager, user_agent);
+    return fake_port_allocator_;
+  }
+  virtual StunPort* CreateStunPort(
+      const std::string& username, const std::string& password,
+      const PortConfiguration* config, rtc::Network* network) {
+    return new FakeStunPort(worker(),
+                            socket_factory_,
+                            network,
+#ifdef USE_WEBRTC_DEV_BRANCH
+                            network->GetBestIP(),
+#else  // USE_WEBRTC_DEV_BRANCH
+                            network->ip(),
+#endif  // USE_WEBRTC_DEV_BRANCH
+                            kMinPort,
+                            kMaxPort,
+                            username,
+                            password,
+                            config->stun_servers);
+  }
+  virtual RelayPort* CreateRelayPort(
+      const std::string& username, const std::string& password,
+      const PortConfiguration* config, rtc::Network* network) {
+    return new FakeRelayPort(worker(),
+                             socket_factory_,
+                             network,
+#ifdef USE_WEBRTC_DEV_BRANCH
+                             network->GetBestIP(),
+#else  // USE_WEBRTC_DEV_BRANCH
+                             network->ip(),
+#endif  // USE_WEBRTC_DEV_BRANCH
+                             kMinPort,
+                             kMaxPort,
+                             username,
+                             password);
+  }
+  virtual void InitiateProxyDetection() {
+    if (!proxy_initiated_) {
+      proxy_initiated_ = true;
+      proxy_info_.address = kProxyAddr;
+      proxy_info_.type = kProxyType;
+      SetProxyInfo(proxy_info_);
+    }
+  }
+
+  virtual rtc::ProxyInfo GetProxyInfo() const {
+    return proxy_info_;
+  }
+
+ private:
+  rtc::BasicPacketSocketFactory* socket_factory_;
+  FakeHttpPortAllocator* fake_port_allocator_;
+  rtc::FakeNetworkManager* network_manager_;
+  rtc::ProxyInfo proxy_info_;
+  bool proxy_initiated_;
+};
+
+class ConnectivityCheckerTest : public testing::Test {
+ protected:
+  void VerifyNic(const NicInfo& info,
+                 const rtc::SocketAddress& local_address) {
+    // Verify that the external address has been set.
+    EXPECT_EQ(kExternalAddr, info.external_address);
+
+    // Verify that the stun server address has been set.
+    EXPECT_EQ(1U, info.stun_server_addresses.size());
+    EXPECT_EQ(kStunAddr, *(info.stun_server_addresses.begin()));
+
+    // Verify that the media server address has been set. Don't care
+    // about port since it is different for different protocols.
+    EXPECT_EQ(kRelayAddr.ipaddr(), info.media_server_address.ipaddr());
+
+    // Verify that local ip matches.
+    EXPECT_EQ(local_address.ipaddr(), info.ip);
+
+    // Verify that we have received responses for our
+    // pings. Unsuccessful ping has rtt value -1, successful >= 0.
+    EXPECT_GE(info.stun.rtt, 0);
+    EXPECT_GE(info.udp.rtt, 0);
+    EXPECT_GE(info.tcp.rtt, 0);
+    EXPECT_GE(info.ssltcp.rtt, 0);
+
+    // If proxy has been set, verify address and type.
+    if (!info.proxy_info.address.IsNil()) {
+      EXPECT_EQ(kProxyAddr, info.proxy_info.address);
+      EXPECT_EQ(kProxyType, info.proxy_info.type);
+    }
+  }
+};
+
+// Tests a configuration with two network interfaces. Verifies that 4
+// combinations of ip/proxy are created and that all protocols are
+// tested on each combination.
+TEST_F(ConnectivityCheckerTest, TestStart) {
+  ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(),
+                                                  kJid,
+                                                  kSessionId,
+                                                  kBrowserAgent,
+                                                  kRelayToken,
+                                                  kConnection);
+  connectivity_checker.Initialize();
+  connectivity_checker.set_stun_address(kStunAddr);
+  connectivity_checker.network_manager()->AddInterface(kClientAddr1);
+  connectivity_checker.network_manager()->AddInterface(kClientAddr2);
+
+  connectivity_checker.Start();
+  rtc::Thread::Current()->ProcessMessages(1000);
+
+  NicMap nics = connectivity_checker.GetResults();
+
+  // There should be 4 nics in our map. 2 for each interface added,
+  // one with proxy set and one without.
+  EXPECT_EQ(4U, nics.size());
+
+  // First verify interfaces without proxy.
+  rtc::SocketAddress nilAddress;
+
+  // First lookup the address of the first nic combined with no proxy.
+  NicMap::iterator i = nics.find(NicId(kClientAddr1.ipaddr(), nilAddress));
+  ASSERT(i != nics.end());
+  NicInfo info = i->second;
+  VerifyNic(info, kClientAddr1);
+
+  // Then make sure the second device has been tested without proxy.
+  i = nics.find(NicId(kClientAddr2.ipaddr(), nilAddress));
+  ASSERT(i != nics.end());
+  info = i->second;
+  VerifyNic(info, kClientAddr2);
+
+  // Now verify both interfaces with proxy.
+  i = nics.find(NicId(kClientAddr1.ipaddr(), kProxyAddr));
+  ASSERT(i != nics.end());
+  info = i->second;
+  VerifyNic(info, kClientAddr1);
+
+  i = nics.find(NicId(kClientAddr2.ipaddr(), kProxyAddr));
+  ASSERT(i != nics.end());
+  info = i->second;
+  VerifyNic(info, kClientAddr2);
+};
+
+// Tests that nothing bad happens if thera are no network interfaces
+// available to check.
+TEST_F(ConnectivityCheckerTest, TestStartNoNetwork) {
+  ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(),
+                                                  kJid,
+                                                  kSessionId,
+                                                  kBrowserAgent,
+                                                  kRelayToken,
+                                                  kConnection);
+  connectivity_checker.Initialize();
+  connectivity_checker.Start();
+  rtc::Thread::Current()->ProcessMessages(1000);
+
+  NicMap nics = connectivity_checker.GetResults();
+
+  // Verify that no nics where checked.
+  EXPECT_EQ(0U, nics.size());
+}
+
+}  // namespace cricket
diff --git a/p2p/client/fakeportallocator.h b/p2p/client/fakeportallocator.h
new file mode 100644
index 0000000..73dae3a
--- /dev/null
+++ b/p2p/client/fakeportallocator.h
@@ -0,0 +1,121 @@
+/*
+ *  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.
+ */
+
+#ifndef WEBRTC_P2P_CLIENT_FAKEPORTALLOCATOR_H_
+#define WEBRTC_P2P_CLIENT_FAKEPORTALLOCATOR_H_
+
+#include <string>
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/udpport.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace rtc {
+class SocketFactory;
+class Thread;
+}
+
+namespace cricket {
+
+class FakePortAllocatorSession : public PortAllocatorSession {
+ public:
+  FakePortAllocatorSession(rtc::Thread* worker_thread,
+                           rtc::PacketSocketFactory* factory,
+                           const std::string& content_name,
+                           int component,
+                           const std::string& ice_ufrag,
+                           const std::string& ice_pwd)
+      : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd,
+                             cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG),
+        worker_thread_(worker_thread),
+        factory_(factory),
+        network_("network", "unittest",
+                 rtc::IPAddress(INADDR_LOOPBACK), 8),
+        port_(), running_(false),
+        port_config_count_(0) {
+    network_.AddIP(rtc::IPAddress(INADDR_LOOPBACK));
+  }
+
+  virtual void StartGettingPorts() {
+    if (!port_) {
+      port_.reset(cricket::UDPPort::Create(worker_thread_,
+                                           factory_,
+                                           &network_,
+#ifdef USE_WEBRTC_DEV_BRANCH
+                                           network_.GetBestIP(),
+#else  // USE_WEBRTC_DEV_BRANCH
+                                           network_.ip(),
+#endif  // USE_WEBRTC_DEV_BRANCH
+                                           0,
+                                           0,
+                                           username(),
+                                           password()));
+      AddPort(port_.get());
+    }
+    ++port_config_count_;
+    running_ = true;
+  }
+
+  virtual void StopGettingPorts() { running_ = false; }
+  virtual bool IsGettingPorts() { return running_; }
+  int port_config_count() { return port_config_count_; }
+
+  void AddPort(cricket::Port* port) {
+    port->set_component(component_);
+    port->set_generation(0);
+    port->SignalPortComplete.connect(
+        this, &FakePortAllocatorSession::OnPortComplete);
+    port->PrepareAddress();
+    SignalPortReady(this, port);
+  }
+  void OnPortComplete(cricket::Port* port) {
+    SignalCandidatesReady(this, port->Candidates());
+    SignalCandidatesAllocationDone(this);
+  }
+
+ private:
+  rtc::Thread* worker_thread_;
+  rtc::PacketSocketFactory* factory_;
+  rtc::Network network_;
+  rtc::scoped_ptr<cricket::Port> port_;
+  bool running_;
+  int port_config_count_;
+};
+
+class FakePortAllocator : public cricket::PortAllocator {
+ public:
+  FakePortAllocator(rtc::Thread* worker_thread,
+                    rtc::PacketSocketFactory* factory)
+      : worker_thread_(worker_thread), factory_(factory) {
+    if (factory_ == NULL) {
+      owned_factory_.reset(new rtc::BasicPacketSocketFactory(
+          worker_thread_));
+      factory_ = owned_factory_.get();
+    }
+  }
+
+  virtual cricket::PortAllocatorSession* CreateSessionInternal(
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd) {
+    return new FakePortAllocatorSession(
+        worker_thread_, factory_, content_name, component, ice_ufrag, ice_pwd);
+  }
+
+ private:
+  rtc::Thread* worker_thread_;
+  rtc::PacketSocketFactory* factory_;
+  rtc::scoped_ptr<rtc::BasicPacketSocketFactory> owned_factory_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_CLIENT_FAKEPORTALLOCATOR_H_
diff --git a/p2p/client/httpportallocator.cc b/p2p/client/httpportallocator.cc
new file mode 100644
index 0000000..c072da2
--- /dev/null
+++ b/p2p/client/httpportallocator.cc
@@ -0,0 +1,326 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/client/httpportallocator.h"
+
+#include <algorithm>
+#include <map>
+
+#include "webrtc/base/asynchttprequest.h"
+#include "webrtc/base/basicdefs.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/nethelpers.h"
+#include "webrtc/base/signalthread.h"
+#include "webrtc/base/stringencode.h"
+
+namespace {
+
+// Helper routine to remove whitespace from the ends of a string.
+void Trim(std::string& str) {
+  size_t first = str.find_first_not_of(" \t\r\n");
+  if (first == std::string::npos) {
+    str.clear();
+    return;
+  }
+
+  ASSERT(str.find_last_not_of(" \t\r\n") != std::string::npos);
+}
+
+// Parses the lines in the result of the HTTP request that are of the form
+// 'a=b' and returns them in a map.
+typedef std::map<std::string, std::string> StringMap;
+void ParseMap(const std::string& string, StringMap& map) {
+  size_t start_of_line = 0;
+  size_t end_of_line = 0;
+
+  for (;;) {  // for each line
+    start_of_line = string.find_first_not_of("\r\n", end_of_line);
+    if (start_of_line == std::string::npos)
+      break;
+
+    end_of_line = string.find_first_of("\r\n", start_of_line);
+    if (end_of_line == std::string::npos) {
+      end_of_line = string.length();
+    }
+
+    size_t equals = string.find('=', start_of_line);
+    if ((equals >= end_of_line) || (equals == std::string::npos))
+      continue;
+
+    std::string key(string, start_of_line, equals - start_of_line);
+    std::string value(string, equals + 1, end_of_line - equals - 1);
+
+    Trim(key);
+    Trim(value);
+
+    if ((key.size() > 0) && (value.size() > 0))
+      map[key] = value;
+  }
+}
+
+}  // namespace
+
+namespace cricket {
+
+// HttpPortAllocatorBase
+
+const int HttpPortAllocatorBase::kNumRetries = 5;
+
+const char HttpPortAllocatorBase::kCreateSessionURL[] = "/create_session";
+
+HttpPortAllocatorBase::HttpPortAllocatorBase(
+    rtc::NetworkManager* network_manager,
+    rtc::PacketSocketFactory* socket_factory,
+    const std::string &user_agent)
+    : BasicPortAllocator(network_manager, socket_factory), agent_(user_agent) {
+  relay_hosts_.push_back("relay.google.com");
+  stun_hosts_.push_back(
+      rtc::SocketAddress("stun.l.google.com", 19302));
+}
+
+HttpPortAllocatorBase::HttpPortAllocatorBase(
+    rtc::NetworkManager* network_manager,
+    const std::string &user_agent)
+    : BasicPortAllocator(network_manager), agent_(user_agent) {
+  relay_hosts_.push_back("relay.google.com");
+  stun_hosts_.push_back(
+      rtc::SocketAddress("stun.l.google.com", 19302));
+}
+
+HttpPortAllocatorBase::~HttpPortAllocatorBase() {
+}
+
+// HttpPortAllocatorSessionBase
+
+HttpPortAllocatorSessionBase::HttpPortAllocatorSessionBase(
+    HttpPortAllocatorBase* allocator,
+    const std::string& content_name,
+    int component,
+    const std::string& ice_ufrag,
+    const std::string& ice_pwd,
+    const std::vector<rtc::SocketAddress>& stun_hosts,
+    const std::vector<std::string>& relay_hosts,
+    const std::string& relay_token,
+    const std::string& user_agent)
+    : BasicPortAllocatorSession(allocator, content_name, component,
+                                ice_ufrag, ice_pwd),
+      relay_hosts_(relay_hosts), stun_hosts_(stun_hosts),
+      relay_token_(relay_token), agent_(user_agent), attempts_(0) {
+}
+
+HttpPortAllocatorSessionBase::~HttpPortAllocatorSessionBase() {}
+
+void HttpPortAllocatorSessionBase::GetPortConfigurations() {
+  // Creating relay sessions can take time and is done asynchronously.
+  // Creating stun sessions could also take time and could be done aysnc also,
+  // but for now is done here and added to the initial config.  Note any later
+  // configs will have unresolved stun ips and will be discarded by the
+  // AllocationSequence.
+  ServerAddresses hosts;
+  for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin();
+      it != stun_hosts_.end(); ++it) {
+    hosts.insert(*it);
+  }
+
+  PortConfiguration* config = new PortConfiguration(hosts,
+                                                    username(),
+                                                    password());
+  ConfigReady(config);
+  TryCreateRelaySession();
+}
+
+void HttpPortAllocatorSessionBase::TryCreateRelaySession() {
+  if (allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY) {
+    LOG(LS_VERBOSE) << "HttpPortAllocator: Relay ports disabled, skipping.";
+    return;
+  }
+
+  if (attempts_ == HttpPortAllocator::kNumRetries) {
+    LOG(LS_ERROR) << "HttpPortAllocator: maximum number of requests reached; "
+                  << "giving up on relay.";
+    return;
+  }
+
+  if (relay_hosts_.size() == 0) {
+    LOG(LS_ERROR) << "HttpPortAllocator: no relay hosts configured.";
+    return;
+  }
+
+  // Choose the next host to try.
+  std::string host = relay_hosts_[attempts_ % relay_hosts_.size()];
+  attempts_++;
+  LOG(LS_INFO) << "HTTPPortAllocator: sending to relay host " << host;
+  if (relay_token_.empty()) {
+    LOG(LS_WARNING) << "No relay auth token found.";
+  }
+
+  SendSessionRequest(host, rtc::HTTP_SECURE_PORT);
+}
+
+std::string HttpPortAllocatorSessionBase::GetSessionRequestUrl() {
+  std::string url = std::string(HttpPortAllocator::kCreateSessionURL);
+  if (allocator()->flags() & PORTALLOCATOR_ENABLE_SHARED_UFRAG) {
+    ASSERT(!username().empty());
+    ASSERT(!password().empty());
+    url = url + "?username=" + rtc::s_url_encode(username()) +
+        "&password=" + rtc::s_url_encode(password());
+  }
+  return url;
+}
+
+void HttpPortAllocatorSessionBase::ReceiveSessionResponse(
+    const std::string& response) {
+
+  StringMap map;
+  ParseMap(response, map);
+
+  if (!username().empty() && map["username"] != username()) {
+    LOG(LS_WARNING) << "Received unexpected username value from relay server.";
+  }
+  if (!password().empty() && map["password"] != password()) {
+    LOG(LS_WARNING) << "Received unexpected password value from relay server.";
+  }
+
+  std::string relay_ip = map["relay.ip"];
+  std::string relay_udp_port = map["relay.udp_port"];
+  std::string relay_tcp_port = map["relay.tcp_port"];
+  std::string relay_ssltcp_port = map["relay.ssltcp_port"];
+
+  ServerAddresses hosts;
+  for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin();
+      it != stun_hosts_.end(); ++it) {
+    hosts.insert(*it);
+  }
+
+  PortConfiguration* config = new PortConfiguration(hosts,
+                                                    map["username"],
+                                                    map["password"]);
+
+  RelayServerConfig relay_config(RELAY_GTURN);
+  if (!relay_udp_port.empty()) {
+    rtc::SocketAddress address(relay_ip, atoi(relay_udp_port.c_str()));
+    relay_config.ports.push_back(ProtocolAddress(address, PROTO_UDP));
+  }
+  if (!relay_tcp_port.empty()) {
+    rtc::SocketAddress address(relay_ip, atoi(relay_tcp_port.c_str()));
+    relay_config.ports.push_back(ProtocolAddress(address, PROTO_TCP));
+  }
+  if (!relay_ssltcp_port.empty()) {
+    rtc::SocketAddress address(relay_ip, atoi(relay_ssltcp_port.c_str()));
+    relay_config.ports.push_back(ProtocolAddress(address, PROTO_SSLTCP));
+  }
+  config->AddRelay(relay_config);
+  ConfigReady(config);
+}
+
+// HttpPortAllocator
+
+HttpPortAllocator::HttpPortAllocator(
+    rtc::NetworkManager* network_manager,
+    rtc::PacketSocketFactory* socket_factory,
+    const std::string &user_agent)
+    : HttpPortAllocatorBase(network_manager, socket_factory, user_agent) {
+}
+
+HttpPortAllocator::HttpPortAllocator(
+    rtc::NetworkManager* network_manager,
+    const std::string &user_agent)
+    : HttpPortAllocatorBase(network_manager, user_agent) {
+}
+HttpPortAllocator::~HttpPortAllocator() {}
+
+PortAllocatorSession* HttpPortAllocator::CreateSessionInternal(
+    const std::string& content_name,
+    int component,
+    const std::string& ice_ufrag, const std::string& ice_pwd) {
+  return new HttpPortAllocatorSession(this, content_name, component,
+                                      ice_ufrag, ice_pwd, stun_hosts(),
+                                      relay_hosts(), relay_token(),
+                                      user_agent());
+}
+
+// HttpPortAllocatorSession
+
+HttpPortAllocatorSession::HttpPortAllocatorSession(
+    HttpPortAllocator* allocator,
+    const std::string& content_name,
+    int component,
+    const std::string& ice_ufrag,
+    const std::string& ice_pwd,
+    const std::vector<rtc::SocketAddress>& stun_hosts,
+    const std::vector<std::string>& relay_hosts,
+    const std::string& relay,
+    const std::string& agent)
+    : HttpPortAllocatorSessionBase(allocator, content_name, component,
+                                   ice_ufrag, ice_pwd, stun_hosts,
+                                   relay_hosts, relay, agent) {
+}
+
+HttpPortAllocatorSession::~HttpPortAllocatorSession() {
+  for (std::list<rtc::AsyncHttpRequest*>::iterator it = requests_.begin();
+       it != requests_.end(); ++it) {
+    (*it)->Destroy(true);
+  }
+}
+
+void HttpPortAllocatorSession::SendSessionRequest(const std::string& host,
+                                                  int port) {
+  // Initiate an HTTP request to create a session through the chosen host.
+  rtc::AsyncHttpRequest* request =
+      new rtc::AsyncHttpRequest(user_agent());
+  request->SignalWorkDone.connect(this,
+      &HttpPortAllocatorSession::OnRequestDone);
+
+  request->set_secure(port == rtc::HTTP_SECURE_PORT);
+  request->set_proxy(allocator()->proxy());
+  request->response().document.reset(new rtc::MemoryStream);
+  request->request().verb = rtc::HV_GET;
+  request->request().path = GetSessionRequestUrl();
+  request->request().addHeader("X-Talk-Google-Relay-Auth", relay_token(), true);
+  request->request().addHeader("X-Stream-Type", "video_rtp", true);
+  request->set_host(host);
+  request->set_port(port);
+  request->Start();
+  request->Release();
+
+  requests_.push_back(request);
+}
+
+void HttpPortAllocatorSession::OnRequestDone(rtc::SignalThread* data) {
+  rtc::AsyncHttpRequest* request =
+      static_cast<rtc::AsyncHttpRequest*>(data);
+
+  // Remove the request from the list of active requests.
+  std::list<rtc::AsyncHttpRequest*>::iterator it =
+      std::find(requests_.begin(), requests_.end(), request);
+  if (it != requests_.end()) {
+    requests_.erase(it);
+  }
+
+  if (request->response().scode != 200) {
+    LOG(LS_WARNING) << "HTTPPortAllocator: request "
+                    << " received error " << request->response().scode;
+    TryCreateRelaySession();
+    return;
+  }
+  LOG(LS_INFO) << "HTTPPortAllocator: request succeeded";
+
+  rtc::MemoryStream* stream =
+      static_cast<rtc::MemoryStream*>(request->response().document.get());
+  stream->Rewind();
+  size_t length;
+  stream->GetSize(&length);
+  std::string resp = std::string(stream->GetBuffer(), length);
+  ReceiveSessionResponse(resp);
+}
+
+}  // namespace cricket
diff --git a/p2p/client/httpportallocator.h b/p2p/client/httpportallocator.h
new file mode 100644
index 0000000..e2fa743
--- /dev/null
+++ b/p2p/client/httpportallocator.h
@@ -0,0 +1,173 @@
+/*
+ *  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_P2P_CLIENT_HTTPPORTALLOCATOR_H_
+#define WEBRTC_P2P_CLIENT_HTTPPORTALLOCATOR_H_
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/client/basicportallocator.h"
+
+class HttpPortAllocatorTest_TestSessionRequestUrl_Test;
+
+namespace rtc {
+class AsyncHttpRequest;
+class SignalThread;
+}
+
+namespace cricket {
+
+class HttpPortAllocatorBase : public BasicPortAllocator {
+ public:
+  // The number of HTTP requests we should attempt before giving up.
+  static const int kNumRetries;
+
+  // Records the URL that we will GET in order to create a session.
+  static const char kCreateSessionURL[];
+
+  HttpPortAllocatorBase(rtc::NetworkManager* network_manager,
+                        const std::string& user_agent);
+  HttpPortAllocatorBase(rtc::NetworkManager* network_manager,
+                        rtc::PacketSocketFactory* socket_factory,
+                        const std::string& user_agent);
+  virtual ~HttpPortAllocatorBase();
+
+  // CreateSession is defined in BasicPortAllocator but is
+  // redefined here as pure virtual.
+  virtual PortAllocatorSession* CreateSessionInternal(
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd) = 0;
+
+  void SetStunHosts(const std::vector<rtc::SocketAddress>& hosts) {
+    if (!hosts.empty()) {
+      stun_hosts_ = hosts;
+    }
+  }
+  void SetRelayHosts(const std::vector<std::string>& hosts) {
+    if (!hosts.empty()) {
+      relay_hosts_ = hosts;
+    }
+  }
+  void SetRelayToken(const std::string& relay) { relay_token_ = relay; }
+
+  const std::vector<rtc::SocketAddress>& stun_hosts() const {
+    return stun_hosts_;
+  }
+
+  const std::vector<std::string>& relay_hosts() const {
+    return relay_hosts_;
+  }
+
+  const std::string& relay_token() const {
+    return relay_token_;
+  }
+
+  const std::string& user_agent() const {
+    return agent_;
+  }
+
+ private:
+  std::vector<rtc::SocketAddress> stun_hosts_;
+  std::vector<std::string> relay_hosts_;
+  std::string relay_token_;
+  std::string agent_;
+};
+
+class RequestData;
+
+class HttpPortAllocatorSessionBase : public BasicPortAllocatorSession {
+ public:
+  HttpPortAllocatorSessionBase(
+      HttpPortAllocatorBase* allocator,
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd,
+      const std::vector<rtc::SocketAddress>& stun_hosts,
+      const std::vector<std::string>& relay_hosts,
+      const std::string& relay,
+      const std::string& agent);
+  virtual ~HttpPortAllocatorSessionBase();
+
+  const std::string& relay_token() const {
+    return relay_token_;
+  }
+
+  const std::string& user_agent() const {
+      return agent_;
+  }
+
+  virtual void SendSessionRequest(const std::string& host, int port) = 0;
+  virtual void ReceiveSessionResponse(const std::string& response);
+
+  // Made public for testing. Should be protected.
+  std::string GetSessionRequestUrl();
+
+ protected:
+  virtual void GetPortConfigurations();
+  void TryCreateRelaySession();
+  virtual HttpPortAllocatorBase* allocator() {
+    return static_cast<HttpPortAllocatorBase*>(
+        BasicPortAllocatorSession::allocator());
+  }
+
+ private:
+  std::vector<std::string> relay_hosts_;
+  std::vector<rtc::SocketAddress> stun_hosts_;
+  std::string relay_token_;
+  std::string agent_;
+  int attempts_;
+};
+
+class HttpPortAllocator : public HttpPortAllocatorBase {
+ public:
+  HttpPortAllocator(rtc::NetworkManager* network_manager,
+                    const std::string& user_agent);
+  HttpPortAllocator(rtc::NetworkManager* network_manager,
+                    rtc::PacketSocketFactory* socket_factory,
+                    const std::string& user_agent);
+  virtual ~HttpPortAllocator();
+  virtual PortAllocatorSession* CreateSessionInternal(
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag, const std::string& ice_pwd);
+};
+
+class HttpPortAllocatorSession : public HttpPortAllocatorSessionBase {
+ public:
+  HttpPortAllocatorSession(
+      HttpPortAllocator* allocator,
+      const std::string& content_name,
+      int component,
+      const std::string& ice_ufrag,
+      const std::string& ice_pwd,
+      const std::vector<rtc::SocketAddress>& stun_hosts,
+      const std::vector<std::string>& relay_hosts,
+      const std::string& relay,
+      const std::string& agent);
+  virtual ~HttpPortAllocatorSession();
+
+  virtual void SendSessionRequest(const std::string& host, int port);
+
+ protected:
+  // Protected for diagnostics.
+  virtual void OnRequestDone(rtc::SignalThread* request);
+
+ private:
+  std::list<rtc::AsyncHttpRequest*> requests_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_CLIENT_HTTPPORTALLOCATOR_H_
diff --git a/p2p/client/portallocator_unittest.cc b/p2p/client/portallocator_unittest.cc
new file mode 100644
index 0000000..5dcc8f9
--- /dev/null
+++ b/p2p/client/portallocator_unittest.cc
@@ -0,0 +1,1066 @@
+/*
+ *  Copyright 2009 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can 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/p2p/base/basicpacketsocketfactory.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/p2ptransportchannel.h"
+#include "webrtc/p2p/base/portallocatorsessionproxy.h"
+#include "webrtc/p2p/base/testrelayserver.h"
+#include "webrtc/p2p/base/teststunserver.h"
+#include "webrtc/p2p/base/testturnserver.h"
+#include "webrtc/p2p/client/basicportallocator.h"
+#include "webrtc/p2p/client/httpportallocator.h"
+#include "webrtc/base/fakenetwork.h"
+#include "webrtc/base/firewallsocketserver.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/natserver.h"
+#include "webrtc/base/natsocketfactory.h"
+#include "webrtc/base/network.h"
+#include "webrtc/base/physicalsocketserver.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/ssladapter.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/virtualsocketserver.h"
+
+using cricket::ServerAddresses;
+using rtc::SocketAddress;
+using rtc::Thread;
+
+static const SocketAddress kClientAddr("11.11.11.11", 0);
+static const SocketAddress kPrivateAddr("192.168.1.11", 0);
+static const SocketAddress kClientIPv6Addr(
+    "2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
+static const SocketAddress kClientAddr2("22.22.22.22", 0);
+static const SocketAddress kNatAddr("77.77.77.77", rtc::NAT_SERVER_PORT);
+static const SocketAddress kRemoteClientAddr("22.22.22.22", 0);
+static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
+static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000);
+static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001);
+static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002);
+static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003);
+static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004);
+static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005);
+static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478);
+static const SocketAddress kTurnTcpIntAddr("99.99.99.5", 3478);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.6", 0);
+
+// Minimum and maximum port for port range tests.
+static const int kMinPort = 10000;
+static const int kMaxPort = 10099;
+
+// Based on ICE_UFRAG_LENGTH
+static const char kIceUfrag0[] = "TESTICEUFRAG0000";
+// Based on ICE_PWD_LENGTH
+static const char kIcePwd0[] = "TESTICEPWD00000000000000";
+
+static const char kContentName[] = "test content";
+
+static const int kDefaultAllocationTimeout = 1000;
+static const char kTurnUsername[] = "test";
+static const char kTurnPassword[] = "test";
+
+namespace cricket {
+
+// Helper for dumping candidates
+std::ostream& operator<<(std::ostream& os, const cricket::Candidate& c) {
+  os << c.ToString();
+  return os;
+}
+
+}  // namespace cricket
+
+class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
+ public:
+  PortAllocatorTest()
+      : pss_(new rtc::PhysicalSocketServer),
+        vss_(new rtc::VirtualSocketServer(pss_.get())),
+        fss_(new rtc::FirewallSocketServer(vss_.get())),
+        ss_scope_(fss_.get()),
+        nat_factory_(vss_.get(), kNatAddr),
+        nat_socket_factory_(&nat_factory_),
+        stun_server_(cricket::TestStunServer::Create(Thread::Current(),
+                                                     kStunAddr)),
+        relay_server_(Thread::Current(), kRelayUdpIntAddr, kRelayUdpExtAddr,
+                      kRelayTcpIntAddr, kRelayTcpExtAddr,
+                      kRelaySslTcpIntAddr, kRelaySslTcpExtAddr),
+        turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr),
+        candidate_allocation_done_(false) {
+    cricket::ServerAddresses stun_servers;
+    stun_servers.insert(kStunAddr);
+    // Passing the addresses of GTURN servers will enable GTURN in
+    // Basicportallocator.
+    allocator_.reset(new cricket::BasicPortAllocator(
+        &network_manager_,
+        stun_servers,
+        kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr));
+    allocator_->set_step_delay(cricket::kMinimumStepDelay);
+  }
+
+  void AddInterface(const SocketAddress& addr) {
+    network_manager_.AddInterface(addr);
+  }
+  bool SetPortRange(int min_port, int max_port) {
+    return allocator_->SetPortRange(min_port, max_port);
+  }
+  void ResetWithNatServer(const rtc::SocketAddress& stun_server) {
+    nat_server_.reset(new rtc::NATServer(
+        rtc::NAT_OPEN_CONE, vss_.get(), kNatAddr, vss_.get(), kNatAddr));
+
+    ServerAddresses stun_servers;
+    stun_servers.insert(stun_server);
+    allocator_.reset(new cricket::BasicPortAllocator(
+        &network_manager_, &nat_socket_factory_, stun_servers));
+    allocator().set_step_delay(cricket::kMinimumStepDelay);
+  }
+
+  // Create a BasicPortAllocator without GTURN and add the TURN servers.
+  void ResetWithTurnServers(const rtc::SocketAddress& udp_turn,
+                            const rtc::SocketAddress& tcp_turn) {
+    allocator_.reset(new cricket::BasicPortAllocator(&network_manager_));
+    allocator().set_step_delay(cricket::kMinimumStepDelay);
+    AddTurnServers(udp_turn, tcp_turn);
+  }
+
+  void AddTurnServers(const rtc::SocketAddress& udp_turn,
+                      const rtc::SocketAddress& tcp_turn) {
+    cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+    cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword);
+    relay_server.credentials = credentials;
+
+    if (!udp_turn.IsNil()) {
+      relay_server.ports.push_back(cricket::ProtocolAddress(
+          kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+    }
+    if (!tcp_turn.IsNil()) {
+      relay_server.ports.push_back(cricket::ProtocolAddress(
+          kTurnTcpIntAddr, cricket::PROTO_TCP, false));
+    }
+    allocator_->AddRelay(relay_server);
+  }
+
+  bool CreateSession(int component) {
+    session_.reset(CreateSession("session", component));
+    if (!session_)
+      return false;
+    return true;
+  }
+
+  bool CreateSession(int component, const std::string& content_name) {
+    session_.reset(CreateSession("session", content_name, component));
+    if (!session_)
+      return false;
+    return true;
+  }
+
+  cricket::PortAllocatorSession* CreateSession(
+      const std::string& sid, int component) {
+    return CreateSession(sid, kContentName, component);
+  }
+
+  cricket::PortAllocatorSession* CreateSession(
+      const std::string& sid, const std::string& content_name, int component) {
+    return CreateSession(sid, content_name, component, kIceUfrag0, kIcePwd0);
+  }
+
+  cricket::PortAllocatorSession* CreateSession(
+      const std::string& sid, const std::string& content_name, int component,
+      const std::string& ice_ufrag, const std::string& ice_pwd) {
+    cricket::PortAllocatorSession* session =
+        allocator_->CreateSession(
+            sid, content_name, component, ice_ufrag, ice_pwd);
+    session->SignalPortReady.connect(this,
+            &PortAllocatorTest::OnPortReady);
+    session->SignalCandidatesReady.connect(this,
+        &PortAllocatorTest::OnCandidatesReady);
+    session->SignalCandidatesAllocationDone.connect(this,
+        &PortAllocatorTest::OnCandidatesAllocationDone);
+    return session;
+  }
+
+  static bool CheckCandidate(const cricket::Candidate& c,
+                             int component, const std::string& type,
+                             const std::string& proto,
+                             const SocketAddress& addr) {
+    return (c.component() == component && c.type() == type &&
+        c.protocol() == proto && c.address().ipaddr() == addr.ipaddr() &&
+        ((addr.port() == 0 && (c.address().port() != 0)) ||
+        (c.address().port() == addr.port())));
+  }
+  static bool CheckPort(const rtc::SocketAddress& addr,
+                        int min_port, int max_port) {
+    return (addr.port() >= min_port && addr.port() <= max_port);
+  }
+
+  void OnCandidatesAllocationDone(cricket::PortAllocatorSession* session) {
+    // We should only get this callback once, except in the mux test where
+    // we have multiple port allocation sessions.
+    if (session == session_.get()) {
+      ASSERT_FALSE(candidate_allocation_done_);
+      candidate_allocation_done_ = true;
+    }
+  }
+
+  // Check if all ports allocated have send-buffer size |expected|. If
+  // |expected| == -1, check if GetOptions returns SOCKET_ERROR.
+  void CheckSendBufferSizesOfAllPorts(int expected) {
+    std::vector<cricket::PortInterface*>::iterator it;
+    for (it = ports_.begin(); it < ports_.end(); ++it) {
+      int send_buffer_size;
+      if (expected == -1) {
+        EXPECT_EQ(SOCKET_ERROR,
+                  (*it)->GetOption(rtc::Socket::OPT_SNDBUF,
+                                   &send_buffer_size));
+      } else {
+        EXPECT_EQ(0, (*it)->GetOption(rtc::Socket::OPT_SNDBUF,
+                                      &send_buffer_size));
+        ASSERT_EQ(expected, send_buffer_size);
+      }
+    }
+  }
+
+ protected:
+  cricket::BasicPortAllocator& allocator() {
+    return *allocator_;
+  }
+
+  void OnPortReady(cricket::PortAllocatorSession* ses,
+                   cricket::PortInterface* port) {
+    LOG(LS_INFO) << "OnPortReady: " << port->ToString();
+    ports_.push_back(port);
+  }
+  void OnCandidatesReady(cricket::PortAllocatorSession* ses,
+                         const std::vector<cricket::Candidate>& candidates) {
+    for (size_t i = 0; i < candidates.size(); ++i) {
+      LOG(LS_INFO) << "OnCandidatesReady: " << candidates[i].ToString();
+      candidates_.push_back(candidates[i]);
+    }
+  }
+
+  bool HasRelayAddress(const cricket::ProtocolAddress& proto_addr) {
+    for (size_t i = 0; i < allocator_->relays().size(); ++i) {
+      cricket::RelayServerConfig server_config = allocator_->relays()[i];
+      cricket::PortList::const_iterator relay_port;
+      for (relay_port = server_config.ports.begin();
+          relay_port != server_config.ports.end(); ++relay_port) {
+        if (proto_addr.address == relay_port->address &&
+            proto_addr.proto == relay_port->proto)
+          return true;
+      }
+    }
+    return false;
+  }
+
+  rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> vss_;
+  rtc::scoped_ptr<rtc::FirewallSocketServer> fss_;
+  rtc::SocketServerScope ss_scope_;
+  rtc::scoped_ptr<rtc::NATServer> nat_server_;
+  rtc::NATSocketFactory nat_factory_;
+  rtc::BasicPacketSocketFactory nat_socket_factory_;
+  rtc::scoped_ptr<cricket::TestStunServer> stun_server_;
+  cricket::TestRelayServer relay_server_;
+  cricket::TestTurnServer turn_server_;
+  rtc::FakeNetworkManager network_manager_;
+  rtc::scoped_ptr<cricket::BasicPortAllocator> allocator_;
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session_;
+  std::vector<cricket::PortInterface*> ports_;
+  std::vector<cricket::Candidate> candidates_;
+  bool candidate_allocation_done_;
+};
+
+// Tests that we can init the port allocator and create a session.
+TEST_F(PortAllocatorTest, TestBasic) {
+  EXPECT_EQ(&network_manager_, allocator().network_manager());
+  EXPECT_EQ(kStunAddr, *allocator().stun_servers().begin());
+  ASSERT_EQ(1u, allocator().relays().size());
+  EXPECT_EQ(cricket::RELAY_GTURN, allocator().relays()[0].type);
+  // Empty relay credentials are used for GTURN.
+  EXPECT_TRUE(allocator().relays()[0].credentials.username.empty());
+  EXPECT_TRUE(allocator().relays()[0].credentials.password.empty());
+  EXPECT_TRUE(HasRelayAddress(cricket::ProtocolAddress(
+      kRelayUdpIntAddr, cricket::PROTO_UDP)));
+  EXPECT_TRUE(HasRelayAddress(cricket::ProtocolAddress(
+      kRelayTcpIntAddr, cricket::PROTO_TCP)));
+  EXPECT_TRUE(HasRelayAddress(cricket::ProtocolAddress(
+      kRelaySslTcpIntAddr, cricket::PROTO_SSLTCP)));
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+}
+
+// Tests that we allocator session not trying to allocate ports for every 250ms.
+TEST_F(PortAllocatorTest, TestNoNetworkInterface) {
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  // Waiting for one second to make sure BasicPortAllocatorSession has not
+  // called OnAllocate multiple times. In old behavior it's called every 250ms.
+  // When there are no network interfaces, each execution of OnAllocate will
+  // result in SignalCandidatesAllocationDone signal.
+  rtc::Thread::Current()->ProcessMessages(1000);
+  EXPECT_TRUE(candidate_allocation_done_);
+  EXPECT_EQ(0U, candidates_.size());
+}
+
+// Tests that we can get all the desired addresses successfully.
+TEST_F(PortAllocatorTest, TestGetAllPortsWithMinimumStepDelay) {
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(4U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[3],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[4],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[5],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[6],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP,
+      "relay", "ssltcp", kRelaySslTcpIntAddr);
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Verify candidates with default step delay of 1sec.
+TEST_F(PortAllocatorTest, TestGetAllPortsWithOneSecondStepDelay) {
+  AddInterface(kClientAddr);
+  allocator_->set_step_delay(cricket::kDefaultStepDelay);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(2U, candidates_.size(), 1000);
+  EXPECT_EQ(2U, ports_.size());
+  ASSERT_EQ_WAIT(4U, candidates_.size(), 2000);
+  EXPECT_EQ(3U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[3],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr);
+  ASSERT_EQ_WAIT(6U, candidates_.size(), 1500);
+  EXPECT_PRED5(CheckCandidate, candidates_[4],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[5],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr);
+  EXPECT_EQ(4U, ports_.size());
+  ASSERT_EQ_WAIT(7U, candidates_.size(), 2000);
+  EXPECT_PRED5(CheckCandidate, candidates_[6],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP,
+               "relay", "ssltcp", kRelaySslTcpIntAddr);
+  EXPECT_EQ(4U, ports_.size());
+  EXPECT_TRUE(candidate_allocation_done_);
+  // If we Stop gathering now, we shouldn't get a second "done" callback.
+  session_->StopGettingPorts();
+}
+
+TEST_F(PortAllocatorTest, TestSetupVideoRtpPortsWithNormalSendBuffers) {
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP,
+                            cricket::CN_VIDEO));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_TRUE(candidate_allocation_done_);
+  // If we Stop gathering now, we shouldn't get a second "done" callback.
+  session_->StopGettingPorts();
+
+  // All ports should have unset send-buffer sizes.
+  CheckSendBufferSizesOfAllPorts(-1);
+}
+
+// Tests that we can get callback after StopGetAllPorts.
+TEST_F(PortAllocatorTest, TestStopGetAllPorts) {
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(2U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(2U, ports_.size());
+  session_->StopGettingPorts();
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+}
+
+// Test that we restrict client ports appropriately when a port range is set.
+// We check the candidates for udp/stun/tcp ports, and the from address
+// for relay ports.
+TEST_F(PortAllocatorTest, TestGetAllPortsPortRange) {
+  AddInterface(kClientAddr);
+  // Check that an invalid port range fails.
+  EXPECT_FALSE(SetPortRange(kMaxPort, kMinPort));
+  // Check that a null port range succeeds.
+  EXPECT_TRUE(SetPortRange(0, 0));
+  // Check that a valid port range succeeds.
+  EXPECT_TRUE(SetPortRange(kMinPort, kMaxPort));
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(4U, ports_.size());
+  // Check the port number for the UDP port object.
+  EXPECT_PRED3(CheckPort, candidates_[0].address(), kMinPort, kMaxPort);
+  // Check the port number for the STUN port object.
+  EXPECT_PRED3(CheckPort, candidates_[1].address(), kMinPort, kMaxPort);
+  // Check the port number used to connect to the relay server.
+  EXPECT_PRED3(CheckPort, relay_server_.GetConnection(0).source(),
+               kMinPort, kMaxPort);
+  // Check the port number for the TCP port object.
+  EXPECT_PRED3(CheckPort, candidates_[5].address(), kMinPort, kMaxPort);
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Test that we don't crash or malfunction if we have no network adapters.
+TEST_F(PortAllocatorTest, TestGetAllPortsNoAdapters) {
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  rtc::Thread::Current()->ProcessMessages(100);
+  // Without network adapter, we should not get any candidate.
+  EXPECT_EQ(0U, candidates_.size());
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Test that we can get OnCandidatesAllocationDone callback when all the ports
+// are disabled.
+TEST_F(PortAllocatorTest, TestDisableAllPorts) {
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->set_flags(cricket::PORTALLOCATOR_DISABLE_UDP |
+                      cricket::PORTALLOCATOR_DISABLE_STUN |
+                      cricket::PORTALLOCATOR_DISABLE_RELAY |
+                      cricket::PORTALLOCATOR_DISABLE_TCP);
+  session_->StartGettingPorts();
+  rtc::Thread::Current()->ProcessMessages(100);
+  EXPECT_EQ(0U, candidates_.size());
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Test that we don't crash or malfunction if we can't create UDP sockets.
+TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpSockets) {
+  AddInterface(kClientAddr);
+  fss_->set_udp_sockets_enabled(false);
+  EXPECT_TRUE(CreateSession(1));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(5U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(2U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[3],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[4],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP,
+      "relay", "ssltcp", kRelaySslTcpIntAddr);
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Test that we don't crash or malfunction if we can't create UDP sockets or
+// listen on TCP sockets. We still give out a local TCP address, since
+// apparently this is needed for the remote side to accept our connection.
+TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpSocketsNoTcpListen) {
+  AddInterface(kClientAddr);
+  fss_->set_udp_sockets_enabled(false);
+  fss_->set_tcp_listen_enabled(false);
+  EXPECT_TRUE(CreateSession(1));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(5U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(2U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      1, "relay", "udp", kRelayUdpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      1, "relay", "udp", kRelayUdpExtAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      1, "relay", "tcp", kRelayTcpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[3],
+      1, "local", "tcp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[4],
+      1, "relay", "ssltcp", kRelaySslTcpIntAddr);
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Test that we don't crash or malfunction if we can't create any sockets.
+// TODO: Find a way to exit early here.
+TEST_F(PortAllocatorTest, TestGetAllPortsNoSockets) {
+  AddInterface(kClientAddr);
+  fss_->set_tcp_sockets_enabled(false);
+  fss_->set_udp_sockets_enabled(false);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  WAIT(candidates_.size() > 0, 2000);
+  // TODO - Check candidate_allocation_done signal.
+  // In case of Relay, ports creation will succeed but sockets will fail.
+  // There is no error reporting from RelayEntry to handle this failure.
+}
+
+// Testing STUN timeout.
+TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpAllowed) {
+  fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr);
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_EQ_WAIT(2U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(2U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr);
+  // RelayPort connection timeout is 3sec. TCP connection with RelayServer
+  // will be tried after 3 seconds.
+  EXPECT_EQ_WAIT(6U, candidates_.size(), 4000);
+  EXPECT_EQ(3U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[3],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[4],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "ssltcp",
+      kRelaySslTcpIntAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[5],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr);
+  // Stun Timeout is 9sec.
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, 9000);
+}
+
+TEST_F(PortAllocatorTest, TestCandidatePriorityOfMultipleInterfaces) {
+  AddInterface(kClientAddr);
+  AddInterface(kClientAddr2);
+  // Allocating only host UDP ports. This is done purely for testing
+  // convenience.
+  allocator().set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
+                        cricket::PORTALLOCATOR_DISABLE_STUN |
+                        cricket::PORTALLOCATOR_DISABLE_RELAY);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  ASSERT_EQ(2U, candidates_.size());
+  EXPECT_EQ(2U, ports_.size());
+  // Candidates priorities should be different.
+  EXPECT_NE(candidates_[0].priority(), candidates_[1].priority());
+}
+
+// Test to verify ICE restart process.
+TEST_F(PortAllocatorTest, TestGetAllPortsRestarts) {
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(4U, ports_.size());
+  EXPECT_TRUE(candidate_allocation_done_);
+  // TODO - Extend this to verify ICE restart.
+}
+
+// Test ICE candidate filter mechanism with options Relay/Host/Reflexive.
+// This test also verifies that when the allocator is only allowed to use
+// relay (i.e. IceTransportsType is relay), the raddr is an empty
+// address with the correct family. This is to prevent any local
+// reflective address leakage in the sdp line.
+TEST_F(PortAllocatorTest, TestCandidateFilterWithRelayOnly) {
+  AddInterface(kClientAddr);
+  // GTURN is not configured here.
+  ResetWithTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
+  allocator().set_candidate_filter(cricket::CF_RELAY);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_PRED5(CheckCandidate,
+               candidates_[0],
+               cricket::ICE_CANDIDATE_COMPONENT_RTP,
+               "relay",
+               "udp",
+               rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+
+  EXPECT_EQ(1U, candidates_.size());
+  EXPECT_EQ(1U, ports_.size());  // Only Relay port will be in ready state.
+  for (size_t i = 0; i < candidates_.size(); ++i) {
+    EXPECT_EQ(std::string(cricket::RELAY_PORT_TYPE), candidates_[i].type());
+    EXPECT_EQ(
+        candidates_[0].related_address(),
+        rtc::EmptySocketAddressWithFamily(candidates_[0].address().family()));
+  }
+}
+
+TEST_F(PortAllocatorTest, TestCandidateFilterWithHostOnly) {
+  AddInterface(kClientAddr);
+  allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  allocator().set_candidate_filter(cricket::CF_HOST);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_EQ(2U, candidates_.size()); // Host UDP/TCP candidates only.
+  EXPECT_EQ(2U, ports_.size()); // UDP/TCP ports only.
+  for (size_t i = 0; i < candidates_.size(); ++i) {
+    EXPECT_EQ(std::string(cricket::LOCAL_PORT_TYPE), candidates_[i].type());
+  }
+}
+
+// Host is behind the NAT.
+TEST_F(PortAllocatorTest, TestCandidateFilterWithReflexiveOnly) {
+  AddInterface(kPrivateAddr);
+  ResetWithNatServer(kStunAddr);
+
+  allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  allocator().set_candidate_filter(cricket::CF_REFLEXIVE);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  // Host is behind NAT, no private address will be exposed. Hence only UDP
+  // port with STUN candidate will be sent outside.
+  EXPECT_EQ(1U, candidates_.size()); // Only STUN candidate.
+  EXPECT_EQ(1U, ports_.size());  // Only UDP port will be in ready state.
+  for (size_t i = 0; i < candidates_.size(); ++i) {
+    EXPECT_EQ(std::string(cricket::STUN_PORT_TYPE), candidates_[i].type());
+    EXPECT_EQ(
+        candidates_[0].related_address(),
+        rtc::EmptySocketAddressWithFamily(candidates_[0].address().family()));
+  }
+}
+
+// Host is not behind the NAT.
+TEST_F(PortAllocatorTest, TestCandidateFilterWithReflexiveOnlyAndNoNAT) {
+  AddInterface(kClientAddr);
+  allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  allocator().set_candidate_filter(cricket::CF_REFLEXIVE);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  // Host has a public address, both UDP and TCP candidates will be exposed.
+  EXPECT_EQ(2U, candidates_.size()); // Local UDP + TCP candidate.
+  EXPECT_EQ(2U, ports_.size());  //  UDP and TCP ports will be in ready state.
+  for (size_t i = 0; i < candidates_.size(); ++i) {
+    EXPECT_EQ(std::string(cricket::LOCAL_PORT_TYPE), candidates_[i].type());
+  }
+}
+
+TEST_F(PortAllocatorTest, TestBasicMuxFeatures) {
+  AddInterface(kClientAddr);
+  allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+  // Session ID - session1.
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session1(
+      CreateSession("session1", cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session2(
+      CreateSession("session1", cricket::ICE_CANDIDATE_COMPONENT_RTCP));
+  session1->StartGettingPorts();
+  session2->StartGettingPorts();
+  // Each session should receive two proxy ports of local and stun.
+  ASSERT_EQ_WAIT(14U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(8U, ports_.size());
+
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session3(
+      CreateSession("session1", cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session3->StartGettingPorts();
+  // Already allocated candidates and ports will be sent to the newly
+  // allocated proxy session.
+  ASSERT_EQ_WAIT(21U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(12U, ports_.size());
+}
+
+// This test verifies by changing ice_ufrag and/or ice_pwd
+// will result in different set of candidates when BUNDLE is enabled.
+// If BUNDLE is disabled, CreateSession will always allocate new
+// set of candidates.
+TEST_F(PortAllocatorTest, TestBundleIceRestart) {
+  AddInterface(kClientAddr);
+  allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+  // Session ID - session1.
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session1(
+      CreateSession("session1", kContentName,
+                    cricket::ICE_CANDIDATE_COMPONENT_RTP,
+                    kIceUfrag0, kIcePwd0));
+  session1->StartGettingPorts();
+  ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(4U, ports_.size());
+
+  // Allocate a different session with sid |session1| and different ice_ufrag.
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session2(
+      CreateSession("session1", kContentName,
+                    cricket::ICE_CANDIDATE_COMPONENT_RTP,
+                    "TestIceUfrag", kIcePwd0));
+  session2->StartGettingPorts();
+  ASSERT_EQ_WAIT(14U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(8U, ports_.size());
+  // Verifying the candidate address different from previously allocated
+  // address.
+  // Skipping verification of component id and candidate type.
+  EXPECT_NE(candidates_[0].address(), candidates_[7].address());
+  EXPECT_NE(candidates_[1].address(), candidates_[8].address());
+
+  // Allocating a different session with sid |session1| and
+  // different ice_pwd.
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session3(
+      CreateSession("session1", kContentName,
+                    cricket::ICE_CANDIDATE_COMPONENT_RTP,
+                    kIceUfrag0, "TestIcePwd"));
+  session3->StartGettingPorts();
+  ASSERT_EQ_WAIT(21U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(12U, ports_.size());
+  // Verifying the candidate address different from previously
+  // allocated address.
+  EXPECT_NE(candidates_[7].address(), candidates_[14].address());
+  EXPECT_NE(candidates_[8].address(), candidates_[15].address());
+
+  // Allocating a session with by changing both ice_ufrag and ice_pwd.
+  rtc::scoped_ptr<cricket::PortAllocatorSession> session4(
+      CreateSession("session1", kContentName,
+                    cricket::ICE_CANDIDATE_COMPONENT_RTP,
+                    "TestIceUfrag", "TestIcePwd"));
+  session4->StartGettingPorts();
+  ASSERT_EQ_WAIT(28U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(16U, ports_.size());
+  // Verifying the candidate address different from previously
+  // allocated address.
+  EXPECT_NE(candidates_[14].address(), candidates_[21].address());
+  EXPECT_NE(candidates_[15].address(), candidates_[22].address());
+}
+
+// Test that when the PORTALLOCATOR_ENABLE_SHARED_UFRAG is enabled we got same
+// ufrag and pwd for the collected candidates.
+TEST_F(PortAllocatorTest, TestEnableSharedUfrag) {
+  allocator().set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG);
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[5],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr);
+  EXPECT_EQ(4U, ports_.size());
+  EXPECT_EQ(kIceUfrag0, candidates_[0].username());
+  EXPECT_EQ(kIceUfrag0, candidates_[1].username());
+  EXPECT_EQ(kIceUfrag0, candidates_[2].username());
+  EXPECT_EQ(kIcePwd0, candidates_[0].password());
+  EXPECT_EQ(kIcePwd0, candidates_[1].password());
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Test that when the PORTALLOCATOR_ENABLE_SHARED_UFRAG isn't enabled we got
+// different ufrag and pwd for the collected candidates.
+TEST_F(PortAllocatorTest, TestDisableSharedUfrag) {
+  allocator().set_flags(allocator().flags() &
+                        ~cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG);
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", kClientAddr);
+  EXPECT_EQ(4U, ports_.size());
+  // Port should generate random ufrag and pwd.
+  EXPECT_NE(kIceUfrag0, candidates_[0].username());
+  EXPECT_NE(kIceUfrag0, candidates_[1].username());
+  EXPECT_NE(candidates_[0].username(), candidates_[1].username());
+  EXPECT_NE(kIcePwd0, candidates_[0].password());
+  EXPECT_NE(kIcePwd0, candidates_[1].password());
+  EXPECT_NE(candidates_[0].password(), candidates_[1].password());
+  EXPECT_TRUE(candidate_allocation_done_);
+}
+
+// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port
+// is allocated for udp and stun. Also verify there is only one candidate
+// (local) if stun candidate is same as local candidate, which will be the case
+// in a public network like the below test.
+TEST_F(PortAllocatorTest, TestSharedSocketWithoutNat) {
+  AddInterface(kClientAddr);
+  allocator_->set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(6U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(3U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+}
+
+// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port
+// is allocated for udp and stun. In this test we should expect both stun and
+// local candidates as client behind a nat.
+TEST_F(PortAllocatorTest, TestSharedSocketWithNat) {
+  AddInterface(kClientAddr);
+  ResetWithNatServer(kStunAddr);
+
+  allocator_->set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+  ASSERT_EQ(2U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
+      rtc::SocketAddress(kNatAddr.ipaddr(), 0));
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_EQ(3U, candidates_.size());
+}
+
+// Test TURN port in shared socket mode with UDP and TCP TURN server adderesses.
+TEST_F(PortAllocatorTest, TestSharedSocketWithoutNatUsingTurn) {
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+  AddInterface(kClientAddr);
+  allocator_.reset(new cricket::BasicPortAllocator(&network_manager_));
+
+  AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr);
+
+  allocator_->set_step_delay(cricket::kMinimumStepDelay);
+  allocator_->set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+                        cricket::PORTALLOCATOR_DISABLE_TCP);
+
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+
+  ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+  ASSERT_EQ(3U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+      rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+      rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_EQ(3U, candidates_.size());
+}
+
+// Testing DNS resolve for the TURN server, this will test AllocationSequence
+// handling the unresolved address signal from TurnPort.
+TEST_F(PortAllocatorTest, TestSharedSocketWithServerAddressResolve) {
+  turn_server_.AddInternalSocket(rtc::SocketAddress("127.0.0.1", 3478),
+                                 cricket::PROTO_UDP);
+  AddInterface(kClientAddr);
+  allocator_.reset(new cricket::BasicPortAllocator(&network_manager_));
+  cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+  cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword);
+  relay_server.credentials = credentials;
+  relay_server.ports.push_back(cricket::ProtocolAddress(
+      rtc::SocketAddress("localhost", 3478),
+      cricket::PROTO_UDP, false));
+  allocator_->AddRelay(relay_server);
+
+  allocator_->set_step_delay(cricket::kMinimumStepDelay);
+  allocator_->set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+                        cricket::PORTALLOCATOR_DISABLE_TCP);
+
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+
+  EXPECT_EQ_WAIT(2U, ports_.size(), kDefaultAllocationTimeout);
+}
+
+// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port
+// is allocated for udp/stun/turn. In this test we should expect all local,
+// stun and turn candidates.
+TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurn) {
+  AddInterface(kClientAddr);
+  ResetWithNatServer(kStunAddr);
+
+  AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
+
+  allocator_->set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+                        cricket::PORTALLOCATOR_DISABLE_TCP);
+
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+
+  ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+  ASSERT_EQ(2U, ports_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
+      rtc::SocketAddress(kNatAddr.ipaddr(), 0));
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+      rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_EQ(3U, candidates_.size());
+  // Local port will be created first and then TURN port.
+  EXPECT_EQ(2U, ports_[0]->Candidates().size());
+  EXPECT_EQ(1U, ports_[1]->Candidates().size());
+}
+
+// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled and the TURN
+// server is also used as the STUN server, we should get 'local', 'stun', and
+// 'relay' candidates.
+TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurnAsStun) {
+  AddInterface(kClientAddr);
+  ResetWithNatServer(kTurnUdpIntAddr);
+  AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
+
+  // Must set the step delay to 0 to make sure the relay allocation phase is
+  // started before the STUN candidates are obtained, so that the STUN binding
+  // response is processed when both StunPort and TurnPort exist to reproduce
+  // webrtc issue 3537.
+  allocator_->set_step_delay(0);
+  allocator_->set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+                        cricket::PORTALLOCATOR_DISABLE_TCP);
+
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+
+  ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
+      rtc::SocketAddress(kNatAddr.ipaddr(), 0));
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+      rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+  EXPECT_EQ(candidates_[2].related_address(), candidates_[1].address());
+
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_EQ(3U, candidates_.size());
+  // Local port will be created first and then TURN port.
+  EXPECT_EQ(2U, ports_[0]->Candidates().size());
+  EXPECT_EQ(1U, ports_[1]->Candidates().size());
+}
+
+// This test verifies when PORTALLOCATOR_ENABLE_SHARED_SOCKET flag is enabled
+// and fail to generate STUN candidate, local UDP candidate is generated
+// properly.
+TEST_F(PortAllocatorTest, TestSharedSocketNoUdpAllowed) {
+  allocator().set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_DISABLE_RELAY |
+                        cricket::PORTALLOCATOR_DISABLE_TCP |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr);
+  AddInterface(kClientAddr);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(1U, ports_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(1U, candidates_.size());
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+  // STUN timeout is 9sec. We need to wait to get candidate done signal.
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, 10000);
+  EXPECT_EQ(1U, candidates_.size());
+}
+
+// This test verifies allocator can use IPv6 addresses along with IPv4.
+TEST_F(PortAllocatorTest, TestEnableIPv6Addresses) {
+  allocator().set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_DISABLE_RELAY |
+                        cricket::PORTALLOCATOR_ENABLE_IPV6 |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  AddInterface(kClientIPv6Addr);
+  AddInterface(kClientAddr);
+  allocator_->set_step_delay(cricket::kMinimumStepDelay);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(4U, ports_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(4U, candidates_.size());
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+      kClientIPv6Addr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+      kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp",
+      kClientIPv6Addr);
+  EXPECT_PRED5(CheckCandidate, candidates_[3],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp",
+      kClientAddr);
+  EXPECT_EQ(4U, candidates_.size());
+}
+
+// Test that the httpportallocator correctly maintains its lists of stun and
+// relay servers, by never allowing an empty list.
+TEST(HttpPortAllocatorTest, TestHttpPortAllocatorHostLists) {
+  rtc::FakeNetworkManager network_manager;
+  cricket::HttpPortAllocator alloc(&network_manager, "unit test agent");
+  EXPECT_EQ(1U, alloc.relay_hosts().size());
+  EXPECT_EQ(1U, alloc.stun_hosts().size());
+
+  std::vector<std::string> relay_servers;
+  std::vector<rtc::SocketAddress> stun_servers;
+
+  alloc.SetRelayHosts(relay_servers);
+  alloc.SetStunHosts(stun_servers);
+  EXPECT_EQ(1U, alloc.relay_hosts().size());
+  EXPECT_EQ(1U, alloc.stun_hosts().size());
+
+  relay_servers.push_back("1.unittest.corp.google.com");
+  relay_servers.push_back("2.unittest.corp.google.com");
+  stun_servers.push_back(
+      rtc::SocketAddress("1.unittest.corp.google.com", 0));
+  stun_servers.push_back(
+      rtc::SocketAddress("2.unittest.corp.google.com", 0));
+
+  alloc.SetRelayHosts(relay_servers);
+  alloc.SetStunHosts(stun_servers);
+  EXPECT_EQ(2U, alloc.relay_hosts().size());
+  EXPECT_EQ(2U, alloc.stun_hosts().size());
+}
+
+// Test that the HttpPortAllocator uses correct URL to create sessions.
+TEST(HttpPortAllocatorTest, TestSessionRequestUrl) {
+  rtc::FakeNetworkManager network_manager;
+  cricket::HttpPortAllocator alloc(&network_manager, "unit test agent");
+
+  // Disable PORTALLOCATOR_ENABLE_SHARED_UFRAG.
+  alloc.set_flags(alloc.flags() & ~cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG);
+  rtc::scoped_ptr<cricket::HttpPortAllocatorSessionBase> session(
+      static_cast<cricket::HttpPortAllocatorSession*>(
+          alloc.CreateSessionInternal(
+              "test content", 0, kIceUfrag0, kIcePwd0)));
+  std::string url = session->GetSessionRequestUrl();
+  LOG(LS_INFO) << "url: " << url;
+  EXPECT_EQ(std::string(cricket::HttpPortAllocator::kCreateSessionURL), url);
+
+  // Enable PORTALLOCATOR_ENABLE_SHARED_UFRAG.
+  alloc.set_flags(alloc.flags() | cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG);
+  session.reset(static_cast<cricket::HttpPortAllocatorSession*>(
+      alloc.CreateSessionInternal("test content", 0, kIceUfrag0, kIcePwd0)));
+  url = session->GetSessionRequestUrl();
+  LOG(LS_INFO) << "url: " << url;
+  std::vector<std::string> parts;
+  rtc::split(url, '?', &parts);
+  ASSERT_EQ(2U, parts.size());
+
+  std::vector<std::string> args_parts;
+  rtc::split(parts[1], '&', &args_parts);
+
+  std::map<std::string, std::string> args;
+  for (std::vector<std::string>::iterator it = args_parts.begin();
+       it != args_parts.end(); ++it) {
+    std::vector<std::string> parts;
+    rtc::split(*it, '=', &parts);
+    ASSERT_EQ(2U, parts.size());
+    args[rtc::s_url_decode(parts[0])] = rtc::s_url_decode(parts[1]);
+  }
+
+  EXPECT_EQ(kIceUfrag0, args["username"]);
+  EXPECT_EQ(kIcePwd0, args["password"]);
+}
diff --git a/p2p/client/sessionmanagertask.h b/p2p/client/sessionmanagertask.h
new file mode 100644
index 0000000..04d79d4
--- /dev/null
+++ b/p2p/client/sessionmanagertask.h
@@ -0,0 +1,76 @@
+/*
+ *  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_P2P_CLIENT_SESSIONMANAGERTASK_H_
+#define WEBRTC_P2P_CLIENT_SESSIONMANAGERTASK_H_
+
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/p2p/client/sessionsendtask.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+
+namespace cricket {
+
+// This class handles sending and receiving XMPP messages on behalf of the
+// SessionManager.  The sending part is handed over to SessionSendTask.
+
+class SessionManagerTask : public buzz::XmppTask {
+ public:
+  SessionManagerTask(buzz::XmppTaskParentInterface* parent,
+                     SessionManager* session_manager)
+      : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
+        session_manager_(session_manager) {
+  }
+
+  ~SessionManagerTask() {
+  }
+
+  // Turns on simple support for sending messages, using SessionSendTask.
+  void EnableOutgoingMessages() {
+    session_manager_->SignalOutgoingMessage.connect(
+        this, &SessionManagerTask::OnOutgoingMessage);
+    session_manager_->SignalRequestSignaling.connect(
+        session_manager_, &SessionManager::OnSignalingReady);
+  }
+
+  virtual int ProcessStart() {
+    const buzz::XmlElement *stanza = NextStanza();
+    if (stanza == NULL)
+      return STATE_BLOCKED;
+    session_manager_->OnIncomingMessage(stanza);
+    return STATE_START;
+  }
+
+ protected:
+  virtual bool HandleStanza(const buzz::XmlElement *stanza) {
+    if (!session_manager_->IsSessionMessage(stanza))
+      return false;
+    // Responses are handled by the SessionSendTask that sent the request.
+    //if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_SET)
+    //  return false;
+    QueueStanza(stanza);
+    return true;
+  }
+
+ private:
+  void OnOutgoingMessage(SessionManager* manager,
+                         const buzz::XmlElement* stanza) {
+    cricket::SessionSendTask* sender =
+        new cricket::SessionSendTask(parent_, session_manager_);
+    sender->Send(stanza);
+    sender->Start();
+  }
+
+  SessionManager* session_manager_;
+};
+
+}  // namespace cricket
+
+#endif // WEBRTC_P2P_CLIENT_SESSIONMANAGERTASK_H_
diff --git a/p2p/client/sessionsendtask.h b/p2p/client/sessionsendtask.h
new file mode 100644
index 0000000..818aa1a
--- /dev/null
+++ b/p2p/client/sessionsendtask.h
@@ -0,0 +1,128 @@
+/*
+ *  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_P2P_CLIENT_SESSIONSENDTASK_H_
+#define WEBRTC_P2P_CLIENT_SESSIONSENDTASK_H_
+
+#include "webrtc/p2p/base/sessionmanager.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/xmppclient.h"
+#include "webrtc/libjingle/xmpp/xmppengine.h"
+#include "webrtc/libjingle/xmpp/xmpptask.h"
+#include "webrtc/base/common.h"
+
+namespace cricket {
+
+// The job of this task is to send an IQ stanza out (after stamping it with
+// an ID attribute) and then wait for a response.  If not response happens
+// within 5 seconds, it will signal failure on a SessionManager.  If an error
+// happens it will also signal failure.  If, however, the send succeeds this
+// task will quietly go away.
+
+class SessionSendTask : public buzz::XmppTask {
+ public:
+  SessionSendTask(buzz::XmppTaskParentInterface* parent,
+                  SessionManager* session_manager)
+    : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
+      session_manager_(session_manager) {
+    set_timeout_seconds(15);
+    session_manager_->SignalDestroyed.connect(
+        this, &SessionSendTask::OnSessionManagerDestroyed);
+  }
+
+  virtual ~SessionSendTask() {
+    SignalDone(this);
+  }
+
+  void Send(const buzz::XmlElement* stanza) {
+    ASSERT(stanza_.get() == NULL);
+
+    // This should be an IQ of type set, result, or error.  In the first case,
+    // we supply an ID.  In the others, it should be present.
+    ASSERT(stanza->Name() == buzz::QN_IQ);
+    ASSERT(stanza->HasAttr(buzz::QN_TYPE));
+    if (stanza->Attr(buzz::QN_TYPE) == "set") {
+      ASSERT(!stanza->HasAttr(buzz::QN_ID));
+    } else {
+      ASSERT((stanza->Attr(buzz::QN_TYPE) == "result") ||
+             (stanza->Attr(buzz::QN_TYPE) == "error"));
+      ASSERT(stanza->HasAttr(buzz::QN_ID));
+    }
+
+    stanza_.reset(new buzz::XmlElement(*stanza));
+    if (stanza_->HasAttr(buzz::QN_ID)) {
+      set_task_id(stanza_->Attr(buzz::QN_ID));
+    } else {
+      stanza_->SetAttr(buzz::QN_ID, task_id());
+    }
+  }
+
+  void OnSessionManagerDestroyed() {
+    // If the session manager doesn't exist anymore, we should still try to
+    // send the message, but avoid calling back into the SessionManager.
+    session_manager_ = NULL;
+  }
+
+  sigslot::signal1<SessionSendTask *> SignalDone;
+
+ protected:
+  virtual int OnTimeout() {
+    if (session_manager_ != NULL) {
+      session_manager_->OnFailedSend(stanza_.get(), NULL);
+    }
+
+    return XmppTask::OnTimeout();
+  }
+
+  virtual int ProcessStart() {
+    SendStanza(stanza_.get());
+    if (stanza_->Attr(buzz::QN_TYPE) == buzz::STR_SET) {
+      return STATE_RESPONSE;
+    } else {
+      return STATE_DONE;
+    }
+  }
+
+  virtual int ProcessResponse() {
+    const buzz::XmlElement* next = NextStanza();
+    if (next == NULL)
+      return STATE_BLOCKED;
+
+    if (session_manager_ != NULL) {
+      if (next->Attr(buzz::QN_TYPE) == buzz::STR_RESULT) {
+        session_manager_->OnIncomingResponse(stanza_.get(), next);
+      } else {
+        session_manager_->OnFailedSend(stanza_.get(), next);
+      }
+    }
+
+    return STATE_DONE;
+  }
+
+  virtual bool HandleStanza(const buzz::XmlElement *stanza) {
+    if (!MatchResponseIq(stanza,
+                         buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id()))
+      return false;
+    if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT ||
+        stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) {
+      QueueStanza(stanza);
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  SessionManager *session_manager_;
+  rtc::scoped_ptr<buzz::XmlElement> stanza_;
+};
+
+}
+
+#endif // WEBRTC_P2P_CLIENT_SESSIONSENDTASK_H_
diff --git a/p2p/client/socketmonitor.cc b/p2p/client/socketmonitor.cc
new file mode 100644
index 0000000..5245535
--- /dev/null
+++ b/p2p/client/socketmonitor.cc
@@ -0,0 +1,97 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/client/socketmonitor.h"
+
+#include "webrtc/base/common.h"
+
+namespace cricket {
+
+enum {
+  MSG_MONITOR_POLL,
+  MSG_MONITOR_START,
+  MSG_MONITOR_STOP,
+  MSG_MONITOR_SIGNAL
+};
+
+SocketMonitor::SocketMonitor(TransportChannel* channel,
+                             rtc::Thread* worker_thread,
+                             rtc::Thread* monitor_thread) {
+  channel_ = channel;
+  channel_thread_ = worker_thread;
+  monitoring_thread_ = monitor_thread;
+  monitoring_ = false;
+}
+
+SocketMonitor::~SocketMonitor() {
+  channel_thread_->Clear(this);
+  monitoring_thread_->Clear(this);
+}
+
+void SocketMonitor::Start(int milliseconds) {
+  rate_ = milliseconds;
+  if (rate_ < 250)
+    rate_ = 250;
+  channel_thread_->Post(this, MSG_MONITOR_START);
+}
+
+void SocketMonitor::Stop() {
+  channel_thread_->Post(this, MSG_MONITOR_STOP);
+}
+
+void SocketMonitor::OnMessage(rtc::Message *message) {
+  rtc::CritScope cs(&crit_);
+  switch (message->message_id) {
+    case MSG_MONITOR_START:
+      ASSERT(rtc::Thread::Current() == channel_thread_);
+      if (!monitoring_) {
+        monitoring_ = true;
+        PollSocket(true);
+      }
+      break;
+
+    case MSG_MONITOR_STOP:
+      ASSERT(rtc::Thread::Current() == channel_thread_);
+      if (monitoring_) {
+        monitoring_ = false;
+        channel_thread_->Clear(this);
+      }
+      break;
+
+    case MSG_MONITOR_POLL:
+      ASSERT(rtc::Thread::Current() == channel_thread_);
+      PollSocket(true);
+      break;
+
+    case MSG_MONITOR_SIGNAL: {
+      ASSERT(rtc::Thread::Current() == monitoring_thread_);
+      std::vector<ConnectionInfo> infos = connection_infos_;
+      crit_.Leave();
+      SignalUpdate(this, infos);
+      crit_.Enter();
+      break;
+    }
+  }
+}
+
+void SocketMonitor::PollSocket(bool poll) {
+  ASSERT(rtc::Thread::Current() == channel_thread_);
+  rtc::CritScope cs(&crit_);
+
+  // Gather connection infos
+  channel_->GetStats(&connection_infos_);
+
+  // Signal the monitoring thread, start another poll timer
+  monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL);
+  if (poll)
+    channel_thread_->PostDelayed(rate_, this, MSG_MONITOR_POLL);
+}
+
+}  // namespace cricket
diff --git a/p2p/client/socketmonitor.h b/p2p/client/socketmonitor.h
new file mode 100644
index 0000000..5c10a4e
--- /dev/null
+++ b/p2p/client/socketmonitor.h
@@ -0,0 +1,54 @@
+/*
+ *  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_P2P_CLIENT_SOCKETMONITOR_H_
+#define WEBRTC_P2P_CLIENT_SOCKETMONITOR_H_
+
+#include <vector>
+
+#include "webrtc/p2p/base/transportchannel.h"
+#include "webrtc/base/criticalsection.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+class SocketMonitor : public rtc::MessageHandler,
+                      public sigslot::has_slots<> {
+ public:
+  SocketMonitor(TransportChannel* channel,
+                rtc::Thread* worker_thread,
+                rtc::Thread* monitor_thread);
+  ~SocketMonitor();
+
+  void Start(int cms);
+  void Stop();
+
+  rtc::Thread* monitor_thread() { return monitoring_thread_; }
+
+  sigslot::signal2<SocketMonitor*,
+                   const std::vector<ConnectionInfo>&> SignalUpdate;
+
+ protected:
+  void OnMessage(rtc::Message* message);
+  void PollSocket(bool poll);
+
+  std::vector<ConnectionInfo> connection_infos_;
+  TransportChannel* channel_;
+  rtc::Thread* channel_thread_;
+  rtc::Thread* monitoring_thread_;
+  rtc::CriticalSection crit_;
+  uint32 rate_;
+  bool monitoring_;
+};
+
+}  // namespace cricket
+
+#endif  // WEBRTC_P2P_CLIENT_SOCKETMONITOR_H_
diff --git a/p2p/p2p.gyp b/p2p/p2p.gyp
new file mode 100644
index 0000000..102e75b
--- /dev/null
+++ b/p2p/p2p.gyp
@@ -0,0 +1,130 @@
+# 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.
+
+{
+  'includes': [ '../build/common.gypi', ],
+  'targets': [
+    {
+      'target_name': 'rtc_p2p',
+      'type': 'static_library',
+      'dependencies': [
+        '<(webrtc_root)/base/base.gyp:webrtc_base',
+        '<(webrtc_root)/libjingle/xmpp/xmpp.gyp:rtc_xmpp',
+        '<(DEPTH)/third_party/expat/expat.gyp:expat',
+      ],
+      'cflags_cc!': [
+        '-Wnon-virtual-dtor',
+      ],
+      'export_dependent_settings': [
+        '<(DEPTH)/third_party/expat/expat.gyp:expat',
+      ],
+      'sources': [
+        'base/asyncstuntcpsocket.cc',
+        'base/asyncstuntcpsocket.h',
+        'base/basicpacketsocketfactory.cc',
+        'base/basicpacketsocketfactory.h',
+        'base/candidate.h',
+        'base/common.h',
+        'base/constants.cc',
+        'base/constants.h',
+        'base/dtlstransportchannel.cc',
+        'base/dtlstransportchannel.h',
+        'base/p2ptransport.cc',
+        'base/p2ptransport.h',
+        'base/p2ptransportchannel.cc',
+        'base/p2ptransportchannel.h',
+        'base/packetsocketfactory.h',
+        'base/parsing.cc',
+        'base/parsing.h',
+        'base/port.cc',
+        'base/port.h',
+        'base/portallocator.cc',
+        'base/portallocator.h',
+        'base/portallocatorsessionproxy.cc',
+        'base/portallocatorsessionproxy.h',
+        'base/portinterface.h',
+        'base/portproxy.cc',
+        'base/portproxy.h',
+        'base/pseudotcp.cc',
+        'base/pseudotcp.h',
+        'base/rawtransport.cc',
+        'base/rawtransport.h',
+        'base/rawtransportchannel.cc',
+        'base/rawtransportchannel.h',
+        'base/relayport.cc',
+        'base/relayport.h',
+        'base/relayserver.cc',
+        'base/relayserver.h',
+        'base/session.cc',
+        'base/session.h',
+        'base/sessionclient.h',
+        'base/sessiondescription.cc',
+        'base/sessiondescription.h',
+        'base/sessionid.h',
+        'base/sessionmanager.cc',
+        'base/sessionmanager.h',
+        'base/sessionmessages.cc',
+        'base/sessionmessages.h',
+        'base/stun.cc',
+        'base/stun.h',
+        'base/stunport.cc',
+        'base/stunport.h',
+        'base/stunrequest.cc',
+        'base/stunrequest.h',
+        'base/stunserver.cc',
+        'base/stunserver.h',
+        'base/tcpport.cc',
+        'base/tcpport.h',
+        'base/transport.cc',
+        'base/transport.h',
+        'base/transportchannel.cc',
+        'base/transportchannel.h',
+        'base/transportchannelimpl.h',
+        'base/transportchannelproxy.cc',
+        'base/transportchannelproxy.h',
+        'base/transportdescription.cc',
+        'base/transportdescription.h',
+        'base/transportdescriptionfactory.cc',
+        'base/transportdescriptionfactory.h',
+        'base/transportinfo.h',
+        'base/turnport.cc',
+        'base/turnport.h',
+        'base/turnserver.cc',
+        'base/turnserver.h',
+        'base/udpport.h',
+        'client/autoportallocator.h',
+        'client/basicportallocator.cc',
+        'client/basicportallocator.h',
+        'client/connectivitychecker.cc',
+        'client/connectivitychecker.h',
+        'client/httpportallocator.cc',
+        'client/httpportallocator.h',
+        'client/sessionmanagertask.h',
+        'client/sessionsendtask.h',
+        'client/socketmonitor.cc',
+        'client/socketmonitor.h',
+      ],
+      'direct_dependent_settings': {
+        'cflags_cc!': [
+          '-Wnon-virtual-dtor',
+        ],
+        'defines': [
+          'FEATURE_ENABLE_VOICEMAIL',
+        ],
+      },
+      'conditions': [
+        ['build_with_chromium==0', {
+          'defines': [
+            'FEATURE_ENABLE_VOICEMAIL',
+            'FEATURE_ENABLE_PSTN',
+          ],
+        }],
+      ],
+    }],
+}
+  
diff --git a/p2p/p2p_tests.gypi b/p2p/p2p_tests.gypi
new file mode 100644
index 0000000..f9e6959
--- /dev/null
+++ b/p2p/p2p_tests.gypi
@@ -0,0 +1,44 @@
+# 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.
+
+{
+  'includes': [ '../build/common.gypi', ],
+  'targets': [
+    {
+      'target_name': 'rtc_p2p_unittest',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'sources': [
+          'base/dtlstransportchannel_unittest.cc',
+          'base/fakesession.h',
+          'base/p2ptransportchannel_unittest.cc',
+          'base/port_unittest.cc',
+          'base/portallocatorsessionproxy_unittest.cc',
+          'base/pseudotcp_unittest.cc',
+          'base/relayport_unittest.cc',
+          'base/relayserver_unittest.cc',
+          'base/session_unittest.cc',
+          'base/stun_unittest.cc',
+          'base/stunport_unittest.cc',
+          'base/stunrequest_unittest.cc',
+          'base/stunserver_unittest.cc',
+          'base/testrelayserver.h',
+          'base/teststunserver.h',
+          'base/testturnserver.h',
+          'base/transport_unittest.cc',
+          'base/transportdescriptionfactory_unittest.cc',
+          'base/turnport_unittest.cc',
+          'client/connectivitychecker_unittest.cc',
+          'client/fakeportallocator.h',
+          'client/portallocator_unittest.cc',
+        ],
+      },
+    },
+  ],
+}
+
diff --git a/rtc_unittests.isolate b/rtc_unittests.isolate
index 7bcfc85..6dfe38d 100644
--- a/rtc_unittests.isolate
+++ b/rtc_unittests.isolate
@@ -12,12 +12,9 @@
         'command': [
           '<(PRODUCT_DIR)/rtc_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(PRODUCT_DIR)/rtc_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/system_wrappers/BUILD.gn b/system_wrappers/BUILD.gn
index c193c28..c4d2192 100644
--- a/system_wrappers/BUILD.gn
+++ b/system_wrappers/BUILD.gn
@@ -35,6 +35,7 @@
     "interface/file_wrapper.h",
     "interface/fix_interlocked_exchange_pointer_win.h",
     "interface/logging.h",
+    "interface/metrics.h",
     "interface/ref_count.h",
     "interface/rtp_to_ntp.h",
     "interface/rw_lock_wrapper.h",
@@ -216,6 +217,42 @@
   ]
 }
 
+source_set("metrics_default") {
+  sources = [
+    "source/metrics_default.cc",
+  ]
+
+  configs += [ "..:common_config" ]
+  public_configs = [ "..:common_inherited_config" ]
+
+  if (is_clang) {
+    # Suppress warnings from Chrome's Clang plugins.
+    # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
+    configs -= [ "//build/config/clang:find_bad_constructs" ]
+  }
+
+  deps = [
+    ":system_wrappers",
+  ]
+}
+
+source_set("system_wrappers_default") {
+
+  configs += [ "..:common_config" ]
+  public_configs = [ "..:common_inherited_config" ]
+
+  if (is_clang) {
+    # Suppress warnings from Chrome's Clang plugins.
+    # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
+    configs -= [ "//build/config/clang:find_bad_constructs" ]
+  }
+
+  deps = [
+    ":field_trial_default",
+    ":metrics_default",
+  ]
+}
+
 if (is_android) {
   source_set("cpu_features_android") {
     sources = [
diff --git a/system_wrappers/interface/metrics.h b/system_wrappers/interface/metrics.h
new file mode 100644
index 0000000..0390140
--- /dev/null
+++ b/system_wrappers/interface/metrics.h
@@ -0,0 +1,130 @@
+//
+// 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_SYSTEM_WRAPPERS_INTERFACE_METRICS_H_
+#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_METRICS_H_
+
+#include <string>
+
+#include "webrtc/common_types.h"
+
+// Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
+// statistics.
+//
+// Histogram for counters.
+// RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count);
+//
+// Histogram for enumerators.
+// The boundary should be above the max enumerator sample.
+// RTC_HISTOGRAM_ENUMERATION(name, sample, boundary);
+//
+//
+// The macros use the methods HistogramFactoryGetCounts,
+// HistogramFactoryGetEnumeration and HistogramAdd.
+//
+// Therefore, WebRTC clients must either:
+//
+// - provide implementations of
+//   Histogram* webrtc::metrics::HistogramFactoryGetCounts(
+//       const std::string& name, int sample, int min, int max,
+//       int bucket_count);
+//   Histogram* webrtc::metrics::HistogramFactoryGetEnumeration(
+//       const std::string& name, int sample, int boundary);
+//   void webrtc::metrics::HistogramAdd(
+//       Histogram* histogram_pointer, const std::string& name, int sample);
+//
+// - or link with the default implementations (i.e.
+//   system_wrappers/source/system_wrappers.gyp:metrics_default).
+//
+//
+// Example usage:
+//
+// RTC_HISTOGRAM_COUNTS("WebRTC.Video.NacksSent", nacks_sent, 1, 100000, 100);
+//
+// enum Types {
+//   kTypeX,
+//   kTypeY,
+//   kBoundary,
+// };
+//
+// RTC_HISTOGRAM_ENUMERATION("WebRTC.Types", kTypeX, kBoundary);
+
+
+// Macros for adding samples to a named histogram.
+//
+// NOTE: this is a temporary solution.
+// The aim is to mimic the behaviour in Chromium's src/base/metrics/histograms.h
+// However as atomics are not supported in webrtc, this is for now a modified
+// and temporary solution. Note that the histogram is constructed/found for
+// each call. Therefore, for now only use this implementation for metrics
+// that do not need to be updated frequently.
+// TODO(asapersson): Change implementation when atomics are supported.
+// Also consider changing string to const char* when switching to atomics.
+
+// Histogram for counters.
+#define RTC_HISTOGRAM_COUNTS_100(name, sample) RTC_HISTOGRAM_COUNTS( \
+    name, sample, 1, 100, 50)
+
+#define RTC_HISTOGRAM_COUNTS_1000(name, sample) RTC_HISTOGRAM_COUNTS( \
+    name, sample, 1, 1000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_10000(name, sample) RTC_HISTOGRAM_COUNTS( \
+    name, sample, 1, 10000, 50)
+
+#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
+    RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
+        webrtc::metrics::HistogramFactoryGetCounts( \
+            name, min, max, bucket_count))
+
+// Histogram for percentage.
+#define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
+    RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
+
+// Histogram for enumerators.
+// |boundary| should be above the max enumerator sample.
+#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
+    RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
+        webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
+
+#define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \
+                                   factory_get_invocation) \
+  do { \
+    webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation; \
+    webrtc::metrics::HistogramAdd(histogram_pointer, constant_name, sample); \
+  } while (0)
+
+
+namespace webrtc {
+namespace metrics {
+
+class Histogram;
+
+// Functions for getting pointer to histogram (constructs or finds the named
+// histogram).
+
+// Get histogram for counters.
+Histogram* HistogramFactoryGetCounts(
+    const std::string& name, int min, int max, int bucket_count);
+
+// Get histogram for enumerators.
+// |boundary| should be above the max enumerator sample.
+Histogram* HistogramFactoryGetEnumeration(
+    const std::string& name, int boundary);
+
+// Function for adding a |sample| to a histogram.
+// |name| can be used to verify that it matches the histogram name.
+void HistogramAdd(
+    Histogram* histogram_pointer, const std::string& name, int sample);
+
+}  // namespace metrics
+}  // namespace webrtc
+
+#endif  // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_METRICS_H_
+
diff --git a/system_wrappers/interface/scoped_ptr.h b/system_wrappers/interface/scoped_ptr.h
index 42bb8a6..1beca1b 100644
--- a/system_wrappers/interface/scoped_ptr.h
+++ b/system_wrappers/interface/scoped_ptr.h
@@ -10,10 +10,10 @@
 
 // Borrowed from Chromium's src/base/memory/scoped_ptr.h.
 
-// Scopers help you manage ownership of a pointer, helping you easily manage the
-// a pointer within a scope, and automatically destroying the pointer at the
-// end of a scope.  There are two main classes you will use, which correspond
-// to the operators new/delete and new[]/delete[].
+// Scopers help you manage ownership of a pointer, helping you easily manage a
+// pointer within a scope, and automatically destroying the pointer at the end
+// of a scope.  There are two main classes you will use, which correspond to the
+// operators new/delete and new[]/delete[].
 //
 // Example usage (scoped_ptr<T>):
 //   {
@@ -66,7 +66,7 @@
 //     TakesOwnership(ptr.Pass());           // 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 NULL.
+//         PassThru(ptr2.Pass());            // ptr2 is correspondingly nullptr.
 //   }
 //
 // Notice that if you do not call Pass() when returning from PassThru(), or
@@ -180,12 +180,23 @@
 
 namespace internal {
 
+template <typename T>
+struct ShouldAbortOnSelfReset {
+  template <typename U>
+  static NoType Test(const typename U::AllowSelfReset*);
+
+  template <typename U>
+  static YesType Test(...);
+
+  static const bool value = sizeof(Test<T>(0)) == sizeof(YesType);
+};
+
 // Minimal implementation of the core logic of scoped_ptr, suitable for
 // reuse in both scoped_ptr and its specializations.
 template <class T, class D>
 class scoped_ptr_impl {
  public:
-  explicit scoped_ptr_impl(T* p) : data_(p) { }
+  explicit scoped_ptr_impl(T* p) : data_(p) {}
 
   // Initializer for deleters that have data parameters.
   scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
@@ -210,7 +221,7 @@
   }
 
   ~scoped_ptr_impl() {
-    if (data_.ptr != NULL) {
+    if (data_.ptr != nullptr) {
       // Not using get_deleter() saves one function call in non-optimized
       // builds.
       static_cast<D&>(data_)(data_.ptr);
@@ -218,12 +229,12 @@
   }
 
   void reset(T* p) {
-    // This is a self-reset, which is no longer allowed: http://crbug.com/162971
-    if (p != NULL && p == data_.ptr)
-      abort();
+    // This is a self-reset, which is no longer allowed for default deleters:
+    // https://crbug.com/162971
+    assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
 
     // Note that running data_.ptr = p can lead to undefined behavior if
-    // get_deleter()(get()) deletes this. In order to pevent this, reset()
+    // get_deleter()(get()) deletes this. In order to prevent this, reset()
     // should update the stored pointer before deleting its old value.
     //
     // However, changing reset() to use that behavior may cause current code to
@@ -232,13 +243,13 @@
     // then it will incorrectly dispatch calls to |p| rather than the original
     // value of |data_.ptr|.
     //
-    // During the transition period, set the stored pointer to NULL while
+    // During the transition period, set the stored pointer to nullptr while
     // deleting the object. Eventually, this safety check will be removed to
-    // prevent the scenario initially described from occuring and
+    // prevent the scenario initially described from occurring and
     // http://crbug.com/176091 can be closed.
     T* old = data_.ptr;
-    data_.ptr = NULL;
-    if (old != NULL)
+    data_.ptr = nullptr;
+    if (old != nullptr)
       static_cast<D&>(data_)(old);
     data_.ptr = p;
   }
@@ -259,7 +270,7 @@
 
   T* release() {
     T* old_ptr = data_.ptr;
-    data_.ptr = NULL;
+    data_.ptr = nullptr;
     return old_ptr;
   }
 
@@ -287,8 +298,8 @@
 // A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
 // automatically deletes the pointer it holds (if any).
 // That is, scoped_ptr<T> owns the T object that it points to.
-// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
-// Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
+// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
 // dereference it, you get the thread safety guarantees of T.
 //
 // The size of scoped_ptr is small. On most compilers, when using the
@@ -298,25 +309,33 @@
 //
 // Current implementation targets having a strict subset of  C++11's
 // unique_ptr<> features. Known deficiencies include not supporting move-only
-// deleteres, function pointers as deleters, and deleters with reference
+// deleters, function pointers as deleters, and deleters with reference
 // types.
 template <class T, class D = webrtc::DefaultDeleter<T> >
 class scoped_ptr {
-  WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+  RTC_MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+
+  // TODO(ajm): If we ever import RefCountedBase, this check needs to be
+  // enabled.
+  //COMPILE_ASSERT(webrtc::internal::IsNotRefCounted<T>::value,
+  //               T_is_refcounted_type_and_needs_scoped_refptr);
 
  public:
   // The element and deleter types.
   typedef T element_type;
   typedef D deleter_type;
 
-  // Constructor.  Defaults to initializing with NULL.
-  scoped_ptr() : impl_(NULL) { }
+  // Constructor.  Defaults to initializing with nullptr.
+  scoped_ptr() : impl_(nullptr) {}
 
   // Constructor.  Takes ownership of p.
-  explicit scoped_ptr(element_type* p) : impl_(p) { }
+  explicit scoped_ptr(element_type* p) : impl_(p) {}
 
   // Constructor.  Allows initialization of a stateful deleter.
-  scoped_ptr(element_type* p, const D& d) : impl_(p, d) { }
+  scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
+
+  // Constructor.  Allows construction from a nullptr.
+  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
 
   // Constructor.  Allows construction from a scoped_ptr rvalue for a
   // convertible type and deleter.
@@ -329,13 +348,11 @@
   // use of SFINAE. You only need to care about this if you modify the
   // implementation of scoped_ptr.
   template <typename U, typename V>
-  scoped_ptr(scoped_ptr<U, V> other) : impl_(&other.impl_) {
+  scoped_ptr(scoped_ptr<U, V>&& other)
+      : impl_(&other.impl_) {
     COMPILE_ASSERT(!webrtc::is_array<U>::value, U_cannot_be_an_array);
   }
 
-  // Constructor.  Move constructor for C++03 move emulation of this type.
-  scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
-
   // operator=.  Allows assignment from a scoped_ptr rvalue for a convertible
   // type and deleter.
   //
@@ -347,24 +364,31 @@
   // You only need to care about this if you modify the implementation of
   // scoped_ptr.
   template <typename U, typename V>
-  scoped_ptr& operator=(scoped_ptr<U, V> rhs) {
+  scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
     COMPILE_ASSERT(!webrtc::is_array<U>::value, U_cannot_be_an_array);
     impl_.TakeState(&rhs.impl_);
     return *this;
   }
 
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // object, if any.
+  scoped_ptr& operator=(decltype(nullptr)) {
+    reset();
+    return *this;
+  }
+
   // Reset.  Deletes the currently owned object, if any.
   // Then takes ownership of a new object, if given.
-  void reset(element_type* p = NULL) { impl_.reset(p); }
+  void reset(element_type* p = nullptr) { impl_.reset(p); }
 
   // Accessors to get the owned object.
   // operator* and operator-> will assert() if there is no current object.
   element_type& operator*() const {
-    assert(impl_.get() != NULL);
+    assert(impl_.get() != nullptr);
     return *impl_.get();
   }
   element_type* operator->() const  {
-    assert(impl_.get() != NULL);
+    assert(impl_.get() != nullptr);
     return impl_.get();
   }
   element_type* get() const { return impl_.get(); }
@@ -385,7 +409,9 @@
       scoped_ptr::*Testable;
 
  public:
-  operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
+  operator Testable() const {
+    return impl_.get() ? &scoped_ptr::impl_ : nullptr;
+  }
 
   // Comparison operators.
   // These return whether two scoped_ptr refer to the same object, not just to
@@ -399,25 +425,13 @@
   }
 
   // Release a pointer.
-  // The return value is the current pointer held by this object.
-  // If this object holds a NULL pointer, the return value is NULL.
-  // After this operation, this object will hold a NULL pointer,
-  // and will not own the object any more.
+  // The return value is the current pointer held by this object. If this object
+  // holds a nullptr, the return value is nullptr. After this operation, this
+  // object will hold a nullptr, and will not own the object any more.
   element_type* release() WARN_UNUSED_RESULT {
     return impl_.release();
   }
 
-  // C++98 doesn't support functions templates with default parameters which
-  // makes it hard to write a PassAs() that understands converting the deleter
-  // while preserving simple calling semantics.
-  //
-  // Until there is a use case for PassAs() with custom deleters, just ignore
-  // the custom deleter.
-  template <typename PassAsType>
-  scoped_ptr<PassAsType> PassAs() {
-    return scoped_ptr<PassAsType>(Pass());
-  }
-
  private:
   // Needed to reach into |impl_| in the constructor.
   template <typename U, typename V> friend class scoped_ptr;
@@ -436,15 +450,15 @@
 
 template <class T, class D>
 class scoped_ptr<T[], D> {
-  WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+  RTC_MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
 
  public:
   // The element and deleter types.
   typedef T element_type;
   typedef D deleter_type;
 
-  // Constructor.  Defaults to initializing with NULL.
-  scoped_ptr() : impl_(NULL) { }
+  // Constructor.  Defaults to initializing with nullptr.
+  scoped_ptr() : impl_(nullptr) {}
 
   // Constructor. Stores the given array. Note that the argument's type
   // must exactly match T*. In particular:
@@ -454,32 +468,39 @@
   //   T and the derived types had different sizes access would be
   //   incorrectly calculated). Deletion is also always undefined
   //   (C++98 [expr.delete]p3). If you're doing this, fix your code.
-  // - it cannot be NULL, because NULL is an integral expression, not a
-  //   pointer to T. Use the no-argument version instead of explicitly
-  //   passing NULL.
   // - it cannot be const-qualified differently from T per unique_ptr spec
   //   (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
   //   to work around this may use implicit_cast<const T*>().
   //   However, because of the first bullet in this comment, users MUST
   //   NOT use implicit_cast<Base*>() to upcast the static type of the array.
-  explicit scoped_ptr(element_type* array) : impl_(array) { }
+  explicit scoped_ptr(element_type* array) : impl_(array) {}
 
-  // Constructor.  Move constructor for C++03 move emulation of this type.
-  scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
+  // Constructor.  Allows construction from a nullptr.
+  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
 
-  // operator=.  Move operator= for C++03 move emulation of this type.
-  scoped_ptr& operator=(RValue rhs) {
-    impl_.TakeState(&rhs.object->impl_);
+  // Constructor.  Allows construction from a scoped_ptr rvalue.
+  scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
+
+  // operator=.  Allows assignment from a scoped_ptr rvalue.
+  scoped_ptr& operator=(scoped_ptr&& rhs) {
+    impl_.TakeState(&rhs.impl_);
+    return *this;
+  }
+
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // array, if any.
+  scoped_ptr& operator=(decltype(nullptr)) {
+    reset();
     return *this;
   }
 
   // Reset.  Deletes the currently owned array, if any.
   // Then takes ownership of a new object, if given.
-  void reset(element_type* array = NULL) { impl_.reset(array); }
+  void reset(element_type* array = nullptr) { impl_.reset(array); }
 
   // Accessors to get the owned array.
   element_type& operator[](size_t i) const {
-    assert(impl_.get() != NULL);
+    assert(impl_.get() != nullptr);
     return impl_.get()[i];
   }
   element_type* get() const { return impl_.get(); }
@@ -495,7 +516,9 @@
       scoped_ptr::*Testable;
 
  public:
-  operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
+  operator Testable() const {
+    return impl_.get() ? &scoped_ptr::impl_ : nullptr;
+  }
 
   // Comparison operators.
   // These return whether two scoped_ptr refer to the same object, not just to
@@ -509,10 +532,9 @@
   }
 
   // Release a pointer.
-  // The return value is the current pointer held by this object.
-  // If this object holds a NULL pointer, the return value is NULL.
-  // After this operation, this object will hold a NULL pointer,
-  // and will not own the object any more.
+  // The return value is the current pointer held by this object. If this object
+  // holds a nullptr, the return value is nullptr. After this operation, this
+  // object will hold a nullptr, and will not own the object any more.
   element_type* release() WARN_UNUSED_RESULT {
     return impl_.release();
   }
@@ -547,7 +569,6 @@
 
 }  // namespace webrtc
 
-// Free functions
 template <class T, class D>
 void swap(webrtc::scoped_ptr<T, D>& p1, webrtc::scoped_ptr<T, D>& p2) {
   p1.swap(p2);
@@ -563,4 +584,12 @@
   return p1 != p2.get();
 }
 
+// A function to convert T* into scoped_ptr<T>
+// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+webrtc::scoped_ptr<T> rtc_make_scoped_ptr(T* ptr) {
+  return webrtc::scoped_ptr<T>(ptr);
+}
+
 #endif  // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_
diff --git a/system_wrappers/interface/scoped_vector.h b/system_wrappers/interface/scoped_vector.h
index 68db3a1..7b8c678 100644
--- a/system_wrappers/interface/scoped_vector.h
+++ b/system_wrappers/interface/scoped_vector.h
@@ -13,10 +13,9 @@
 #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_
 #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_
 
-#include <assert.h>
-#include <algorithm>
 #include <vector>
 
+#include "webrtc/base/checks.h"
 #include "webrtc/system_wrappers/interface/stl_util.h"
 #include "webrtc/system_wrappers/source/move.h"
 
@@ -26,7 +25,7 @@
 // destructor.
 template <class T>
 class ScopedVector {
-  WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
+  RTC_MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
 
  public:
   typedef typename std::vector<T*>::allocator_type allocator_type;
@@ -76,7 +75,7 @@
   void push_back(T* elem) { v_.push_back(elem); }
 
   void pop_back() {
-    assert(!empty());
+    DCHECK(!empty());
     delete v_.back();
     v_.pop_back();
   }
diff --git a/system_wrappers/interface/timestamp_extrapolator.h b/system_wrappers/interface/timestamp_extrapolator.h
index d067198..b78cf64 100644
--- a/system_wrappers/interface/timestamp_extrapolator.h
+++ b/system_wrappers/interface/timestamp_extrapolator.h
@@ -31,7 +31,7 @@
     bool DelayChangeDetection(double error);
     RWLockWrapper*        _rwLock;
     double                _w[2];
-    double                _P[2][2];
+    double                _pP[2][2];
     int64_t         _startMs;
     int64_t         _prevMs;
     uint32_t        _firstTimestamp;
@@ -48,7 +48,7 @@
     const double        _alarmThreshold;
     const double        _accDrift;
     const double        _accMaxError;
-    const double        _P11;
+    const double        _pP11;
 };
 
 }  // namespace webrtc
diff --git a/system_wrappers/source/cpu_features_android.target.darwin-arm.mk b/system_wrappers/source/cpu_features_android.target.darwin-arm.mk
index 61c917a..c247f87 100644
--- a/system_wrappers/source/cpu_features_android.target.darwin-arm.mk
+++ b/system_wrappers/source/cpu_features_android.target.darwin-arm.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.darwin-arm64.mk b/system_wrappers/source/cpu_features_android.target.darwin-arm64.mk
index 2017818..49b3332 100644
--- a/system_wrappers/source/cpu_features_android.target.darwin-arm64.mk
+++ b/system_wrappers/source/cpu_features_android.target.darwin-arm64.mk
@@ -71,11 +71,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -84,10 +86,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -168,11 +172,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -181,10 +187,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.darwin-mips.mk b/system_wrappers/source/cpu_features_android.target.darwin-mips.mk
index afbf953..f4e1bb6 100644
--- a/system_wrappers/source/cpu_features_android.target.darwin-mips.mk
+++ b/system_wrappers/source/cpu_features_android.target.darwin-mips.mk
@@ -75,11 +75,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -94,6 +96,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.darwin-mips64.mk b/system_wrappers/source/cpu_features_android.target.darwin-mips64.mk
new file mode 100644
index 0000000..6c25a0e
--- /dev/null
+++ b/system_wrappers/source/cpu_features_android.target.darwin-mips64.mk
@@ -0,0 +1,262 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_system_wrappers_source_cpu_features_android_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/system_wrappers/source/cpu_features_android.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+
+LOCAL_STATIC_LIBRARIES := \
+	cpufeatures
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_system_wrappers_source_cpu_features_android_gyp
+
+# Alias gyp target name.
+.PHONY: cpu_features_android
+cpu_features_android: third_party_webrtc_system_wrappers_source_cpu_features_android_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/system_wrappers/source/cpu_features_android.target.darwin-x86.mk b/system_wrappers/source/cpu_features_android.target.darwin-x86.mk
index b9b61ef..c5c4ed6 100644
--- a/system_wrappers/source/cpu_features_android.target.darwin-x86.mk
+++ b/system_wrappers/source/cpu_features_android.target.darwin-x86.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -94,6 +96,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -180,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -197,6 +202,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.darwin-x86_64.mk b/system_wrappers/source/cpu_features_android.target.darwin-x86_64.mk
index cd1b819..f0ca654 100644
--- a/system_wrappers/source/cpu_features_android.target.darwin-x86_64.mk
+++ b/system_wrappers/source/cpu_features_android.target.darwin-x86_64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -93,6 +95,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +181,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,6 +200,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.linux-arm.mk b/system_wrappers/source/cpu_features_android.target.linux-arm.mk
index 61c917a..c247f87 100644
--- a/system_wrappers/source/cpu_features_android.target.linux-arm.mk
+++ b/system_wrappers/source/cpu_features_android.target.linux-arm.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -102,6 +104,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -194,11 +197,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,6 +219,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.linux-arm64.mk b/system_wrappers/source/cpu_features_android.target.linux-arm64.mk
index 2017818..49b3332 100644
--- a/system_wrappers/source/cpu_features_android.target.linux-arm64.mk
+++ b/system_wrappers/source/cpu_features_android.target.linux-arm64.mk
@@ -71,11 +71,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -84,10 +86,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -168,11 +172,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -181,10 +187,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.linux-mips.mk b/system_wrappers/source/cpu_features_android.target.linux-mips.mk
index afbf953..f4e1bb6 100644
--- a/system_wrappers/source/cpu_features_android.target.linux-mips.mk
+++ b/system_wrappers/source/cpu_features_android.target.linux-mips.mk
@@ -75,11 +75,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -94,6 +96,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.linux-mips64.mk b/system_wrappers/source/cpu_features_android.target.linux-mips64.mk
new file mode 100644
index 0000000..6c25a0e
--- /dev/null
+++ b/system_wrappers/source/cpu_features_android.target.linux-mips64.mk
@@ -0,0 +1,262 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_system_wrappers_source_cpu_features_android_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/system_wrappers/source/cpu_features_android.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+
+LOCAL_STATIC_LIBRARIES := \
+	cpufeatures
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_system_wrappers_source_cpu_features_android_gyp
+
+# Alias gyp target name.
+.PHONY: cpu_features_android
+cpu_features_android: third_party_webrtc_system_wrappers_source_cpu_features_android_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/system_wrappers/source/cpu_features_android.target.linux-x86.mk b/system_wrappers/source/cpu_features_android.target.linux-x86.mk
index b9b61ef..c5c4ed6 100644
--- a/system_wrappers/source/cpu_features_android.target.linux-x86.mk
+++ b/system_wrappers/source/cpu_features_android.target.linux-x86.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -94,6 +96,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -180,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -197,6 +202,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/cpu_features_android.target.linux-x86_64.mk b/system_wrappers/source/cpu_features_android.target.linux-x86_64.mk
index cd1b819..f0ca654 100644
--- a/system_wrappers/source/cpu_features_android.target.linux-x86_64.mk
+++ b/system_wrappers/source/cpu_features_android.target.linux-x86_64.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -93,6 +95,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -178,11 +181,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -195,6 +200,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/logging.cc b/system_wrappers/source/logging.cc
index 922a272..da1c1a5 100644
--- a/system_wrappers/source/logging.cc
+++ b/system_wrappers/source/logging.cc
@@ -55,7 +55,7 @@
 
 LogMessage::~LogMessage() {
   const std::string& str = print_stream_.str();
-  Trace::Add(WebRtcSeverity(severity_), kTraceUndefined, 0, str.c_str());
+  Trace::Add(WebRtcSeverity(severity_), kTraceUndefined, 0, "%s", str.c_str());
 }
 
 }  // namespace webrtc
diff --git a/system_wrappers/source/metrics_default.cc b/system_wrappers/source/metrics_default.cc
new file mode 100644
index 0000000..af950b4
--- /dev/null
+++ b/system_wrappers/source/metrics_default.cc
@@ -0,0 +1,29 @@
+// 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.
+//
+
+#include "webrtc/system_wrappers/interface/metrics.h"
+
+// Default implementation of histogram methods for WebRTC clients that do not
+// want to provide their own implementation.
+
+namespace webrtc {
+namespace metrics {
+
+Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max,
+    int bucket_count) { return NULL; }
+
+Histogram* HistogramFactoryGetEnumeration(const std::string& name,
+    int boundary) { return NULL; }
+
+void HistogramAdd(
+    Histogram* histogram_pointer, const std::string& name, int sample) {}
+
+}  // namespace metrics
+}  // namespace webrtc
+
diff --git a/system_wrappers/source/move.h b/system_wrappers/source/move.h
index 2e93641..80aed9a 100644
--- a/system_wrappers/source/move.h
+++ b/system_wrappers/source/move.h
@@ -10,8 +10,10 @@
 
 // Borrowed from Chromium's src/base/move.h.
 
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_
+#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_MOVE_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_MOVE_H_
+
+#include "webrtc/typedefs.h"
 
 // Macro with the boilerplate that makes a type move-only in C++03.
 //
@@ -209,7 +211,7 @@
 //
 // The workaround is to explicitly declare your copy constructor.
 //
-#define WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
+#define RTC_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
  private: \
   struct rvalue_type { \
     explicit rvalue_type(type* object) : object(object) {} \
@@ -219,8 +221,17 @@
   void operator=(type&); \
  public: \
   operator rvalue_type() { return rvalue_type(this); } \
-  type Pass() { return type(rvalue_type(this)); } \
+  type Pass() WARN_UNUSED_RESULT { return type(rvalue_type(this)); } \
   typedef void MoveOnlyTypeForCPP03; \
  private:
 
-#endif  // WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_
+#define RTC_MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
+ private: \
+  type(type&); \
+  void operator=(type&); \
+ public: \
+  type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
+  typedef void MoveOnlyTypeForCPP03; \
+ private:
+
+#endif  // WEBRTC_SYSTEM_WRAPPERS_SOURCE_MOVE_H_
diff --git a/system_wrappers/source/system_wrappers.gyp b/system_wrappers/source/system_wrappers.gyp
index 870d88a..2cdd23d 100644
--- a/system_wrappers/source/system_wrappers.gyp
+++ b/system_wrappers/source/system_wrappers.gyp
@@ -44,6 +44,7 @@
         '../interface/fix_interlocked_exchange_pointer_win.h',
         '../interface/logcat_trace_context.h',
         '../interface/logging.h',
+        '../interface/metrics.h',
         '../interface/ref_count.h',
         '../interface/rtp_to_ntp.h',
         '../interface/rw_lock_wrapper.h',
@@ -204,6 +205,22 @@
       'dependencies': [
         'system_wrappers',
       ]
+    }, {
+      'target_name': 'metrics_default',
+      'type': 'static_library',
+      'sources': [
+        'metrics_default.cc',
+      ],
+      'dependencies': [
+        'system_wrappers',
+      ]
+    }, {
+      'target_name': 'system_wrappers_default',
+      'type': 'static_library',
+      'dependencies': [
+        'field_trial_default',
+        'metrics_default',
+      ]
     },
   ], # targets
   'conditions': [
diff --git a/system_wrappers/source/system_wrappers.target.darwin-arm.mk b/system_wrappers/source/system_wrappers.target.darwin-arm.mk
index 2877b67..410731a 100644
--- a/system_wrappers/source/system_wrappers.target.darwin-arm.mk
+++ b/system_wrappers/source/system_wrappers.target.darwin-arm.mk
@@ -111,11 +111,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -227,11 +230,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -249,6 +254,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.darwin-arm64.mk b/system_wrappers/source/system_wrappers.target.darwin-arm64.mk
index 7ad5d7b..9a13f39 100644
--- a/system_wrappers/source/system_wrappers.target.darwin-arm64.mk
+++ b/system_wrappers/source/system_wrappers.target.darwin-arm64.mk
@@ -100,11 +100,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -113,12 +115,14 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +205,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,12 +220,14 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.darwin-mips.mk b/system_wrappers/source/system_wrappers.target.darwin-mips.mk
index 7fcc084..8739abc 100644
--- a/system_wrappers/source/system_wrappers.target.darwin-mips.mk
+++ b/system_wrappers/source/system_wrappers.target.darwin-mips.mk
@@ -104,11 +104,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -212,11 +215,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -233,6 +238,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.darwin-mips64.mk b/system_wrappers/source/system_wrappers.target.darwin-mips64.mk
new file mode 100644
index 0000000..7eeb03d
--- /dev/null
+++ b/system_wrappers/source/system_wrappers.target.darwin-mips64.mk
@@ -0,0 +1,293 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_system_wrappers_source_system_wrappers_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/system_wrappers/source/aligned_malloc.cc \
+	third_party/webrtc/system_wrappers/source/atomic32_posix.cc \
+	third_party/webrtc/system_wrappers/source/clock.cc \
+	third_party/webrtc/system_wrappers/source/condition_variable.cc \
+	third_party/webrtc/system_wrappers/source/condition_variable_posix.cc \
+	third_party/webrtc/system_wrappers/source/cpu_info.cc \
+	third_party/webrtc/system_wrappers/source/cpu_features.cc \
+	third_party/webrtc/system_wrappers/source/critical_section.cc \
+	third_party/webrtc/system_wrappers/source/critical_section_posix.cc \
+	third_party/webrtc/system_wrappers/source/data_log_c.cc \
+	third_party/webrtc/system_wrappers/source/data_log_no_op.cc \
+	third_party/webrtc/system_wrappers/source/event.cc \
+	third_party/webrtc/system_wrappers/source/event_posix.cc \
+	third_party/webrtc/system_wrappers/source/event_tracer.cc \
+	third_party/webrtc/system_wrappers/source/file_impl.cc \
+	third_party/webrtc/system_wrappers/source/logcat_trace_context.cc \
+	third_party/webrtc/system_wrappers/source/logging.cc \
+	third_party/webrtc/system_wrappers/source/rtp_to_ntp.cc \
+	third_party/webrtc/system_wrappers/source/rw_lock.cc \
+	third_party/webrtc/system_wrappers/source/rw_lock_generic.cc \
+	third_party/webrtc/system_wrappers/source/rw_lock_posix.cc \
+	third_party/webrtc/system_wrappers/source/sleep.cc \
+	third_party/webrtc/system_wrappers/source/sort.cc \
+	third_party/webrtc/system_wrappers/source/tick_util.cc \
+	third_party/webrtc/system_wrappers/source/thread.cc \
+	third_party/webrtc/system_wrappers/source/thread_posix.cc \
+	third_party/webrtc/system_wrappers/source/timestamp_extrapolator.cc \
+	third_party/webrtc/system_wrappers/source/trace_impl.cc \
+	third_party/webrtc/system_wrappers/source/trace_posix.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_THREAD_RR' \
+	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/source/spreadsortlib \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_THREAD_RR' \
+	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/source/spreadsortlib \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_system_wrappers_source_system_wrappers_gyp
+
+# Alias gyp target name.
+.PHONY: system_wrappers
+system_wrappers: third_party_webrtc_system_wrappers_source_system_wrappers_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/system_wrappers/source/system_wrappers.target.darwin-x86.mk b/system_wrappers/source/system_wrappers.target.darwin-x86.mk
index 1515c61..4e16a4b 100644
--- a/system_wrappers/source/system_wrappers.target.darwin-x86.mk
+++ b/system_wrappers/source/system_wrappers.target.darwin-x86.mk
@@ -106,11 +106,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -213,11 +216,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -232,6 +237,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.darwin-x86_64.mk b/system_wrappers/source/system_wrappers.target.darwin-x86_64.mk
index ef73414..3aeeea4 100644
--- a/system_wrappers/source/system_wrappers.target.darwin-x86_64.mk
+++ b/system_wrappers/source/system_wrappers.target.darwin-x86_64.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -211,11 +214,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -230,6 +235,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.linux-arm.mk b/system_wrappers/source/system_wrappers.target.linux-arm.mk
index 2877b67..410731a 100644
--- a/system_wrappers/source/system_wrappers.target.linux-arm.mk
+++ b/system_wrappers/source/system_wrappers.target.linux-arm.mk
@@ -111,11 +111,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -133,6 +135,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -227,11 +230,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -249,6 +254,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.linux-arm64.mk b/system_wrappers/source/system_wrappers.target.linux-arm64.mk
index 7ad5d7b..9a13f39 100644
--- a/system_wrappers/source/system_wrappers.target.linux-arm64.mk
+++ b/system_wrappers/source/system_wrappers.target.linux-arm64.mk
@@ -100,11 +100,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -113,12 +115,14 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +205,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,12 +220,14 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.linux-mips.mk b/system_wrappers/source/system_wrappers.target.linux-mips.mk
index 7fcc084..8739abc 100644
--- a/system_wrappers/source/system_wrappers.target.linux-mips.mk
+++ b/system_wrappers/source/system_wrappers.target.linux-mips.mk
@@ -104,11 +104,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -212,11 +215,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -233,6 +238,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.linux-mips64.mk b/system_wrappers/source/system_wrappers.target.linux-mips64.mk
new file mode 100644
index 0000000..7eeb03d
--- /dev/null
+++ b/system_wrappers/source/system_wrappers.target.linux-mips64.mk
@@ -0,0 +1,293 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_system_wrappers_source_system_wrappers_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/system_wrappers/source/aligned_malloc.cc \
+	third_party/webrtc/system_wrappers/source/atomic32_posix.cc \
+	third_party/webrtc/system_wrappers/source/clock.cc \
+	third_party/webrtc/system_wrappers/source/condition_variable.cc \
+	third_party/webrtc/system_wrappers/source/condition_variable_posix.cc \
+	third_party/webrtc/system_wrappers/source/cpu_info.cc \
+	third_party/webrtc/system_wrappers/source/cpu_features.cc \
+	third_party/webrtc/system_wrappers/source/critical_section.cc \
+	third_party/webrtc/system_wrappers/source/critical_section_posix.cc \
+	third_party/webrtc/system_wrappers/source/data_log_c.cc \
+	third_party/webrtc/system_wrappers/source/data_log_no_op.cc \
+	third_party/webrtc/system_wrappers/source/event.cc \
+	third_party/webrtc/system_wrappers/source/event_posix.cc \
+	third_party/webrtc/system_wrappers/source/event_tracer.cc \
+	third_party/webrtc/system_wrappers/source/file_impl.cc \
+	third_party/webrtc/system_wrappers/source/logcat_trace_context.cc \
+	third_party/webrtc/system_wrappers/source/logging.cc \
+	third_party/webrtc/system_wrappers/source/rtp_to_ntp.cc \
+	third_party/webrtc/system_wrappers/source/rw_lock.cc \
+	third_party/webrtc/system_wrappers/source/rw_lock_generic.cc \
+	third_party/webrtc/system_wrappers/source/rw_lock_posix.cc \
+	third_party/webrtc/system_wrappers/source/sleep.cc \
+	third_party/webrtc/system_wrappers/source/sort.cc \
+	third_party/webrtc/system_wrappers/source/tick_util.cc \
+	third_party/webrtc/system_wrappers/source/thread.cc \
+	third_party/webrtc/system_wrappers/source/thread_posix.cc \
+	third_party/webrtc/system_wrappers/source/timestamp_extrapolator.cc \
+	third_party/webrtc/system_wrappers/source/trace_impl.cc \
+	third_party/webrtc/system_wrappers/source/trace_posix.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_THREAD_RR' \
+	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/source/spreadsortlib \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DWEBRTC_THREAD_RR' \
+	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/source/spreadsortlib \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_system_wrappers_source_system_wrappers_gyp
+
+# Alias gyp target name.
+.PHONY: system_wrappers
+system_wrappers: third_party_webrtc_system_wrappers_source_system_wrappers_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/system_wrappers/source/system_wrappers.target.linux-x86.mk b/system_wrappers/source/system_wrappers.target.linux-x86.mk
index 1515c61..4e16a4b 100644
--- a/system_wrappers/source/system_wrappers.target.linux-x86.mk
+++ b/system_wrappers/source/system_wrappers.target.linux-x86.mk
@@ -106,11 +106,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -125,6 +127,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -213,11 +216,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -232,6 +237,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers.target.linux-x86_64.mk b/system_wrappers/source/system_wrappers.target.linux-x86_64.mk
index ef73414..3aeeea4 100644
--- a/system_wrappers/source/system_wrappers.target.linux-x86_64.mk
+++ b/system_wrappers/source/system_wrappers.target.linux-x86_64.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -211,11 +214,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -230,6 +235,7 @@
 	'-DWEBRTC_ANDROID_OPENSLES' \
 	'-DWEBRTC_THREAD_RR' \
 	'-DWEBRTC_CLOCK_TYPE_REALTIME' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/system_wrappers/source/system_wrappers_tests.gyp b/system_wrappers/source/system_wrappers_tests.gyp
index f77b985..1877592 100644
--- a/system_wrappers/source/system_wrappers_tests.gyp
+++ b/system_wrappers/source/system_wrappers_tests.gyp
@@ -80,7 +80,6 @@
           ],
           'includes': [
             '../../build/isolate.gypi',
-            'system_wrappers_unittests.isolate',
           ],
           'sources': [
             'system_wrappers_unittests.isolate',
diff --git a/system_wrappers/source/system_wrappers_unittests.isolate b/system_wrappers/source/system_wrappers_unittests.isolate
index f505771..0a56470 100644
--- a/system_wrappers/source/system_wrappers_unittests.isolate
+++ b/system_wrappers/source/system_wrappers_unittests.isolate
@@ -10,7 +10,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -22,13 +22,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/system_wrappers_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/system_wrappers_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/system_wrappers/source/timestamp_extrapolator.cc b/system_wrappers/source/timestamp_extrapolator.cc
index afd212b..f2b7092 100644
--- a/system_wrappers/source/timestamp_extrapolator.cc
+++ b/system_wrappers/source/timestamp_extrapolator.cc
@@ -30,7 +30,7 @@
       _alarmThreshold(60e3),
       _accDrift(6600),  // in timestamp ticks, i.e. 15 ms
       _accMaxError(7000),
-      _P11(1e10) {
+      _pP11(1e10) {
     Reset(start_ms);
 }
 
@@ -47,9 +47,9 @@
     _firstTimestamp = 0;
     _w[0] = 90.0;
     _w[1] = 0;
-    _P[0][0] = 1;
-    _P[1][1] = _P11;
-    _P[0][1] = _P[1][0] = 0;
+    _pP[0][0] = 1;
+    _pP[1][1] = _pP11;
+    _pP[0][1] = _pP[1][0] = 0;
     _firstAfterReset = true;
     _prevUnwrappedTimestamp = -1;
     _prevWrapTimestamp = -1;
@@ -112,14 +112,14 @@
         // A sudden change of average network delay has been detected.
         // Force the filter to adjust its offset parameter by changing
         // the offset uncertainty. Don't do this during startup.
-        _P[1][1] = _P11;
+        _pP[1][1] = _pP11;
     }
     //T = [t(k) 1]';
     //that = T'*w;
     //K = P*T/(lambda + T'*P*T);
     double K[2];
-    K[0] = _P[0][0] * tMs + _P[0][1];
-    K[1] = _P[1][0] * tMs + _P[1][1];
+    K[0] = _pP[0][0] * tMs + _pP[0][1];
+    K[1] = _pP[1][0] * tMs + _pP[1][1];
     double TPT = _lambda + tMs * K[0] + K[1];
     K[0] /= TPT;
     K[1] /= TPT;
@@ -127,12 +127,16 @@
     _w[0] = _w[0] + K[0] * residual;
     _w[1] = _w[1] + K[1] * residual;
     //P = 1/lambda*(P - K*T'*P);
-    double p00 = 1 / _lambda * (_P[0][0] - (K[0] * tMs * _P[0][0] + K[0] * _P[1][0]));
-    double p01 = 1 / _lambda * (_P[0][1] - (K[0] * tMs * _P[0][1] + K[0] * _P[1][1]));
-    _P[1][0] = 1 / _lambda * (_P[1][0] - (K[1] * tMs * _P[0][0] + K[1] * _P[1][0]));
-    _P[1][1] = 1 / _lambda * (_P[1][1] - (K[1] * tMs * _P[0][1] + K[1] * _P[1][1]));
-    _P[0][0] = p00;
-    _P[0][1] = p01;
+    double p00 = 1 / _lambda *
+        (_pP[0][0] - (K[0] * tMs * _pP[0][0] + K[0] * _pP[1][0]));
+    double p01 = 1 / _lambda *
+        (_pP[0][1] - (K[0] * tMs * _pP[0][1] + K[0] * _pP[1][1]));
+    _pP[1][0] = 1 / _lambda *
+        (_pP[1][0] - (K[1] * tMs * _pP[0][0] + K[1] * _pP[1][0]));
+    _pP[1][1] = 1 / _lambda *
+        (_pP[1][1] - (K[1] * tMs * _pP[0][1] + K[1] * _pP[1][1]));
+    _pP[0][0] = p00;
+    _pP[0][1] = p01;
     _prevUnwrappedTimestamp = unwrapped_ts90khz;
     if (_packetCount < _startUpFilterDelayInPackets)
     {
diff --git a/system_wrappers/source/trace_impl.h b/system_wrappers/source/trace_impl.h
index 9e6e0a2..5548e98 100644
--- a/system_wrappers/source/trace_impl.h
+++ b/system_wrappers/source/trace_impl.h
@@ -30,7 +30,7 @@
 #define WEBRTC_TRACE_MAX_QUEUE  8000
 #endif
 #define WEBRTC_TRACE_NUM_ARRAY 2
-#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 256
+#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 1024
 // Total buffer size is WEBRTC_TRACE_NUM_ARRAY (number of buffer partitions) *
 // WEBRTC_TRACE_MAX_QUEUE (number of lines per buffer partition) *
 // WEBRTC_TRACE_MAX_MESSAGE_SIZE (number of 1 byte charachters per line) =
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 7bb11a1..db17c31 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -95,6 +95,7 @@
   deps = [
     ":field_trial",
     ":test_support",
+    "../system_wrappers:metrics_default",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/gflags",
diff --git a/test/call_test.cc b/test/call_test.cc
index d49f6e3..126c716 100644
--- a/test/call_test.cc
+++ b/test/call_test.cc
@@ -19,6 +19,7 @@
       send_stream_(NULL),
       fake_encoder_(clock_) {
 }
+
 CallTest::~CallTest() {
 }
 
@@ -98,23 +99,15 @@
 void CallTest::CreateMatchingReceiveConfigs() {
   assert(!send_config_.rtp.ssrcs.empty());
   assert(receive_configs_.empty());
-  assert(fake_decoders_.empty());
+  assert(allocated_decoders_.empty());
   VideoReceiveStream::Config config;
-  VideoCodec codec =
-      test::CreateDecoderVideoCodec(send_config_.encoder_settings);
-  config.codecs.push_back(codec);
   config.rtp.local_ssrc = kReceiverLocalSsrc;
-  if (send_config_.encoder_settings.encoder == &fake_encoder_) {
-    config.external_decoders.resize(1);
-    config.external_decoders[0].payload_type =
-        send_config_.encoder_settings.payload_type;
-  }
   for (size_t i = 0; i < send_config_.rtp.ssrcs.size(); ++i) {
-    if (send_config_.encoder_settings.encoder == &fake_encoder_) {
-      FakeDecoder* decoder = new FakeDecoder();
-      fake_decoders_.push_back(decoder);
-      config.external_decoders[0].decoder = decoder;
-    }
+    VideoReceiveStream::Decoder decoder =
+        test::CreateMatchingDecoder(send_config_.encoder_settings);
+    allocated_decoders_.push_back(decoder.decoder);
+    config.decoders.clear();
+    config.decoders.push_back(decoder);
     config.rtp.remote_ssrc = send_config_.rtp.ssrcs[i];
     receive_configs_.push_back(config);
   }
@@ -149,7 +142,7 @@
   for (size_t i = 0; i < receive_streams_.size(); ++i)
     receiver_call_->DestroyVideoReceiveStream(receive_streams_[i]);
   receive_streams_.clear();
-  fake_decoders_.clear();
+  allocated_decoders_.clear();
 }
 
 const unsigned int CallTest::kDefaultTimeoutMs = 30 * 1000;
diff --git a/test/call_test.h b/test/call_test.h
index 695fb2a..b9a091b 100644
--- a/test/call_test.h
+++ b/test/call_test.h
@@ -74,7 +74,7 @@
 
   scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer_;
   test::FakeEncoder fake_encoder_;
-  ScopedVector<test::FakeDecoder> fake_decoders_;
+  ScopedVector<VideoDecoder> allocated_decoders_;
 };
 
 class BaseTest : public RtpRtcpObserver {
diff --git a/test/encoder_settings.cc b/test/encoder_settings.cc
index 0eeb0b9..db064bb 100644
--- a/test/encoder_settings.cc
+++ b/test/encoder_settings.cc
@@ -12,8 +12,8 @@
 #include <assert.h>
 #include <string.h>
 
-#include "webrtc/video_encoder.h"
-#include "webrtc/video_engine/vie_defines.h"
+#include "webrtc/test/fake_decoder.h"
+#include "webrtc/video_decoder.h"
 
 namespace webrtc {
 namespace test {
@@ -53,33 +53,17 @@
   return stream_settings;
 }
 
-VideoCodec CreateDecoderVideoCodec(
+VideoReceiveStream::Decoder CreateMatchingDecoder(
     const VideoSendStream::Config::EncoderSettings& encoder_settings) {
-  VideoCodec codec;
-  memset(&codec, 0, sizeof(codec));
-
-  codec.plType = encoder_settings.payload_type;
-  strcpy(codec.plName, encoder_settings.payload_name.c_str());
+  VideoReceiveStream::Decoder decoder;
+  decoder.payload_type = encoder_settings.payload_type;
+  decoder.payload_name = encoder_settings.payload_name;
   if (encoder_settings.payload_name == "VP8") {
-    codec.codecType = kVideoCodecVP8;
-  } else if (encoder_settings.payload_name == "H264") {
-    codec.codecType = kVideoCodecH264;
+    decoder.decoder = VideoDecoder::Create(VideoDecoder::kVp8);
   } else {
-    codec.codecType = kVideoCodecGeneric;
+    decoder.decoder = new FakeDecoder();
   }
-
-  if (codec.codecType == kVideoCodecVP8) {
-    codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
-  } else if (codec.codecType == kVideoCodecH264) {
-    codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
-  }
-
-  codec.width = 320;
-  codec.height = 180;
-  codec.startBitrate = codec.minBitrate = codec.maxBitrate = 300;
-
-  return codec;
+  return decoder;
 }
-
 }  // namespace test
 }  // namespace webrtc
diff --git a/test/encoder_settings.h b/test/encoder_settings.h
index ea2be97..a44d366 100644
--- a/test/encoder_settings.h
+++ b/test/encoder_settings.h
@@ -10,13 +10,14 @@
 #ifndef WEBRTC_TEST_ENCODER_SETTINGS_H_
 #define WEBRTC_TEST_ENCODER_SETTINGS_H_
 
+#include "webrtc/video_receive_stream.h"
 #include "webrtc/video_send_stream.h"
 
 namespace webrtc {
 namespace test {
 std::vector<VideoStream> CreateVideoStreams(size_t num_streams);
 
-VideoCodec CreateDecoderVideoCodec(
+VideoReceiveStream::Decoder CreateMatchingDecoder(
     const VideoSendStream::Config::EncoderSettings& encoder_settings);
 }  // namespace test
 }  // namespace webrtc
diff --git a/test/run_loop.cc b/test/run_loop.cc
index cda1e10..92f85dd 100644
--- a/test/run_loop.cc
+++ b/test/run_loop.cc
@@ -16,7 +16,7 @@
 
 void PressEnterToContinue() {
   puts(">> Press ENTER to continue...");
-  while (getchar() != '\n' && !feof(stdin));
+  while (getc(stdin) != '\n' && !feof(stdin));
 }
 }  // namespace test
 }  // namespace webrtc
diff --git a/test/test.gyp b/test/test.gyp
index 154ba2c..5c959b9 100644
--- a/test/test.gyp
+++ b/test/test.gyp
@@ -53,11 +53,13 @@
       ],
     },
     {
-      'target_name': 'rtcp_packet_parser',
+      'target_name': 'rtp_test_utils',
       'type': 'static_library',
       'sources': [
         'rtcp_packet_parser.cc',
         'rtcp_packet_parser.h',
+        'rtp_file_reader.cc',
+        'rtp_file_reader.h',
       ],
       'dependencies': [
         '<(webrtc_root)/modules/modules.gyp:rtp_rtcp',
@@ -84,6 +86,7 @@
         'field_trial',
         '<(DEPTH)/testing/gtest.gyp:gtest',
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:metrics_default',
       ],
     },
     {
@@ -140,6 +143,7 @@
         '<(DEPTH)/testing/gmock.gyp:gmock',
         '<(DEPTH)/testing/gtest.gyp:gtest',
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:metrics_default',
       ],
       'sources': [
         'run_all_unittests.cc',
@@ -220,7 +224,6 @@
           ],
           'includes': [
             '../build/isolate.gypi',
-            'test_support_unittests.isolate',
           ],
           'sources': [
             'test_support_unittests.isolate',
diff --git a/test/test_support_unittests.isolate b/test/test_support_unittests.isolate
index 08bd4a4..c1419e7 100644
--- a/test/test_support_unittests.isolate
+++ b/test/test_support_unittests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,14 +21,11 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/test_support_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/DEPS',
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/test_support_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/test/webrtc_test_common.gyp b/test/webrtc_test_common.gyp
index 477ec0f..cd07663 100644
--- a/test/webrtc_test_common.gyp
+++ b/test/webrtc_test_common.gyp
@@ -35,8 +35,6 @@
         'mock_transport.h',
         'null_transport.cc',
         'null_transport.h',
-        'rtp_file_reader.cc',
-        'rtp_file_reader.h',
         'rtp_rtcp_observer.h',
         'run_loop.cc',
         'run_loop.h',
@@ -60,10 +58,10 @@
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
         '<(webrtc_root)/base/base.gyp:rtc_base',
         '<(webrtc_root)/modules/modules.gyp:media_file',
-        '<(webrtc_root)/modules/modules.gyp:video_capture_module_impl',
         '<(webrtc_root)/modules/modules.gyp:video_render_module_impl',
         '<(webrtc_root)/test/test.gyp:frame_generator',
         '<(webrtc_root)/test/test.gyp:test_support',
+        '<(webrtc_root)/test/test.gyp:rtp_test_utils',
         '<(webrtc_root)/webrtc.gyp:webrtc',
       ],
     },
@@ -153,6 +151,7 @@
             'webrtc_test_common',
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(DEPTH)/testing/gmock.gyp:gmock',
+            '<(webrtc_root)/modules/modules.gyp:video_capture_module_impl',
             '<(webrtc_root)/test/test.gyp:test_support_main',
           ],
           'sources': [
diff --git a/tools/rtcbot/README b/tools/rtcbot/README
index bfa981c..1f4d7c1 100644
--- a/tools/rtcbot/README
+++ b/tools/rtcbot/README
@@ -17,8 +17,18 @@
 == How to run the test ==
  $ cd trunk/webrtc/tool/rtcbot
  $ npm install express browserify ws websocket-stream dnode
+ $ mkdir configurations
+ $ cd configurations
+ $ openssl genrsa -out priv.pem 1024
+ $ openssl req -x509 -new -key priv.pem -days 3650 -out cert.crt
+ $ cd trunk/webrtc/tool/rtcbot
  $ node main.js "<test_name>"
 
+* Note:
+    In first time you will use rtcBot you will receive a warning telling
+  you that your connection is not private. Just avoid this warning and
+  click Proceed to localhost (unsafe).
+
 == How can I see the list of available tests? ==
  $ node main.js
 
@@ -29,6 +39,10 @@
  $ nvm install 0.10
  $ nvm use 0.10
 
+== Why generating the private key and self signed certificate? ==
+  - Private key and certificate are used for creating HTTPs server in
+    rtcBot for loading the required files on the different types of the bots.
+
 == Supported Bot Types ==
   - "chrome": chrome on host machine.
   - "android-chrome": chrome on android device. Details in "Android" Section.
diff --git a/tools/rtcbot/bot/api.js b/tools/rtcbot/bot/api.js
index b51d49d..7e1a436 100644
--- a/tools/rtcbot/bot/api.js
+++ b/tools/rtcbot/bot/api.js
@@ -15,7 +15,7 @@
 var Dnode = require('dnode');
 
 function connectToServer(api) {
-  var stream = new WebSocketStream("ws://127.0.0.1:8080/");
+  var stream = new WebSocketStream("wss://localhost:8080/");
   var dnode = new Dnode(api);
   dnode.on('error', function (error) { console.log(error); });
   dnode.pipe(stream).pipe(dnode);
diff --git a/tools/rtcbot/bot/browser/bot.js b/tools/rtcbot/bot/browser/bot.js
index 99ff84d..a5785df 100644
--- a/tools/rtcbot/bot/browser/bot.js
+++ b/tools/rtcbot/bot/browser/bot.js
@@ -113,9 +113,28 @@
   return null;
 };
 
+function downloadFile(path, onSuccess, onError) {
+  var xhr = new XMLHttpRequest();
+  function onResult() {
+    if (xhr.readyState != 4)
+      return;
+
+    if (xhr.status != 200) {
+      onError("Download request failed!");
+      return;
+    }
+    onSuccess(xhr.responseText);
+  }
+
+  xhr.onreadystatechange = onResult;
+  xhr.open('GET', path, true);
+  xhr.send();
+};
+
 connectToServer({
   ping: ping,
   getUserMedia: getUserMedia,
   createPeerConnection: createPeerConnection,
   showStream: showStream,
+  downloadFile: downloadFile,
 });
diff --git a/tools/rtcbot/botmanager.js b/tools/rtcbot/botmanager.js
index cd88f19..5b325bd 100644
--- a/tools/rtcbot/botmanager.js
+++ b/tools/rtcbot/botmanager.js
@@ -8,7 +8,8 @@
 //
 // botmanager.js module allows a test to spawn bots that expose an RPC API
 // to be controlled by tests.
-var http = require('http');
+var https = require('https');
+var fs = require('fs');
 var child = require('child_process');
 var Browserify = require('browserify');
 var Dnode = require('dnode');
@@ -16,7 +17,7 @@
 var WebSocketServer = require('ws').Server;
 var WebSocketStream = require('websocket-stream');
 
-// BotManager runs a HttpServer that serves bots assets and and WebSocketServer
+// BotManager runs a HttpsServer that serves bots assets and and WebSocketServer
 // that listens to incoming connections. Once a connection is available it
 // connects it to bots pending endpoints.
 //
@@ -66,7 +67,11 @@
 
     this.app_.use('/bot/', Express.static(__dirname + '/bot'));
 
-    this.server_ = http.createServer(this.app_);
+    var options = options = {
+      key: fs.readFileSync('configurations/priv.pem', 'utf8'),
+      cert: fs.readFileSync('configurations/cert.crt', 'utf8')
+    };
+    this.server_ = https.createServer(options, this.app_);
 
     this.webSocketServer_ = new WebSocketServer({ server: this.server_ });
     this.webSocketServer_.on('connection', this.onConnection_.bind(this));
@@ -116,7 +121,7 @@
   }
 }
 
-// BrowserBot spawns a process to open "http://localhost:8080/bot/browser".
+// BrowserBot spawns a process to open "https://localhost:8080/bot/browser".
 //
 // That page once loaded, connects to the websocket server run by BotManager
 // and exposes the bot api.
@@ -128,14 +133,14 @@
 BrowserBot.prototype = {
   spawnBotProcess_: function () {
     this.log('Spawning browser');
-    child.exec('google-chrome "http://localhost:8080/bot/browser/"');
+    child.exec('google-chrome "https://localhost:8080/bot/browser/"');
   },
 
   __proto__: Bot.prototype
 }
 
 // AndroidChromeBot spawns a process to open
-// "http://localhost:8080/bot/browser/" on chrome for Android.
+// "https://localhost:8080/bot/browser/" on chrome for Android.
 AndroidChromeBot = function (name, androidDeviceManager, callback) {
   Bot.call(this, name, callback);
   androidDeviceManager.getNewDevice(function (serialNumber) {
@@ -149,7 +154,7 @@
     this.log('Spawning Android device with serial ' + this.serialNumber_);
     var runChrome = 'adb -s ' + this.serialNumber_ + ' shell am start ' +
     '-n com.android.chrome/com.google.android.apps.chrome.Main ' +
-    '-d http://localhost:8080/bot/browser/';
+    '-d https://localhost:8080/bot/browser/';
     child.exec(runChrome, function (error, stdout, stderr) {
       if (error) {
         this.log(error);
diff --git a/tools/rtcbot/rtcBotReportVisualizer/index.html b/tools/rtcbot/rtcBotReportVisualizer/index.html
new file mode 100644
index 0000000..7ff59fc
--- /dev/null
+++ b/tools/rtcbot/rtcBotReportVisualizer/index.html
@@ -0,0 +1,14 @@
+<!--
+// 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.
+-->
+<html>
+  <script src="https://www.google.com/jsapi"></script>
+  <script type="text/javascript" src="main.js"></script>
+  <input type="file" onchange="openFiles(event)" multiple>
+</html>
\ No newline at end of file
diff --git a/tools/rtcbot/rtcBotReportVisualizer/main.js b/tools/rtcbot/rtcBotReportVisualizer/main.js
new file mode 100644
index 0000000..91b0eec
--- /dev/null
+++ b/tools/rtcbot/rtcBotReportVisualizer/main.js
@@ -0,0 +1,191 @@
+// 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.
+//
+google.load("visualization", "1", {packages:["corechart"]});
+
+function openFiles(event) {
+  var files = event.target.files;
+  readAndAnalyzeFiles(files)
+}
+
+function readAndAnalyzeFiles(files) {
+  if(!files) {
+    alert("No files have been selected!");
+    return;
+  }
+
+  var reports = [];
+  var filesNames = [];
+  missingFiles = files.length;
+
+  for(var i = 0; i < files.length; i++) {
+    var reader = new FileReader();
+    reader.onload = onReaderLoad.bind(reader, files[i].name);
+    reader.readAsText(files[i]);
+  }
+
+  function onReaderLoad(fileName) {
+    reports.push(JSON.parse(this.result));
+    filesNames.push(fileName);
+
+    missingFiles--;
+    if(missingFiles == 0) {
+      analyzeReports_(reports, filesNames);
+    }
+  }
+}
+
+// TODO(houssainy) take the input stats from the select list or
+// drop down menu in html.
+function analyzeReports_(reports, filesNames) {
+  filesNames.unshift(""); // ned
+
+  // Rtt
+  analyzeRttData(reports, filesNames, "bot1");
+  analyzeRttData(reports, filesNames, "bot2");
+
+  // Send Packets Lost
+  analyzePacketsLostData(reports, filesNames, "bot1");
+  analyzePacketsLostData(reports, filesNames, "bot2");
+
+  // Send bandwidth
+  analyzeData(reports, filesNames, "Available Send Bandwidth-bot1", "bot1",
+      "bweforvideo", "googAvailableSendBandwidth");
+  analyzeData(reports, filesNames, "Available Send Bandwidth-bot2", "bot2",
+      "bweforvideo", "googAvailableSendBandwidth");
+
+   // Receive bandwidth
+   analyzeData(reports, filesNames, "Available Receive Bandwidth-bot1", "bot1",
+       "bweforvideo", "googAvailableReceiveBandwidth");
+   analyzeData(reports, filesNames, "Available Receive Bandwidth-bot2", "bot2",
+     "bweforvideo", "googAvailableReceiveBandwidth");
+
+  drawSeparatorLine();
+}
+
+function analyzeRttData(reports, filesNames, botName) {
+  var outPut = [];
+  outPut.push(filesNames);
+
+  var avergaData = ['Average Rtt x10'];
+  var maxData = ['Max Rtt'];
+
+  var average;
+  var max;
+  for(var index in reports) {
+    average = getStateAverage(reports[index], botName, "Conn-audio-1-0",
+      "googRtt");
+    avergaData.push(average*10);
+
+    max = getStateMax(reports[index], botName, "Conn-audio-1-0",
+      "googRtt");
+    maxData.push(max);
+  }
+  outPut.push(avergaData);
+  outPut.push(maxData);
+
+  drawChart("Rtt-" + botName, outPut);
+}
+
+function analyzePacketsLostData(reports, filesNames, botName) {
+  var outPut = [];
+  outPut.push(filesNames);
+
+  var maxData = ['Max Send PacketsLost'];
+  var max;
+  for(var index in reports) {
+    max = getStateMax(reports[index], botName, "ssrc_[0-9]+_send",
+        "packetsLost");
+    maxData.push(max);
+  }
+  outPut.push(maxData);
+
+  drawChart("Send PacketsLost-" + botName, outPut);
+}
+
+function analyzeData(reports, filesNames, chartName, botName, reportId,
+    statName) {
+  var outPut = [];
+  outPut.push(filesNames);
+
+  var avergaData = ['Average ' + statName];
+  var maxData = ['Max ' + statName];
+
+  var average;
+  var max;
+  for(var index in reports) {
+    average = getStateAverage(reports[index], botName, reportId, statName);
+    avergaData.push(average);
+
+    max = getStateMax(reports[index], botName, reportId, statName);
+    maxData.push(max);
+  }
+  outPut.push(avergaData);
+  outPut.push(maxData);
+
+  drawChart(chartName, outPut);
+}
+
+function getStateAverage(reports, botName, reportId, statName) {
+  var sum = 0;
+  var count = 0;
+
+  for (var index in reports) {
+    var data = reports[index].data;
+    if(index == 0 || !data.hasOwnProperty(botName))
+      continue;
+
+    var stats = data[botName];
+    for (var key in stats) {
+      if(key.search(reportId) != -1) {
+        var value = parseInt(stats[key][statName]);
+        sum += value;
+        count++;
+      }
+    }
+  }
+  return Math.round(sum/count);
+}
+
+function getStateMax(reports, botName, reportId, statName) {
+  var max = -1;
+
+  for (var index in reports) {
+    var data = reports[index].data;
+    if(index == 0 || !data.hasOwnProperty(botName))
+      continue;
+
+    var stats = data[botName];
+    for (var key in stats) {
+      if(key.search(reportId) != -1) {
+        var value = parseInt(stats[key][statName]);
+        max = Math.max(value, max);
+      }
+    }
+  }
+  return max;
+}
+
+function drawChart(title, data) {
+  var dataTable = google.visualization.arrayToDataTable(data);
+
+  var options = {
+    title: title,
+  };
+
+  var div = document.createElement('div');
+  document.body.appendChild(div);
+
+  var chart = new google.visualization.ColumnChart(div);
+  chart.draw(dataTable, options);
+}
+
+function drawSeparatorLine()  {
+  var hr = document.createElement('hr');
+  document.body.appendChild(hr);
+}
diff --git a/tools/rtcbot/test/oneWayVideoStreamingWithDownloadingFile.js b/tools/rtcbot/test/oneWayVideoStreamingWithDownloadingFile.js
new file mode 100644
index 0000000..857d838
--- /dev/null
+++ b/tools/rtcbot/test/oneWayVideoStreamingWithDownloadingFile.js
@@ -0,0 +1,122 @@
+// 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.
+//
+// A unidirectional video and audio flowing test from bot 1 to bot 2,
+// and download a file from a server after 2 seconds of establishing
+// the call.
+//
+// The test succeeds after collecting stats for 10 seconds from both bots
+// and then write these stats to a file.
+//
+// Note: the source of the video and audio stream is getUserMedia().
+//
+function testOneWayVideoWithDownloading(test, bot1, bot2) {
+  var report = test.createStatisticsReport("testOneWayVideoWithDownloading");
+
+  test.wait([
+      createPeerConnection.bind(bot1),
+      createPeerConnection.bind(bot2) ],
+    onPeerConnectionCreated);
+
+  function createPeerConnection(done) {
+    test.createTurnConfig(onTurnConfig.bind(this), test.fail);
+
+    function onTurnConfig(config) {
+      this.createPeerConnection(config, done, test.fail);
+    };
+  }
+
+  function onPeerConnectionCreated(pc1, pc2) {
+    test.log("RTC Peers created.");
+    pc1.addEventListener('addstream', test.fail);
+    pc2.addEventListener('addstream', onAddStream);
+    pc1.addEventListener('icecandidate', onIceCandidate.bind(pc2));
+    pc2.addEventListener('icecandidate', onIceCandidate.bind(pc1));
+
+    bot1.getUserMedia({video:true, audio:true}, onUserMediaSuccess, test.fail);
+
+    function onUserMediaSuccess(stream) {
+      test.log("User has granted access to local media.");
+      pc1.addStream(stream);
+      bot1.showStream(stream.id, true, true);
+
+      createOfferAndAnswer(pc1, pc2);
+    }
+  }
+
+  function onAddStream(event) {
+    test.log("On Add stream.");
+    bot2.showStream(event.stream.id, true, false);
+  }
+
+  function onIceCandidate(event) {
+    if(event.candidate) {
+      test.log(event.candidate.candidate);
+      this.addIceCandidate(event.candidate,
+         onAddIceCandidateSuccess, test.fail);
+    }
+
+    function onAddIceCandidateSuccess() {
+      test.log("Candidate added successfully");
+    }
+  }
+
+  function createOfferAndAnswer(pc1, pc2) {
+    test.log("Creating offer.");
+    pc1.createOffer(gotOffer, test.fail);
+
+    function gotOffer(offer) {
+      test.log("Got offer");
+      pc1.setLocalDescription(offer, onSetSessionDescriptionSuccess, test.fail);
+      pc2.setRemoteDescription(offer, onSetSessionDescriptionSuccess,
+          test.fail);
+      test.log("Creating answer");
+      pc2.createAnswer(gotAnswer, test.fail);
+    }
+
+    function gotAnswer(answer) {
+      test.log("Got answer");
+      pc2.setLocalDescription(answer, onSetSessionDescriptionSuccess,
+          test.fail);
+      pc1.setRemoteDescription(answer, onSetSessionDescriptionSuccess,
+          test.fail);
+      collectStats();
+
+      setTimeout(function() {
+        downloadFile(bot1, "bot1");
+        downloadFile(bot2, "bot2");
+      }, 2000);
+    }
+
+    function onSetSessionDescriptionSuccess() {
+      test.log("Set session description success.");
+    }
+
+    function collectStats() {
+      report.collectStatsFromPeerConnection("bot1", pc1);
+      report.collectStatsFromPeerConnection("bot2", pc2);
+
+      setTimeout(function() {
+        report.finish(test.done);
+        }, 10000);
+    }
+
+    function downloadFile(bot, name) {
+      bot.downloadFile("https://test.webrtc.org/test-download-file/9000KB.data",
+          onDownloadSuccess.bind(null, name), test.fail);
+
+      function onDownloadSuccess(name, data) {
+        test.log( name + " downloaded " +
+            Math.round(data.length/(1024*1024)) + "MB.");
+      }
+    }
+  }
+}
+
+registerBotTest('testOneWayVideoWithDownloading/chrome-chrome',
+                testOneWayVideoWithDownloading, ['chrome', 'chrome']);
diff --git a/tools/rtcbot/test/three_bots_video_conference.js b/tools/rtcbot/test/three_bots_video_conference.js
new file mode 100644
index 0000000..65c3e99
--- /dev/null
+++ b/tools/rtcbot/test/three_bots_video_conference.js
@@ -0,0 +1,135 @@
+// 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.
+//
+// A video conference between 3 bots streaming video and audio between
+// each other.
+// The test succeeds after establishing the call between the three
+// devices.
+//
+// Note: the source of the video and audio stream is getUserMedia().
+function testTwoWayVideoStreaming(test, bot1, bot2, bot3) {
+  var answersCount = 0;
+  var statsCollector;
+
+  test.wait([
+      createBotPeerConnectionsWithLocalStream.bind(bot1),
+      createBotPeerConnectionsWithLocalStream.bind(bot2),
+      createBotPeerConnectionsWithLocalStream.bind(bot3)],
+    onPeerConnectionCreated);
+
+  // done() callback is called with list of peers as argument.
+  function createBotPeerConnectionsWithLocalStream(done) {
+    var peerConnections = [];
+
+    this.getUserMedia({video:true, audio:true},
+        onUserMediaSuccess.bind(this), test.fail);
+
+    function onUserMediaSuccess(stream) {
+      test.log("User has granted access to local media.");
+      this.showStream(stream.id, true, true);
+
+      test.createTurnConfig(onTurnConfig.bind(this), test.fail);
+
+      function onTurnConfig(config) {
+        this.createPeerConnection(config, addStream.bind(this),
+            test.fail);
+        this.createPeerConnection(config, addStream.bind(this),
+            test.fail);
+      }
+
+      function addStream(pc) {
+        pc.addStream(stream);
+        pc.addEventListener('addstream', onAddStream.bind(this));
+
+        peerConnections.push(pc);
+        if(peerConnections.length == 2)
+          done(peerConnections);
+      }
+    }
+  }
+
+  function onPeerConnectionCreated(peerConnections1,
+      peerConnections2, peerConnections3) {
+    test.log("RTC Peers created.");
+
+    // Bot1 and Bot2
+    establichCall(peerConnections1[0], peerConnections2[1]);
+    // Bot2 and Bot3
+    establichCall(peerConnections2[0], peerConnections3[1]);
+    // Bot3 and Bot1
+    establichCall(peerConnections3[0], peerConnections1[1]);
+  }
+
+  function establichCall(pc1, pc2) {
+    pc1.addEventListener('icecandidate', onIceCandidate.bind(pc2));
+    pc2.addEventListener('icecandidate', onIceCandidate.bind(pc1));
+
+    createOfferAndAnswer(pc1, pc2);
+  }
+
+  function onAddStream(event) {
+    test.log("On Add stream.");
+    this.showStream(event.stream.id, true, false);
+  }
+
+  function onIceCandidate(event) {
+    if(event.candidate) {
+      this.addIceCandidate(event.candidate,
+         onAddIceCandidateSuccess, test.fail);
+    };
+
+    function onAddIceCandidateSuccess() {
+      test.log("Candidate added successfully");
+    };
+  }
+
+  function createOfferAndAnswer(pc1, pc2) {
+    test.log("Creating offer.");
+    pc1.createOffer(gotOffer, test.fail);
+
+    function gotOffer(offer) {
+      test.log("Got offer");
+      pc1.setLocalDescription(offer, onSetSessionDescriptionSuccess, test.fail);
+      pc2.setRemoteDescription(offer, onSetSessionDescriptionSuccess,
+          test.fail);
+      test.log("Creating answer");
+      pc2.createAnswer(gotAnswer, test.fail);
+    }
+
+    function gotAnswer(answer) {
+      test.log("Got answer");
+      pc2.setLocalDescription(answer, onSetSessionDescriptionSuccess,
+          test.fail);
+      pc1.setRemoteDescription(answer, onSetSessionDescriptionSuccess,
+          test.fail);
+
+      answersCount++;
+      if(answersCount == 3) {
+        // SetTimeout used because creating the three answers will very fast
+        // and test will success and the vm will be closed before establishing
+        // the calls.
+        setTimeout(function() {
+            test.done();
+          }, 5000);
+      }
+    }
+
+    function onSetSessionDescriptionSuccess() {
+      test.log("Set session description success.");
+    }
+  }
+}
+
+registerBotTest('threeBotsVideoConference/android+android+chrome',
+                testTwoWayVideoStreaming, ['android-chrome', 'android-chrome',
+                'chrome']);
+registerBotTest('threeBotsVideoConference/chrome-chrome-chrome',
+                testTwoWayVideoStreaming, ['chrome', 'chrome', 'chrome']);
+registerBotTest('threeBotsVideoConference/android-android-android',
+                testTwoWayVideoStreaming, ['android-chrome', 'android-chrome',
+                'android-chrome']);
\ No newline at end of file
diff --git a/tools/rtcbot/test/two_way_video_streaming.js b/tools/rtcbot/test/two_way_video_streaming.js
new file mode 100644
index 0000000..7b02dce
--- /dev/null
+++ b/tools/rtcbot/test/two_way_video_streaming.js
@@ -0,0 +1,112 @@
+// 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.
+//
+// A two way video and audio flowing test between bot 1 and bot 2.
+// The test succeeds after collecting stats for 10 seconds from both bots
+// and then write these stats to a file.
+//
+// Note: the source of the video and audio stream is getUserMedia().
+function testTwoWayVideoStreaming(test, bot1, bot2) {
+  var report = test.createStatisticsReport("two_way_video_streaming");
+  var statsCollector;
+
+  test.wait([
+      createPeerConnectionWithLocalStream.bind(bot1),
+      createPeerConnectionWithLocalStream.bind(bot2)],
+    onPeerConnectionCreated);
+
+  function createPeerConnectionWithLocalStream(done) {
+    this.getUserMedia({video:true, audio:true},
+        onUserMediaSuccess.bind(this), test.fail);
+
+    function onUserMediaSuccess(stream) {
+      test.log("User has granted access to local media.");
+      test.createTurnConfig(onTurnConfig.bind(this), test.fail);
+
+      function onTurnConfig(config) {
+        this.createPeerConnection(config, addAndShowStream.bind(this),
+            test.fail);
+      };
+
+      function addAndShowStream(pc) {
+        pc.addStream(stream);
+        this.showStream(stream.id, true, true);
+
+        done(pc);
+      }
+    }
+  }
+
+  function onPeerConnectionCreated(pc1, pc2) {
+    test.log("RTC Peers created.");
+    pc1.addEventListener('addstream', onAddStream.bind(bot1));
+    pc2.addEventListener('addstream', onAddStream.bind(bot2));
+    pc1.addEventListener('icecandidate', onIceCandidate.bind(pc2));
+    pc2.addEventListener('icecandidate', onIceCandidate.bind(pc1));
+
+    createOfferAndAnswer(pc1, pc2);
+  }
+
+  function onAddStream(event) {
+    test.log("On Add stream.");
+    this.showStream(event.stream.id, true, false);
+  }
+
+  function onIceCandidate(event) {
+    if(event.candidate) {
+      test.log(event.candidate.candidate);
+      this.addIceCandidate(event.candidate,
+         onAddIceCandidateSuccess, test.fail);
+    };
+
+    function onAddIceCandidateSuccess() {
+      test.log("Candidate added successfully");
+    };
+  }
+
+  function createOfferAndAnswer(pc1, pc2) {
+    test.log("Creating offer.");
+    pc1.createOffer(gotOffer, test.fail);
+
+    function gotOffer(offer) {
+      test.log("Got offer");
+      pc1.setLocalDescription(offer, onSetSessionDescriptionSuccess, test.fail);
+      pc2.setRemoteDescription(offer, onSetSessionDescriptionSuccess,
+          test.fail);
+      test.log("Creating answer");
+      pc2.createAnswer(gotAnswer, test.fail);
+    }
+
+    function gotAnswer(answer) {
+      test.log("Got answer");
+      pc2.setLocalDescription(answer, onSetSessionDescriptionSuccess,
+          test.fail);
+      pc1.setRemoteDescription(answer, onSetSessionDescriptionSuccess,
+          test.fail);
+      collectStats();
+    }
+
+    function onSetSessionDescriptionSuccess() {
+      test.log("Set session description success.");
+    }
+
+    function collectStats() {
+      report.collectStatsFromPeerConnection("bot1", pc1);
+      report.collectStatsFromPeerConnection("bot2", pc2);
+
+      setTimeout(function() {
+        report.finish(test.done);
+        }, 10000);
+    }
+  }
+}
+
+registerBotTest('testTwoWayVideo/android-android',
+                testTwoWayVideoStreaming, ['android-chrome', 'android-chrome']);
+registerBotTest('testTwoWayVideo/chrome-chrome',
+                testTwoWayVideoStreaming, ['chrome', 'chrome']);
\ No newline at end of file
diff --git a/tools/rtcbot/test/webrtc_video_streaming.js b/tools/rtcbot/test/webrtc_video_streaming.js
index 60df68e..6518c20 100644
--- a/tools/rtcbot/test/webrtc_video_streaming.js
+++ b/tools/rtcbot/test/webrtc_video_streaming.js
@@ -20,7 +20,7 @@
     onPeerConnectionCreated);
 
   function createPeerConnection(done) {
-    test.createTurnConfig(onTrunConfig.bind(this), test.fail);
+    test.createTurnConfig(onTurnConfig.bind(this), test.fail);
 
     function onTurnConfig(config) {
       this.createPeerConnection(config, done, test.fail);
diff --git a/tools/tools.gyp b/tools/tools.gyp
index 38a19fc..102ba8e 100644
--- a/tools/tools.gyp
+++ b/tools/tools.gyp
@@ -91,7 +91,7 @@
       'type': 'executable',
       'dependencies': [
         '<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
       ],
       'sources': [
         'force_mic_volume_max/force_mic_volume_max.cc',
@@ -107,7 +107,7 @@
           'dependencies': [
             '<(webrtc_root)/test/test.gyp:channel_transport',
             '<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
-            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
           ],
@@ -165,7 +165,6 @@
               ],
               'includes': [
                 '../build/isolate.gypi',
-                'tools_unittests.isolate',
               ],
               'sources': [
                 'tools_unittests.isolate',
diff --git a/tools/tools_unittests.isolate b/tools/tools_unittests.isolate
index 1806574..bf1fd01 100644
--- a/tools/tools_unittests.isolate
+++ b/tools/tools_unittests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,15 +21,12 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/tools_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/DEPS',
           '<(DEPTH)/resources/foreman_cif.yuv',
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/tools_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/video/bitrate_estimator_tests.cc b/video/bitrate_estimator_tests.cc
index cb7c391..29fb730 100644
--- a/video/bitrate_estimator_tests.cc
+++ b/video/bitrate_estimator_tests.cc
@@ -151,11 +151,7 @@
     encoder_config_.streams = test::CreateVideoStreams(1);
 
     receive_config_ = VideoReceiveStream::Config();
-    assert(receive_config_.codecs.empty());
-    VideoCodec codec =
-        test::CreateDecoderVideoCodec(send_config_.encoder_settings);
-    receive_config_.codecs.push_back(codec);
-    // receive_config_.external_decoders will be set by every stream separately.
+    // 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.extensions.push_back(
@@ -206,12 +202,13 @@
       send_stream_->Start();
       frame_generator_capturer_->Start();
 
-      ExternalVideoDecoder decoder;
+      VideoReceiveStream::Decoder decoder;
       decoder.decoder = &fake_decoder_;
       decoder.payload_type = test_->send_config_.encoder_settings.payload_type;
+      decoder.payload_name = test_->send_config_.encoder_settings.payload_name;
+      test_->receive_config_.decoders.push_back(decoder);
       test_->receive_config_.rtp.remote_ssrc = test_->send_config_.rtp.ssrcs[0];
       test_->receive_config_.rtp.local_ssrc++;
-      test_->receive_config_.external_decoders.push_back(decoder);
       receive_stream_ = test_->receiver_call_->CreateVideoReceiveStream(
           test_->receive_config_);
       receive_stream_->Start();
diff --git a/video/call.cc b/video/call.cc
index f37e538..fd41d75 100644
--- a/video/call.cc
+++ b/video/call.cc
@@ -20,6 +20,7 @@
 #include "webrtc/config.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
+#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
@@ -46,6 +47,17 @@
   switch (codec_type) {
     case kVp8:
       return VP8Encoder::Create();
+    case kVp9:
+      return VP9Encoder::Create();
+  }
+  assert(false);
+  return NULL;
+}
+
+VideoDecoder* VideoDecoder::Create(VideoDecoder::DecoderType codec_type) {
+  switch (codec_type) {
+    case kVp8:
+      return VP8Decoder::Create();
   }
   assert(false);
   return NULL;
diff --git a/video/call_perf_tests.cc b/video/call_perf_tests.cc
index f42e5dd..9776fb7 100644
--- a/video/call_perf_tests.cc
+++ b/video/call_perf_tests.cc
@@ -543,9 +543,9 @@
         std::vector<VideoReceiveStream::Config>* receive_configs,
         VideoEncoderConfig* encoder_config) OVERRIDE {
       if (pad_to_min_bitrate_) {
-        send_config->rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
+        encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps;
       } else {
-        assert(send_config->rtp.min_transmit_bitrate_bps == 0);
+        assert(encoder_config->min_transmit_bitrate_bps == 0);
       }
     }
 
@@ -570,4 +570,92 @@
   TestMinTransmitBitrate(false);
 }
 
+TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) {
+  static const uint32_t kInitialBitrateKbps = 400;
+  static const uint32_t kReconfigureThresholdKbps = 600;
+  static const uint32_t kPermittedReconfiguredBitrateDiffKbps = 100;
+
+  class BitrateObserver : public test::EndToEndTest, public test::FakeEncoder {
+   public:
+    BitrateObserver()
+        : EndToEndTest(kDefaultTimeoutMs),
+          FakeEncoder(Clock::GetRealTimeClock()),
+          time_to_reconfigure_(webrtc::EventWrapper::Create()),
+          encoder_inits_(0) {}
+
+    virtual int32_t InitEncode(const VideoCodec* config,
+                               int32_t number_of_cores,
+                               uint32_t max_payload_size) OVERRIDE {
+      if (encoder_inits_ == 0) {
+        EXPECT_EQ(kInitialBitrateKbps, config->startBitrate)
+            << "Encoder not initialized at expected bitrate.";
+      }
+      ++encoder_inits_;
+      if (encoder_inits_ == 2) {
+        EXPECT_GE(last_set_bitrate_, kReconfigureThresholdKbps);
+        EXPECT_NEAR(config->startBitrate,
+                    last_set_bitrate_,
+                    kPermittedReconfiguredBitrateDiffKbps)
+            << "Encoder reconfigured with bitrate too far away from last set.";
+        observation_complete_->Set();
+      }
+      return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
+    }
+
+    virtual int32_t SetRates(uint32_t new_target_bitrate_kbps,
+                             uint32_t framerate) OVERRIDE {
+      last_set_bitrate_ = new_target_bitrate_kbps;
+      if (encoder_inits_ == 1 &&
+          new_target_bitrate_kbps > kReconfigureThresholdKbps) {
+        time_to_reconfigure_->Set();
+      }
+      return FakeEncoder::SetRates(new_target_bitrate_kbps, framerate);
+    }
+
+    Call::Config GetSenderCallConfig() OVERRIDE {
+      Call::Config config = EndToEndTest::GetSenderCallConfig();
+      config.stream_start_bitrate_bps = kInitialBitrateKbps * 1000;
+      return config;
+    }
+
+    virtual void ModifyConfigs(
+        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 =
+          encoder_config->streams[0].max_bitrate_bps = 2000000;
+
+      encoder_config_ = *encoder_config;
+    }
+
+    virtual void OnStreamsCreated(
+        VideoSendStream* send_stream,
+        const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
+      send_stream_ = send_stream;
+    }
+
+    virtual void PerformTest() OVERRIDE {
+      ASSERT_EQ(kEventSignaled, 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())
+          << "Timed out while waiting for a couple of high bitrate estimates "
+             "after reconfiguring the send stream.";
+    }
+
+   private:
+    scoped_ptr<webrtc::EventWrapper> time_to_reconfigure_;
+    int encoder_inits_;
+    uint32_t last_set_bitrate_;
+    VideoSendStream* send_stream_;
+    VideoEncoderConfig encoder_config_;
+  } test;
+
+  RunBaseTest(&test);
+}
+
 }  // namespace webrtc
diff --git a/video/end_to_end_tests.cc b/video/end_to_end_tests.cc
index 0e87a03..96249c3 100644
--- a/video/end_to_end_tests.cc
+++ b/video/end_to_end_tests.cc
@@ -19,6 +19,9 @@
 #include "webrtc/call.h"
 #include "webrtc/frame_callback.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
+#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
+#include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/event_wrapper.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
@@ -222,6 +225,57 @@
   DestroyStreams();
 }
 
+// TODO(marpan): Re-enable this test on the next libvpx roll.
+TEST_F(EndToEndTest, DISABLED_SendsAndReceivesVP9) {
+  class VP9Observer : public test::EndToEndTest, public VideoRenderer {
+   public:
+    VP9Observer()
+        : EndToEndTest(2 * kDefaultTimeoutMs),
+          encoder_(VideoEncoder::Create(VideoEncoder::kVp9)),
+          decoder_(VP9Decoder::Create()),
+          frame_counter_(0) {}
+
+    virtual void PerformTest() OVERRIDE {
+      EXPECT_EQ(kEventSignaled, Wait())
+          << "Timed out while waiting for enough frames to be decoded.";
+    }
+
+    virtual void ModifyConfigs(
+        VideoSendStream::Config* send_config,
+        std::vector<VideoReceiveStream::Config>* receive_configs,
+        VideoEncoderConfig* encoder_config) OVERRIDE {
+      send_config->encoder_settings.encoder = encoder_.get();
+      send_config->encoder_settings.payload_name = "VP9";
+      send_config->encoder_settings.payload_type = VCM_VP9_PAYLOAD_TYPE;
+      encoder_config->streams[0].min_bitrate_bps = 50000;
+      encoder_config->streams[0].target_bitrate_bps =
+          encoder_config->streams[0].max_bitrate_bps = 2000000;
+
+      (*receive_configs)[0].renderer = this;
+      (*receive_configs)[0].decoders.resize(1);
+      (*receive_configs)[0].decoders[0].payload_type =
+          send_config->encoder_settings.payload_type;
+      (*receive_configs)[0].decoders[0].payload_name =
+          send_config->encoder_settings.payload_name;
+      (*receive_configs)[0].decoders[0].decoder = decoder_.get();
+    }
+
+    virtual void RenderFrame(const I420VideoFrame& video_frame,
+                             int time_to_render_ms) OVERRIDE {
+      const int kRequiredFrames = 500;
+      if (++frame_counter_ == kRequiredFrames)
+        observation_complete_->Set();
+    }
+
+   private:
+    scoped_ptr<webrtc::VideoEncoder> encoder_;
+    scoped_ptr<webrtc::VideoDecoder> decoder_;
+    int frame_counter_;
+  } test;
+
+  RunBaseTest(&test);
+}
+
 TEST_F(EndToEndTest, SendsAndReceivesH264) {
   class H264Observer : public test::EndToEndTest, public VideoRenderer {
    public:
@@ -247,14 +301,12 @@
           encoder_config->streams[0].max_bitrate_bps = 2000000;
 
       (*receive_configs)[0].renderer = this;
-      VideoCodec codec =
-          test::CreateDecoderVideoCodec(send_config->encoder_settings);
-      (*receive_configs)[0].codecs.resize(1);
-      (*receive_configs)[0].codecs[0] = codec;
-      (*receive_configs)[0].external_decoders.resize(1);
-      (*receive_configs)[0].external_decoders[0].payload_type =
+      (*receive_configs)[0].decoders.resize(1);
+      (*receive_configs)[0].decoders[0].payload_type =
           send_config->encoder_settings.payload_type;
-      (*receive_configs)[0].external_decoders[0].decoder = &fake_decoder_;
+      (*receive_configs)[0].decoders[0].payload_name =
+          send_config->encoder_settings.payload_name;
+      (*receive_configs)[0].decoders[0].decoder = &fake_decoder_;
     }
 
     virtual void RenderFrame(const I420VideoFrame& video_frame,
@@ -977,6 +1029,7 @@
   for (size_t i = 0; i < kNumStreams; ++i)
     encoders[i].reset(VideoEncoder::Create(VideoEncoder::kVp8));
 
+  ScopedVector<VideoDecoder> allocated_decoders;
   for (size_t i = 0; i < kNumStreams; ++i) {
     uint32_t ssrc = codec_settings[i].ssrc;
     int width = codec_settings[i].width;
@@ -1004,9 +1057,10 @@
     receive_config.renderer = observers[i];
     receive_config.rtp.remote_ssrc = ssrc;
     receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
-    VideoCodec codec =
-        test::CreateDecoderVideoCodec(send_config.encoder_settings);
-    receive_config.codecs.push_back(codec);
+    VideoReceiveStream::Decoder decoder =
+        test::CreateMatchingDecoder(send_config.encoder_settings);
+    allocated_decoders.push_back(decoder.decoder);
+    receive_config.decoders.push_back(decoder);
     receive_streams[i] =
         receiver_call->CreateVideoReceiveStream(receive_config);
     receive_streams[i]->Start();
@@ -1653,15 +1707,16 @@
         encoder_config->streams[i].target_bitrate_bps = 15000;
         encoder_config->streams[i].max_bitrate_bps = 20000;
       }
-      // Significantly higher than max bitrates for all video streams -> forcing
-      // padding to trigger redundant padding on all RTX SSRCs.
-      send_config->rtp.min_transmit_bitrate_bps = 100000;
 
       send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
       send_config->rtp.rtx.pad_with_redundant_payloads = true;
 
       for (size_t i = 0; i < kNumSsrcs; ++i)
         send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]);
+
+      // Significantly higher than max bitrates for all video streams -> forcing
+      // padding to trigger redundant padding on all RTX SSRCs.
+      encoder_config->min_transmit_bitrate_bps = 100000;
     }
 
     virtual void PerformTest() OVERRIDE {
@@ -1791,6 +1846,19 @@
     encoder_config_.streams[i].max_bitrate_bps = 20000;
   }
 
+  // Use the same total bitrates when sending a single stream to avoid lowering
+  // the bitrate estimate and requiring a subsequent rampup.
+  VideoEncoderConfig one_stream = encoder_config_;
+  one_stream.streams.resize(1);
+  for (size_t i = 1; i < encoder_config_.streams.size(); ++i) {
+    one_stream.streams.front().min_bitrate_bps +=
+        encoder_config_.streams[i].min_bitrate_bps;
+    one_stream.streams.front().target_bitrate_bps +=
+        encoder_config_.streams[i].target_bitrate_bps;
+    one_stream.streams.front().max_bitrate_bps +=
+        encoder_config_.streams[i].max_bitrate_bps;
+  }
+
   CreateMatchingReceiveConfigs();
 
   CreateStreams();
@@ -1807,8 +1875,6 @@
     sender_call_->DestroyVideoSendStream(send_stream_);
 
     // Re-create VideoSendStream with only one stream.
-    VideoEncoderConfig one_stream = encoder_config_;
-    one_stream.streams.resize(1);
     send_stream_ =
         sender_call_->CreateVideoSendStream(send_config_, one_stream);
     send_stream_->Start();
@@ -2074,4 +2140,39 @@
 
   DestroyStreams();
 }
+
+// TODO(pbos): Remove this regression test when VideoEngine is no longer used as
+// a backend. This is to test that we hand channels back properly.
+TEST_F(EndToEndTest, CanCreateAndDestroyManyVideoStreams) {
+  test::NullTransport transport;
+  scoped_ptr<Call> call(Call::Create(Call::Config(&transport)));
+  test::FakeDecoder fake_decoder;
+  test::FakeEncoder fake_encoder(Clock::GetRealTimeClock());
+  for (size_t i = 0; i < 100; ++i) {
+    VideoSendStream::Config send_config;
+    send_config.encoder_settings.encoder = &fake_encoder;
+    send_config.encoder_settings.payload_name = "FAKE";
+    send_config.encoder_settings.payload_type = 123;
+
+    VideoEncoderConfig encoder_config;
+    encoder_config.streams = test::CreateVideoStreams(1);
+    send_config.rtp.ssrcs.push_back(1);
+    VideoSendStream* send_stream =
+        call->CreateVideoSendStream(send_config, encoder_config);
+    call->DestroyVideoSendStream(send_stream);
+
+    VideoReceiveStream::Config receive_config;
+    receive_config.rtp.remote_ssrc = 1;
+    receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
+    VideoReceiveStream::Decoder decoder;
+    decoder.decoder = &fake_decoder;
+    decoder.payload_type = 123;
+    decoder.payload_name = "FAKE";
+    receive_config.decoders.push_back(decoder);
+    VideoReceiveStream* receive_stream =
+        call->CreateVideoReceiveStream(receive_config);
+    call->DestroyVideoReceiveStream(receive_stream);
+  }
+}
+
 }  // namespace webrtc
diff --git a/video/full_stack.cc b/video/full_stack.cc
index 0c3ea78..25e60eb 100644
--- a/video/full_stack.cc
+++ b/video/full_stack.cc
@@ -360,8 +360,8 @@
   std::map<uint32_t, int64_t> send_times_ GUARDED_BY(crit_);
   std::map<uint32_t, int64_t> recv_times_ GUARDED_BY(crit_);
   I420VideoFrame* first_send_frame_ GUARDED_BY(crit_);
-  double avg_psnr_threshold_ GUARDED_BY(crit_);
-  double avg_ssim_threshold_ GUARDED_BY(crit_);
+  const double avg_psnr_threshold_;
+  const double avg_ssim_threshold_;
 
   const scoped_ptr<CriticalSectionWrapper> comparison_lock_;
   const scoped_ptr<ThreadWrapper> comparison_thread_;
diff --git a/video/loopback.cc b/video/loopback.cc
index ffc5bcc..4b49c31 100644
--- a/video/loopback.cc
+++ b/video/loopback.cc
@@ -22,13 +22,18 @@
 #include "webrtc/test/direct_transport.h"
 #include "webrtc/test/encoder_settings.h"
 #include "webrtc/test/fake_encoder.h"
+#include "webrtc/test/field_trial.h"
 #include "webrtc/test/run_loop.h"
 #include "webrtc/test/run_test.h"
+#include "webrtc/test/testsupport/trace_to_stderr.h"
 #include "webrtc/test/video_capturer.h"
 #include "webrtc/test/video_renderer.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
+
+static const int kAbsSendTimeExtensionId = 7;
+
 namespace flags {
 
 DEFINE_int32(width, 640, "Video width.");
@@ -82,6 +87,16 @@
 int StdPropagationDelayMs() {
   return static_cast<int>(FLAGS_std_propagation_delay_ms);
 }
+
+DEFINE_bool(logs, false, "print logs to stderr");
+
+DEFINE_string(
+    force_fieldtrials,
+    "",
+    "Field trials control experimental feature code which can be forced. "
+    "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
+    " will assign the group Enable to field trial WebRTC-FooFeature. Multiple "
+    "trials are separated by \"/\"");
 }  // namespace flags
 
 static const uint32_t kSendSsrc = 0x654321;
@@ -91,6 +106,10 @@
 static const uint8_t kRtxPayloadType = 96;
 
 void Loopback() {
+  scoped_ptr<test::TraceToStderr> trace_to_stderr_;
+  if (webrtc::flags::FLAGS_logs)
+    trace_to_stderr_.reset(new test::TraceToStderr);
+
   scoped_ptr<test::VideoRenderer> local_preview(test::VideoRenderer::Create(
       "Local Preview", flags::Width(), flags::Height()));
   scoped_ptr<test::VideoRenderer> loopback_video(test::VideoRenderer::Create(
@@ -116,6 +135,8 @@
   send_config.rtp.rtx.ssrcs.push_back(kSendRtxSsrc);
   send_config.rtp.rtx.payload_type = kRtxPayloadType;
   send_config.rtp.nack.rtp_history_ms = 1000;
+  send_config.rtp.extensions.push_back(
+      RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
 
   send_config.local_renderer = local_preview.get();
   scoped_ptr<VideoEncoder> encoder;
@@ -158,10 +179,12 @@
   receive_config.rtp.nack.rtp_history_ms = 1000;
   receive_config.rtp.rtx[kRtxPayloadType].ssrc = kSendRtxSsrc;
   receive_config.rtp.rtx[kRtxPayloadType].payload_type = kRtxPayloadType;
+  receive_config.rtp.extensions.push_back(
+      RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
   receive_config.renderer = loopback_video.get();
-  VideoCodec codec =
-      test::CreateDecoderVideoCodec(send_config.encoder_settings);
-  receive_config.codecs.push_back(codec);
+  VideoReceiveStream::Decoder decoder =
+      test::CreateMatchingDecoder(send_config.encoder_settings);
+  receive_config.decoders.push_back(decoder);
 
   VideoReceiveStream* receive_stream =
       call->CreateVideoReceiveStream(receive_config);
@@ -179,6 +202,8 @@
   call->DestroyVideoReceiveStream(receive_stream);
   call->DestroyVideoSendStream(send_stream);
 
+  delete decoder.decoder;
+
   transport.StopSending();
 }
 }  // namespace webrtc
@@ -186,7 +211,8 @@
 int main(int argc, char* argv[]) {
   ::testing::InitGoogleTest(&argc, argv);
   google::ParseCommandLineFlags(&argc, &argv, true);
-
+  webrtc::test::InitFieldTrialsFromString(
+      webrtc::flags::FLAGS_force_fieldtrials);
   webrtc::test::RunTest(webrtc::Loopback);
   return 0;
 }
diff --git a/video/rampup_tests.cc b/video/rampup_tests.cc
index 96a2276..011ef6a 100644
--- a/video/rampup_tests.cc
+++ b/video/rampup_tests.cc
@@ -154,7 +154,9 @@
   return true;
 }
 
-EventTypeWrapper StreamObserver::Wait() { return test_done_->Wait(120 * 1000); }
+EventTypeWrapper StreamObserver::Wait() {
+  return test_done_->Wait(test::CallTest::kLongTimeoutMs);
+}
 
 void StreamObserver::ReportResult(const std::string& measurement,
                   size_t value,
diff --git a/video/replay.cc b/video/replay.cc
index 3d2689e..5cfb06f 100644
--- a/video/replay.cc
+++ b/video/replay.cc
@@ -30,6 +30,7 @@
 #include "webrtc/test/video_capturer.h"
 #include "webrtc/test/video_renderer.h"
 #include "webrtc/typedefs.h"
+#include "webrtc/video_decoder.h"
 
 namespace webrtc {
 namespace flags {
@@ -212,8 +213,9 @@
   VideoSendStream::Config::EncoderSettings encoder_settings;
   encoder_settings.payload_name = flags::Codec();
   encoder_settings.payload_type = flags::PayloadType();
-  VideoCodec codec = test::CreateDecoderVideoCodec(encoder_settings);
-  receive_config.codecs.push_back(codec);
+  VideoReceiveStream::Decoder decoder =
+      test::CreateMatchingDecoder(encoder_settings);
+  receive_config.decoders.push_back(decoder);
 
   VideoReceiveStream* receive_stream =
       call->CreateVideoReceiveStream(receive_config);
@@ -271,6 +273,8 @@
   }
 
   call->DestroyVideoReceiveStream(receive_stream);
+
+  delete decoder.decoder;
 }
 }  // namespace webrtc
 
diff --git a/video/video_receive_stream.cc b/video/video_receive_stream.cc
index 41a800f..5b085bb 100644
--- a/video/video_receive_stream.cc
+++ b/video/video_receive_stream.cc
@@ -19,6 +19,7 @@
 #include "webrtc/system_wrappers/interface/clock.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/video/receive_statistics_proxy.h"
+#include "webrtc/video_encoder.h"
 #include "webrtc/video_engine/include/vie_base.h"
 #include "webrtc/video_engine/include/vie_capture.h"
 #include "webrtc/video_engine/include/vie_codec.h"
@@ -31,6 +32,35 @@
 
 namespace webrtc {
 namespace internal {
+namespace {
+VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
+  VideoCodec codec;
+  memset(&codec, 0, sizeof(codec));
+
+  codec.plType = decoder.payload_type;
+  strcpy(codec.plName, decoder.payload_name.c_str());
+  if (decoder.payload_name == "VP8") {
+    codec.codecType = kVideoCodecVP8;
+  } else if (decoder.payload_name == "H264") {
+    codec.codecType = kVideoCodecH264;
+  } else {
+    codec.codecType = kVideoCodecGeneric;
+  }
+
+  if (codec.codecType == kVideoCodecVP8) {
+    codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
+  } else if (codec.codecType == kVideoCodecH264) {
+    codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
+  }
+
+  codec.width = 320;
+  codec.height = 180;
+  codec.startBitrate = codec.minBitrate = codec.maxBitrate =
+      Call::Config::kDefaultStartBitrateBps / 1000;
+
+  return codec;
+}
+}  // namespace
 
 VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
                                        const VideoReceiveStream::Config& config,
@@ -118,15 +148,6 @@
     }
   }
 
-  assert(!config_.codecs.empty());
-  for (size_t i = 0; i < config_.codecs.size(); ++i) {
-    if (codec_->SetReceiveCodec(channel_, config_.codecs[i]) != 0) {
-      // TODO(pbos): Abort gracefully, this can be a runtime error.
-      //             Factor out to an Init() method.
-      abort();
-    }
-  }
-
   stats_proxy_.reset(new ReceiveStatisticsProxy(
       config_.rtp.local_ssrc, clock_, rtp_rtcp_, codec_, channel_));
 
@@ -142,8 +163,9 @@
     abort();
 
   external_codec_ = ViEExternalCodec::GetInterface(video_engine);
-  for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
-    const ExternalVideoDecoder& decoder = config_.external_decoders[i];
+  assert(!config_.decoders.empty());
+  for (size_t i = 0; i < config_.decoders.size(); ++i) {
+    const Decoder& decoder = config_.decoders[i];
     if (external_codec_->RegisterExternalReceiveCodec(
             channel_,
             decoder.payload_type,
@@ -153,6 +175,14 @@
       // TODO(pbos): Abort gracefully? Can this be a runtime error?
       abort();
     }
+
+    VideoCodec codec = CreateDecoderVideoCodec(decoder);
+
+    if (codec_->SetReceiveCodec(channel_, codec) != 0) {
+      // TODO(pbos): Abort gracefully, this can be a runtime error.
+      //             Factor out to an Init() method.
+      abort();
+    }
   }
 
   render_ = ViERender::GetInterface(video_engine);
@@ -160,7 +190,7 @@
 
   render_->AddRenderCallback(channel_, this);
 
-  if (voice_engine) {
+  if (voice_engine && config_.audio_channel_id != -1) {
     video_engine_base_->SetVoiceEngine(voice_engine);
     video_engine_base_->ConnectAudioChannel(channel_, config_.audio_channel_id);
   }
@@ -183,16 +213,15 @@
 
   render_->RemoveRenderer(channel_);
 
-  for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
+  for (size_t i = 0; i < config_.decoders.size(); ++i) {
     external_codec_->DeRegisterExternalReceiveCodec(
-        channel_, config_.external_decoders[i].payload_type);
+        channel_, config_.decoders[i].payload_type);
   }
 
   network_->DeregisterSendTransport(channel_);
 
   video_engine_base_->SetVoiceEngine(NULL);
   image_process_->Release();
-  video_engine_base_->Release();
   external_codec_->Release();
   codec_->DeregisterDecoderObserver(channel_);
   rtp_rtcp_->DeregisterReceiveChannelRtpStatisticsCallback(channel_,
@@ -203,6 +232,8 @@
   network_->Release();
   render_->Release();
   rtp_rtcp_->Release();
+  video_engine_base_->DeleteChannel(channel_);
+  video_engine_base_->Release();
 }
 
 void VideoReceiveStream::Start() {
@@ -225,10 +256,6 @@
   return stats_proxy_->GetStats();
 }
 
-void VideoReceiveStream::GetCurrentReceiveCodec(VideoCodec* receive_codec) {
-  // TODO(pbos): Implement
-}
-
 bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
   return network_->ReceivedRTCPPacket(
              channel_, packet, static_cast<int>(length)) == 0;
diff --git a/video/video_receive_stream.h b/video/video_receive_stream.h
index 6894828..2aa39e2 100644
--- a/video/video_receive_stream.h
+++ b/video/video_receive_stream.h
@@ -53,8 +53,6 @@
   virtual void Stop() OVERRIDE;
   virtual Stats GetStats() const OVERRIDE;
 
-  virtual void GetCurrentReceiveCodec(VideoCodec* receive_codec) OVERRIDE;
-
   // Overrides I420FrameCallback.
   virtual void FrameCallback(I420VideoFrame* video_frame) OVERRIDE;
 
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index 6e8f238..28231b0 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -66,8 +66,6 @@
   ss << '}';
 
   ss << ", max_packet_size: " << max_packet_size;
-  if (min_transmit_bitrate_bps != 0)
-    ss << ", min_transmit_bitrate_bps: " << min_transmit_bitrate_bps;
 
   ss << ", extensions: {";
   for (size_t i = 0; i < extensions.size(); ++i) {
@@ -125,6 +123,7 @@
       suspended_ssrcs_(suspended_ssrcs),
       external_codec_(NULL),
       channel_(-1),
+      use_default_bitrate_(true),
       stats_proxy_(config) {
   video_engine_base_ = ViEBase::GetInterface(video_engine);
   video_engine_base_->CreateChannel(channel_, base_channel);
@@ -136,10 +135,6 @@
 
   assert(config_.rtp.ssrcs.size() > 0);
 
-  assert(config_.rtp.min_transmit_bitrate_bps >= 0);
-  rtp_rtcp_->SetMinTransmitBitrate(channel_,
-                                   config_.rtp.min_transmit_bitrate_bps / 1000);
-
   for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
     const std::string& extension = config_.rtp.extensions[i].name;
     int id = config_.rtp.extensions[i].id;
@@ -297,6 +292,7 @@
 
 bool VideoSendStream::ReconfigureVideoEncoder(
     const VideoEncoderConfig& config) {
+  LOG(LS_INFO) << "(Re)configureVideoEncoder: " << config.ToString();
   const std::vector<VideoStream>& streams = config.streams;
   assert(!streams.empty());
   assert(config_.rtp.ssrcs.size() >= streams.size());
@@ -305,22 +301,32 @@
   memset(&video_codec, 0, sizeof(video_codec));
   if (config_.encoder_settings.payload_name == "VP8") {
     video_codec.codecType = kVideoCodecVP8;
+  } else if (config_.encoder_settings.payload_name == "VP9") {
+    video_codec.codecType = kVideoCodecVP9;
   } else if (config_.encoder_settings.payload_name == "H264") {
     video_codec.codecType = kVideoCodecH264;
   } else {
     video_codec.codecType = kVideoCodecGeneric;
   }
+
   switch (config.content_type) {
     case VideoEncoderConfig::kRealtimeVideo:
       video_codec.mode = kRealtimeVideo;
       break;
     case VideoEncoderConfig::kScreenshare:
       video_codec.mode = kScreensharing;
+      if (config.streams.size() == 1 &&
+          config.streams[0].temporal_layer_thresholds_bps.size() == 1) {
+        video_codec.targetBitrate =
+            config.streams[0].temporal_layer_thresholds_bps[0] / 1000;
+      }
       break;
   }
 
   if (video_codec.codecType == kVideoCodecVP8) {
     video_codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
+  } else if (video_codec.codecType == kVideoCodecVP9) {
+    video_codec.codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings();
   } else if (video_codec.codecType == kVideoCodecH264) {
     video_codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
   }
@@ -331,7 +337,8 @@
                                           config.encoder_specific_settings);
     }
     video_codec.codecSpecific.VP8.numberOfTemporalLayers =
-        static_cast<unsigned char>(streams.back().temporal_layers.size());
+        static_cast<unsigned char>(
+            streams.back().temporal_layer_thresholds_bps.size() + 1);
   } else {
     // TODO(pbos): Support encoder_settings codec-agnostically.
     assert(config.encoder_specific_settings == NULL);
@@ -364,8 +371,8 @@
     sim_stream->targetBitrate = streams[i].target_bitrate_bps / 1000;
     sim_stream->maxBitrate = streams[i].max_bitrate_bps / 1000;
     sim_stream->qpMax = streams[i].max_qp;
-    sim_stream->numberOfTemporalLayers =
-        static_cast<unsigned char>(streams[i].temporal_layers.size());
+    sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
+        streams[i].temporal_layer_thresholds_bps.size() + 1);
 
     video_codec.width = std::max(video_codec.width,
                                  static_cast<unsigned short>(streams[i].width));
@@ -378,8 +385,13 @@
     video_codec.qpMax = std::max(video_codec.qpMax,
                                  static_cast<unsigned int>(streams[i].max_qp));
   }
+  unsigned int start_bitrate_bps;
+  if (codec_->GetCodecTargetBitrate(channel_, &start_bitrate_bps) != 0 ||
+      use_default_bitrate_) {
+    start_bitrate_bps = start_bitrate_bps_;
+  }
   video_codec.startBitrate =
-      static_cast<unsigned int>(start_bitrate_bps_) / 1000;
+      static_cast<unsigned int>(start_bitrate_bps) / 1000;
 
   if (video_codec.minBitrate < kViEMinCodecBitrate)
     video_codec.minBitrate = kViEMinCodecBitrate;
@@ -398,7 +410,15 @@
   assert(streams[0].max_framerate > 0);
   video_codec.maxFramerate = streams[0].max_framerate;
 
-  return codec_->SetSendCodec(channel_, video_codec) == 0;
+  if (codec_->SetSendCodec(channel_, video_codec) != 0)
+    return false;
+
+  assert(config.min_transmit_bitrate_bps >= 0);
+  rtp_rtcp_->SetMinTransmitBitrate(channel_,
+                                   config.min_transmit_bitrate_bps / 1000);
+
+  use_default_bitrate_ = false;
+  return true;
 }
 
 bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
diff --git a/video/video_send_stream.h b/video/video_send_stream.h
index 8a77852..f787430 100644
--- a/video/video_send_stream.h
+++ b/video/video_send_stream.h
@@ -94,6 +94,11 @@
   int channel_;
   int capture_id_;
 
+  // Used as a workaround to indicate that we should be using the configured
+  // start bitrate initially, instead of the one reported by VideoEngine (which
+  // defaults to too high).
+  bool use_default_bitrate_;
+
   SendStatisticsProxy stats_proxy_;
 };
 }  // namespace internal
diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc
index 6c2fa39..b863957 100644
--- a/video/video_send_stream_tests.cc
+++ b/video/video_send_stream_tests.cc
@@ -201,7 +201,7 @@
 
     virtual void PerformTest() OVERRIDE {
       EXPECT_EQ(kEventSignaled, Wait())
-          << "Timed out while waiting single RTP packet.";
+          << "Timed out while waiting for a single RTP packet.";
     }
 
     class DelayedEncoder : public test::FakeEncoder {
@@ -1075,7 +1075,7 @@
         VideoSendStream::Config* send_config,
         std::vector<VideoReceiveStream::Config>* receive_configs,
         VideoEncoderConfig* encoder_config) OVERRIDE {
-      send_config->rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
+      encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps;
     }
 
     virtual void PerformTest() OVERRIDE {
@@ -1440,8 +1440,8 @@
       send_config->encoder_settings.payload_name = "VP8";
 
       for (size_t i = 0; i < encoder_config->streams.size(); ++i) {
-        encoder_config->streams[i].temporal_layers.resize(
-            kNumberOfTemporalLayers);
+        encoder_config->streams[i].temporal_layer_thresholds_bps.resize(
+            kNumberOfTemporalLayers - 1);
       }
 
       encoder_config->encoder_specific_settings = &vp8_settings_;
@@ -1550,4 +1550,44 @@
   RunBaseTest(&test);
 }
 
+TEST_F(VideoSendStreamTest, TranslatesTwoLayerScreencastToTargetBitrate) {
+  static const int kScreencastTargetBitrateKbps = 200;
+  class ScreencastTargetBitrateTest : public test::SendTest,
+                                      public test::FakeEncoder {
+   public:
+    ScreencastTargetBitrateTest()
+        : SendTest(kDefaultTimeoutMs),
+          test::FakeEncoder(Clock::GetRealTimeClock()) {}
+
+   private:
+    virtual int32_t InitEncode(const VideoCodec* config,
+                               int32_t number_of_cores,
+                               uint32_t max_payload_size) {
+      EXPECT_EQ(static_cast<unsigned int>(kScreencastTargetBitrateKbps),
+                config->targetBitrate);
+      observation_complete_->Set();
+      return test::FakeEncoder::InitEncode(
+          config, number_of_cores, max_payload_size);
+    }
+    virtual void ModifyConfigs(
+        VideoSendStream::Config* send_config,
+        std::vector<VideoReceiveStream::Config>* receive_configs,
+        VideoEncoderConfig* encoder_config) OVERRIDE {
+      send_config->encoder_settings.encoder = this;
+      EXPECT_EQ(1u, encoder_config->streams.size());
+      EXPECT_TRUE(
+          encoder_config->streams[0].temporal_layer_thresholds_bps.empty());
+      encoder_config->streams[0].temporal_layer_thresholds_bps.push_back(
+          kScreencastTargetBitrateKbps * 1000);
+      encoder_config->content_type = VideoEncoderConfig::kScreenshare;
+    }
+
+    virtual void PerformTest() OVERRIDE {
+      EXPECT_EQ(kEventSignaled, Wait())
+          << "Timed out while waiting for the encoder to be initialized.";
+    }
+  } test;
+
+  RunBaseTest(&test);
+}
 }  // namespace webrtc
diff --git a/video_decoder.h b/video_decoder.h
new file mode 100644
index 0000000..03a564e
--- /dev/null
+++ b/video_decoder.h
@@ -0,0 +1,74 @@
+/*
+ *  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_VIDEO_DECODER_H_
+#define WEBRTC_VIDEO_DECODER_H_
+
+#include <vector>
+
+#include "webrtc/common_types.h"
+#include "webrtc/typedefs.h"
+#include "webrtc/video_frame.h"
+
+namespace webrtc {
+
+class RTPFragmentationHeader;
+// TODO(pbos): Expose these through a public (root) header or change these APIs.
+struct CodecSpecificInfo;
+struct VideoCodec;
+
+class DecodedImageCallback {
+ public:
+  virtual ~DecodedImageCallback() {}
+
+  virtual int32_t Decoded(I420VideoFrame& decodedImage) = 0;
+  virtual int32_t ReceivedDecodedReferenceFrame(const uint64_t pictureId) {
+    return -1;
+  }
+
+  virtual int32_t ReceivedDecodedFrame(const uint64_t pictureId) { return -1; }
+};
+
+class VideoDecoder {
+ public:
+  enum DecoderType {
+    kVp8,
+  };
+
+  static VideoDecoder* Create(DecoderType codec_type);
+
+  virtual ~VideoDecoder() {}
+
+  virtual int32_t InitDecode(const VideoCodec* codecSettings,
+                             int32_t numberOfCores) = 0;
+
+  virtual int32_t Decode(const EncodedImage& inputImage,
+                         bool missingFrames,
+                         const RTPFragmentationHeader* fragmentation,
+                         const CodecSpecificInfo* codecSpecificInfo = NULL,
+                         int64_t renderTimeMs = -1) = 0;
+
+  virtual int32_t RegisterDecodeCompleteCallback(
+      DecodedImageCallback* callback) = 0;
+
+  virtual int32_t Release() = 0;
+  virtual int32_t Reset() = 0;
+
+  virtual int32_t SetCodecConfigParameters(const uint8_t* /*buffer*/,
+                                           int32_t /*size*/) {
+    return -1;
+  }
+
+  virtual VideoDecoder* Copy() { return NULL; }
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_VIDEO_DECODER_H_
diff --git a/video_encoder.h b/video_encoder.h
index cbdf1ef..2bf52f3 100644
--- a/video_encoder.h
+++ b/video_encoder.h
@@ -40,28 +40,84 @@
  public:
   enum EncoderType {
     kVp8,
+    kVp9,
   };
 
   static VideoEncoder* Create(EncoderType codec_type);
 
   static VideoCodecVP8 GetDefaultVp8Settings();
+  static VideoCodecVP9 GetDefaultVp9Settings();
   static VideoCodecH264 GetDefaultH264Settings();
 
   virtual ~VideoEncoder() {}
 
+  // Initialize the encoder with the information from the codecSettings
+  //
+  // Input:
+  //          - codec_settings    : Codec settings
+  //          - number_of_cores   : Number of cores available for the encoder
+  //          - max_payload_size  : The maximum size each payload is allowed
+  //                                to have. Usually MTU - overhead.
+  //
+  // Return value                  : Set bit rate if OK
+  //                                 <0 - Errors:
+  //                                  WEBRTC_VIDEO_CODEC_ERR_PARAMETER
+  //                                  WEBRTC_VIDEO_CODEC_ERR_SIZE
+  //                                  WEBRTC_VIDEO_CODEC_LEVEL_EXCEEDED
+  //                                  WEBRTC_VIDEO_CODEC_MEMORY
+  //                                  WEBRTC_VIDEO_CODEC_ERROR
   virtual int32_t InitEncode(const VideoCodec* codec_settings,
                              int32_t number_of_cores,
                              uint32_t max_payload_size) = 0;
+
+  // Register an encode complete callback object.
+  //
+  // Input:
+  //          - callback         : Callback object which handles encoded images.
+  //
+  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
   virtual int32_t RegisterEncodeCompleteCallback(
       EncodedImageCallback* callback) = 0;
+
+  // Free encoder memory.
+  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
   virtual int32_t Release() = 0;
 
-
+  // Encode an I420 image (as a part of a video stream). The encoded image
+  // will be returned to the user through the encode complete callback.
+  //
+  // Input:
+  //          - frame             : Image to be encoded
+  //          - frame_types       : Frame type to be generated by the encoder.
+  //
+  // Return value                 : WEBRTC_VIDEO_CODEC_OK if OK
+  //                                <0 - Errors:
+  //                                  WEBRTC_VIDEO_CODEC_ERR_PARAMETER
+  //                                  WEBRTC_VIDEO_CODEC_MEMORY
+  //                                  WEBRTC_VIDEO_CODEC_ERROR
+  //                                  WEBRTC_VIDEO_CODEC_TIMEOUT
   virtual int32_t Encode(const I420VideoFrame& frame,
                          const CodecSpecificInfo* codec_specific_info,
                          const std::vector<VideoFrameType>* frame_types) = 0;
 
+  // Inform the encoder of the new packet loss rate and the round-trip time of
+  // the network.
+  //
+  // Input:
+  //          - packet_loss : Fraction lost
+  //                          (loss rate in percent = 100 * packetLoss / 255)
+  //          - rtt         : Round-trip time in milliseconds
+  // Return value           : WEBRTC_VIDEO_CODEC_OK if OK
+  //                          <0 - Errors: WEBRTC_VIDEO_CODEC_ERROR
   virtual int32_t SetChannelParameters(uint32_t packet_loss, int rtt) = 0;
+
+  // Inform the encoder about the new target bit rate.
+  //
+  // Input:
+  //          - bitrate         : New target bit rate
+  //          - framerate       : The target frame rate
+  //
+  // Return value                : WEBRTC_VIDEO_CODEC_OK if OK, < 0 otherwise.
   virtual int32_t SetRates(uint32_t bitrate, uint32_t framerate) = 0;
 
   virtual int32_t SetPeriodicKeyFrames(bool enable) { return -1; }
diff --git a/video_engine/include/vie_base.h b/video_engine/include/vie_base.h
index a49aba7..ae80cd7 100644
--- a/video_engine/include/vie_base.h
+++ b/video_engine/include/vie_base.h
@@ -63,6 +63,7 @@
   bool enable_encode_usage_method;
   int low_encode_usage_threshold_percent;  // Threshold for triggering underuse.
   int high_encode_usage_threshold_percent; // Threshold for triggering overuse.
+  // TODO(asapersson): Remove options, not used.
   int low_encode_time_rsd_threshold;   // Additional threshold for triggering
                                        // underuse (used in addition to
                                        // threshold above if configured).
@@ -117,6 +118,7 @@
   int avg_encode_time_ms;   // The average encode time in ms.
   int encode_usage_percent; // The average encode time divided by the average
                             // time difference between incoming captured frames.
+  // TODO(asapersson): Remove metric, not used.
   int encode_rsd;           // The relative std dev of encode time of frames.
   int capture_queue_delay_ms_per_s;  // The current time delay between an
                                      // incoming captured frame until the frame
diff --git a/video_engine/overuse_frame_detector.cc b/video_engine/overuse_frame_detector.cc
index 9603613..32b0d25 100644
--- a/video_engine/overuse_frame_detector.cc
+++ b/video_engine/overuse_frame_detector.cc
@@ -212,112 +212,6 @@
   scoped_ptr<rtc::ExpFilter> filtered_frame_diff_ms_;
 };
 
-// Class for calculating the relative standard deviation of the processing time
-// of frame on the send-side.
-// Currently only used for testing.
-class OveruseFrameDetector::SendProcessingRsd {
- public:
-  SendProcessingRsd(Clock* clock)
-      : kWeightFactor(0.6f),
-        count_(0),
-        filtered_rsd_(new rtc::ExpFilter(kWeightFactor)),
-        hist_samples_(0),
-        hist_sum_(0.0f),
-        last_process_time_ms_(clock->TimeInMilliseconds()) {
-    Reset();
-  }
-  ~SendProcessingRsd() {}
-
-  void SetOptions(const CpuOveruseOptions& options) {
-    options_ = options;
-  }
-
-  void Reset() {
-    count_ = 0;
-    filtered_rsd_->Reset(kWeightFactor);
-    filtered_rsd_->Apply(1.0f, InitialValue());
-    hist_.clear();
-    hist_samples_ = 0;
-    hist_sum_ = 0.0f;
-  }
-
-  void AddSample(float processing_ms) {
-    int bin = static_cast<int>(processing_ms + 0.5f);
-    if (bin <= 0) {
-      return;
-    }
-    ++count_;
-    ++hist_[bin];
-    ++hist_samples_;
-    hist_sum_ += bin;
-  }
-
-  void Process(int64_t now) {
-    if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
-      // Have not received min number of frames since last reset.
-      return;
-    }
-    const int kMinHistSamples = 20;
-    if (hist_samples_ < kMinHistSamples) {
-      return;
-    }
-    const int64_t kMinDiffSinceLastProcessMs = 1000;
-    int64_t diff_last_process_ms = now - last_process_time_ms_;
-    if (now - last_process_time_ms_ <= kMinDiffSinceLastProcessMs) {
-      return;
-    }
-    last_process_time_ms_ = now;
-
-    // Calculate variance (using samples above the mean).
-    // Checks for a larger processing time of some frames while there is a small
-    // increase in the average time.
-    int mean = hist_sum_ / hist_samples_;
-    float variance = 0.0f;
-    int total_count = 0;
-    for (std::map<int,int>::iterator it = hist_.begin();
-         it != hist_.end(); ++it) {
-      int time = it->first;
-      int count = it->second;
-      if (time > mean) {
-        total_count += count;
-        for (int i = 0; i < count; ++i) {
-          variance += ((time - mean) * (time - mean));
-        }
-      }
-    }
-    variance /= std::max(total_count, 1);
-    float cov = sqrt(variance) / mean;
-
-    hist_.clear();
-    hist_samples_ = 0;
-    hist_sum_ = 0.0f;
-
-    float exp = static_cast<float>(diff_last_process_ms) / kProcessIntervalMs;
-    exp = std::min(exp, kMaxExp);
-    filtered_rsd_->Apply(exp, 100.0f * cov);
-  }
-
-  int Value() const {
-    return static_cast<int>(filtered_rsd_->filtered() + 0.5);
-  }
-
- private:
-  float InitialValue() const {
-    // Start in between the underuse and overuse threshold.
-    return std::max(((options_.low_encode_time_rsd_threshold +
-                      options_.high_encode_time_rsd_threshold) / 2.0f), 0.0f);
-  }
-
-  const float kWeightFactor;
-  uint32_t count_;  // Number of samples since last reset.
-  CpuOveruseOptions options_;
-  scoped_ptr<rtc::ExpFilter> filtered_rsd_;
-  int hist_samples_;
-  float hist_sum_;
-  std::map<int, int> hist_;  // Histogram of time spent on processing frames.
-  int64_t last_process_time_ms_;
-};
-
 // Class for calculating the processing time of frames.
 class OveruseFrameDetector::FrameQueue {
  public:
@@ -439,7 +333,6 @@
       num_pixels_(0),
       last_encode_sample_ms_(0),
       encode_time_(new EncodeTimeAvg()),
-      rsd_(new SendProcessingRsd(clock)),
       usage_(new SendProcessingUsage()),
       frame_queue_(new FrameQueue()),
       last_sample_time_ms_(0),
@@ -463,7 +356,6 @@
   options_ = options;
   capture_deltas_.SetOptions(options);
   usage_->SetOptions(options);
-  rsd_->SetOptions(options);
   ResetAll(num_pixels_);
 }
 
@@ -487,7 +379,7 @@
   CriticalSectionScoped cs(crit_.get());
   metrics->capture_jitter_ms = static_cast<int>(capture_deltas_.StdDev() + 0.5);
   metrics->avg_encode_time_ms = encode_time_->Value();
-  metrics->encode_rsd = rsd_->Value();
+  metrics->encode_rsd = 0;
   metrics->encode_usage_percent = usage_->Value();
   metrics->capture_queue_delay_ms_per_s = capture_queue_delay_->Value();
 }
@@ -515,7 +407,6 @@
   num_pixels_ = num_pixels;
   capture_deltas_.Reset();
   usage_->Reset();
-  rsd_->Reset();
   frame_queue_->Reset();
   capture_queue_delay_->ClearFrames();
   last_capture_time_ = 0;
@@ -581,7 +472,6 @@
   if (last_sample_time_ms_ != 0) {
     int64_t diff_ms = now - last_sample_time_ms_;
     usage_->AddSample(elapsed_ms, diff_ms);
-    rsd_->AddSample(elapsed_ms);
   }
   last_sample_time_ms_ = now;
 }
@@ -599,7 +489,6 @@
   next_process_time_ = now + kProcessIntervalMs;
   ++num_process_times_;
 
-  rsd_->Process(now);
   capture_queue_delay_->CalculateDelayChange(diff_ms);
 
   if (num_process_times_ <= options_.min_process_count) {
@@ -644,7 +533,6 @@
   LOG(LS_VERBOSE) << " Frame stats: capture avg: " << capture_deltas_.Mean()
                   << " capture stddev " << capture_deltas_.StdDev()
                   << " encode usage " << usage_->Value()
-                  << " encode rsd " << rsd_->Value()
                   << " overuse detections " << num_overuse_detections_
                   << " rampup delay " << rampup_delay;
   return 0;
@@ -656,13 +544,7 @@
     overusing = capture_deltas_.StdDev() >=
         options_.high_capture_jitter_threshold_ms;
   } else if (options_.enable_encode_usage_method) {
-    bool usage_overuse =
-        usage_->Value() >= options_.high_encode_usage_threshold_percent;
-    bool rsd_overuse = false;
-    if (options_.high_encode_time_rsd_threshold > 0) {
-      rsd_overuse = (rsd_->Value() >= options_.high_encode_time_rsd_threshold);
-    }
-    overusing = usage_overuse || rsd_overuse;
+    overusing = usage_->Value() >= options_.high_encode_usage_threshold_percent;
   }
 
   if (overusing) {
@@ -683,13 +565,7 @@
     underusing = capture_deltas_.StdDev() <
         options_.low_capture_jitter_threshold_ms;
   } else if (options_.enable_encode_usage_method) {
-    bool usage_underuse =
-        usage_->Value() < options_.low_encode_usage_threshold_percent;
-    bool rsd_underuse = true;
-    if (options_.low_encode_time_rsd_threshold > 0) {
-      rsd_underuse = (rsd_->Value() < options_.low_encode_time_rsd_threshold);
-    }
-    underusing = usage_underuse && rsd_underuse;
+    underusing = usage_->Value() < options_.low_encode_usage_threshold_percent;
   }
   return underusing;
 }
diff --git a/video_engine/overuse_frame_detector.h b/video_engine/overuse_frame_detector.h
index 421e9de..f90a4f8 100644
--- a/video_engine/overuse_frame_detector.h
+++ b/video_engine/overuse_frame_detector.h
@@ -103,7 +103,6 @@
 
  private:
   class EncodeTimeAvg;
-  class SendProcessingRsd;
   class SendProcessingUsage;
   class CaptureQueueDelay;
   class FrameQueue;
@@ -146,8 +145,6 @@
 
   int64_t last_encode_sample_ms_;
   scoped_ptr<EncodeTimeAvg> encode_time_;
-
-  scoped_ptr<SendProcessingRsd> rsd_;
   scoped_ptr<SendProcessingUsage> usage_;
   scoped_ptr<FrameQueue> frame_queue_;
   int64_t last_sample_time_ms_;
diff --git a/video_engine/overuse_frame_detector_unittest.cc b/video_engine/overuse_frame_detector_unittest.cc
index 553c351..e236169 100644
--- a/video_engine/overuse_frame_detector_unittest.cc
+++ b/video_engine/overuse_frame_detector_unittest.cc
@@ -71,12 +71,6 @@
              options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5;
   }
 
-  int InitialRsd() {
-    return std::max(
-        ((options_.low_encode_time_rsd_threshold +
-          options_.high_encode_time_rsd_threshold) / 2.0f) + 0.5f, 0.0f);
-  }
-
   void InsertFramesWithInterval(
       size_t num_frames, int interval_ms, int width, int height) {
     while (num_frames-- > 0) {
@@ -120,18 +114,6 @@
     }
   }
 
-  void TriggerOveruseWithRsd(int num_times) {
-    const int kDelayMs1 = 10;
-    const int kDelayMs2 = 25;
-    for (int i = 0; i < num_times; ++i) {
-      InsertAndSendFramesWithInterval(
-          200, kFrameInterval33ms, kWidth, kHeight, kDelayMs1);
-      InsertAndSendFramesWithInterval(
-          10, kFrameInterval33ms, kWidth, kHeight, kDelayMs2);
-      overuse_detector_->Process();
-    }
-  }
-
   void TriggerUnderuseWithProcessingUsage() {
     const int kDelayMs1 = 5;
     const int kDelayMs2 = 6;
@@ -160,12 +142,6 @@
     return metrics.encode_usage_percent;
   }
 
-  int Rsd() {
-    CpuOveruseMetrics metrics;
-    overuse_detector_->GetCpuOveruseMetrics(&metrics);
-    return metrics.encode_rsd;
-  }
-
   CpuOveruseOptions options_;
   scoped_ptr<SimulatedClock> clock_;
   scoped_ptr<MockCpuOveruseObserver> observer_;
@@ -571,73 +547,4 @@
   TriggerUnderuseWithProcessingUsage();
 }
 
-TEST_F(OveruseFrameDetectorTest, RsdResetAfterChangingThreshold) {
-  EXPECT_EQ(InitialRsd(), Rsd());
-  options_.high_encode_time_rsd_threshold = 100;
-  overuse_detector_->SetOptions(options_);
-  EXPECT_EQ(InitialRsd(), Rsd());
-  options_.low_encode_time_rsd_threshold = 20;
-  overuse_detector_->SetOptions(options_);
-  EXPECT_EQ(InitialRsd(), Rsd());
-}
-
-// enable_encode_usage_method = true;
-// low/high_encode_time_rsd_threshold >= 0
-// UsagePercent() > high_encode_usage_threshold_percent ||
-// Rsd() > high_encode_time_rsd_threshold => overuse.
-// UsagePercent() < low_encode_usage_threshold_percent &&
-// Rsd() < low_encode_time_rsd_threshold => underuse.
-TEST_F(OveruseFrameDetectorTest, TriggerOveruseWithRsd) {
-  options_.enable_capture_jitter_method = false;
-  options_.enable_encode_usage_method = true;
-  options_.high_encode_time_rsd_threshold = 80;
-  overuse_detector_->SetOptions(options_);
-  // rsd > high, usage < high => overuse
-  EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
-  TriggerOveruseWithRsd(options_.high_threshold_consecutive_count);
-  EXPECT_LT(UsagePercent(), options_.high_encode_usage_threshold_percent);
-}
-
-TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithRsd) {
-  options_.enable_capture_jitter_method = false;
-  options_.enable_encode_usage_method = true;
-  options_.low_encode_time_rsd_threshold = 25;
-  options_.high_encode_time_rsd_threshold = 80;
-  overuse_detector_->SetOptions(options_);
-  // rsd > high, usage < high => overuse
-  EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
-  TriggerOveruseWithRsd(options_.high_threshold_consecutive_count);
-  EXPECT_LT(UsagePercent(), options_.high_encode_usage_threshold_percent);
-  // rsd < low, usage < low => underuse
-  EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1));
-  TriggerUnderuseWithProcessingUsage();
-}
-
-TEST_F(OveruseFrameDetectorTest, NoUnderuseWithRsd_UsageGtLowThreshold) {
-  options_.enable_capture_jitter_method = false;
-  options_.enable_encode_usage_method = true;
-  options_.low_encode_usage_threshold_percent = 1;
-  options_.low_encode_time_rsd_threshold = 25;
-  options_.high_encode_time_rsd_threshold = 90;
-  overuse_detector_->SetOptions(options_);
-  // rsd < low, usage > low => no underuse
-  EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0);
-  TriggerUnderuseWithProcessingUsage();
-  EXPECT_LT(Rsd(), options_.low_encode_time_rsd_threshold);
-  EXPECT_GT(UsagePercent(), options_.low_encode_usage_threshold_percent);
-}
-
-TEST_F(OveruseFrameDetectorTest, NoUnderuseWithRsd_RsdGtLowThreshold) {
-  options_.enable_capture_jitter_method = false;
-  options_.enable_encode_usage_method = true;
-  options_.low_encode_usage_threshold_percent = 20;
-  options_.low_encode_time_rsd_threshold = 1;
-  options_.high_encode_time_rsd_threshold = 90;
-  overuse_detector_->SetOptions(options_);
-  // rsd > low, usage < low => no underuse
-  EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0);
-  TriggerUnderuseWithProcessingUsage();
-  EXPECT_GT(Rsd(), options_.low_encode_time_rsd_threshold);
-  EXPECT_LT(UsagePercent(), options_.low_encode_usage_threshold_percent);
-}
 }  // namespace webrtc
diff --git a/video_engine/test/auto_test/source/vie_autotest.cc b/video_engine/test/auto_test/source/vie_autotest.cc
index fb1a46f..41fafae 100644
--- a/video_engine/test/auto_test/source/vie_autotest.cc
+++ b/video_engine/test/auto_test/source/vie_autotest.cc
@@ -98,6 +98,9 @@
         case webrtc::kVideoCodecVP8:
             ViETest::Log("\tcodecType: VP8");
             break;
+        case webrtc::kVideoCodecVP9:
+            ViETest::Log("\tcodecType: VP9");
+            break;
         case webrtc::kVideoCodecI420:
             ViETest::Log("\tcodecType: I420");
             break;
diff --git a/video_engine/test/auto_test/source/vie_autotest_loopback.cc b/video_engine/test/auto_test/source/vie_autotest_loopback.cc
index 9b8040d..03a82b4 100644
--- a/video_engine/test/auto_test/source/vie_autotest_loopback.cc
+++ b/video_engine/test/auto_test/source/vie_autotest_loopback.cc
@@ -158,7 +158,7 @@
         printf("Error in scanf()\n");
         return -1;
     }
-    getchar();
+    getc(stdin);
     captureIdx = captureIdx - 1; // Compensate for idx start at 1.
 #endif
     error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
@@ -350,7 +350,7 @@
         printf("Error in scanf()\n");
         return -1;
     }
-    getchar();
+    getc(stdin);
     codecIdx = codecIdx - 1; // Compensate for idx start at 1.
 #endif
     // VP8 over generic transport gets this special one.
@@ -624,7 +624,7 @@
     // Call started
     printf("\nLoopback call started\n\n");
     printf("Press enter to stop...");
-    while ((getchar()) != '\n')
+    while ((getc(stdin)) != '\n')
         ;
 
     //********************************************************
diff --git a/video_engine/test/auto_test/source/vie_autotest_main.cc b/video_engine/test/auto_test/source/vie_autotest_main.cc
index c688e2e..1617258 100644
--- a/video_engine/test/auto_test/source/vie_autotest_main.cc
+++ b/video_engine/test/auto_test/source/vie_autotest_main.cc
@@ -106,10 +106,10 @@
   int result;
   if (scanf("%d", &result) <= 0) {
     ViETest::Log("\nPlease enter a number instead, then hit enter.");
-    getchar();
+    getc(stdin);
     return kInvalidChoice;
   }
-  getchar();  // Consume enter key.
+  getc(stdin);  // Consume enter key.
 
   if (result < min_allowed || result > max_allowed) {
     ViETest::Log("%d-%d are valid choices. Please try again.", min_allowed,
diff --git a/video_engine/test/auto_test/source/vie_autotest_network.cc b/video_engine/test/auto_test/source/vie_autotest_network.cc
index df5b5ef..1ccac70 100644
--- a/video_engine/test/auto_test/source/vie_autotest_network.cc
+++ b/video_engine/test/auto_test/source/vie_autotest_network.cc
@@ -150,7 +150,7 @@
             ViETest::Log("On Win7 and late Vista, you need to right click the "
                          "exe and choose");
             ViETest::Log("\"Run as administrator\"\n");
-            getchar();
+            getc(stdin);
         }
         EXPECT_EQ(0, ViE.network->GetSendToS(
             tbChannel.videoChannel, DSCP, useSetSockOpt));  // No ToS set
@@ -390,7 +390,7 @@
             ViETest::Log("On Win7 and late Vista, you need to right click the "
                          "exe and choose");
             ViETest::Log("\"Run as administrator\"\n");
-            getchar();
+            getc(stdin);
         }
         EXPECT_EQ(0, ViE.network->GetSendToS(
             tbChannel.videoChannel, DSCP, useSetSockOpt));
diff --git a/video_engine/test/auto_test/source/vie_autotest_record.cc b/video_engine/test/auto_test/source/vie_autotest_record.cc
index 1fb11ad..89575ce 100644
--- a/video_engine/test/auto_test/source/vie_autotest_record.cc
+++ b/video_engine/test/auto_test/source/vie_autotest_record.cc
@@ -216,7 +216,7 @@
     printf("Error in scanf()\n");
     return -1;
   }
-  getchar();
+  getc(stdin);
   captureIdx = captureIdx - 1;  // Compensate for idx start at 1.
 #endif
   error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
@@ -441,14 +441,14 @@
     clock_time = webrtc::TickTime::MillisecondTimestamp();
     timing << clock_time << std::endl;
   }
-  char c = getchar();
+  char c = getc(stdin);
   fflush(stdin);
   while (c != 's') {
     if (c == '\n' && enable_labeling == 1) {
       clock_time = webrtc::TickTime::MillisecondTimestamp();
       timing << clock_time << std::endl;
     }
-    c = getchar();
+    c = getc(stdin);
   }
   if (enable_labeling == 1) {
     clock_time = webrtc::TickTime::MillisecondTimestamp();
diff --git a/video_engine/test/auto_test/vie_auto_test.gypi b/video_engine/test/auto_test/vie_auto_test.gypi
index a415b3b..c8886d8 100644
--- a/video_engine/test/auto_test/vie_auto_test.gypi
+++ b/video_engine/test/auto_test/vie_auto_test.gypi
@@ -13,7 +13,7 @@
       'type': 'executable',
       'dependencies': [
         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:metrics_default',
         '<(webrtc_root)/modules/modules.gyp:video_capture_module_internal_impl',
         '<(webrtc_root)/modules/modules.gyp:video_render_module_internal_impl',
         '<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
@@ -137,7 +137,6 @@
           ],
           'includes': [
             '../../../build/isolate.gypi',
-            'vie_auto_test.isolate',
           ],
           'sources': [
             'vie_auto_test.isolate',
diff --git a/video_engine/test/auto_test/vie_auto_test.isolate b/video_engine/test/auto_test/vie_auto_test.isolate
index 762a7ac..da09a6e 100644
--- a/video_engine/test/auto_test/vie_auto_test.isolate
+++ b/video_engine/test/auto_test/vie_auto_test.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,16 +21,11 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/vie_auto_test<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_touched': [
+        'files': [
           '<(DEPTH)/DEPS',
-        ],
-        'isolate_dependency_tracked': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/vie_auto_test<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/video_engine/video_engine_core.gypi b/video_engine/video_engine_core.gypi
index fd61043..2bfc653 100644
--- a/video_engine/video_engine_core.gypi
+++ b/video_engine/video_engine_core.gypi
@@ -123,7 +123,7 @@
           'dependencies': [
             'video_engine_core',
             '<(webrtc_root)/modules/modules.gyp:video_capture_module_internal_impl',
-	    '<(webrtc_root)/modules/modules.gyp:video_render_module_internal_impl',
+            '<(webrtc_root)/modules/modules.gyp:video_render_module_internal_impl',
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(DEPTH)/testing/gmock.gyp:gmock',
             '<(webrtc_root)/test/test.gyp:test_support_main',
@@ -168,7 +168,6 @@
               ],
               'includes': [
                 '../build/isolate.gypi',
-                'video_engine_core_unittests.isolate',
               ],
               'sources': [
                 'video_engine_core_unittests.isolate',
diff --git a/video_engine/video_engine_core.target.darwin-arm.mk b/video_engine/video_engine_core.target.darwin-arm.mk
index 8111c94..cd60eb0 100644
--- a/video_engine/video_engine_core.target.darwin-arm.mk
+++ b/video_engine/video_engine_core.target.darwin-arm.mk
@@ -112,11 +112,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -227,11 +230,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -247,6 +252,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.darwin-arm64.mk b/video_engine/video_engine_core.target.darwin-arm64.mk
index aefe44b..1ee5c36 100644
--- a/video_engine/video_engine_core.target.darwin-arm64.mk
+++ b/video_engine/video_engine_core.target.darwin-arm64.mk
@@ -101,11 +101,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,10 +116,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +205,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,10 +220,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.darwin-mips.mk b/video_engine/video_engine_core.target.darwin-mips.mk
index 4a7236f..6ab77b9 100644
--- a/video_engine/video_engine_core.target.darwin-mips.mk
+++ b/video_engine/video_engine_core.target.darwin-mips.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -212,11 +215,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -231,6 +236,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.darwin-mips64.mk b/video_engine/video_engine_core.target.darwin-mips64.mk
new file mode 100644
index 0000000..35d9ba5
--- /dev/null
+++ b/video_engine/video_engine_core.target.darwin-mips64.mk
@@ -0,0 +1,292 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_video_engine_video_engine_core_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/video_engine/call_stats.cc \
+	third_party/webrtc/video_engine/encoder_state_feedback.cc \
+	third_party/webrtc/video_engine/overuse_frame_detector.cc \
+	third_party/webrtc/video_engine/stream_synchronization.cc \
+	third_party/webrtc/video_engine/vie_base_impl.cc \
+	third_party/webrtc/video_engine/vie_capture_impl.cc \
+	third_party/webrtc/video_engine/vie_codec_impl.cc \
+	third_party/webrtc/video_engine/vie_external_codec_impl.cc \
+	third_party/webrtc/video_engine/vie_image_process_impl.cc \
+	third_party/webrtc/video_engine/vie_impl.cc \
+	third_party/webrtc/video_engine/vie_network_impl.cc \
+	third_party/webrtc/video_engine/vie_ref_count.cc \
+	third_party/webrtc/video_engine/vie_render_impl.cc \
+	third_party/webrtc/video_engine/vie_rtp_rtcp_impl.cc \
+	third_party/webrtc/video_engine/vie_shared_data.cc \
+	third_party/webrtc/video_engine/vie_capturer.cc \
+	third_party/webrtc/video_engine/vie_channel.cc \
+	third_party/webrtc/video_engine/vie_channel_group.cc \
+	third_party/webrtc/video_engine/vie_channel_manager.cc \
+	third_party/webrtc/video_engine/vie_encoder.cc \
+	third_party/webrtc/video_engine/vie_file_image.cc \
+	third_party/webrtc/video_engine/vie_frame_provider_base.cc \
+	third_party/webrtc/video_engine/vie_input_manager.cc \
+	third_party/webrtc/video_engine/vie_manager_base.cc \
+	third_party/webrtc/video_engine/vie_receiver.cc \
+	third_party/webrtc/video_engine/vie_remb.cc \
+	third_party/webrtc/video_engine/vie_renderer.cc \
+	third_party/webrtc/video_engine/vie_render_manager.cc \
+	third_party/webrtc/video_engine/vie_sender.cc \
+	third_party/webrtc/video_engine/vie_sync_module.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_video_engine_video_engine_core_gyp
+
+# Alias gyp target name.
+.PHONY: video_engine_core
+video_engine_core: third_party_webrtc_video_engine_video_engine_core_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/video_engine/video_engine_core.target.darwin-x86.mk b/video_engine/video_engine_core.target.darwin-x86.mk
index 56bb12c..bb96064 100644
--- a/video_engine/video_engine_core.target.darwin-x86.mk
+++ b/video_engine/video_engine_core.target.darwin-x86.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -213,11 +216,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -230,6 +235,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.darwin-x86_64.mk b/video_engine/video_engine_core.target.darwin-x86_64.mk
index 9fd0648..ea3ccb4 100644
--- a/video_engine/video_engine_core.target.darwin-x86_64.mk
+++ b/video_engine/video_engine_core.target.darwin-x86_64.mk
@@ -106,11 +106,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -123,6 +125,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -211,11 +214,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.linux-arm.mk b/video_engine/video_engine_core.target.linux-arm.mk
index 8111c94..cd60eb0 100644
--- a/video_engine/video_engine_core.target.linux-arm.mk
+++ b/video_engine/video_engine_core.target.linux-arm.mk
@@ -112,11 +112,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -132,6 +134,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -227,11 +230,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -247,6 +252,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.linux-arm64.mk b/video_engine/video_engine_core.target.linux-arm64.mk
index aefe44b..1ee5c36 100644
--- a/video_engine/video_engine_core.target.linux-arm64.mk
+++ b/video_engine/video_engine_core.target.linux-arm64.mk
@@ -101,11 +101,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -114,10 +116,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +205,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -214,10 +220,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.linux-mips.mk b/video_engine/video_engine_core.target.linux-mips.mk
index 4a7236f..6ab77b9 100644
--- a/video_engine/video_engine_core.target.linux-mips.mk
+++ b/video_engine/video_engine_core.target.linux-mips.mk
@@ -105,11 +105,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -212,11 +215,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -231,6 +236,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.linux-mips64.mk b/video_engine/video_engine_core.target.linux-mips64.mk
new file mode 100644
index 0000000..35d9ba5
--- /dev/null
+++ b/video_engine/video_engine_core.target.linux-mips64.mk
@@ -0,0 +1,292 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_video_engine_video_engine_core_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/video_engine/call_stats.cc \
+	third_party/webrtc/video_engine/encoder_state_feedback.cc \
+	third_party/webrtc/video_engine/overuse_frame_detector.cc \
+	third_party/webrtc/video_engine/stream_synchronization.cc \
+	third_party/webrtc/video_engine/vie_base_impl.cc \
+	third_party/webrtc/video_engine/vie_capture_impl.cc \
+	third_party/webrtc/video_engine/vie_codec_impl.cc \
+	third_party/webrtc/video_engine/vie_external_codec_impl.cc \
+	third_party/webrtc/video_engine/vie_image_process_impl.cc \
+	third_party/webrtc/video_engine/vie_impl.cc \
+	third_party/webrtc/video_engine/vie_network_impl.cc \
+	third_party/webrtc/video_engine/vie_ref_count.cc \
+	third_party/webrtc/video_engine/vie_render_impl.cc \
+	third_party/webrtc/video_engine/vie_rtp_rtcp_impl.cc \
+	third_party/webrtc/video_engine/vie_shared_data.cc \
+	third_party/webrtc/video_engine/vie_capturer.cc \
+	third_party/webrtc/video_engine/vie_channel.cc \
+	third_party/webrtc/video_engine/vie_channel_group.cc \
+	third_party/webrtc/video_engine/vie_channel_manager.cc \
+	third_party/webrtc/video_engine/vie_encoder.cc \
+	third_party/webrtc/video_engine/vie_file_image.cc \
+	third_party/webrtc/video_engine/vie_frame_provider_base.cc \
+	third_party/webrtc/video_engine/vie_input_manager.cc \
+	third_party/webrtc/video_engine/vie_manager_base.cc \
+	third_party/webrtc/video_engine/vie_receiver.cc \
+	third_party/webrtc/video_engine/vie_remb.cc \
+	third_party/webrtc/video_engine/vie_renderer.cc \
+	third_party/webrtc/video_engine/vie_render_manager.cc \
+	third_party/webrtc/video_engine/vie_sender.cc \
+	third_party/webrtc/video_engine/vie_sync_module.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/interface \
+	$(LOCAL_PATH)/third_party/webrtc/common_video/libyuv/include \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_video_engine_video_engine_core_gyp
+
+# Alias gyp target name.
+.PHONY: video_engine_core
+video_engine_core: third_party_webrtc_video_engine_video_engine_core_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/video_engine/video_engine_core.target.linux-x86.mk b/video_engine/video_engine_core.target.linux-x86.mk
index 56bb12c..bb96064 100644
--- a/video_engine/video_engine_core.target.linux-x86.mk
+++ b/video_engine/video_engine_core.target.linux-x86.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -124,6 +126,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -213,11 +216,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -230,6 +235,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core.target.linux-x86_64.mk b/video_engine/video_engine_core.target.linux-x86_64.mk
index 9fd0648..ea3ccb4 100644
--- a/video_engine/video_engine_core.target.linux-x86_64.mk
+++ b/video_engine/video_engine_core.target.linux-x86_64.mk
@@ -106,11 +106,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -123,6 +125,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -211,11 +214,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -228,6 +233,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/video_engine/video_engine_core_unittests.isolate b/video_engine/video_engine_core_unittests.isolate
index ec65e73..b95d84c 100644
--- a/video_engine/video_engine_core_unittests.isolate
+++ b/video_engine/video_engine_core_unittests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,13 +21,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/video_engine_core_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/video_engine_core_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/video_engine/vie_channel.cc b/video_engine/vie_channel.cc
index bbcb602..ded2140 100644
--- a/video_engine/vie_channel.cc
+++ b/video_engine/vie_channel.cc
@@ -25,6 +25,7 @@
 #include "webrtc/modules/video_render/include/video_render_defines.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/metrics.h"
 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
 #include "webrtc/video_engine/call_stats.h"
 #include "webrtc/video_engine/include/vie_codec.h"
@@ -147,7 +148,8 @@
       sender_(sender),
       nack_history_size_sender_(kSendSidePacketHistorySize),
       max_nack_reordering_threshold_(kMaxPacketAgeToNack),
-      pre_render_callback_(NULL) {
+      pre_render_callback_(NULL),
+      start_ms_(Clock::GetRealTimeClock()->TimeInMilliseconds()) {
   RtpRtcp::Configuration configuration;
   configuration.id = ViEModuleId(engine_id, channel_id);
   configuration.audio = false;
@@ -222,6 +224,7 @@
 }
 
 ViEChannel::~ViEChannel() {
+  UpdateHistograms();
   // Make sure we don't get more callbacks from the RTP module.
   module_process_thread_.DeRegisterModule(vie_receiver_.GetReceiveStatistics());
   module_process_thread_.DeRegisterModule(rtp_rtcp_.get());
@@ -246,6 +249,55 @@
   VideoCodingModule::Destroy(vcm_);
 }
 
+void ViEChannel::UpdateHistograms() {
+  const float kMinCallLengthInMinutes = 0.5f;
+  float elapsed_minutes =
+      (Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_) / 60000.0f;
+  if (elapsed_minutes < kMinCallLengthInMinutes) {
+    return;
+  }
+  RtcpPacketTypeCounter rtcp_sent;
+  RtcpPacketTypeCounter rtcp_received;
+  GetRtcpPacketTypeCounters(&rtcp_sent, &rtcp_received);
+
+  if (sender_) {
+    if (rtcp_received.nack_requests > 0) {
+      RTC_HISTOGRAM_PERCENTAGE(
+          "WebRTC.Video.UniqueNackRequestsReceivedInPercent",
+              rtcp_received.UniqueNackRequestsInPercent());
+    }
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsReceivedPerMinute",
+        rtcp_received.nack_packets / elapsed_minutes);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsReceivedPerMinute",
+        rtcp_received.fir_packets / elapsed_minutes);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsReceivedPerMinute",
+        rtcp_received.pli_packets / elapsed_minutes);
+  } else if (vie_receiver_.GetRemoteSsrc() > 0)  {
+    // Get receive stats if we are receiving packets, i.e. there is a remote
+    // ssrc.
+    if (rtcp_sent.nack_requests > 0) {
+      RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
+          rtcp_sent.UniqueNackRequestsInPercent());
+    }
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
+        rtcp_sent.nack_packets / elapsed_minutes);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute",
+        rtcp_sent.fir_packets / elapsed_minutes);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute",
+        rtcp_sent.pli_packets / elapsed_minutes);
+
+    webrtc::VCMFrameCount frames;
+    if (vcm_->ReceivedFrameCount(frames) == VCM_OK) {
+      uint32_t total_frames = frames.numKeyFrames + frames.numDeltaFrames;
+      if (total_frames > 0) {
+        RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesReceivedInPermille",
+            static_cast<int>((frames.numKeyFrames * 1000.0f / total_frames) +
+                0.5f));
+      }
+    }
+  }
+}
+
 int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
                                  bool new_stream) {
   if (!sender_) {
diff --git a/video_engine/vie_channel.h b/video_engine/vie_channel.h
index e55ade7..0327906 100644
--- a/video_engine/vie_channel.h
+++ b/video_engine/vie_channel.h
@@ -383,6 +383,8 @@
   int GetRequiredNackListSize(int target_delay_ms);
   void SetRtxSendStatus(bool enable);
 
+  void UpdateHistograms();
+
   // ViEChannel exposes methods that allow to modify observers and callbacks
   // to be modified. Such an API-style is cumbersome to implement and maintain
   // at all the levels when comparing to only setting them at construction. As
@@ -499,6 +501,7 @@
   int nack_history_size_sender_;
   int max_nack_reordering_threshold_;
   I420FrameCallback* pre_render_callback_;
+  const int64_t start_ms_;
 
   std::map<uint32_t, RTCPReportBlock> prev_report_blocks_;
 };
diff --git a/video_engine/vie_channel_group.cc b/video_engine/vie_channel_group.cc
index c6b3f74..9c2d59f 100644
--- a/video_engine/vie_channel_group.cc
+++ b/video_engine/vie_channel_group.cc
@@ -41,7 +41,7 @@
         crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
         engine_id_(engine_id),
         min_bitrate_bps_(config.Get<RemoteBitrateEstimatorMinRate>().min_rate),
-        rate_control_type_(kMimdControl),
+        rate_control_type_(kAimdControl),
         rbe_(RemoteBitrateEstimatorFactory().Create(observer_,
                                                     clock_,
                                                     rate_control_type_,
diff --git a/video_engine/vie_codec_impl.cc b/video_engine/vie_codec_impl.cc
index f939a66..0ef039d 100644
--- a/video_engine/vie_codec_impl.cc
+++ b/video_engine/vie_codec_impl.cc
@@ -640,6 +640,8 @@
     return false;
   } else if ((video_codec.codecType == kVideoCodecVP8 &&
               strncmp(video_codec.plName, "VP8", 4) == 0) ||
+             (video_codec.codecType == kVideoCodecVP9 &&
+              strncmp(video_codec.plName, "VP9", 4) == 0) ||
              (video_codec.codecType == kVideoCodecI420 &&
               strncmp(video_codec.plName, "I420", 4) == 0) ||
              (video_codec.codecType == kVideoCodecH264 &&
diff --git a/video_engine/vie_encoder.cc b/video_engine/vie_encoder.cc
index 0955066..3cb0ae7 100644
--- a/video_engine/vie_encoder.cc
+++ b/video_engine/vie_encoder.cc
@@ -26,6 +26,7 @@
 #include "webrtc/system_wrappers/interface/clock.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/metrics.h"
 #include "webrtc/system_wrappers/interface/tick_util.h"
 #include "webrtc/system_wrappers/interface/trace_event.h"
 #include "webrtc/video_engine/include/vie_codec.h"
@@ -109,8 +110,10 @@
       : owner_(owner) {
   }
   virtual ~ViEPacedSenderCallback() {}
-  virtual bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number,
-                                int64_t capture_time_ms, bool retransmission) {
+  virtual bool TimeToSendPacket(uint32_t ssrc,
+                                uint16_t sequence_number,
+                                int64_t capture_time_ms,
+                                bool retransmission) {
     return owner_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms,
                                     retransmission);
   }
@@ -154,7 +157,8 @@
     picture_id_rpsi_(0),
     qm_callback_(NULL),
     video_suspended_(false),
-    pre_encode_callback_(NULL) {
+    pre_encode_callback_(NULL),
+    start_ms_(Clock::GetRealTimeClock()->TimeInMilliseconds()) {
   RtpRtcp::Configuration configuration;
   configuration.id = ViEModuleId(engine_id_, channel_id_);
   configuration.audio = false;  // Video.
@@ -162,9 +166,12 @@
   default_rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
   bitrate_observer_.reset(new ViEBitrateObserver(this));
   pacing_callback_.reset(new ViEPacedSenderCallback(this));
-  paced_sender_.reset(
-      new PacedSender(Clock::GetRealTimeClock(), pacing_callback_.get(),
-                      PacedSender::kDefaultInitialPaceKbps, 0));
+  paced_sender_.reset(new PacedSender(
+      Clock::GetRealTimeClock(),
+      pacing_callback_.get(),
+      kDefaultStartBitrateKbps,
+      PacedSender::kDefaultPaceMultiplier * kDefaultStartBitrateKbps,
+      0));
 }
 
 bool ViEEncoder::Init() {
@@ -220,6 +227,7 @@
 }
 
 ViEEncoder::~ViEEncoder() {
+  UpdateHistograms();
   if (bitrate_controller_) {
     bitrate_controller_->RemoveBitrateObserver(bitrate_observer_.get());
   }
@@ -232,6 +240,25 @@
   delete qm_callback_;
 }
 
+void ViEEncoder::UpdateHistograms() {
+  const float kMinCallLengthInMinutes = 0.5f;
+  float elapsed_minutes =
+      (Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_) / 60000.0f;
+  if (elapsed_minutes < kMinCallLengthInMinutes) {
+    return;
+  }
+  webrtc::VCMFrameCount frames;
+  if (vcm_.SentFrameCount(frames) != VCM_OK) {
+    return;
+  }
+  uint32_t total_frames = frames.numKeyFrames + frames.numDeltaFrames;
+  if (total_frames > 0) {
+    RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesSentInPermille",
+        static_cast<int>(
+            (frames.numKeyFrames * 1000.0f / total_frames) + 0.5f));
+  }
+}
+
 int ViEEncoder::Owner() const {
   return channel_id_;
 }
@@ -368,6 +395,7 @@
     pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_;
 
   paced_sender_->UpdateBitrate(
+      video_codec.startBitrate,
       PacedSender::kDefaultPaceMultiplier * video_codec.startBitrate,
       pad_up_to_bitrate_kbps);
 
@@ -442,9 +470,31 @@
         std::max(static_cast<int>(target_delay_ms_ * kEncoderPausePacerMargin),
                  kMinPacingDelayMs);
   }
+  if (paced_sender_->ExpectedQueueTimeMs() >
+      PacedSender::kDefaultMaxQueueLengthMs) {
+    // Too much data in pacer queue, drop frame.
+    return true;
+  }
   return !network_is_transmitting_;
 }
 
+void ViEEncoder::TraceFrameDropStart() {
+  // Start trace event only on the first frame after encoder is paused.
+  if (!encoder_paused_and_dropped_frame_) {
+    TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
+  }
+  encoder_paused_and_dropped_frame_ = true;
+  return;
+}
+
+void ViEEncoder::TraceFrameDropEnd() {
+  // End trace event on first frame after encoder resumes, if frame was dropped.
+  if (encoder_paused_and_dropped_frame_) {
+    TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
+  }
+  encoder_paused_and_dropped_frame_ = false;
+}
+
 RtpRtcp* ViEEncoder::SendRtpRtcpModule() {
   return default_rtp_rtcp_.get();
 }
@@ -461,16 +511,10 @@
     CriticalSectionScoped cs(data_cs_.get());
     time_of_last_incoming_frame_ms_ = TickTime::MillisecondTimestamp();
     if (EncoderPaused()) {
-      if (!encoder_paused_and_dropped_frame_) {
-        TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
-      }
-      encoder_paused_and_dropped_frame_ = true;
+      TraceFrameDropStart();
       return;
     }
-    if (encoder_paused_and_dropped_frame_) {
-      TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
-    }
-    encoder_paused_and_dropped_frame_ = false;
+    TraceFrameDropEnd();
   }
 
   // Convert render time, in ms, to RTP timestamp.
@@ -674,15 +718,10 @@
     // Disable external frame-droppers.
     vcm_.EnableFrameDropper(false);
     vpm_.EnableTemporalDecimation(false);
-    // We don't put any limits on the pacer queue when running in buffered mode
-    // since the encoder will be paused if the queue grow too large.
-    paced_sender_->set_max_queue_length_ms(-1);
   } else {
     // Real-time mode - enable frame droppers.
     vpm_.EnableTemporalDecimation(true);
     vcm_.EnableFrameDropper(true);
-    paced_sender_->set_max_queue_length_ms(
-        PacedSender::kDefaultMaxQueueLengthMs);
   }
 }
 
@@ -885,6 +924,7 @@
       pad_up_to_bitrate_kbps = bitrate_kbps;
 
     paced_sender_->UpdateBitrate(
+        bitrate_kbps,
         PacedSender::kDefaultPaceMultiplier * bitrate_kbps,
         pad_up_to_bitrate_kbps);
     default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);
diff --git a/video_engine/vie_encoder.h b/video_engine/vie_encoder.h
index 51c1d01..1e358de 100644
--- a/video_engine/vie_encoder.h
+++ b/video_engine/vie_encoder.h
@@ -192,6 +192,10 @@
   int TimeToSendPadding(int bytes);
  private:
   bool EncoderPaused() const EXCLUSIVE_LOCKS_REQUIRED(data_cs_);
+  void TraceFrameDropStart() EXCLUSIVE_LOCKS_REQUIRED(data_cs_);
+  void TraceFrameDropEnd() EXCLUSIVE_LOCKS_REQUIRED(data_cs_);
+
+  void UpdateHistograms();
 
   int32_t engine_id_;
   const int channel_id_;
@@ -235,6 +239,7 @@
   QMVideoSettingsCallback* qm_callback_;
   bool video_suspended_ GUARDED_BY(data_cs_);
   I420FrameCallback* pre_encode_callback_ GUARDED_BY(callback_cs_);
+  const int64_t start_ms_;
 };
 
 }  // namespace webrtc
diff --git a/video_engine_tests.isolate b/video_engine_tests.isolate
index 40454bd..fc84082 100644
--- a/video_engine_tests.isolate
+++ b/video_engine_tests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -20,14 +20,11 @@
         'command': [
           '<(PRODUCT_DIR)/video_engine_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/DEPS',
           '<(DEPTH)/resources/foreman_cif_short.yuv',
           '<(PRODUCT_DIR)/video_engine_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/video_receive_stream.h b/video_receive_stream.h
index 4eb5532..5ab898c 100644
--- a/video_receive_stream.h
+++ b/video_receive_stream.h
@@ -31,30 +31,38 @@
 
 class VideoDecoder;
 
-// TODO(mflodman) Move all these settings to VideoDecoder and move the
-// declaration to common_types.h.
-struct ExternalVideoDecoder {
-  ExternalVideoDecoder()
-      : decoder(NULL), payload_type(0), renderer(false), expected_delay_ms(0) {}
-  // The actual decoder.
-  VideoDecoder* decoder;
-
-  // Received RTP packets with this payload type will be sent to this decoder
-  // instance.
-  int payload_type;
-
-  // 'true' if the decoder handles rendering as well.
-  bool renderer;
-
-  // The expected delay for decoding and rendering, i.e. the frame will be
-  // delivered this many milliseconds, if possible, earlier than the ideal
-  // render time.
-  // Note: Ignored if 'renderer' is false.
-  int expected_delay_ms;
-};
-
 class VideoReceiveStream {
  public:
+  // TODO(mflodman) Move all these settings to VideoDecoder and move the
+  // declaration to common_types.h.
+  struct Decoder {
+    Decoder()
+        : decoder(NULL),
+          payload_type(0),
+          renderer(false),
+          expected_delay_ms(0) {}
+
+    // The actual decoder instance.
+    VideoDecoder* decoder;
+
+    // Received RTP packets with this payload type will be sent to this decoder
+    // instance.
+    int payload_type;
+
+    // Name of the decoded payload (such as VP8). Maps back to the depacketizer
+    // used to unpack incoming packets.
+    std::string payload_name;
+
+    // 'true' if the decoder handles rendering as well.
+    bool renderer;
+
+    // The expected delay for decoding and rendering, i.e. the frame will be
+    // delivered this many milliseconds, if possible, earlier than the ideal
+    // render time.
+    // Note: Ignored if 'renderer' is false.
+    int expected_delay_ms;
+  };
+
   struct Stats : public StreamStats {
     Stats()
         : network_frame_rate(0),
@@ -77,12 +85,13 @@
     Config()
         : renderer(NULL),
           render_delay_ms(0),
-          audio_channel_id(0),
+          audio_channel_id(-1),
           pre_decode_callback(NULL),
           pre_render_callback(NULL),
           target_delay_ms(0) {}
-    // Codecs the receive stream can receive.
-    std::vector<VideoCodec> codecs;
+
+    // Decoders for every payload that we can receive.
+    std::vector<Decoder> decoders;
 
     // Receive-stream specific RTP settings.
     struct Rtp {
@@ -162,10 +171,6 @@
     // stream. 'NULL' disables the callback.
     I420FrameCallback* pre_render_callback;
 
-    // External video decoders to be used if incoming payload type matches the
-    // registered type for an external decoder.
-    std::vector<ExternalVideoDecoder> external_decoders;
-
     // Target delay in milliseconds. A positive value indicates this stream is
     // used for streaming instead of a real-time call.
     int target_delay_ms;
@@ -173,10 +178,9 @@
 
   virtual void Start() = 0;
   virtual void Stop() = 0;
-  virtual Stats GetStats() const = 0;
 
-  // TODO(mflodman) Replace this with callback.
-  virtual void GetCurrentReceiveCodec(VideoCodec* receive_codec) = 0;
+  // TODO(pbos): Add info on currently-received codec to Stats.
+  virtual Stats GetStats() const = 0;
 
  protected:
   virtual ~VideoReceiveStream() {}
diff --git a/video_send_stream.h b/video_send_stream.h
index dd2bec1..aa5033a 100644
--- a/video_send_stream.h
+++ b/video_send_stream.h
@@ -60,6 +60,7 @@
 
     struct EncoderSettings {
       EncoderSettings() : payload_type(-1), encoder(NULL) {}
+
       std::string ToString() const;
 
       std::string payload_name;
@@ -72,9 +73,7 @@
 
     static const size_t kDefaultMaxPacketSize = 1500 - 40;  // TCP over IPv4.
     struct Rtp {
-      Rtp()
-          : max_packet_size(kDefaultMaxPacketSize),
-            min_transmit_bitrate_bps(0) {}
+      Rtp() : max_packet_size(kDefaultMaxPacketSize) {}
       std::string ToString() const;
 
       std::vector<uint32_t> ssrcs;
@@ -82,11 +81,6 @@
       // Max RTP packet size delivered to send transport from VideoEngine.
       size_t max_packet_size;
 
-      // Padding will be used up to this bitrate regardless of the bitrate
-      // produced by the encoder. Padding above what's actually produced by the
-      // encoder helps maintaining a higher bitrate estimate.
-      int min_transmit_bitrate_bps;
-
       // RTP header extensions to use for this send stream.
       std::vector<RtpExtension> extensions;
 
diff --git a/voice_engine/utility.cc b/voice_engine/utility.cc
index 561b4ef..f952d6c 100644
--- a/voice_engine/utility.cc
+++ b/voice_engine/utility.cc
@@ -22,8 +22,7 @@
 namespace voe {
 
 // TODO(ajm): There is significant overlap between RemixAndResample and
-// ConvertToCodecFormat, but if we're to consolidate we should probably make a
-// real converter class.
+// ConvertToCodecFormat. Consolidate using AudioConverter.
 void RemixAndResample(const AudioFrame& src_frame,
                       PushResampler<int16_t>* resampler,
                       AudioFrame* dst_frame) {
diff --git a/voice_engine/voe_auto_test.isolate b/voice_engine/voe_auto_test.isolate
index 3722b7d..c13110e 100644
--- a/voice_engine/voe_auto_test.isolate
+++ b/voice_engine/voe_auto_test.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,13 +21,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/voe_auto_test<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/voe_auto_test<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/voice_engine/voice_engine.gyp b/voice_engine/voice_engine.gyp
index deed467..83b356d 100644
--- a/voice_engine/voice_engine.gyp
+++ b/voice_engine/voice_engine.gyp
@@ -148,7 +148,7 @@
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
             '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
             '<(webrtc_root)/test/test.gyp:channel_transport',
             '<(webrtc_root)/test/test.gyp:test_support',
            ],
@@ -216,7 +216,7 @@
             '<(DEPTH)/testing/gtest.gyp:gtest',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
             '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
-            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
             '<(webrtc_root)/test/test.gyp:channel_transport',
             '<(webrtc_root)/test/test.gyp:test_support',
           ],
@@ -293,7 +293,6 @@
               ],
               'includes': [
                 '../build/isolate.gypi',
-                'voice_engine_unittests.isolate',
               ],
               'sources': [
                 'voice_engine_unittests.isolate',
@@ -307,7 +306,6 @@
               ],
               'includes': [
                 '../build/isolate.gypi',
-                'voe_auto_test.isolate',
               ],
               'sources': [
                 'voe_auto_test.isolate',
diff --git a/voice_engine/voice_engine.target.darwin-arm.mk b/voice_engine/voice_engine.target.darwin-arm.mk
index 10a0554..2b86f9c 100644
--- a/voice_engine/voice_engine.target.darwin-arm.mk
+++ b/voice_engine/voice_engine.target.darwin-arm.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -127,6 +129,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -229,11 +232,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -249,6 +254,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.darwin-arm64.mk b/voice_engine/voice_engine.target.darwin-arm64.mk
index 6c0fd63..62897d8 100644
--- a/voice_engine/voice_engine.target.darwin-arm64.mk
+++ b/voice_engine/voice_engine.target.darwin-arm64.mk
@@ -96,11 +96,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,10 +111,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -216,10 +222,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.darwin-mips.mk b/voice_engine/voice_engine.target.darwin-mips.mk
index c58e683..1b28efb 100644
--- a/voice_engine/voice_engine.target.darwin-mips.mk
+++ b/voice_engine/voice_engine.target.darwin-mips.mk
@@ -100,11 +100,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -119,6 +121,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -214,11 +217,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -233,6 +238,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.darwin-mips64.mk b/voice_engine/voice_engine.target.darwin-mips64.mk
new file mode 100644
index 0000000..8878576
--- /dev/null
+++ b/voice_engine/voice_engine.target.darwin-mips64.mk
@@ -0,0 +1,301 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_voice_engine_voice_engine_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/voice_engine/channel.cc \
+	third_party/webrtc/voice_engine/channel_manager.cc \
+	third_party/webrtc/voice_engine/dtmf_inband.cc \
+	third_party/webrtc/voice_engine/dtmf_inband_queue.cc \
+	third_party/webrtc/voice_engine/level_indicator.cc \
+	third_party/webrtc/voice_engine/monitor_module.cc \
+	third_party/webrtc/voice_engine/network_predictor.cc \
+	third_party/webrtc/voice_engine/output_mixer.cc \
+	third_party/webrtc/voice_engine/shared_data.cc \
+	third_party/webrtc/voice_engine/statistics.cc \
+	third_party/webrtc/voice_engine/transmit_mixer.cc \
+	third_party/webrtc/voice_engine/utility.cc \
+	third_party/webrtc/voice_engine/voe_audio_processing_impl.cc \
+	third_party/webrtc/voice_engine/voe_base_impl.cc \
+	third_party/webrtc/voice_engine/voe_codec_impl.cc \
+	third_party/webrtc/voice_engine/voe_dtmf_impl.cc \
+	third_party/webrtc/voice_engine/voe_external_media_impl.cc \
+	third_party/webrtc/voice_engine/voe_file_impl.cc \
+	third_party/webrtc/voice_engine/voe_hardware_impl.cc \
+	third_party/webrtc/voice_engine/voe_neteq_stats_impl.cc \
+	third_party/webrtc/voice_engine/voe_network_impl.cc \
+	third_party/webrtc/voice_engine/voe_rtp_rtcp_impl.cc \
+	third_party/webrtc/voice_engine/voe_video_sync_impl.cc \
+	third_party/webrtc/voice_engine/voe_volume_control_impl.cc \
+	third_party/webrtc/voice_engine/voice_engine_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_voice_engine_voice_engine_gyp
+
+# Alias gyp target name.
+.PHONY: voice_engine
+voice_engine: third_party_webrtc_voice_engine_voice_engine_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/voice_engine/voice_engine.target.darwin-x86.mk b/voice_engine/voice_engine.target.darwin-x86.mk
index af4c7ad..3e1bcae 100644
--- a/voice_engine/voice_engine.target.darwin-x86.mk
+++ b/voice_engine/voice_engine.target.darwin-x86.mk
@@ -102,11 +102,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -119,6 +121,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -215,11 +218,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -232,6 +237,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.darwin-x86_64.mk b/voice_engine/voice_engine.target.darwin-x86_64.mk
index 6a78b6b..55afb79 100644
--- a/voice_engine/voice_engine.target.darwin-x86_64.mk
+++ b/voice_engine/voice_engine.target.darwin-x86_64.mk
@@ -101,11 +101,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -118,6 +120,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -213,11 +216,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -230,6 +235,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.linux-arm.mk b/voice_engine/voice_engine.target.linux-arm.mk
index 10a0554..2b86f9c 100644
--- a/voice_engine/voice_engine.target.linux-arm.mk
+++ b/voice_engine/voice_engine.target.linux-arm.mk
@@ -107,11 +107,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -127,6 +129,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -229,11 +232,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -249,6 +254,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.linux-arm64.mk b/voice_engine/voice_engine.target.linux-arm64.mk
index 6c0fd63..62897d8 100644
--- a/voice_engine/voice_engine.target.linux-arm64.mk
+++ b/voice_engine/voice_engine.target.linux-arm64.mk
@@ -96,11 +96,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,10 +111,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -203,11 +207,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -216,10 +222,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.linux-mips.mk b/voice_engine/voice_engine.target.linux-mips.mk
index c58e683..1b28efb 100644
--- a/voice_engine/voice_engine.target.linux-mips.mk
+++ b/voice_engine/voice_engine.target.linux-mips.mk
@@ -100,11 +100,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -119,6 +121,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -214,11 +217,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -233,6 +238,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.linux-mips64.mk b/voice_engine/voice_engine.target.linux-mips64.mk
new file mode 100644
index 0000000..8878576
--- /dev/null
+++ b/voice_engine/voice_engine.target.linux-mips64.mk
@@ -0,0 +1,301 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_voice_engine_voice_engine_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/voice_engine/channel.cc \
+	third_party/webrtc/voice_engine/channel_manager.cc \
+	third_party/webrtc/voice_engine/dtmf_inband.cc \
+	third_party/webrtc/voice_engine/dtmf_inband_queue.cc \
+	third_party/webrtc/voice_engine/level_indicator.cc \
+	third_party/webrtc/voice_engine/monitor_module.cc \
+	third_party/webrtc/voice_engine/network_predictor.cc \
+	third_party/webrtc/voice_engine/output_mixer.cc \
+	third_party/webrtc/voice_engine/shared_data.cc \
+	third_party/webrtc/voice_engine/statistics.cc \
+	third_party/webrtc/voice_engine/transmit_mixer.cc \
+	third_party/webrtc/voice_engine/utility.cc \
+	third_party/webrtc/voice_engine/voe_audio_processing_impl.cc \
+	third_party/webrtc/voice_engine/voe_base_impl.cc \
+	third_party/webrtc/voice_engine/voe_codec_impl.cc \
+	third_party/webrtc/voice_engine/voe_dtmf_impl.cc \
+	third_party/webrtc/voice_engine/voe_external_media_impl.cc \
+	third_party/webrtc/voice_engine/voe_file_impl.cc \
+	third_party/webrtc/voice_engine/voe_hardware_impl.cc \
+	third_party/webrtc/voice_engine/voe_neteq_stats_impl.cc \
+	third_party/webrtc/voice_engine/voe_network_impl.cc \
+	third_party/webrtc/voice_engine/voe_rtp_rtcp_impl.cc \
+	third_party/webrtc/voice_engine/voe_video_sync_impl.cc \
+	third_party/webrtc/voice_engine/voe_volume_control_impl.cc \
+	third_party/webrtc/voice_engine/voice_engine_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/resampler/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/signal_processing/include \
+	$(LOCAL_PATH)/third_party/webrtc/common_audio/vad/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_coding/main/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/interface \
+	$(LOCAL_PATH)/third_party/webrtc \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_conference_mixer/interface \
+	$(LOCAL_PATH)/third_party/webrtc/modules/audio_device/include \
+	$(LOCAL_PATH)/third_party/webrtc/modules/media_file/interface \
+	$(LOCAL_PATH)/third_party/webrtc/system_wrappers/interface
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_voice_engine_voice_engine_gyp
+
+# Alias gyp target name.
+.PHONY: voice_engine
+voice_engine: third_party_webrtc_voice_engine_voice_engine_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/voice_engine/voice_engine.target.linux-x86.mk b/voice_engine/voice_engine.target.linux-x86.mk
index af4c7ad..3e1bcae 100644
--- a/voice_engine/voice_engine.target.linux-x86.mk
+++ b/voice_engine/voice_engine.target.linux-x86.mk
@@ -102,11 +102,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -119,6 +121,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -215,11 +218,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -232,6 +237,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine.target.linux-x86_64.mk b/voice_engine/voice_engine.target.linux-x86_64.mk
index 6a78b6b..55afb79 100644
--- a/voice_engine/voice_engine.target.linux-x86_64.mk
+++ b/voice_engine/voice_engine.target.linux-x86_64.mk
@@ -101,11 +101,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -118,6 +120,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -213,11 +216,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -230,6 +235,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/voice_engine/voice_engine_unittests.isolate b/voice_engine/voice_engine_unittests.isolate
index 0235680..4cd1f90 100644
--- a/voice_engine/voice_engine_unittests.isolate
+++ b/voice_engine/voice_engine_unittests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -21,13 +21,10 @@
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/voice_engine_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/testing/test_env.py',
           '<(PRODUCT_DIR)/voice_engine_unittests<(EXECUTABLE_SUFFIX)',
         ],
-       'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/webrtc.gyp b/webrtc.gyp
index bfcec04..f9ed883 100644
--- a/webrtc.gyp
+++ b/webrtc.gyp
@@ -10,6 +10,8 @@
     ['include_tests==1', {
       'includes': [
         'libjingle/xmllite/xmllite_tests.gypi',
+        'libjingle/xmpp/xmpp_tests.gypi',
+        'p2p/p2p_tests.gypi',
         'sound/sound_tests.gypi',
         'webrtc_tests.gypi',
       ],
@@ -27,11 +29,14 @@
       'common_audio/common_audio.gyp:*',
       'common_video/common_video.gyp:*',
       'libjingle/xmllite/xmllite.gyp:*',
+      'libjingle/xmpp/xmpp.gyp:*',
       'modules/modules.gyp:*',
+      'p2p/p2p.gyp:*',
       'system_wrappers/source/system_wrappers.gyp:*',
       'video_engine/video_engine.gyp:*',
       'voice_engine/voice_engine.gyp:*',
       '<(webrtc_vp8_dir)/vp8.gyp:*',
+      '<(webrtc_vp9_dir)/vp9.gyp:*',
     ],
   },
   'targets': [
diff --git a/webrtc.target.darwin-arm.mk b/webrtc.target.darwin-arm.mk
index ce02281..6395a83 100644
--- a/webrtc.target.darwin-arm.mk
+++ b/webrtc.target.darwin-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +204,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.darwin-arm64.mk b/webrtc.target.darwin-arm64.mk
index 6b65797..b14a1ef 100644
--- a/webrtc.target.darwin-arm64.mk
+++ b/webrtc.target.darwin-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -175,11 +179,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -188,10 +194,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.darwin-mips.mk b/webrtc.target.darwin-mips.mk
index 21c735f..06bb28b 100644
--- a/webrtc.target.darwin-mips.mk
+++ b/webrtc.target.darwin-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -186,11 +189,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.darwin-mips64.mk b/webrtc.target.darwin-mips64.mk
new file mode 100644
index 0000000..e24144c
--- /dev/null
+++ b/webrtc.target.darwin-mips64.mk
@@ -0,0 +1,263 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_webrtc_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/video/call.cc \
+	third_party/webrtc/video/encoded_frame_callback_adapter.cc \
+	third_party/webrtc/video/send_statistics_proxy.cc \
+	third_party/webrtc/video/receive_statistics_proxy.cc \
+	third_party/webrtc/video/transport_adapter.cc \
+	third_party/webrtc/video/video_receive_stream.cc \
+	third_party/webrtc/video/video_send_stream.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_webrtc_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc
+webrtc: third_party_webrtc_webrtc_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc.target.darwin-x86.mk b/webrtc.target.darwin-x86.mk
index ed38533..8365cfa 100644
--- a/webrtc.target.darwin-x86.mk
+++ b/webrtc.target.darwin-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.darwin-x86_64.mk b/webrtc.target.darwin-x86_64.mk
index a68c725..5bdde76 100644
--- a/webrtc.target.darwin-x86_64.mk
+++ b/webrtc.target.darwin-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -185,11 +188,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -202,6 +207,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.linux-arm.mk b/webrtc.target.linux-arm.mk
index ce02281..6395a83 100644
--- a/webrtc.target.linux-arm.mk
+++ b/webrtc.target.linux-arm.mk
@@ -89,11 +89,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -109,6 +111,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -201,11 +204,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -221,6 +226,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.linux-arm64.mk b/webrtc.target.linux-arm64.mk
index 6b65797..b14a1ef 100644
--- a/webrtc.target.linux-arm64.mk
+++ b/webrtc.target.linux-arm64.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -91,10 +93,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -175,11 +179,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -188,10 +194,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.linux-mips.mk b/webrtc.target.linux-mips.mk
index 21c735f..06bb28b 100644
--- a/webrtc.target.linux-mips.mk
+++ b/webrtc.target.linux-mips.mk
@@ -82,11 +82,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -186,11 +189,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -205,6 +210,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.linux-mips64.mk b/webrtc.target.linux-mips64.mk
new file mode 100644
index 0000000..e24144c
--- /dev/null
+++ b/webrtc.target.linux-mips64.mk
@@ -0,0 +1,263 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_webrtc_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/video/call.cc \
+	third_party/webrtc/video/encoded_frame_callback_adapter.cc \
+	third_party/webrtc/video/send_statistics_proxy.cc \
+	third_party/webrtc/video/receive_statistics_proxy.cc \
+	third_party/webrtc/video/transport_adapter.cc \
+	third_party/webrtc/video/video_receive_stream.cc \
+	third_party/webrtc/video/video_send_stream.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_webrtc_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc
+webrtc: third_party_webrtc_webrtc_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc.target.linux-x86.mk b/webrtc.target.linux-x86.mk
index ed38533..8365cfa 100644
--- a/webrtc.target.linux-x86.mk
+++ b/webrtc.target.linux-x86.mk
@@ -84,11 +84,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -101,6 +103,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -187,11 +190,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -204,6 +209,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc.target.linux-x86_64.mk b/webrtc.target.linux-x86_64.mk
index a68c725..5bdde76 100644
--- a/webrtc.target.linux-x86_64.mk
+++ b/webrtc.target.linux-x86_64.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -100,6 +102,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -185,11 +188,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -202,6 +207,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.darwin-arm.mk b/webrtc_common.target.darwin-arm.mk
index aa34248..9464538 100644
--- a/webrtc_common.target.darwin-arm.mk
+++ b/webrtc_common.target.darwin-arm.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -103,6 +105,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.darwin-arm64.mk b/webrtc_common.target.darwin-arm64.mk
index 8d6a4cd..882b81b 100644
--- a/webrtc_common.target.darwin-arm64.mk
+++ b/webrtc_common.target.darwin-arm64.mk
@@ -72,11 +72,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -85,10 +87,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -169,11 +173,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -182,10 +188,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.darwin-mips.mk b/webrtc_common.target.darwin-mips.mk
index 9b6bc75..9270d93 100644
--- a/webrtc_common.target.darwin-mips.mk
+++ b/webrtc_common.target.darwin-mips.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,6 +97,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -180,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -199,6 +204,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.darwin-mips64.mk b/webrtc_common.target.darwin-mips64.mk
new file mode 100644
index 0000000..be67b86
--- /dev/null
+++ b/webrtc_common.target.darwin-mips64.mk
@@ -0,0 +1,257 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_webrtc_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/config.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_webrtc_common_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_common
+webrtc_common: third_party_webrtc_webrtc_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc_common.target.darwin-x86.mk b/webrtc_common.target.darwin-x86.mk
index 2d7b03b..3f123a3 100644
--- a/webrtc_common.target.darwin-x86.mk
+++ b/webrtc_common.target.darwin-x86.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,6 +97,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.darwin-x86_64.mk b/webrtc_common.target.darwin-x86_64.mk
index a89d1ed..05aebf0 100644
--- a/webrtc_common.target.darwin-x86_64.mk
+++ b/webrtc_common.target.darwin-x86_64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -94,6 +96,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -196,6 +201,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.linux-arm.mk b/webrtc_common.target.linux-arm.mk
index aa34248..9464538 100644
--- a/webrtc_common.target.linux-arm.mk
+++ b/webrtc_common.target.linux-arm.mk
@@ -83,11 +83,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -103,6 +105,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -195,11 +198,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -215,6 +220,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.linux-arm64.mk b/webrtc_common.target.linux-arm64.mk
index 8d6a4cd..882b81b 100644
--- a/webrtc_common.target.linux-arm64.mk
+++ b/webrtc_common.target.linux-arm64.mk
@@ -72,11 +72,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -85,10 +87,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -169,11 +173,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -182,10 +188,12 @@
 	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
 	'-DWEBRTC_CHROMIUM_BUILD' \
 	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_ARCH_ARM' \
 	'-DWEBRTC_POSIX' \
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.linux-mips.mk b/webrtc_common.target.linux-mips.mk
index 9b6bc75..9270d93 100644
--- a/webrtc_common.target.linux-mips.mk
+++ b/webrtc_common.target.linux-mips.mk
@@ -76,11 +76,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,6 +97,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -180,11 +183,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -199,6 +204,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.linux-mips64.mk b/webrtc_common.target.linux-mips64.mk
new file mode 100644
index 0000000..be67b86
--- /dev/null
+++ b/webrtc_common.target.linux-mips64.mk
@@ -0,0 +1,257 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_webrtc_webrtc_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)
+LOCAL_SDK_VERSION := 21
+gyp_intermediate_dir := $(call local-intermediates-dir,,$(GYP_VAR_PREFIX))
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	third_party/webrtc/config.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-g \
+	-gdwarf-4 \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Debug := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-unused-local-typedefs \
+	-fno-builtin-cos \
+	-fno-builtin-sin \
+	-fno-builtin-cosf \
+	-fno-builtin-sinf \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Wno-unused-but-set-variable \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer \
+	-funwind-tables
+
+MY_DEFS_Release := \
+	'-DV8_DEPRECATION_WARNINGS' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DENABLE_WEBRTC=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDONT_EMBED_BUILD_METADATA' \
+	'-DCLD_VERSION=1' \
+	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
+	'-DENABLE_MANAGED_USERS=1' \
+	'-DVIDEO_HOLE=1' \
+	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
+	'-DWEBRTC_RESTRICT_LOGGING' \
+	'-DEXPAT_RELATIVE_PATH' \
+	'-DWEBRTC_MODULE_UTILITY_VIDEO' \
+	'-DWEBRTC_CHROMIUM_BUILD' \
+	'-DLOGGING_INSIDE_WEBRTC' \
+	'-DWEBRTC_POSIX' \
+	'-DWEBRTC_LINUX' \
+	'-DWEBRTC_ANDROID' \
+	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DUSE_OPENSSL_CERTS=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/webrtc/overrides \
+	$(LOCAL_PATH)/third_party
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-exceptions \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-uninitialized \
+	-std=gnu++11 \
+	-Wno-narrowing \
+	-Wno-literal-suffix \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+### Rules for final target.
+### Set directly by aosp_build_settings.
+LOCAL_CLANG := false
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_webrtc_webrtc_common_gyp
+
+# Alias gyp target name.
+.PHONY: webrtc_common
+webrtc_common: third_party_webrtc_webrtc_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc_common.target.linux-x86.mk b/webrtc_common.target.linux-x86.mk
index 2d7b03b..3f123a3 100644
--- a/webrtc_common.target.linux-x86.mk
+++ b/webrtc_common.target.linux-x86.mk
@@ -78,11 +78,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -95,6 +97,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -181,11 +184,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -198,6 +203,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_common.target.linux-x86_64.mk b/webrtc_common.target.linux-x86_64.mk
index a89d1ed..05aebf0 100644
--- a/webrtc_common.target.linux-x86_64.mk
+++ b/webrtc_common.target.linux-x86_64.mk
@@ -77,11 +77,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -94,6 +96,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
@@ -179,11 +182,13 @@
 	'-DUSE_PROPRIETARY_CODECS' \
 	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_NOTIFICATIONS' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
-	'-DENABLE_EGLIMAGE=1' \
+	'-DDONT_EMBED_BUILD_METADATA' \
 	'-DCLD_VERSION=1' \
 	'-DENABLE_PRINTING=1' \
+	'-DENABLE_BASIC_PRINTING=1' \
 	'-DENABLE_MANAGED_USERS=1' \
 	'-DVIDEO_HOLE=1' \
 	'-DENABLE_LOAD_COMPLETION_HACKS=1' \
@@ -196,6 +201,7 @@
 	'-DWEBRTC_LINUX' \
 	'-DWEBRTC_ANDROID' \
 	'-DWEBRTC_ANDROID_OPENSLES' \
+	'-DUSE_LIBPCI=1' \
 	'-DUSE_OPENSSL=1' \
 	'-DUSE_OPENSSL_CERTS=1' \
 	'-D__STDC_CONSTANT_MACROS' \
diff --git a/webrtc_examples.gyp b/webrtc_examples.gyp
index 0c7293f..4d63110 100644
--- a/webrtc_examples.gyp
+++ b/webrtc_examples.gyp
@@ -18,7 +18,7 @@
             '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
             '<(webrtc_root)/modules/modules.gyp:video_capture_module_internal_impl',
 	    '<(webrtc_root)/modules/modules.gyp:video_render_module_internal_impl',
-            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+            '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
             '<(webrtc_root)/test/test.gyp:channel_transport',
             '<(webrtc_root)/video_engine/video_engine.gyp:video_engine_core',
             '<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
diff --git a/webrtc_perf_tests.isolate b/webrtc_perf_tests.isolate
index b39c83d..2c547be 100644
--- a/webrtc_perf_tests.isolate
+++ b/webrtc_perf_tests.isolate
@@ -9,7 +9,7 @@
   'conditions': [
     ['OS=="android"', {
       'variables': {
-        'isolate_dependency_untracked': [
+        'files': [
           '<(DEPTH)/data/',
           '<(DEPTH)/resources/',
         ],
@@ -20,16 +20,13 @@
         'command': [
           '<(PRODUCT_DIR)/webrtc_perf_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_tracked': [
+        'files': [
           '<(DEPTH)/DEPS',
           '<(DEPTH)/resources/foreman_cif.yuv',
           '<(DEPTH)/resources/paris_qcif.yuv',
           '<(DEPTH)/resources/voice_engine/audio_long16.pcm',
           '<(PRODUCT_DIR)/webrtc_perf_tests<(EXECUTABLE_SUFFIX)',
         ],
-        'isolate_dependency_untracked': [
-          '<(DEPTH)/tools/swarming_client/',
-        ],
       },
     }],
   ],
diff --git a/webrtc_tests.gypi b/webrtc_tests.gypi
index cfd5a4b..dc17e70 100644
--- a/webrtc_tests.gypi
+++ b/webrtc_tests.gypi
@@ -15,8 +15,12 @@
         'base/base_tests.gyp:rtc_base_tests_utils',
         'base/base_tests.gyp:rtc_base_tests',
         'libjingle/xmllite/xmllite.gyp:rtc_xmllite',
+        'libjingle/xmpp/xmpp.gyp:rtc_xmpp',
+        'p2p/p2p.gyp:rtc_p2p',
+        'rtc_p2p_unittest',
         'rtc_sound_tests',
         'rtc_xmllite_unittest',
+        'rtc_xmpp_unittest',
         'sound/sound.gyp:rtc_sound',
         '<(DEPTH)/testing/gtest.gyp:gtest',
       ],
@@ -52,8 +56,10 @@
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
         'test/webrtc_test_common.gyp:webrtc_test_common',
         'test/webrtc_test_common.gyp:webrtc_test_renderer',
+        '<(webrtc_root)/modules/modules.gyp:video_capture_module_internal_impl',
         '<(webrtc_root)/modules/modules.gyp:video_render_module_impl',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
+        'test/test.gyp:test_main',
         'webrtc',
       ],
     },
@@ -78,8 +84,9 @@
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
         'test/webrtc_test_common.gyp:webrtc_test_common',
         'test/webrtc_test_common.gyp:webrtc_test_renderer',
+        '<(webrtc_root)/modules/modules.gyp:video_capture_module_impl',
         '<(webrtc_root)/modules/modules.gyp:video_render_module_impl',
-        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+        '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
         'webrtc',
       ],
     },
@@ -97,6 +104,7 @@
       'dependencies': [
         '<(DEPTH)/testing/gtest.gyp:gtest',
         '<(webrtc_root)/modules/modules.gyp:rtp_rtcp',
+        '<(webrtc_root)/modules/modules.gyp:video_capture_module_impl',
         '<(webrtc_root)/modules/modules.gyp:video_render_module_impl',
         'test/metrics.gyp:metrics',
         'test/webrtc_test_common.gyp:webrtc_test_common',
@@ -125,6 +133,7 @@
         '<(DEPTH)/testing/gtest.gyp:gtest',
         'modules/modules.gyp:neteq_test_support',  # Needed by neteq_performance_unittest.
         'modules/modules.gyp:rtp_rtcp',
+        '<(webrtc_root)/modules/modules.gyp:video_capture_module_impl',
         'test/webrtc_test_common.gyp:webrtc_test_common',
         'test/test.gyp:test_main',
         'webrtc',
@@ -167,7 +176,6 @@
           ],
           'includes': [
             'build/isolate.gypi',
-            'rtc_unittests.isolate',
           ],
           'sources': [
             'rtc_unittests.isolate',
@@ -181,7 +189,6 @@
           ],
           'includes': [
             'build/isolate.gypi',
-            'video_engine_tests.isolate',
           ],
           'sources': [
             'video_engine_tests.isolate',
@@ -195,7 +202,6 @@
           ],
           'includes': [
             'build/isolate.gypi',
-            'webrtc_perf_tests.isolate',
           ],
           'sources': [
             'webrtc_perf_tests.isolate',