Bug 877954 - Implement Load Management service. Add callbacks to ViEncoder. r=jesup
authorGian-Carlo Pascutto <gpascutto@mozilla.com>
Thu, 13 Mar 2014 11:05:27 +0100
changeset 190594 519ae59fa49e5f2e796076c9a34f4624e67da6f0
parent 190593 638dd7ab1dc88c35a1d9e42a74feb16b3edcfa71
child 190595 7d879d9643edadb953af9ab1bb6c6c7273e0c480
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs877954
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 877954 - Implement Load Management service. Add callbacks to ViEncoder. r=jesup
content/media/webrtc/LoadManager.cpp
content/media/webrtc/LoadManager.h
content/media/webrtc/LoadManagerFactory.cpp
content/media/webrtc/LoadManagerFactory.h
content/media/webrtc/LoadMonitor.cpp
content/media/webrtc/LoadMonitor.h
content/media/webrtc/MediaEngine.h
content/media/webrtc/MediaEngineWebRTC.cpp
content/media/webrtc/MediaEngineWebRTC.h
content/media/webrtc/moz.build
dom/media/MediaManager.cpp
media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
media/webrtc/signaling/src/media-conduit/CodecConfig.h
media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
media/webrtc/trunk/webrtc/common_types.h
media/webrtc/trunk/webrtc/video_engine/include/vie_base.h
media/webrtc/trunk/webrtc/video_engine/vie_base_impl.cc
media/webrtc/trunk/webrtc/video_engine/vie_base_impl.h
media/webrtc/trunk/webrtc/video_engine/vie_channel_manager.cc
media/webrtc/trunk/webrtc/video_engine/vie_channel_manager.h
media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc
media/webrtc/trunk/webrtc/video_engine/vie_encoder.h
media/webrtc/trunk/webrtc/video_engine/vie_shared_data.cc
media/webrtc/trunk/webrtc/video_engine/vie_shared_data.h
modules/libpref/src/init/all.js
new file mode 100644
--- /dev/null
+++ b/content/media/webrtc/LoadManager.cpp
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "LoadManager.h"
+#include "LoadMonitor.h"
+#include "nsString.h"
+#include "prlog.h"
+#include "prtime.h"
+#include "prinrval.h"
+#include "prsystem.h"
+
+#include "nsString.h"
+#include "nsThreadUtils.h"
+#include "nsReadableUtils.h"
+#include "nsNetUtil.h"
+
+// NSPR_LOG_MODULES=LoadManager:5
+PRLogModuleInfo *gLoadManagerLog = nullptr;
+#undef LOG
+#undef LOG_ENABLED
+#if defined(PR_LOGGING)
+#define LOG(args) PR_LOG(gLoadManagerLog, PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(gLoadManagerLog, 5)
+#else
+#define LOG(args)
+#define LOG_ENABLED() (false)
+#endif
+
+namespace mozilla {
+
+LoadManager::LoadManager(int aLoadMeasurementInterval,
+                         int aAveragingMeasurements,
+                         float aHighLoadThreshold,
+                         float aLowLoadThreshold)
+  : mLastSystemLoad(0),
+    mLoadSum(0.0f),
+    mLoadSumMeasurements(0),
+    mOveruseActive(false),
+    mLoadMeasurementInterval(aLoadMeasurementInterval),
+    mAveragingMeasurements(aAveragingMeasurements),
+    mHighLoadThreshold(aHighLoadThreshold),
+    mLowLoadThreshold(aLowLoadThreshold),
+    mCurrentState(webrtc::kLoadNormal)
+{
+#if defined(PR_LOGGING)
+  if (!gLoadManagerLog)
+    gLoadManagerLog = PR_NewLogModule("LoadManager");
+#endif
+  LOG(("LoadManager - Initializing (%dms x %d, %f, %f)",
+       mLoadMeasurementInterval, mAveragingMeasurements,
+       mHighLoadThreshold, mLowLoadThreshold));
+  MOZ_ASSERT(mHighLoadThreshold > mLowLoadThreshold);
+  mLoadMonitor = new LoadMonitor(mLoadMeasurementInterval);
+  mLoadMonitor->Init(mLoadMonitor);
+  mLoadMonitor->SetLoadChangeCallback(this);
+}
+
+LoadManager::~LoadManager()
+{
+  mLoadMonitor->Shutdown();
+}
+
+void
+LoadManager::LoadChanged(float aSystemLoad, float aProcesLoad)
+{
+  // Update total load, and total amount of measured seconds.
+  mLoadSum += aSystemLoad;
+  mLoadSumMeasurements++;
+
+  if (mLoadSumMeasurements >= mAveragingMeasurements) {
+    double averagedLoad = mLoadSum / (float)mLoadSumMeasurements;
+
+    webrtc::CPULoadState oldState = mCurrentState;
+
+    if (mOveruseActive || averagedLoad > mHighLoadThreshold) {
+      LOG(("LoadManager - LoadStressed"));
+      mCurrentState = webrtc::kLoadStressed;
+    } else if (averagedLoad < mLowLoadThreshold) {
+      LOG(("LoadManager - LoadRelaxed"));
+      mCurrentState = webrtc::kLoadRelaxed;
+    } else {
+      LOG(("LoadManager - LoadNormal"));
+      mCurrentState = webrtc::kLoadNormal;
+    }
+
+    if (oldState != mCurrentState)
+      LoadHasChanged();
+
+    mLoadSum = 0;
+    mLoadSumMeasurements = 0;
+  }
+}
+
+void
+LoadManager::OveruseDetected()
+{
+  LOG(("LoadManager - Overuse Detected"));
+  mOveruseActive = true;
+  if (mCurrentState != webrtc::kLoadStressed) {
+    mCurrentState = webrtc::kLoadStressed;
+    LoadHasChanged();
+  }
+}
+
+void
+LoadManager::NormalUsage()
+{
+  LOG(("LoadManager - Overuse finished"));
+  mOveruseActive = false;
+}
+
+void
+LoadManager::LoadHasChanged()
+{
+  LOG(("LoadManager - Signaling LoadHasChanged to %d listeners", mObservers.Length()));
+  for (size_t i = 0; i < mObservers.Length(); i++) {
+    mObservers.ElementAt(i)->onLoadStateChanged(mCurrentState);
+  }
+}
+
+void
+LoadManager::AddObserver(webrtc::CPULoadStateObserver * aObserver)
+{
+  LOG(("LoadManager - Adding Observer"));
+  mObservers.AppendElement(aObserver);
+}
+
+void
+LoadManager::RemoveObserver(webrtc::CPULoadStateObserver * aObserver)
+{
+  LOG(("LoadManager - Removing Observer"));
+  if (!mObservers.RemoveElement(aObserver)) {
+    LOG(("LOadManager - Element to remove not found"));
+  }
+}
+
+
+}
new file mode 100644
--- /dev/null
+++ b/content/media/webrtc/LoadManager.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _LOADMANAGER_H_
+#define _LOADMANAGER_H_
+
+#include "LoadMonitor.h"
+#include "webrtc/common_types.h"
+#include "webrtc/video_engine/include/vie_base.h"
+#include "mozilla/TimeStamp.h"
+#include "nsTArray.h"
+
+extern PRLogModuleInfo *gLoadManagerLog;
+
+namespace mozilla {
+
+class LoadManager : public LoadNotificationCallback,
+                    public webrtc::CPULoadStateCallbackInvoker,
+                    public webrtc::CpuOveruseObserver
+{
+public:
+    LoadManager(int aLoadMeasurementInterval,
+                int aAveragingMeasurements,
+                float aHighLoadThreshold,
+                float aLowLoadThreshold);
+    ~LoadManager();
+
+    // LoadNotificationCallback interface
+    virtual void LoadChanged(float aSystemLoad, float aProcessLoad) MOZ_OVERRIDE;
+    // CpuOveruseObserver interface
+    // Called as soon as an overuse is detected.
+    virtual void OveruseDetected() MOZ_OVERRIDE;
+    // Called periodically when the system is not overused any longer.
+    virtual void NormalUsage() MOZ_OVERRIDE;
+    // CPULoadStateCallbackInvoker interface
+    virtual void AddObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE;
+    virtual void RemoveObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE;
+
+private:
+    void LoadHasChanged();
+
+    nsRefPtr<LoadMonitor> mLoadMonitor;
+    float mLastSystemLoad;
+    float mLoadSum;
+    int   mLoadSumMeasurements;
+    // Set when overuse was signaled to us, and hasn't been un-signaled yet.
+    bool  mOveruseActive;
+    // Load measurement settings
+    int mLoadMeasurementInterval;
+    int mAveragingMeasurements;
+    float mHighLoadThreshold;
+    float mLowLoadThreshold;
+
+    webrtc::CPULoadState mCurrentState;
+
+    nsTArray<webrtc::CPULoadStateObserver*> mObservers;
+};
+
+} //namespace
+
+#endif /* _LOADMANAGER_H_ */
new file mode 100644
--- /dev/null
+++ b/content/media/webrtc/LoadManagerFactory.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "LoadManager.h"
+#include "LoadManagerFactory.h"
+#include "MainThreadUtils.h"
+
+#include "mozilla/Preferences.h"
+
+namespace mozilla {
+
+LoadManager* LoadManagerBuild(void)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  int loadMeasurementInterval =
+    mozilla::Preferences::GetInt("media.navigator.load_adapt.measure_interval", 1000);
+  int averagingSeconds =
+    mozilla::Preferences::GetInt("media.navigator.load_adapt.avg_seconds", 3);
+  float highLoadThreshold =
+    mozilla::Preferences::GetFloat("media.navigator.load_adapt.high_load", 0.90);
+  float lowLoadThreshold =
+    mozilla::Preferences::GetFloat("media.navigator.load_adapt.low_load", 0.40);
+
+  return new LoadManager(loadMeasurementInterval,
+                         averagingSeconds,
+                         highLoadThreshold,
+                         lowLoadThreshold);
+}
+
+void LoadManagerDestroy(mozilla::LoadManager* aLoadManager)
+{
+  delete aLoadManager;
+}
+
+}; // namespace
new file mode 100644
--- /dev/null
+++ b/content/media/webrtc/LoadManagerFactory.h
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _LOADMANAGERFACTORY_H_
+#define _LOADMANAGERFACTORY_H_
+
+namespace mozilla {
+
+class LoadManager;
+
+mozilla::LoadManager* LoadManagerBuild();
+void LoadManagerDestroy(mozilla::LoadManager* aLoadManager);
+
+} //namespace
+
+#endif /* _LOADMANAGERFACTORY_H_ */
--- a/content/media/webrtc/LoadMonitor.cpp
+++ b/content/media/webrtc/LoadMonitor.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LoadMonitor.h"
+#include "LoadManager.h"
 #include "nsString.h"
 #include "prlog.h"
 #include "prtime.h"
 #include "prinrval.h"
 #include "prsystem.h"
 #include "prprf.h"
 
 #include "nsString.h"
@@ -20,44 +21,45 @@
 #include "nsIServiceManager.h"
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Services.h"
 
 #if defined(ANDROID) || defined(LINUX) || defined(XP_MACOSX)
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <unistd.h>
 #endif
 
-// NSPR_LOG_MODULES=LoadMonitor:5
-PRLogModuleInfo *gLoadMonitorLog = nullptr;
+// NSPR_LOG_MODULES=LoadManager:5
+#undef LOG
+#undef LOG_ENABLED
 #if defined(PR_LOGGING)
-#define LOG(args) PR_LOG(gLoadMonitorLog, PR_LOG_DEBUG, args)
-#define LOG_ENABLED() PR_LOG_TEST(gLoadMonitorLog, 4)
-#define LOG_MANY_ENABLED() PR_LOG_TEST(gLoadMonitorLog, 5)
+#define LOG(args) PR_LOG(gLoadManagerLog, PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(gLoadManagerLog, 4)
+#define LOG_MANY_ENABLED() PR_LOG_TEST(gLoadManagerLog, 5)
 #else
 #define LOG(args)
 #define LOG_ENABLED() (false)
 #define LOG_MANY_ENABLED() (false)
 #endif
 
-using namespace mozilla;
-
-// Update the system load every x milliseconds
-static const int kLoadUpdateInterval = 1000;
+namespace mozilla {
 
 NS_IMPL_ISUPPORTS1(LoadMonitor, nsIObserver)
 
-LoadMonitor::LoadMonitor()
-  : mLock("LoadMonitor.mLock"),
+LoadMonitor::LoadMonitor(int aLoadUpdateInterval)
+  : mLoadUpdateInterval(aLoadUpdateInterval),
+    mLock("LoadMonitor.mLock"),
     mCondVar(mLock, "LoadMonitor.mCondVar"),
     mShutdownPending(false),
     mLoadInfoThread(nullptr),
     mSystemLoad(0.0f),
-    mProcessLoad(0.0f)
+    mProcessLoad(0.0f),
+    mLoadNotificationCallback(nullptr)
 {
 }
 
 LoadMonitor::~LoadMonitor()
 {
   Shutdown();
 }
 
@@ -153,46 +155,68 @@ public:
   uint64_t mPrevCpuTimes;
   float mPrevLoad;               // Previous load value.
 };
 
 class LoadInfo : public mozilla::RefCounted<LoadInfo>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(LoadInfo)
+  LoadInfo(int aLoadUpdateInterval);
   double GetSystemLoad() { return mSystemLoad.GetLoad(); };
   double GetProcessLoad() { return mProcessLoad.GetLoad(); };
   nsresult UpdateSystemLoad();
   nsresult UpdateProcessLoad();
 
 private:
-  void UpdateCpuLoad(uint64_t current_total_times,
+  void UpdateCpuLoad(uint64_t ticks_per_interval,
+                     uint64_t current_total_times,
                      uint64_t current_cpu_times,
                      LoadStats* loadStat);
   LoadStats mSystemLoad;
   LoadStats mProcessLoad;
+  uint64_t mTicksPerInterval;
+  int mLoadUpdateInterval;
 };
 
-void LoadInfo::UpdateCpuLoad(uint64_t current_total_times,
+LoadInfo::LoadInfo(int aLoadUpdateInterval)
+  : mLoadUpdateInterval(aLoadUpdateInterval)
+{
+#if defined(ANDROID) || defined(LINUX) || defined(XP_MACOSX)
+  mTicksPerInterval = (sysconf(_SC_CLK_TCK) * mLoadUpdateInterval) / 1000;
+#endif
+}
+
+void LoadInfo::UpdateCpuLoad(uint64_t ticks_per_interval,
+                             uint64_t current_total_times,
                              uint64_t current_cpu_times,
                              LoadStats *loadStat) {
-  float result = 0.0f;
 
-  if (current_total_times < loadStat->mPrevTotalTimes ||
-      current_cpu_times < loadStat->mPrevCpuTimes) {
-    //LOG(("Current total: %lld old total: %lld", current_total_times, loadStat->mPrevTotalTimes));
-    //LOG(("Current cpu: %lld old cpu: %lld", current_cpu_times, loadStat->mPrevCpuTimes));
+  // Check if we get an inconsistent number of ticks.
+  if (((current_total_times - loadStat->mPrevTotalTimes)
+      > (ticks_per_interval * 10))
+      || current_total_times < loadStat->mPrevTotalTimes
+      || current_cpu_times < loadStat->mPrevCpuTimes) {
+    // Bug at least on the Nexus 4 and Galaxy S4
+    // https://code.google.com/p/android/issues/detail?id=41630
+    // We do need to update our previous times, or we can get stuck
+    // when there is a blip upwards and then we get a bunch of consecutive
+    // lower times. Just skip the load calculation.
     LOG(("Inconsistent time values are passed. ignored"));
-  } else {
-    const uint64_t cpu_diff = current_cpu_times - loadStat->mPrevCpuTimes;
-    const uint64_t total_diff = current_total_times - loadStat->mPrevTotalTimes;
-    if (total_diff > 0) {
-      result =  (float)cpu_diff / (float)total_diff;
-      loadStat->mPrevLoad = result;
-    }
+    // Try to recover next tick
+    loadStat->mPrevTotalTimes = current_total_times;
+    loadStat->mPrevCpuTimes = current_cpu_times;
+    return;
+  }
+
+  const uint64_t cpu_diff = current_cpu_times - loadStat->mPrevCpuTimes;
+  const uint64_t total_diff = current_total_times - loadStat->mPrevTotalTimes;
+  if (total_diff > 0) {
+    float result =  (float)cpu_diff / (float)total_diff;
+    loadStat->mPrevLoad = result;
   }
   loadStat->mPrevTotalTimes = current_total_times;
   loadStat->mPrevCpuTimes = current_cpu_times;
 }
 
 nsresult LoadInfo::UpdateSystemLoad()
 {
 #if defined(LINUX) || defined(ANDROID)
@@ -220,18 +244,19 @@ nsresult LoadInfo::UpdateSystemLoad()
                 &system, &idle) != 4) {
     LOG(("Error parsing /proc/stat"));
     return NS_ERROR_FAILURE;
   }
 
   const uint64_t cpu_times = nice + system + user;
   const uint64_t total_times = cpu_times + idle;
 
-  UpdateCpuLoad(total_times,
-                cpu_times * PR_GetNumberOfProcessors(),
+  UpdateCpuLoad(mTicksPerInterval,
+                total_times,
+                cpu_times,
                 &mSystemLoad);
   return NS_OK;
 #else
   // Not implemented
   return NS_OK;
 #endif
 }
 
@@ -246,56 +271,61 @@ nsresult LoadInfo::UpdateProcessLoad() {
     LOG(("getrusage failed"));
     return NS_ERROR_FAILURE;
   }
 
   const uint64_t cpu_times =
       (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * PR_USEC_PER_SEC +
        usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
 
-  UpdateCpuLoad(total_times,
+  UpdateCpuLoad(PR_USEC_PER_MSEC * mLoadUpdateInterval,
+                total_times,
                 cpu_times,
                 &mProcessLoad);
 #endif // defined(LINUX) || defined(ANDROID)
   return NS_OK;
 }
 
 class LoadInfoCollectRunner : public nsRunnable
 {
 public:
-  LoadInfoCollectRunner(nsRefPtr<LoadMonitor> loadMonitor)
+  LoadInfoCollectRunner(nsRefPtr<LoadMonitor> loadMonitor,
+                        int aLoadUpdateInterval)
+    : mLoadUpdateInterval(aLoadUpdateInterval),
+      mLoadNoiseCounter(0)
   {
     mLoadMonitor = loadMonitor;
-    mLoadInfo = new LoadInfo();
-    mLoadNoiseCounter = 0;
+    mLoadInfo = new LoadInfo(mLoadUpdateInterval);
   }
 
   NS_IMETHOD Run()
   {
     MutexAutoLock lock(mLoadMonitor->mLock);
     while (!mLoadMonitor->mShutdownPending) {
       mLoadInfo->UpdateSystemLoad();
       mLoadInfo->UpdateProcessLoad();
       float sysLoad = mLoadInfo->GetSystemLoad();
       float procLoad = mLoadInfo->GetProcessLoad();
       if ((++mLoadNoiseCounter % (LOG_MANY_ENABLED() ? 1 : 10)) == 0) {
         LOG(("System Load: %f Process Load: %f", sysLoad, procLoad));
         mLoadNoiseCounter = 0;
       }
       mLoadMonitor->SetSystemLoad(sysLoad);
       mLoadMonitor->SetProcessLoad(procLoad);
+      mLoadMonitor->FireCallbacks();
 
-      mLoadMonitor->mCondVar.Wait(PR_MillisecondsToInterval(kLoadUpdateInterval));
+      mLoadMonitor->mCondVar.Wait(PR_MillisecondsToInterval(mLoadUpdateInterval));
     }
     return NS_OK;
   }
 
 private:
   RefPtr<LoadInfo> mLoadInfo;
   nsRefPtr<LoadMonitor> mLoadMonitor;
+  int mLoadUpdateInterval;
   int mLoadNoiseCounter;
 };
 
 void
 LoadMonitor::SetProcessLoad(float load) {
   mLock.AssertCurrentThreadOwns();
   mProcessLoad = load;
 }
@@ -308,36 +338,48 @@ LoadMonitor::SetSystemLoad(float load) {
 
 float
 LoadMonitor::GetProcessLoad() {
   MutexAutoLock lock(mLock);
   float load = mProcessLoad;
   return load;
 }
 
+void
+LoadMonitor::FireCallbacks() {
+  if (mLoadNotificationCallback) {
+    mLoadNotificationCallback->LoadChanged(mSystemLoad, mProcessLoad);
+  }
+}
+
 float
 LoadMonitor::GetSystemLoad() {
   MutexAutoLock lock(mLock);
   float load = mSystemLoad;
   return load;
 }
 
 nsresult
 LoadMonitor::Init(nsRefPtr<LoadMonitor> &self)
 {
-#if defined(PR_LOGGING)
-  if (!gLoadMonitorLog)
-    gLoadMonitorLog = PR_NewLogModule("LoadMonitor");
   LOG(("Initializing LoadMonitor"));
-#endif
 
 #if defined(ANDROID) || defined(LINUX)
   nsRefPtr<LoadMonitorAddObserver> addObsRunner = new LoadMonitorAddObserver(self);
   NS_DispatchToMainThread(addObsRunner, NS_DISPATCH_NORMAL);
 
   NS_NewNamedThread("Sys Load Info", getter_AddRefs(mLoadInfoThread));
 
-  nsRefPtr<LoadInfoCollectRunner> runner = new LoadInfoCollectRunner(self);
+  nsRefPtr<LoadInfoCollectRunner> runner =
+    new LoadInfoCollectRunner(self, mLoadUpdateInterval);
   mLoadInfoThread->Dispatch(runner, NS_DISPATCH_NORMAL);
 #endif
 
   return NS_OK;
 }
+
+void
+LoadMonitor::SetLoadChangeCallback(LoadNotificationCallback* aCallback)
+{
+  mLoadNotificationCallback = aCallback;
+}
+
+}
--- a/content/media/webrtc/LoadMonitor.h
+++ b/content/media/webrtc/LoadMonitor.h
@@ -10,41 +10,55 @@
 #include "mozilla/CondVar.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Atomics.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 #include "nsIObserver.h"
 
+namespace mozilla {
 class LoadInfoUpdateRunner;
 class LoadInfoCollectRunner;
 
+class LoadNotificationCallback
+{
+public:
+    virtual void LoadChanged(float aSystemLoad, float aProcessLoad) = 0;
+};
+
 class LoadMonitor MOZ_FINAL : public nsIObserver
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIOBSERVER
 
-    LoadMonitor();
+    LoadMonitor(int aLoadUpdateInterval);
     ~LoadMonitor();
 
     nsresult Init(nsRefPtr<LoadMonitor> &self);
+    void SetLoadChangeCallback(LoadNotificationCallback* aCallback);
     void Shutdown();
     float GetSystemLoad();
     float GetProcessLoad();
 
     friend class LoadInfoCollectRunner;
 
 private:
 
     void SetProcessLoad(float load);
     void SetSystemLoad(float load);
+    void FireCallbacks();
 
+    int                  mLoadUpdateInterval;
     mozilla::Mutex       mLock;
     mozilla::CondVar     mCondVar;
     bool                 mShutdownPending;
     nsCOMPtr<nsIThread>  mLoadInfoThread;
+    uint64_t             mTicksPerInterval;
     float                mSystemLoad;
     float                mProcessLoad;
+    LoadNotificationCallback* mLoadNotificationCallback;
 };
 
+} //namespace
+
 #endif /* _LOADMONITOR_H_ */
--- a/content/media/webrtc/MediaEngine.h
+++ b/content/media/webrtc/MediaEngine.h
@@ -42,17 +42,16 @@ public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(MediaEngine)
   virtual ~MediaEngine() {}
 
   static const int DEFAULT_VIDEO_FPS = 30;
   static const int DEFAULT_VIDEO_MIN_FPS = 10;
   static const int DEFAULT_VIDEO_WIDTH = 640;
   static const int DEFAULT_VIDEO_HEIGHT = 480;
   static const int DEFAULT_AUDIO_TIMER_MS = 10;
-  static const bool DEFAULT_LOAD_ADAPT = false;
 
   /* Populate an array of video sources in the nsTArray. Also include devices
    * that are currently unavailable. */
   virtual void EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >*) = 0;
 
   /* Populate an array of audio sources in the nsTArray. Also include devices
    * that are currently unavailable. */
   virtual void EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >*) = 0;
@@ -128,17 +127,16 @@ protected:
 /**
  * Video source and friends.
  */
 struct MediaEnginePrefs {
   int32_t mWidth;
   int32_t mHeight;
   int32_t mFPS;
   int32_t mMinFPS;
-  bool mLoadAdapt;
 };
 
 class MediaEngineVideoSource : public MediaEngineSource
 {
 public:
   virtual ~MediaEngineVideoSource() {}
 };
 
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -55,20 +55,16 @@ MediaEngineWebRTC::MediaEngineWebRTC(Med
   nsCOMPtr<nsIComponentRegistrar> compMgr;
   NS_GetComponentRegistrar(getter_AddRefs(compMgr));
   if (compMgr) {
     compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
   }
 #else
   AsyncLatencyLogger::Get()->AddRef();
 #endif
-  if (aPrefs.mLoadAdapt) {
-      mLoadMonitor = new LoadMonitor();
-      mLoadMonitor->Init(mLoadMonitor);
-  }
 }
 
 void
 MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources)
 {
 #ifdef MOZ_B2G_CAMERA
   MutexAutoLock lock(mMutex);
 
@@ -349,14 +345,11 @@ MediaEngineWebRTC::Shutdown()
 
   if (mVoiceEngine) {
     mAudioSources.Clear();
     webrtc::VoiceEngine::Delete(mVoiceEngine);
   }
 
   mVideoEngine = nullptr;
   mVoiceEngine = nullptr;
-
-  if (mLoadMonitor)
-    mLoadMonitor->Shutdown();
 }
 
 }
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -21,17 +21,16 @@
 #include "nsRefPtrHashtable.h"
 
 #include "VideoUtils.h"
 #include "MediaEngine.h"
 #include "VideoSegment.h"
 #include "AudioSegment.h"
 #include "StreamBuffer.h"
 #include "MediaStreamGraph.h"
-#include "LoadMonitor.h"
 
 #include "MediaEngineWrapper.h"
 
 // WebRTC library includes follow
 
 // Audio Engine
 #include "webrtc/voice_engine/include/voe_base.h"
 #include "webrtc/voice_engine/include/voe_codec.h"
@@ -366,15 +365,13 @@ private:
   bool mVideoEngineInit;
   bool mAudioEngineInit;
   bool mHasTabVideoSource;
 
   // Store devices we've already seen in a hashtable for quick return.
   // Maps UUID to MediaEngineSource (one set for audio, one for video).
   nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCVideoSource > mVideoSources;
   nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCAudioSource > mAudioSources;
-
-  nsRefPtr<LoadMonitor> mLoadMonitor;
 };
 
 }
 
 #endif /* NSMEDIAENGINEWEBRTC_H_ */
--- a/content/media/webrtc/moz.build
+++ b/content/media/webrtc/moz.build
@@ -7,18 +7,23 @@
 XPIDL_MODULE = 'content_webrtc'
 
 EXPORTS += [
     'MediaEngine.h',
     'MediaEngineDefault.h',
 ]
 
 if CONFIG['MOZ_WEBRTC']:
-    EXPORTS += ['LoadMonitor.h', 'MediaEngineWebRTC.h']
+    EXPORTS += ['LoadManager.h',
+                'LoadManagerFactory.h',
+                'LoadMonitor.h',
+                'MediaEngineWebRTC.h']
     UNIFIED_SOURCES += [
+        'LoadManager.cpp',
+        'LoadManagerFactory.cpp',
         'LoadMonitor.cpp',
         'MediaEngineTabVideoSource.cpp',
         'MediaEngineWebRTCAudio.cpp',
         'MediaEngineWebRTCVideo.cpp',
     ]
     # MediaEngineWebRTC.cpp needs to be built separately.
     SOURCES += [
         'MediaEngineWebRTC.cpp',
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1122,17 +1122,16 @@ private:
 MediaManager::MediaManager()
   : mMediaThread(nullptr)
   , mMutex("mozilla::MediaManager")
   , mBackend(nullptr) {
   mPrefs.mWidth  = MediaEngine::DEFAULT_VIDEO_WIDTH;
   mPrefs.mHeight = MediaEngine::DEFAULT_VIDEO_HEIGHT;
   mPrefs.mFPS    = MediaEngine::DEFAULT_VIDEO_FPS;
   mPrefs.mMinFPS = MediaEngine::DEFAULT_VIDEO_MIN_FPS;
-  mPrefs.mLoadAdapt = MediaEngine::DEFAULT_LOAD_ADAPT;
 
   nsresult rv;
   nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
   if (NS_SUCCEEDED(rv)) {
     nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
     if (branch) {
       GetPrefs(branch, nullptr);
     }
@@ -1167,17 +1166,16 @@ MediaManager::Get() {
     }
     // else MediaManager won't work properly and will leak (see bug 837874)
     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefs) {
       prefs->AddObserver("media.navigator.video.default_width", sSingleton, false);
       prefs->AddObserver("media.navigator.video.default_height", sSingleton, false);
       prefs->AddObserver("media.navigator.video.default_fps", sSingleton, false);
       prefs->AddObserver("media.navigator.video.default_minfps", sSingleton, false);
-      prefs->AddObserver("media.navigator.load_adapt", sSingleton, false);
     }
   }
   return sSingleton;
 }
 
 /* static */ already_AddRefed<MediaManager>
 MediaManager::GetInstance()
 {
@@ -1684,17 +1682,16 @@ MediaManager::GetPrefBool(nsIPrefBranch 
 
 void
 MediaManager::GetPrefs(nsIPrefBranch *aBranch, const char *aData)
 {
   GetPref(aBranch, "media.navigator.video.default_width", aData, &mPrefs.mWidth);
   GetPref(aBranch, "media.navigator.video.default_height", aData, &mPrefs.mHeight);
   GetPref(aBranch, "media.navigator.video.default_fps", aData, &mPrefs.mFPS);
   GetPref(aBranch, "media.navigator.video.default_minfps", aData, &mPrefs.mMinFPS);
-  GetPrefBool(aBranch, "media.navigator.load_adapt", aData, &mPrefs.mLoadAdapt);
 }
 
 nsresult
 MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
   const char16_t* aData)
 {
   NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
@@ -1713,17 +1710,16 @@ MediaManager::Observe(nsISupports* aSubj
     obs->RemoveObserver(this, "getUserMedia:revoke");
 
     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefs) {
       prefs->RemoveObserver("media.navigator.video.default_width", this);
       prefs->RemoveObserver("media.navigator.video.default_height", this);
       prefs->RemoveObserver("media.navigator.video.default_fps", this);
       prefs->RemoveObserver("media.navigator.video.default_minfps", this);
-      prefs->RemoveObserver("media.navigator.load_adapt", this);
     }
 
     // Close off any remaining active windows.
     {
       MutexAutoLock lock(mMutex);
       GetActiveWindows()->Clear();
       mActiveCallbacks.Clear();
       mCallIds.Clear();
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -442,17 +442,18 @@ WebrtcAudioConduit::ConfigureSendMediaCo
   //Copy the applied config for future reference.
   delete mCurSendCodecConfig;
 
   mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
                                               codecConfig->mName,
                                               codecConfig->mFreq,
                                               codecConfig->mPacSize,
                                               codecConfig->mChannels,
-                                              codecConfig->mRate);
+                                              codecConfig->mRate,
+                                              codecConfig->mLoadManager);
 
   mEngineTransmitting = true;
   return kMediaConduitNoError;
 }
 
 MediaConduitErrorCode
 WebrtcAudioConduit::ConfigureRecvMediaCodecs(
                     const std::vector<AudioCodecConfig*>& codecConfigList)
@@ -922,17 +923,18 @@ bool
 WebrtcAudioConduit::CopyCodecToDB(const AudioCodecConfig* codecInfo)
 {
 
   AudioCodecConfig* cdcConfig = new AudioCodecConfig(codecInfo->mType,
                                                      codecInfo->mName,
                                                      codecInfo->mFreq,
                                                      codecInfo->mPacSize,
                                                      codecInfo->mChannels,
-                                                     codecInfo->mRate);
+                                                     codecInfo->mRate,
+                                                     codecInfo->mLoadManager);
   mRecvCodecList.push_back(cdcConfig);
   return true;
 }
 
 /**
  * Checks if 2 codec structs are same
  */
 bool
--- a/media/webrtc/signaling/src/media-conduit/CodecConfig.h
+++ b/media/webrtc/signaling/src/media-conduit/CodecConfig.h
@@ -6,43 +6,49 @@
 #ifndef CODEC_CONFIG_H_
 #define CODEC_CONFIG_H_
 
 #include <string>
 #include "ccsdp_rtcp_fb.h"
 
 namespace mozilla {
 
+class LoadManager;
+
 /**
  * Minimalistic Audio Codec Config Params
  */
 struct AudioCodecConfig
 {
   /*
    * The data-types for these properties mimic the
    * corresponding webrtc::CodecInst data-types.
    */
   int mType;
   std::string mName;
   int mFreq;
   int mPacSize;
   int mChannels;
   int mRate;
+  LoadManager* mLoadManager;
 
   /* Default constructor is not provided since as a consumer, we
    * can't decide the default configuration for the codec
    */
   explicit AudioCodecConfig(int type, std::string name,
                             int freq,int pacSize,
-                            int channels, int rate): mType(type),
+                            int channels, int rate,
+                            LoadManager* load_manager = nullptr)
+                                                   : mType(type),
                                                      mName(name),
                                                      mFreq(freq),
                                                      mPacSize(pacSize),
                                                      mChannels(channels),
-                                                     mRate(rate)
+                                                     mRate(rate),
+                                                     mLoadManager(load_manager)
 
   {
   }
 };
 
 /*
  * Minimalisitc video codec configuration
  * More to be added later depending on the use-case
@@ -54,36 +60,43 @@ struct VideoCodecConfig
    * The data-types for these properties mimic the
    * corresponding webrtc::VideoCodec data-types.
    */
   int mType;
   std::string mName;
   uint32_t mRtcpFbTypes;
   unsigned int mMaxFrameSize;
   unsigned int mMaxFrameRate;
+  LoadManager* mLoadManager;
 
   VideoCodecConfig(int type,
                    std::string name,
-                   int rtcpFbTypes): mType(type),
+                   int rtcpFbTypes,
+                   LoadManager* load_manager = nullptr) :
+                                     mType(type),
                                      mName(name),
                                      mRtcpFbTypes(rtcpFbTypes),
                                      mMaxFrameSize(0),
-                                     mMaxFrameRate(0)
+                                     mMaxFrameRate(0),
+                                     mLoadManager(load_manager)
   {
   }
 
   VideoCodecConfig(int type,
                    std::string name,
                    int rtcpFbTypes,
                    unsigned int max_fs,
-                   unsigned int max_fr): mType(type),
+                   unsigned int max_fr,
+                   LoadManager* load_manager = nullptr) :
+                                         mType(type),
                                          mName(name),
                                          mRtcpFbTypes(rtcpFbTypes),
                                          mMaxFrameSize(max_fs),
-                                         mMaxFrameRate(max_fr)
+                                         mMaxFrameRate(max_fr),
+                                         mLoadManager(load_manager)
   {
   }
 
 
   bool RtcpFbIsSet(sdp_rtcp_fb_nack_type_e type) const
   {
     return mRtcpFbTypes & sdp_rtcp_fb_nack_to_bitmap(type);
   }
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -7,16 +7,18 @@
 
 // For rtcp-fb constants
 #include "ccsdp.h"
 
 #include "VideoConduit.h"
 #include "AudioConduit.h"
 #include "nsThreadUtils.h"
 
+#include "LoadManager.h"
+
 #include "webrtc/video_engine/include/vie_errors.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidJNIWrapper.h"
 #endif
 
 #include <algorithm>
 #include <math.h>
@@ -481,16 +483,21 @@ WebrtcVideoConduit::ConfigureSendMediaCo
       CSFLogError(logTag, "%s StopSend() Failed %d ",__FUNCTION__,
                   mPtrViEBase->LastError());
       return kMediaConduitUnknownError;
     }
   }
 
   mEngineTransmitting = false;
 
+  if (codecConfig->mLoadManager) {
+    mPtrViEBase->RegisterCpuOveruseObserver(mChannel, codecConfig->mLoadManager);
+    mPtrViEBase->SetLoadManager(codecConfig->mLoadManager);
+  }
+
   // we should be good here to set the new codec.
   for(int idx=0; idx < mPtrViECodec->NumberOfCodecs(); idx++)
   {
     if(0 == mPtrViECodec->GetCodec(idx, video_codec))
     {
       payloadName = video_codec.plName;
       if(codecConfig->mName.compare(payloadName) == 0)
       {
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -1628,17 +1628,18 @@ static int vcmRxStartICE_m(cc_mcapid_t m
     for(int i=0; i <num_payloads ; i++)
     {
       config_raw = new mozilla::AudioCodecConfig(
         payloads[i].remote_rtp_pt,
         ccsdpCodecName(payloads[i].codec_type),
         payloads[i].audio.frequency,
         payloads[i].audio.packet_size,
         payloads[i].audio.channels,
-        payloads[i].audio.bitrate);
+        payloads[i].audio.bitrate,
+        pc.impl()->load_manager());
       configs.push_back(config_raw);
     }
 
     if (conduit->ConfigureRecvMediaCodecs(configs))
       return VCM_ERROR;
 
     // Now we have all the pieces, create the pipeline
     mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
@@ -1685,17 +1686,18 @@ static int vcmRxStartICE_m(cc_mcapid_t m
 
     mozilla::VideoCodecConfig *config_raw;
 
     for(int i=0; i <num_payloads; i++)
     {
       config_raw = new mozilla::VideoCodecConfig(
         payloads[i].remote_rtp_pt,
         ccsdpCodecName(payloads[i].codec_type),
-        payloads[i].video.rtcp_fb_types);
+        payloads[i].video.rtcp_fb_types,
+        pc.impl()->load_manager());
       configs.push_back(config_raw);
     }
 
     if (conduit->ConfigureRecvMediaCodecs(configs))
       return VCM_ERROR;
 
     // Now we have all the pieces, create the pipeline
     mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
@@ -2286,17 +2288,18 @@ static int vcmTxStartICE_m(cc_mcapid_t m
   if (CC_IS_AUDIO(mcap_id)) {
     mozilla::AudioCodecConfig *config_raw;
     config_raw = new mozilla::AudioCodecConfig(
       payload->remote_rtp_pt,
       ccsdpCodecName(payload->codec_type),
       payload->audio.frequency,
       payload->audio.packet_size,
       payload->audio.channels,
-      payload->audio.bitrate);
+      payload->audio.bitrate,
+      pc.impl()->load_manager());
 
     // Take possession of this pointer
     mozilla::ScopedDeletePtr<mozilla::AudioCodecConfig> config(config_raw);
 
     // Instantiate an appropriate conduit
     mozilla::RefPtr<mozilla::MediaSessionConduit> rx_conduit =
       pc.impl()->media()->GetConduit(level, true);
     MOZ_ASSERT_IF(rx_conduit, rx_conduit->type() == MediaSessionConduit::AUDIO);
@@ -2338,17 +2341,18 @@ static int vcmTxStartICE_m(cc_mcapid_t m
 
   } else if (CC_IS_VIDEO(mcap_id)) {
     mozilla::VideoCodecConfig *config_raw;
     config_raw = new mozilla::VideoCodecConfig(
       payload->remote_rtp_pt,
       ccsdpCodecName(payload->codec_type),
       payload->video.rtcp_fb_types,
       payload->video.max_fs,
-      payload->video.max_fr);
+      payload->video.max_fr,
+      pc.impl()->load_manager());
 
     // Take possession of this pointer
     mozilla::ScopedDeletePtr<mozilla::VideoCodecConfig> config(config_raw);
 
     // Instantiate an appropriate conduit
     mozilla::RefPtr<mozilla::MediaSessionConduit> rx_conduit =
       pc.impl()->media()->GetConduit(level, true);
     MOZ_ASSERT_IF(rx_conduit, rx_conduit->type() == MediaSessionConduit::VIDEO);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -45,16 +45,17 @@
 #include "dtlsidentity.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "nsPerformance.h"
 #include "nsGlobalWindow.h"
 #include "nsDOMDataChannel.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/Preferences.h"
 #include "mozilla/PublicSSL.h"
 #include "nsXULAppAPI.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsIDocument.h"
 #include "nsIScriptError.h"
 #include "nsPrintfCString.h"
 #include "nsURLHelper.h"
@@ -473,16 +474,17 @@ PeerConnectionImpl::PeerConnectionImpl(c
   , mInternal(new Internal())
   , mReadyState(PCImplReadyState::New)
   , mSignalingState(PCImplSignalingState::SignalingStable)
   , mIceConnectionState(PCImplIceConnectionState::New)
   , mIceGatheringState(PCImplIceGatheringState::New)
   , mWindow(nullptr)
   , mIdentity(nullptr)
   , mSTSThread(nullptr)
+  , mLoadManager(nullptr)
   , mMedia(nullptr)
   , mNumAudioStreams(0)
   , mNumVideoStreams(0)
   , mHaveDataStream(false)
   , mTrickle(true) // TODO(ekr@rtfm.com): Use pref
 {
 #ifdef MOZILLA_INTERNAL_API
   MOZ_ASSERT(NS_IsMainThread());
@@ -520,16 +522,20 @@ PeerConnectionImpl::~PeerConnectionImpl(
   {
     // Deregister as an NSS Shutdown Object
     nsNSSShutDownPreventionLock locker;
     if (!isAlreadyShutDown()) {
       destructorSafeDestroyNSSReference();
       shutdown(calledFromObject);
     }
   }
+  if (mLoadManager) {
+      mozilla::LoadManagerDestroy(mLoadManager);
+      mLoadManager = nullptr;
+  }
 #endif
 
   // Since this and Initialize() occur on MainThread, they can't both be
   // running at once
 
   // Right now, we delete PeerConnectionCtx at XPCOM shutdown only, but we
   // probably want to shut it down more aggressively to save memory.  We
   // could shut down here when there are no uses.  It might be more optimal
@@ -843,16 +849,22 @@ PeerConnectionImpl::Initialize(PeerConne
   }
 
   mFingerprint = mIdentity->GetFormattedFingerprint();
   if (mFingerprint.empty()) {
     CSFLogError(logTag, "%s: unable to get fingerprint", __FUNCTION__);
     return res;
   }
 
+#ifdef MOZILLA_INTERNAL_API
+  if (mozilla::Preferences::GetBool("media.navigator.load_adapt", false)) {
+    mLoadManager = mozilla::LoadManagerBuild();
+  }
+#endif
+
   return NS_OK;
 }
 
 RefPtr<DtlsIdentity> const
 PeerConnectionImpl::GetIdentity() const
 {
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
   return mIdentity;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -22,16 +22,17 @@
 #include "nricemediastream.h"
 #include "nsComponentManagerUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIThread.h"
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
 #include "StreamBuffer.h"
+#include "LoadManagerFactory.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "mozilla/TimeStamp.h"
 #include "mozilla/net/DataChannel.h"
 #include "VideoUtils.h"
 #include "VideoSegment.h"
 #include "nsNSSShutDown.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
@@ -238,16 +239,20 @@ public:
   void NotifyDataChannel(already_AddRefed<mozilla::DataChannel> aChannel);
 
   // Get the media object
   const nsRefPtr<PeerConnectionMedia>& media() const {
     PC_AUTO_ENTER_API_CALL_NO_CHECK();
     return mMedia;
   }
 
+  mozilla::LoadManager* load_manager()  {
+    return mLoadManager;
+  }
+
   // Handle system to allow weak references to be passed through C code
   virtual const std::string& GetHandle();
 
   // Name suitable for exposing to content
   virtual const std::string& GetName();
 
   // ICE events
   void IceConnectionStateChange(NrIceCtx* ctx,
@@ -617,16 +622,19 @@ private:
   std::string mHandle;
 
   // A name for this PC that we are willing to expose to content.
   std::string mName;
 
   // The target to run stuff on
   nsCOMPtr<nsIEventTarget> mSTSThread;
 
+  // CPU Load adaptation stuff
+  mozilla::LoadManager* mLoadManager;
+
 #ifdef MOZILLA_INTERNAL_API
   // DataConnection that's used to get all the DataChannels
 	nsRefPtr<mozilla::DataChannelConnection> mDataConnection;
 #endif
 
   nsRefPtr<PeerConnectionMedia> mMedia;
 
 #ifdef MOZILLA_INTERNAL_API
--- a/media/webrtc/trunk/webrtc/common_types.h
+++ b/media/webrtc/trunk/webrtc/common_types.h
@@ -596,12 +596,31 @@ struct OverUseDetectorOptions {
   double initial_offset;
   double initial_e[2][2];
   double initial_process_noise[2];
   double initial_avg_noise;
   double initial_var_noise;
   double initial_threshold;
 };
 
+enum CPULoadState {
+  kLoadRelaxed,
+  kLoadNormal,
+  kLoadStressed
+};
+
+class CPULoadStateObserver {
+public:
+  virtual void onLoadStateChanged(CPULoadState aNewState) = 0;
+  virtual ~CPULoadStateObserver() {};
+};
+
+class CPULoadStateCallbackInvoker {
+public:
+    virtual void AddObserver(CPULoadStateObserver* aObserver) = 0;
+    virtual void RemoveObserver(CPULoadStateObserver* aObserver) = 0;
+    virtual ~CPULoadStateCallbackInvoker() {};
+};
+
 }  // namespace webrtc
 
 #endif  // WEBRTC_COMMON_TYPES_H_
 
--- a/media/webrtc/trunk/webrtc/video_engine/include/vie_base.h
+++ b/media/webrtc/trunk/webrtc/video_engine/include/vie_base.h
@@ -34,17 +34,16 @@ class CpuOveruseObserver {
   virtual void OveruseDetected() = 0;
   // Called periodically when the system is not overused any longer.
   virtual void NormalUsage() = 0;
 
  protected:
   virtual ~CpuOveruseObserver() {}
 };
 
-
 class WEBRTC_DLLEXPORT VideoEngine {
  public:
   // Creates a VideoEngine object, which can then be used to acquire subā€APIs.
   static VideoEngine* Create();
   static VideoEngine* Create(const Config& config);
 
   // Deletes a VideoEngine instance.
   static bool Delete(VideoEngine*& video_engine);
@@ -111,16 +110,20 @@ class WEBRTC_DLLEXPORT ViEBase {
   virtual int DeleteChannel(const int video_channel) = 0;
 
   // Registers an observer to be called when an overuse is detected, see
   // 'CpuOveruseObserver' for details.
   // NOTE: This is still very experimental functionality.
   virtual int RegisterCpuOveruseObserver(int channel,
                                          CpuOveruseObserver* observer) = 0;
 
+  // Changing the current state of the host CPU. Encoding engines
+  // can adapt their behavior if needed. (Optional)
+  virtual void SetLoadManager(CPULoadStateCallbackInvoker* load_manager) = 0;
+
   // Specifies the VoiceEngine and VideoEngine channel pair to use for
   // audio/video synchronization.
   virtual int ConnectAudioChannel(const int video_channel,
                                   const int audio_channel) = 0;
 
   // Disconnects a previously paired VideoEngine and VoiceEngine channel pair.
   virtual int DisconnectAudioChannel(const int video_channel) = 0;
 
--- a/media/webrtc/trunk/webrtc/video_engine/vie_base_impl.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_base_impl.cc
@@ -82,16 +82,20 @@ int ViEBaseImpl::SetVoiceEngine(VoiceEng
                "%s", __FUNCTION__);
   if (shared_data_.channel_manager()->SetVoiceEngine(voice_engine) != 0) {
     shared_data_.SetLastError(kViEBaseVoEFailure);
     return -1;
   }
   return 0;
 }
 
+void ViEBaseImpl::SetLoadManager(CPULoadStateCallbackInvoker* aLoadManager) {
+  shared_data_.set_load_manager(aLoadManager);
+}
+
 int ViEBaseImpl::RegisterCpuOveruseObserver(int video_channel,
                                             CpuOveruseObserver* observer) {
   ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
   ViEChannel* vie_channel = cs.Channel(video_channel);
   if (!vie_channel) {
     WEBRTC_TRACE(kTraceError,
                  kTraceVideo,
                  ViEId(shared_data_.instance_id()),
--- a/media/webrtc/trunk/webrtc/video_engine/vie_base_impl.h
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_base_impl.h
@@ -28,16 +28,17 @@ class ViEBaseImpl
  public:
   virtual int Release();
 
   // Implements ViEBase.
   virtual int Init();
   virtual int SetVoiceEngine(VoiceEngine* voice_engine);
   virtual int RegisterCpuOveruseObserver(int channel,
                                          CpuOveruseObserver* observer);
+  virtual void SetLoadManager(CPULoadStateCallbackInvoker* aLoadManager);
   virtual int CreateChannel(int& video_channel);  // NOLINT
   virtual int CreateChannel(int& video_channel,  // NOLINT
                             int original_channel);
   virtual int CreateReceiveChannel(int& video_channel,  // NOLINT
                                    int original_channel);
   virtual int DeleteChannel(const int video_channel);
   virtual int ConnectAudioChannel(const int video_channel,
                                   const int audio_channel);
--- a/media/webrtc/trunk/webrtc/video_engine/vie_channel_manager.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel_manager.cc
@@ -32,17 +32,19 @@ ViEChannelManager::ViEChannelManager(
     : channel_id_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
       engine_id_(engine_id),
       number_of_cores_(number_of_cores),
       free_channel_ids_(new bool[kViEMaxNumberOfChannels]),
       free_channel_ids_size_(kViEMaxNumberOfChannels),
       voice_sync_interface_(NULL),
       voice_engine_(NULL),
       module_process_thread_(NULL),
-      config_(config) {
+      config_(config),
+      load_manager_(NULL)
+{
   WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id),
                "ViEChannelManager::ViEChannelManager(engine_id: %d)",
                engine_id);
   for (int idx = 0; idx < free_channel_ids_size_; idx++) {
     free_channel_ids_[idx] = true;
   }
 }
 
@@ -74,16 +76,25 @@ ViEChannelManager::~ViEChannelManager() 
 }
 
 void ViEChannelManager::SetModuleProcessThread(
     ProcessThread* module_process_thread) {
   assert(!module_process_thread_);
   module_process_thread_ = module_process_thread;
 }
 
+void ViEChannelManager::SetLoadManager(
+    CPULoadStateCallbackInvoker* load_manager) {
+  load_manager_ = load_manager;
+  for (EncoderMap::const_iterator comp_it = vie_encoder_map_.begin();
+       comp_it != vie_encoder_map_.end(); ++comp_it) {
+    comp_it->second->SetLoadManager(load_manager);
+  }
+}
+
 int ViEChannelManager::CreateChannel(int* channel_id) {
   CriticalSectionScoped cs(channel_id_critsect_);
 
   // Get a new channel id.
   int new_channel_id = FreeChannelId();
   if (new_channel_id == -1) {
     return -1;
   }
--- a/media/webrtc/trunk/webrtc/video_engine/vie_channel_manager.h
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel_manager.h
@@ -44,16 +44,18 @@ class ViEChannelManager: private ViEMana
  public:
   ViEChannelManager(int engine_id,
                     int number_of_cores,
                     const Config& config);
   ~ViEChannelManager();
 
   void SetModuleProcessThread(ProcessThread* module_process_thread);
 
+  void SetLoadManager(CPULoadStateCallbackInvoker* load_manager);
+
   // Creates a new channel. 'channel_id' will be the id of the created channel.
   int CreateChannel(int* channel_id);
 
   // Creates a new channel grouped with |original_channel|. The new channel
   // will get its own |ViEEncoder| if |sender| is set to true. It will be a
   // receive only channel, without an own |ViEEncoder| if |sender| is false.
   int CreateChannel(int* channel_id, int original_channel, bool sender);
 
@@ -131,16 +133,17 @@ class ViEChannelManager: private ViEMana
   // TODO(mflodman) Make part of channel group.
   // Maps Channel id -> ViEEncoder.
   EncoderMap vie_encoder_map_;
   VoEVideoSync* voice_sync_interface_;
 
   VoiceEngine* voice_engine_;
   ProcessThread* module_process_thread_;
   const Config& config_;
+  CPULoadStateCallbackInvoker* load_manager_;
 };
 
 class ViEChannelManagerScoped: private ViEManagerScopedBase {
  public:
   explicit ViEChannelManagerScoped(
       const ViEChannelManager& vie_channel_manager);
   ViEChannel* Channel(int vie_channel_id) const;
   ViEEncoder* Encoder(int vie_channel_id) const;
--- a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.cc
@@ -120,16 +120,30 @@ class ViEPacedSenderCallback : public Pa
   }
   virtual int TimeToSendPadding(int bytes) {
     return owner_->TimeToSendPadding(bytes);
   }
  private:
   ViEEncoder* owner_;
 };
 
+class ViECPULoadStateObserver : public CPULoadStateObserver {
+ public:
+  explicit ViECPULoadStateObserver(ViEEncoder* owner)
+      : owner_(owner) {
+  }
+  virtual ~ViECPULoadStateObserver() {};
+    // Implements CPULoadStateObserver.
+    virtual void onLoadStateChanged(CPULoadState state) {
+    owner_->onLoadStateChanged(state);
+  }
+ private:
+  ViEEncoder* owner_;
+};
+
 ViEEncoder::ViEEncoder(int32_t engine_id,
                        int32_t channel_id,
                        uint32_t number_of_cores,
                        const Config& config,
                        ProcessThread& module_process_thread,
                        BitrateController* bitrate_controller)
   : engine_id_(engine_id),
     channel_id_(channel_id),
@@ -137,16 +151,17 @@ ViEEncoder::ViEEncoder(int32_t engine_id
     vcm_(*webrtc::VideoCodingModule::Create(ViEModuleId(engine_id,
                                                         channel_id))),
     vpm_(*webrtc::VideoProcessingModule::Create(ViEModuleId(engine_id,
                                                             channel_id))),
     default_rtp_rtcp_(NULL),
     callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
     data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
     bitrate_controller_(bitrate_controller),
+    load_manager_(NULL),
     send_padding_(false),
     target_delay_ms_(0),
     network_is_transmitting_(true),
     encoder_paused_(false),
     encoder_paused_and_dropped_frame_(false),
     channels_dropping_delta_frames_(0),
     drop_next_frame_(false),
     fec_enabled_(false),
@@ -166,16 +181,17 @@ ViEEncoder::ViEEncoder(int32_t engine_id
 
   RtpRtcp::Configuration configuration;
   configuration.id = ViEModuleId(engine_id_, channel_id_);
   configuration.audio = false;  // Video.
 
   default_rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
   bitrate_observer_.reset(new ViEBitrateObserver(this));
   pacing_callback_.reset(new ViEPacedSenderCallback(this));
+  loadstate_observer_.reset(new ViECPULoadStateObserver(this));
   paced_sender_.reset(
       new PacedSender(pacing_callback_.get(), kInitialPace, kPaceMultiplier));
 }
 
 bool ViEEncoder::Init() {
   if (vcm_.InitializeSender() != 0) {
     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
                  ViEId(engine_id_, channel_id_),
@@ -250,23 +266,31 @@ bool ViEEncoder::Init() {
     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
                  ViEId(engine_id_, channel_id_),
                  "VCM::RegisterQMCallback failure");
     return false;
   }
   return true;
 }
 
+void ViEEncoder::SetLoadManager(CPULoadStateCallbackInvoker* load_manager) {
+  load_manager_ = load_manager;
+  load_manager_->AddObserver(loadstate_observer_.get());
+}
+
 ViEEncoder::~ViEEncoder() {
   WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
                ViEId(engine_id_, channel_id_),
                "ViEEncoder Destructor 0x%p, engine_id: %d", this, engine_id_);
   if (bitrate_controller_) {
     bitrate_controller_->RemoveBitrateObserver(bitrate_observer_.get());
   }
+  if (load_manager_) {
+    load_manager_->RemoveObserver(loadstate_observer_.get());
+  }
   module_process_thread_.DeRegisterModule(&vcm_);
   module_process_thread_.DeRegisterModule(&vpm_);
   module_process_thread_.DeRegisterModule(default_rtp_rtcp_.get());
   module_process_thread_.DeRegisterModule(paced_sender_.get());
   VideoCodingModule::Destroy(&vcm_);
   VideoProcessingModule::Destroy(&vpm_);
   delete qm_callback_;
 }
@@ -1066,16 +1090,23 @@ void ViEEncoder::OnNetworkChanged(const 
   }
   pad_up_to_bitrate_kbps = std::min(bitrate_kbps, pad_up_to_bitrate_kbps);
   paced_sender_->UpdateBitrate(bitrate_kbps,
                                max_padding_bitrate_kbps,
                                pad_up_to_bitrate_kbps);
   default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);
 }
 
+void ViEEncoder::onLoadStateChanged(CPULoadState load_state) {
+    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
+                 ViEId(engine_id_, channel_id_),
+                 "%s: load state changed to %d",
+                 __FUNCTION__, (int)load_state);
+}
+
 PacedSender* ViEEncoder::GetPacedSender() {
   return paced_sender_.get();
 }
 
 int32_t ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effect_filter) {
   CriticalSectionScoped cs(callback_cs_.get());
   if (effect_filter == NULL) {
     if (effect_filter_ == NULL) {
--- a/media/webrtc/trunk/webrtc/video_engine/vie_encoder.h
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_encoder.h
@@ -32,26 +32,28 @@ class PacedSender;
 class ProcessThread;
 class QMVideoSettingsCallback;
 class RtpRtcp;
 class ViEBitrateObserver;
 class ViEEffectFilter;
 class ViEEncoderObserver;
 class VideoCodingModule;
 class ViEPacedSenderCallback;
+class ViECPULoadStateObserver;
 
 class ViEEncoder
     : public RtcpIntraFrameObserver,
       public VCMPacketizationCallback,
       public VCMProtectionCallback,
       public VCMSendStatisticsCallback,
       public ViEFrameCallback {
  public:
   friend class ViEBitrateObserver;
   friend class ViEPacedSenderCallback;
+  friend class ViECPULoadStateObserver;
 
   ViEEncoder(int32_t engine_id,
              int32_t channel_id,
              uint32_t number_of_cores,
              const Config& config,
              ProcessThread& module_process_thread,
              BitrateController* bitrate_controller);
   ~ViEEncoder();
@@ -151,29 +153,35 @@ class ViEEncoder
   virtual void OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc);
 
   // Sets SSRCs for all streams.
   bool SetSsrcs(const std::list<unsigned int>& ssrcs);
 
   // Effect filter.
   int32_t RegisterEffectFilter(ViEEffectFilter* effect_filter);
 
+  // Load Management
+  void SetLoadManager(CPULoadStateCallbackInvoker* load_manager);
+
   // Enables recording of debugging information.
   virtual int StartDebugRecording(const char* fileNameUTF8);
 
   // Disables recording of debugging information.
   virtual int StopDebugRecording();
 
   int channel_id() const { return channel_id_; }
  protected:
   // Called by BitrateObserver.
   void OnNetworkChanged(const uint32_t bitrate_bps,
                         const uint8_t fraction_lost,
                         const uint32_t round_trip_time_ms);
 
+  // Called by CPULoadStateObserver
+  void onLoadStateChanged(CPULoadState load_state);
+
   // Called by PacedSender.
   bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number,
                         int64_t capture_time_ms);
   int TimeToSendPadding(int bytes);
 
  private:
   bool EncoderPaused() const;
 
@@ -183,19 +191,22 @@ class ViEEncoder
 
   VideoCodingModule& vcm_;
   VideoProcessingModule& vpm_;
   scoped_ptr<RtpRtcp> default_rtp_rtcp_;
   scoped_ptr<CriticalSectionWrapper> callback_cs_;
   scoped_ptr<CriticalSectionWrapper> data_cs_;
   scoped_ptr<BitrateObserver> bitrate_observer_;
   scoped_ptr<PacedSender> paced_sender_;
+  scoped_ptr<webrtc::CPULoadStateObserver> loadstate_observer_;
   scoped_ptr<ViEPacedSenderCallback> pacing_callback_;
 
   BitrateController* bitrate_controller_;
+  // Owned by PeerConnection, not ViEEncoder
+  CPULoadStateCallbackInvoker* load_manager_;
 
   bool send_padding_;
   int target_delay_ms_;
   bool network_is_transmitting_;
   bool encoder_paused_;
   bool encoder_paused_and_dropped_frame_;
   std::map<unsigned int, int64_t> time_last_intra_request_ms_;
   int32_t channels_dropping_delta_frames_;
--- a/media/webrtc/trunk/webrtc/video_engine/vie_shared_data.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_shared_data.cc
@@ -20,16 +20,17 @@
 namespace webrtc {
 
 ViESharedData::ViESharedData(const Config& config)
     : number_cores_(CpuInfo::DetectNumberOfCores()),
       channel_manager_(new ViEChannelManager(0, number_cores_, config)),
       input_manager_(new ViEInputManager(0, config)),
       render_manager_(new ViERenderManager(0)),
       module_process_thread_(ProcessThread::CreateProcessThread()),
+      load_manager_(NULL),
       last_error_(0) {
   Trace::CreateTrace();
   channel_manager_->SetModuleProcessThread(module_process_thread_);
   input_manager_->SetModuleProcessThread(module_process_thread_);
   module_process_thread_->Start();
 }
 
 ViESharedData::~ViESharedData() {
@@ -52,9 +53,14 @@ int ViESharedData::LastErrorInternal() c
   last_error_ = 0;
   return error;
 }
 
 int ViESharedData::NumberOfCores() const {
   return number_cores_;
 }
 
+void ViESharedData::set_load_manager(CPULoadStateCallbackInvoker* load_manager) {
+  load_manager_ = load_manager;
+  channel_manager_->SetLoadManager(load_manager);
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/video_engine/vie_shared_data.h
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_shared_data.h
@@ -40,23 +40,28 @@ class ViESharedData {
   int instance_id() { return 0;}
   ViEChannelManager* channel_manager() { return channel_manager_.get(); }
   ViEInputManager* input_manager() { return input_manager_.get(); }
   ViERenderManager* render_manager() { return render_manager_.get(); }
 
   std::map<int, CpuOveruseObserver*>* overuse_observers() {
     return &overuse_observers_; }
 
+  CPULoadStateCallbackInvoker* load_manager() { return load_manager_; }
+  void set_load_manager(CPULoadStateCallbackInvoker* load_manager);
+
  private:
   const int number_cores_;
 
   scoped_ptr<ViEChannelManager> channel_manager_;
   scoped_ptr<ViEInputManager> input_manager_;
   scoped_ptr<ViERenderManager> render_manager_;
   ProcessThread* module_process_thread_;
+  // Owned by PeerConnection, not ViEEngine
+  CPULoadStateCallbackInvoker* load_manager_;
   mutable int last_error_;
 
   std::map<int, CpuOveruseObserver*> overuse_observers_;
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_VIDEO_ENGINE_VIE_SHARED_DATA_H_
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -223,16 +223,20 @@ pref("media.gstreamer.enabled", true);
 #endif
 #ifdef MOZ_APPLEMEDIA
 pref("media.apple.mp3.enabled", true);
 #endif
 #ifdef MOZ_WEBRTC
 pref("media.navigator.enabled", true);
 pref("media.navigator.video.enabled", true);
 pref("media.navigator.load_adapt", false);
+pref("media.navigator.load_adapt.measure_interval",1000);
+pref("media.navigator.load_adapt.avg_seconds",3);
+pref("media.navigator.load_adapt.high_load","0.90");
+pref("media.navigator.load_adapt.low_load","0.40");
 pref("media.navigator.video.default_fps",30);
 pref("media.navigator.video.default_minfps",10);
 #ifdef MOZ_WIDGET_GONK
 pref("media.navigator.video.default_width",320);
 pref("media.navigator.video.default_height",240);
 pref("media.peerconnection.enabled", true);
 pref("media.peerconnection.video.enabled", true);
 pref("media.navigator.video.max_fs", 1200); // 640x480 == 1200mb