Bug 1173255 - Cleanup MediaManager e10s code in prep for deviceId constraint. r=jesup
authorJan-Ivar Bruaroey <jib@mozilla.com>
Thu, 18 Jun 2015 11:46:36 -0400
changeset 249779 53063473eb54c1b4cd701be4d54eead966a51603
parent 249778 eca22a9aca5762dcbe1729c0b1cdf7620600fe64
child 249780 4c42035bc7f8945ca10f799925ec54d25dd7d154
push idunknown
push userunknown
push dateunknown
reviewersjesup
bugs1173255
milestone41.0a1
Bug 1173255 - Cleanup MediaManager e10s code in prep for deviceId constraint. r=jesup
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/media/MediaManager.cpp
dom/media/MediaManager.h
dom/media/PeerConnection.js
dom/media/nsIDOMNavigatorUserMedia.idl
dom/media/systemservices/MediaChild.cpp
dom/media/systemservices/MediaChild.h
dom/media/systemservices/MediaParent.cpp
dom/media/systemservices/MediaParent.h
dom/media/systemservices/MediaUtils.h
dom/media/systemservices/PMedia.ipdl
dom/media/tests/mochitest/test_getUserMedia_constraints.html
dom/media/webrtc/MediaEngine.h
dom/media/webrtc/MediaEngineCameraVideoSource.cpp
dom/media/webrtc/MediaEngineCameraVideoSource.h
dom/media/webrtc/MediaEngineDefault.cpp
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineGonkVideoSource.cpp
dom/media/webrtc/MediaEngineTabVideoSource.cpp
dom/media/webrtc/MediaEngineTabVideoSource.h
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
dom/media/webrtc/MediaEngineWebRTCVideo.cpp
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -47,16 +47,17 @@
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 #include "mozilla/widget/WidgetMessageUtils.h"
+#include "mozilla/media/MediaChild.h"
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #if defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
 #elif defined(XP_LINUX)
 #include "mozilla/Sandbox.h"
 #include "mozilla/SandboxInfo.h"
@@ -199,16 +200,17 @@ using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::icc;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::dom::mobileconnection;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
+using namespace mozilla::media;
 using namespace mozilla::embedding;
 using namespace mozilla::gmp;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 using namespace mozilla::jsipc;
 using namespace mozilla::psm;
@@ -1745,16 +1747,28 @@ ContentChild::SendPVoicemailConstructor(
 
 bool
 ContentChild::DeallocPVoicemailChild(PVoicemailChild* aActor)
 {
     static_cast<VoicemailIPCService*>(aActor)->Release();
     return true;
 }
 
+media::PMediaChild*
+ContentChild::AllocPMediaChild()
+{
+  return media::AllocPMediaChild();
+}
+
+bool
+ContentChild::DeallocPMediaChild(media::PMediaChild *aActor)
+{
+  return media::DeallocPMediaChild(aActor);
+}
+
 PStorageChild*
 ContentChild::AllocPStorageChild()
 {
     NS_NOTREACHED("We should never be manually allocating PStorageChild actors");
     return nullptr;
 }
 
 bool
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -257,16 +257,19 @@ public:
 
     virtual PTelephonyChild* AllocPTelephonyChild() override;
     virtual bool DeallocPTelephonyChild(PTelephonyChild*) override;
 
     virtual PVoicemailChild* AllocPVoicemailChild() override;
     PVoicemailChild* SendPVoicemailConstructor(PVoicemailChild* aActor);
     virtual bool DeallocPVoicemailChild(PVoicemailChild*) override;
 
+    virtual PMediaChild* AllocPMediaChild() override;
+    virtual bool DeallocPMediaChild(PMediaChild* aActor) override;
+
     virtual PStorageChild* AllocPStorageChild() override;
     virtual bool DeallocPStorageChild(PStorageChild* aActor) override;
 
     virtual PBluetoothChild* AllocPBluetoothChild() override;
     virtual bool DeallocPBluetoothChild(PBluetoothChild* aActor) override;
 
     virtual PFMRadioChild* AllocPFMRadioChild() override;
     virtual bool DeallocPFMRadioChild(PFMRadioChild* aActor) override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -69,16 +69,17 @@
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/LookAndFeel.h"
+#include "mozilla/media/MediaParent.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "mozilla/ProfileGatherer.h"
 #endif
@@ -253,16 +254,17 @@ using namespace mozilla::dom::cellbroadc
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::icc;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::dom::power;
 using namespace mozilla::dom::mobileconnection;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
+using namespace mozilla::media;
 using namespace mozilla::embedding;
 using namespace mozilla::gmp;
 using namespace mozilla::hal;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 using namespace mozilla::jsipc;
 using namespace mozilla::psm;
@@ -3802,16 +3804,28 @@ ContentParent::RecvPVoicemailConstructor
 
 bool
 ContentParent::DeallocPVoicemailParent(PVoicemailParent* aActor)
 {
     static_cast<VoicemailParent*>(aActor)->Release();
     return true;
 }
 
+media::PMediaParent*
+ContentParent::AllocPMediaParent()
+{
+  return media::AllocPMediaParent();
+}
+
+bool
+ContentParent::DeallocPMediaParent(media::PMediaParent *aActor)
+{
+  return media::DeallocPMediaParent(aActor);
+}
+
 PStorageParent*
 ContentParent::AllocPStorageParent()
 {
     return new DOMStorageDBParent();
 }
 
 bool
 ContentParent::DeallocPStorageParent(PStorageParent* aActor)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -641,16 +641,19 @@ private:
 
     virtual PTelephonyParent* AllocPTelephonyParent() override;
     virtual bool DeallocPTelephonyParent(PTelephonyParent*) override;
 
     virtual PVoicemailParent* AllocPVoicemailParent() override;
     virtual bool RecvPVoicemailConstructor(PVoicemailParent* aActor) override;
     virtual bool DeallocPVoicemailParent(PVoicemailParent* aActor) override;
 
+    virtual PMediaParent* AllocPMediaParent() override;
+    virtual bool DeallocPMediaParent(PMediaParent* aActor) override;
+
     virtual bool DeallocPStorageParent(PStorageParent* aActor) override;
 
     virtual PBluetoothParent* AllocPBluetoothParent() override;
     virtual bool DeallocPBluetoothParent(PBluetoothParent* aActor) override;
     virtual bool RecvPBluetoothConstructor(PBluetoothParent* aActor) override;
 
     virtual PFMRadioParent* AllocPFMRadioParent() override;
     virtual bool DeallocPFMRadioParent(PFMRadioParent* aActor) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -20,16 +20,17 @@ include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PFileDescriptorSet;
 include protocol PFMRadio;
 include protocol PFileSystemRequest;
 include protocol PHal;
 include protocol PIcc;
 include protocol PProcessHangMonitor;
 include protocol PImageBridge;
+include protocol PMedia;
 include protocol PMemoryReportRequest;
 include protocol PMobileConnection;
 include protocol PNecko;
 // FIXME This is pretty ridiculous, but we have to keep the order of the
 //       following 4 includes, or the parser is confused about PGMPContent
 //       bridging PContent and PGMP. As soon as it registers the bridge between
 //       PContent and PPluginModule it seems to think that PContent's parent and
 //       child live in the same process!
@@ -424,16 +425,17 @@ prio(normal upto urgent) sync protocol P
     manages PDeviceStorageRequest;
     manages PFileSystemRequest;
     manages PPSMContentDownloader;
     manages PExternalHelperApp;
     manages PFileDescriptorSet;
     manages PFMRadio;
     manages PHal;
     manages PIcc;
+    manages PMedia;
     manages PMemoryReportRequest;
     manages PMobileConnection;
     manages PNecko;
     manages POfflineCacheUpdate;
     manages PPrinting;
     manages PScreenManager;
     manages PSms;
     manages PSpeechSynthesis;
@@ -759,16 +761,18 @@ parent:
     PSpeechSynthesis();
 
     prio(urgent) async PStorage();
 
     PTelephony();
 
     PVoicemail();
 
+    PMedia();
+
     PBluetooth();
 
     PFMRadio();
 
     PAsmJSCacheEntry(OpenMode openMode, WriteParams write, Principal principal);
 
     PWebrtcGlobal();
 
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -118,16 +118,19 @@ using dom::MediaStreamConstraints;
 using dom::MediaTrackConstraintSet;
 using dom::MediaTrackConstraints;
 using dom::MediaStreamError;
 using dom::GetUserMediaRequest;
 using dom::Sequence;
 using dom::OwningBooleanOrMediaTrackConstraints;
 using dom::SupportedAudioConstraints;
 using dom::SupportedVideoConstraints;
+using media::Pledge;
+using media::NewRunnableFrom;
+using media::NewTaskFrom;
 
 static Atomic<bool> sInShutdown;
 
 static bool
 HostInDomain(const nsCString &aHost, const nsCString &aPattern)
 {
   int32_t patternOffset = 0;
   int32_t hostOffset = 0;
@@ -262,160 +265,16 @@ private:
 
   nsCOMPtr<SuccessCallbackType> mOnSuccess;
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   nsRefPtr<MediaMgrError> mError;
   uint64_t mWindowID;
   nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
 };
 
-/**
- * Invoke the GetUserMediaDevices success callback. Wrapped in a runnable
- * so that it may be called on the main thread. The error callback is also
- * passed so it can be released correctly.
- */
-class DeviceSuccessCallbackRunnable : public nsRunnable
-{
-public:
-  DeviceSuccessCallbackRunnable(
-    uint64_t aWindowID,
-    nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aOnSuccess,
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
-    nsTArray<nsRefPtr<MediaDevice>>* aDevices,
-    bool aIsGum)
-    : mDevices(aDevices)
-    , mWindowID(aWindowID)
-    , mIsGum(aIsGum)
-    , mManager(MediaManager::GetInstance())
-  {
-    mOnSuccess.swap(aOnSuccess);
-    mOnFailure.swap(aOnFailure);
-  }
-
-  ~DeviceSuccessCallbackRunnable()
-  {
-    if (!NS_IsMainThread()) {
-      // This can happen if the main thread processes the runnable before
-      // GetUserMediaDevicesTask::Run returns.
-      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-
-      NS_ProxyRelease(mainThread, mOnSuccess);
-      NS_ProxyRelease(mainThread, mOnFailure);
-    }
-  }
-
-  nsresult
-  AnonymizeId(nsAString& aId, const nsACString& aOriginKey)
-  {
-    nsresult rv;
-    nsCOMPtr<nsIKeyObjectFactory> factory =
-      do_GetService("@mozilla.org/security/keyobjectfactory;1", &rv);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    nsCString rawKey;
-    rv = Base64Decode(aOriginKey, rawKey);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    nsCOMPtr<nsIKeyObject> key;
-    rv = factory->KeyFromString(nsIKeyObject::HMAC, rawKey, getter_AddRefs(key));
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    nsCOMPtr<nsICryptoHMAC> hasher =
-      do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    rv = hasher->Init(nsICryptoHMAC::SHA256, key);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    NS_ConvertUTF16toUTF8 id(aId);
-    rv = hasher->Update(reinterpret_cast<const uint8_t*> (id.get()), id.Length());
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    nsCString mac;
-    rv = hasher->Finish(true, mac);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    aId = NS_ConvertUTF8toUTF16(mac);
-    return NS_OK;
-  }
-
-  NS_IMETHOD
-  Run()
-  {
-    NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
-
-    // Only run if window is still on our active list.
-    if (!mManager->IsWindowStillActive(mWindowID)) {
-      return NS_OK;
-    }
-
-    nsCOMPtr<nsIWritableVariant> devices =
-      do_CreateInstance("@mozilla.org/variant;1");
-
-    size_t len = mDevices->Length();
-
-    if (!len) {
-      if (mIsGum) { // gUM fails on 0 devices whereas enumerateDevices doesn't.
-        // XXX
-        // We should in the future return an empty array, and dynamically add
-        // devices to the dropdowns if things are hotplugged while the
-        // requester is up.
-        nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
-        if (window) {
-          nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
-              NS_LITERAL_STRING("NotFoundError"));
-          mOnFailure->OnError(error);
-        }
-        return NS_OK;
-      }
-      devices->SetAsEmptyArray(); // SetAsArray() fails on zero length arrays.
-    } else {
-      nsTArray<nsIMediaDevice*> tmp(len);
-      for (auto& device : *mDevices) {
-        if (!mOriginKey.IsEmpty()) {
-          nsString id;
-          device->GetId(id);
-          AnonymizeId(id, mOriginKey);
-          device->SetId(id);
-        }
-        tmp.AppendElement(device);
-      }
-      nsresult rv = devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
-                                        &NS_GET_IID(nsIMediaDevice),
-                                        mDevices->Length(),
-                                        const_cast<void*>(
-                                          static_cast<const void*>(tmp.Elements())
-                                        ));
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
-    }
-    mOnSuccess->OnSuccess(devices);
-    return NS_OK;
-  }
-
-  nsCString mOriginKey;
-private:
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
-  nsAutoPtr<nsTArray<nsRefPtr<MediaDevice>>> mDevices;
-  uint64_t mWindowID;
-  bool mIsGum;
-  nsRefPtr<MediaManager> mManager;
-};
-
 // Handle removing GetUserMediaCallbackMediaStreamListener from main thread
 class GetUserMediaListenerRemove: public nsRunnable
 {
 public:
   GetUserMediaListenerRemove(uint64_t aWindowID,
     GetUserMediaCallbackMediaStreamListener *aListener)
     : mWindowID(aWindowID)
     , mListener(aListener) {}
@@ -435,125 +294,49 @@ protected:
 };
 
 /**
  * nsIMediaDevice implementation.
  */
 NS_IMPL_ISUPPORTS(MediaDevice, nsIMediaDevice)
 
 MediaDevice::MediaDevice(MediaEngineSource* aSource)
-  : mHasFacingMode(false)
-  , mSource(aSource) {
+  : mSource(aSource) {
   mSource->GetName(mName);
-  mSource->GetUUID(mID);
+  nsCString id;
+  mSource->GetUUID(id);
+  CopyUTF8toUTF16(id, mID);
 }
 
 VideoDevice::VideoDevice(MediaEngineVideoSource* aSource)
   : MediaDevice(aSource) {
-#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
-  if (mName.EqualsLiteral("back")) {
-    mHasFacingMode = true;
-    mFacingMode = dom::VideoFacingModeEnum::Environment;
-  } else if (mName.EqualsLiteral("front")) {
-    mHasFacingMode = true;
-    mFacingMode = dom::VideoFacingModeEnum::User;
-  }
-#endif // MOZ_B2G_CAMERA
-#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
-  // Names are generated. Example: "Camera 0, Facing back, Orientation 90"
-  //
-  // See media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/
-  // webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
-
-  if (mName.Find(NS_LITERAL_STRING("Facing back")) != kNotFound) {
-    mHasFacingMode = true;
-    mFacingMode = dom::VideoFacingModeEnum::Environment;
-  } else if (mName.Find(NS_LITERAL_STRING("Facing front")) != kNotFound) {
-    mHasFacingMode = true;
-    mFacingMode = dom::VideoFacingModeEnum::User;
-  }
-#endif // ANDROID
-#ifdef XP_MACOSX
-  // Kludge to test user-facing cameras on OSX.
-  if (mName.Find(NS_LITERAL_STRING("Face")) != -1) {
-    mHasFacingMode = true;
-    mFacingMode = dom::VideoFacingModeEnum::User;
-  }
-#endif
   mMediaSource = aSource->GetMediaSource();
 }
 
 /**
  * Helper functions that implement the constraints algorithm from
  * http://dev.w3.org/2011/webrtc/editor/getusermedia.html#methods-5
  */
 
 // Reminder: add handling for new constraints both here and in GetSources below!
 
 uint32_t
 VideoDevice::GetBestFitnessDistance(
     const nsTArray<const MediaTrackConstraintSet*>& aConstraintSets)
 {
-  // TODO: Minimal kludge to fix plain and ideal facingMode regression, for
-  // smooth landing and uplift. Proper cleanup is forthcoming (1037389).
-  uint64_t distance = 0;
-
   // Interrogate device-inherent properties first.
-  for (size_t i = 0; i < aConstraintSets.Length(); i++) {
-    auto& c = *aConstraintSets[i];
-    if (!c.mFacingMode.IsConstrainDOMStringParameters() ||
-        c.mFacingMode.GetAsConstrainDOMStringParameters().mIdeal.WasPassed() ||
-        c.mFacingMode.GetAsConstrainDOMStringParameters().mExact.WasPassed()) {
-      nsString deviceFacingMode;
-      GetFacingMode(deviceFacingMode);
-      if (c.mFacingMode.IsString()) {
-        if (c.mFacingMode.GetAsString() != deviceFacingMode) {
-          if (i == 0) {
-            distance = 1000;
-          }
-        }
-      } else if (c.mFacingMode.IsStringSequence()) {
-        if (!c.mFacingMode.GetAsStringSequence().Contains(deviceFacingMode)) {
-          if (i == 0) {
-            distance = 1000;
-          }
-        }
-      } else if (c.mFacingMode.GetAsConstrainDOMStringParameters().mExact.WasPassed()) {
-        auto& exact = c.mFacingMode.GetAsConstrainDOMStringParameters().mExact.Value();
-        if (exact.IsString()) {
-          if (exact.GetAsString() != deviceFacingMode) {
-            return UINT32_MAX;
-          }
-        } else if (!exact.GetAsStringSequence().Contains(deviceFacingMode)) {
-          return UINT32_MAX;
-        }
-      } else if (c.mFacingMode.GetAsConstrainDOMStringParameters().mIdeal.WasPassed()) {
-        auto& ideal = c.mFacingMode.GetAsConstrainDOMStringParameters().mIdeal.Value();
-        if (ideal.IsString()) {
-          if (ideal.GetAsString() != deviceFacingMode) {
-            if (i == 0) {
-              distance = 1000;
-            }
-          }
-        } else if (!ideal.GetAsStringSequence().Contains(deviceFacingMode)) {
-          if (i == 0) {
-            distance = 1000;
-          }
-        }
-      }
-    }
+  for (const auto& constraint : aConstraintSets) {
     nsString s;
     GetMediaSource(s);
-    if (s != c.mMediaSource) {
+    if (s != constraint->mMediaSource) {
       return UINT32_MAX;
     }
   }
   // Forward request to underlying object to interrogate per-mode capabilities.
-  distance += uint64_t(GetSource()->GetBestFitnessDistance(aConstraintSets));
-  return uint32_t(std::min(distance, uint64_t(UINT32_MAX)));
+  return GetSource()->GetBestFitnessDistance(aConstraintSets);
 }
 
 AudioDevice::AudioDevice(MediaEngineAudioSource* aSource)
   : MediaDevice(aSource) {}
 
 uint32_t
 AudioDevice::GetBestFitnessDistance(
     const nsTArray<const MediaTrackConstraintSet*>& aConstraintSets)
@@ -598,28 +381,16 @@ MediaDevice::GetId(nsAString& aID)
 
 void
 MediaDevice::SetId(const nsAString& aID)
 {
   mID.Assign(aID);
 }
 
 NS_IMETHODIMP
-MediaDevice::GetFacingMode(nsAString& aFacingMode)
-{
-  if (mHasFacingMode) {
-    aFacingMode.Assign(NS_ConvertUTF8toUTF16(
-        dom::VideoFacingModeEnumValues::strings[uint32_t(mFacingMode)].value));
-  } else {
-    aFacingMode.Truncate(0);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 MediaDevice::GetMediaSource(nsAString& aMediaSource)
 {
   if (mMediaSource == dom::MediaSourceEnum::Microphone) {
     aMediaSource.Assign(NS_LITERAL_STRING("microphone"));
   } else if (mMediaSource == dom::MediaSourceEnum::Window) { // this will go away
     aMediaSource.Assign(NS_LITERAL_STRING("window"));
   } else { // all the rest are shared
     aMediaSource.Assign(NS_ConvertUTF8toUTF16(
@@ -1434,145 +1205,95 @@ public:
     return NS_OK;
   }
 
 private:
   nsAutoPtr<GetUserMediaTask> mTask;
 };
 #endif
 
-class SanitizeDeviceIdsTask : public Task
-{
-public:
-  explicit SanitizeDeviceIdsTask(int64_t aSinceWhen)
-  : mSinceWhen(aSinceWhen) {}
+// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func:
+// error: 'this' was not captured for this lambda function
 
-  void // NS_IMETHOD
-  Run()
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-    nsRefPtr<media::ChildPledge<bool>> p =
-        mozilla::media::SanitizeOriginKeys(mSinceWhen); // we fire and forget
-  }
-private:
-  int64_t mSinceWhen;
-};
+static auto& MediaManager_GetInstance = MediaManager::GetInstance;
+static auto& MediaManager_ToJSArray = MediaManager::ToJSArray;
+static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices;
 
 /**
- * Similar to GetUserMediaTask, but used for the chrome-only
- * GetUserMediaDevices function. Enumerates a list of audio & video devices,
- * wraps them up in nsIMediaDevice objects and returns it to the success
- * callback.
- *
- * All code in this class runs on the MediaManager thread.
+ * EnumerateRawDevices - Enumerate a list of audio & video devices that
+ * satisfy passed-in constraints. List contains raw id's.
  */
-class GetUserMediaDevicesTask : public Task
+
+already_AddRefed<MediaManager::PledgeSourceSet>
+MediaManager::EnumerateRawDevices(uint64_t aWindowId,
+                                  const MediaStreamConstraints& aConstraints)
 {
-public:
-  GetUserMediaDevicesTask(
-    const MediaStreamConstraints& aConstraints,
-    already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aOnSuccess,
-    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure,
-    uint64_t aWindowId, nsACString& aAudioLoopbackDev,
-    nsACString& aVideoLoopbackDev, bool aPrivileged, const nsACString& aOrigin,
-    bool aInPrivateBrowsing, bool aUseFakeDevices)
-    : mConstraints(aConstraints)
-    , mOnSuccess(aOnSuccess)
-    , mOnFailure(aOnFailure)
-    , mManager(MediaManager::GetInstance())
-    , mWindowId(aWindowId)
-    , mLoopbackAudioDevice(aAudioLoopbackDev)
-    , mLoopbackVideoDevice(aVideoLoopbackDev)
-    , mPrivileged(aPrivileged)
-    , mOrigin(aOrigin)
-    , mInPrivateBrowsing(aInPrivateBrowsing)
-    , mUseFakeDevices(aUseFakeDevices) {}
+  MOZ_ASSERT(NS_IsMainThread());
+  nsRefPtr<PledgeSourceSet> p = new PledgeSourceSet();
+  uint32_t id = mOutstandingPledges.Append(*p);
+
+  // Check if the preference for using audio/video loopback devices is
+  // enabled. This is currently used for automated media tests only.
+  auto audioLoopDev = Preferences::GetCString("media.audio_loopback_dev");
+  auto videoLoopDev = Preferences::GetCString("media.video_loopback_dev");
+  bool fake = Preferences::GetBool("media.navigator.streams.fake", false);
 
-  void // NS_IMETHOD
-  Run()
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-
+  MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aConstraints, aWindowId,
+                                                 audioLoopDev,  videoLoopDev,
+                                                 fake]() mutable {
     nsRefPtr<MediaEngine> backend;
-    if (mConstraints.mFake || mUseFakeDevices)
-      backend = new MediaEngineDefault(mConstraints.mFakeTracks);
-    else
-      backend = mManager->GetBackend(mWindowId);
-
-    typedef nsTArray<nsRefPtr<MediaDevice>> SourceSet;
+    if (aConstraints.mFake || fake) {
+      backend = new MediaEngineDefault(aConstraints.mFakeTracks);
+    } else {
+      nsRefPtr<MediaManager> manager = MediaManager_GetInstance();
+      backend = manager->GetBackend(aWindowId);
+    }
 
     ScopedDeletePtr<SourceSet> result(new SourceSet);
-    if (IsOn(mConstraints.mVideo)) {
+    if (IsOn(aConstraints.mVideo)) {
       nsTArray<nsRefPtr<VideoDevice>> sources;
-      GetSources(backend, GetInvariant(mConstraints.mVideo),
-                 &MediaEngine::EnumerateVideoDevices, sources,
-                 mLoopbackVideoDevice.get());
+      GetSources(backend, GetInvariant(aConstraints.mVideo),
+                 &MediaEngine::EnumerateVideoDevices, sources, videoLoopDev);
       for (auto& source : sources) {
         result->AppendElement(source);
       }
     }
-    if (IsOn(mConstraints.mAudio)) {
+    if (IsOn(aConstraints.mAudio)) {
       nsTArray<nsRefPtr<AudioDevice>> sources;
-      GetSources(backend, GetInvariant(mConstraints.mAudio),
-                 &MediaEngine::EnumerateAudioDevices, sources,
-                 mLoopbackAudioDevice.get());
+      GetSources(backend, GetInvariant(aConstraints.mAudio),
+                 &MediaEngine::EnumerateAudioDevices, sources, audioLoopDev);
       for (auto& source : sources) {
         result->AppendElement(source);
       }
     }
-    nsRefPtr<DeviceSuccessCallbackRunnable> runnable =
-        new DeviceSuccessCallbackRunnable(mWindowId, mOnSuccess, mOnFailure,
-                                          result.forget(), mPrivileged);
-    if (mPrivileged) {
-      NS_DispatchToMainThread(runnable);
-    } else {
-      // Get persistent origin-unique uuid to anonymize deviceIds back on main.
-      //
-      // GetOriginKey is an async API that returns a pledge (as promise-like
-      // pattern). We use .Then() to pass in a lambda to run back on this
-      // thread once GetOriginKey resolves asynchronously . The "runnable"
-      // pointer is "captured" (passed by value) into the lambda.
-      nsRefPtr<media::ChildPledge<nsCString>> p =
-          media::GetOriginKey(mOrigin, mInPrivateBrowsing);
-      p->Then([runnable](nsCString result) mutable {
-        runnable->mOriginKey = result;
-        NS_DispatchToMainThread(runnable);
-      });
-    }
-    // One of the Runnables have taken these.
-    MOZ_ASSERT(!mOnSuccess && !mOnFailure);
-  }
-
-private:
-  MediaStreamConstraints mConstraints;
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
-  nsRefPtr<MediaManager> mManager;
-  uint64_t mWindowId;
-  const nsString mCallId;
-  // Audio & Video loopback devices to be used based on
-  // the preference settings. This is currently used for
-  // automated media tests only.
-  nsCString mLoopbackAudioDevice;
-  nsCString mLoopbackVideoDevice;
-  bool mPrivileged;
-  nsCString mOrigin;
-  bool mInPrivateBrowsing;
-  bool mUseFakeDevices;
-};
+    SourceSet* handoff = result.forget();
+    NS_DispatchToMainThread(NewRunnableFrom([id, handoff]() mutable {
+      ScopedDeletePtr<SourceSet> result(handoff);
+      nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
+      if (!mgr) {
+        return NS_OK;
+      }
+      nsRefPtr<PledgeSourceSet> p = mgr->mOutstandingPledges.Remove(id);
+      if (p) {
+        p->Resolve(result.forget());
+      }
+      return NS_OK;
+    }));
+  }));
+  return p.forget();
+}
 
 MediaManager::MediaManager()
   : mMediaThread(nullptr)
   , mMutex("mozilla::MediaManager")
   , mBackend(nullptr) {
   mPrefs.mWidth  = 0; // adaptive default
   mPrefs.mHeight = 0; // adaptive default
   mPrefs.mFPS    = MediaEngine::DEFAULT_VIDEO_FPS;
   mPrefs.mMinFPS = MediaEngine::DEFAULT_VIDEO_MIN_FPS;
-
   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);
     }
   }
@@ -1649,16 +1370,25 @@ MediaManager::GetIfExists() {
 /* static */ already_AddRefed<MediaManager>
 MediaManager::GetInstance()
 {
   // so we can have non-refcounted getters
   nsRefPtr<MediaManager> service = MediaManager::Get();
   return service.forget();
 }
 
+media::Parent<media::NonE10s>*
+MediaManager::GetNonE10sParent()
+{
+  if (!mNonE10sParent) {
+    mNonE10sParent = new media::Parent<media::NonE10s>(true);
+  }
+  return mNonE10sParent;
+}
+
 /* static */
 void
 MediaManager::PostTask(const tracked_objects::Location& from_here, Task* task)
 {
   if (sInShutdown) {
     // Can't safely delete task here since it may have items with specific
     // thread-release requirements.
     return;
@@ -1731,32 +1461,30 @@ MediaManager::NotifyRecordingStatusChang
 }
 
 /**
  * The entry point for this file. A call from Navigator::mozGetUserMedia
  * will end up here. MediaManager is a singleton that is responsible
  * for handling all incoming getUserMedia calls from every window.
  */
 nsresult
-MediaManager::GetUserMedia(
-  nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints,
-  nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
-  nsIDOMGetUserMediaErrorCallback* aOnFailure)
+MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
+                           const MediaStreamConstraints& aConstraints,
+                           nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
+                           nsIDOMGetUserMediaErrorCallback* aOnFailure)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
-
-  NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aWindow);
+  MOZ_ASSERT(aOnFailure);
+  MOZ_ASSERT(aOnSuccess);
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
 
   bool privileged = nsContentUtils::IsCallerChrome();
 
-  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
-
   MediaStreamConstraints c(aConstraints); // copy
 
   static bool created = false;
   if (!created) {
     // Force MediaManager to startup before we try to access it from other threads
     // Hack: should init singleton earlier unless it's expensive (mem or CPU)
     (void) MediaManager::Get();
 #ifdef MOZ_B2G
@@ -1976,72 +1704,223 @@ MediaManager::GetUserMedia(
 
 #ifdef MOZ_WEBRTC
   EnableWebRtcLog();
 #endif
 
   return NS_OK;
 }
 
-nsresult
-MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
-  const MediaStreamConstraints& aConstraints,
-  nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
-  nsIDOMGetUserMediaErrorCallback* aOnFailure,
-  uint64_t aInnerWindowID,
-  bool aPrivileged)
+/* static */ void
+MediaManager::AnonymizeDevices(SourceSet& aDevices, const nsACString& aOriginKey)
+{
+  if (!aOriginKey.IsEmpty()) {
+    for (auto& device : aDevices) {
+      nsString id;
+      device->GetId(id);
+      AnonymizeId(id, aOriginKey);
+      device->SetId(id);
+    }
+  }
+}
+
+/* static */ nsresult
+MediaManager::AnonymizeId(nsAString& aId, const nsACString& aOriginKey)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv;
+  nsCOMPtr<nsIKeyObjectFactory> factory =
+    do_GetService("@mozilla.org/security/keyobjectfactory;1", &rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  nsCString rawKey;
+  rv = Base64Decode(aOriginKey, rawKey);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  nsCOMPtr<nsIKeyObject> key;
+  rv = factory->KeyFromString(nsIKeyObject::HMAC, rawKey, getter_AddRefs(key));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
-  NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(!sInShutdown, NS_ERROR_FAILURE);
+  nsCOMPtr<nsICryptoHMAC> hasher =
+    do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = hasher->Init(nsICryptoHMAC::SHA256, key);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  NS_ConvertUTF16toUTF8 id(aId);
+  rv = hasher->Update(reinterpret_cast<const uint8_t*> (id.get()), id.Length());
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  nsCString mac;
+  rv = hasher->Finish(true, mac);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
+  aId = NS_ConvertUTF8toUTF16(mac);
+  return NS_OK;
+}
 
-  // Check if the preference for using loopback devices is enabled.
-  nsAdoptingCString loopbackAudioDevice =
-    Preferences::GetCString("media.audio_loopback_dev");
-  nsAdoptingCString loopbackVideoDevice =
-    Preferences::GetCString("media.video_loopback_dev");
-  bool useFakeStreams =
-    Preferences::GetBool("media.navigator.streams.fake", false);
+/* static */
+already_AddRefed<nsIWritableVariant>
+MediaManager::ToJSArray(SourceSet& aDevices)
+{
+  nsCOMPtr<nsIWritableVariant> var = do_CreateInstance("@mozilla.org/variant;1");
+  size_t len = aDevices.Length();
+  if (len) {
+    nsTArray<nsIMediaDevice*> tmp(len);
+    for (auto& device : aDevices) {
+      tmp.AppendElement(device);
+    }
+    auto* elements = static_cast<const void*>(tmp.Elements());
+    nsresult rv = var->SetAsArray(nsIDataType::VTYPE_INTERFACE,
+                                  &NS_GET_IID(nsIMediaDevice), len,
+                                  const_cast<void*>(elements));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return nullptr;
+    }
+  } else {
+    var->SetAsEmptyArray(); // because SetAsArray() fails on zero length arrays.
+  }
+  return var.forget();
+}
+
+already_AddRefed<MediaManager::PledgeSourceSet>
+MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
+                                   const MediaStreamConstraints& aConstraints)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // This function returns a pledge, a promise-like object with the future result
+  nsRefPtr<PledgeSourceSet> pledge = new PledgeSourceSet();
+  uint32_t id = mOutstandingPledges.Append(*pledge);
+
+  // To get a device list anonymized for a particular origin, we must:
+  // 1. Get an origin-key (for either regular or private browsing)
+  // 2. Get the raw devices list
+  // 3. Anonymize the raw list with the origin-key.
 
   nsCString origin;
-  nsPrincipal::GetOriginForURI(aWindow->GetDocumentURI(), origin);
-  bool inPrivateBrowsing;
+  bool privateBrowsing;
   {
-    nsCOMPtr<nsIDocument> doc = aWindow->GetDoc();
+    nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
+        (nsGlobalWindow::GetInnerWindowWithId(aWindowId));
+    nsPrincipal::GetOriginForURI(window->GetDocumentURI(), origin);
+
+    nsCOMPtr<nsIDocument> doc = window->GetDoc();
     nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
-    inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
+    privateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
   }
-  MediaManager::PostTask(FROM_HERE,
-    new GetUserMediaDevicesTask(
-      aConstraints, onSuccess.forget(), onFailure.forget(),
-      (aInnerWindowID ? aInnerWindowID : aWindow->WindowID()),
-      loopbackAudioDevice, loopbackVideoDevice, aPrivileged, origin,
-      inPrivateBrowsing, useFakeStreams));
+  // GetOriginKey is an async API that returns a pledge (a promise-like
+  // pattern). We use .Then() to pass in a lambda to run back on this same
+  // thread later once GetOriginKey resolves. Needed variables are "captured"
+  // (passed by value) safely into the lambda.
+
+  nsRefPtr<Pledge<nsCString>> p = media::GetOriginKey(origin, privateBrowsing);
+  p->Then([id, aWindowId, aConstraints](const nsCString& aOriginKey) mutable {
+    MOZ_ASSERT(NS_IsMainThread());
+    nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
+
+    nsRefPtr<PledgeSourceSet> p = mgr->EnumerateRawDevices(aWindowId, aConstraints);
+    p->Then([id, aWindowId, aOriginKey](SourceSet*& aDevices) mutable {
+      ScopedDeletePtr<SourceSet> devices(aDevices); // secondary result
 
-  return NS_OK;
+      // Only run if window is still on our active list.
+      nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
+      if (!mgr) {
+        return NS_OK;
+      }
+      nsRefPtr<PledgeSourceSet> p = mgr->mOutstandingPledges.Remove(id);
+      if (!p || !mgr->IsWindowStillActive(aWindowId)) {
+        return NS_OK;
+      }
+      MediaManager_AnonymizeDevices(*devices, aOriginKey);
+      p->Resolve(devices.forget());
+      return NS_OK;
+    });
+  });
+  return pledge.forget();
 }
 
 nsresult
 MediaManager::EnumerateDevices(nsPIDOMWindow* aWindow,
                                nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
                                nsIDOMGetUserMediaErrorCallback* aOnFailure)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_TRUE(!sInShutdown, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
+  uint64_t windowId = aWindow->WindowID();
+
+  AddWindowID(windowId);
 
   MediaStreamConstraints c;
   c.mVideo.SetAsBoolean() = true;
   c.mAudio.SetAsBoolean() = true;
 
-  AddWindowID(aWindow->WindowID());
-  return GetUserMediaDevices(aWindow, c, aOnSuccess, aOnFailure, 0, false);
+  nsRefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowId, c);
+  p->Then([onSuccess](SourceSet*& aDevices) mutable {
+    ScopedDeletePtr<SourceSet> devices(aDevices); // grab result
+    nsCOMPtr<nsIWritableVariant> array = MediaManager_ToJSArray(*devices);
+    onSuccess->OnSuccess(array);
+  }, [onFailure](MediaStreamError& reason) mutable {
+    onFailure->OnError(&reason);
+  });
+  return NS_OK;
+}
+
+/*
+ * GetUserMediaDevices - called by the UI-part of getUserMedia from chrome JS.
+ */
+
+nsresult
+MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
+                                  const MediaStreamConstraints& aConstraints,
+                                  nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
+                                  nsIDOMGetUserMediaErrorCallback* aOnFailure,
+                                  uint64_t aWindowId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
+  if (!aWindowId) {
+    aWindowId = aWindow->WindowID();
+  }
+
+  nsRefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(aWindowId, aConstraints);
+  p->Then([aWindowId, onSuccess, onFailure](SourceSet*& aDevices) mutable {
+    ScopedDeletePtr<SourceSet> devices(aDevices); // grab result
+
+    if (devices->Length()) {
+      nsCOMPtr<nsIWritableVariant> array = MediaManager_ToJSArray(*devices);
+      onSuccess->OnSuccess(array);
+    } else {
+      nsRefPtr<nsGlobalWindow> window = nsGlobalWindow::GetInnerWindowWithId(aWindowId);
+      if (!window) {
+        return NS_ERROR_UNEXPECTED;
+      }
+      nsRefPtr<MediaStreamError> reason =
+          new MediaStreamError(window, NS_LITERAL_STRING("NotFoundError"));
+      onFailure->OnError(reason);
+    }
+    return NS_OK;
+  }, [onFailure](MediaStreamError& reason) mutable {
+    onFailure->OnError(&reason);
+  });
+  return NS_OK;
 }
 
 MediaEngine*
 MediaManager::GetBackend(uint64_t aWindowId)
 {
   // Plugin backends as appropriate. The default engine also currently
   // includes picture support for Android.
   // This IS called off main-thread.
@@ -2545,17 +2424,17 @@ MediaManager::MediaCaptureWindowState(ns
 }
 
 NS_IMETHODIMP
 MediaManager::SanitizeDeviceIds(int64_t aSinceWhen)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   LOG(("%s: sinceWhen = %llu", __FUNCTION__, aSinceWhen));
 
-  MediaManager::PostTask(FROM_HERE, new SanitizeDeviceIdsTask(aSinceWhen));
+  media::SanitizeOriginKeys(aSinceWhen); // we fire and forget
   return NS_OK;
 }
 
 static void
 StopScreensharingCallback(MediaManager *aThis,
                           uint64_t aWindowID,
                           StreamListeners *aListeners,
                           void *aData)
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -22,16 +22,18 @@
 #include "nsIDOMNavigatorUserMedia.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/MediaStreamError.h"
+#include "mozilla/media/MediaChild.h"
+#include "mozilla/media/MediaParent.h"
 #include "mozilla/Logging.h"
 #include "DOMMediaStream.h"
 
 #ifdef MOZ_WEBRTC
 #include "mtransport/runnable_utils.h"
 #endif
 
 // Note, these suck in Windows headers, unfortunately.
@@ -463,18 +465,16 @@ public:
   NS_DECL_NSIMEDIADEVICE
 
   void SetId(const nsAString& aID);
 protected:
   virtual ~MediaDevice() {}
   explicit MediaDevice(MediaEngineSource* aSource);
   nsString mName;
   nsString mID;
-  bool mHasFacingMode;
-  dom::VideoFacingModeEnum mFacingMode;
   dom::MediaSourceEnum mMediaSource;
   nsRefPtr<MediaEngineSource> mSource;
 };
 
 class VideoDevice : public MediaDevice
 {
 public:
   typedef MediaEngineVideoSource Source;
@@ -529,16 +529,17 @@ public:
                                               const nsString& aMsg,
                                               const bool& aIsAudio,
                                               const bool& aIsVideo);
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIMEDIAMANAGERSERVICE
 
+  media::Parent<media::NonE10s>* GetNonE10sParent();
   MediaEngine* GetBackend(uint64_t aWindowId = 0);
   StreamListeners *GetWindowListeners(uint64_t aWindowId) {
     NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
 
     return mActiveWindows.Get(aWindowId);
   }
   void RemoveWindowID(uint64_t aWindowId);
   bool IsWindowStillActive(uint64_t aWindowId) {
@@ -550,33 +551,47 @@ public:
 
   nsresult GetUserMedia(
     nsPIDOMWindow* aWindow,
     const dom::MediaStreamConstraints& aConstraints,
     nsIDOMGetUserMediaSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
 
   nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
-    const dom::MediaStreamConstraints& aConstraints,
-    nsIGetUserMediaDevicesSuccessCallback* onSuccess,
-    nsIDOMGetUserMediaErrorCallback* onError,
-    uint64_t aInnerWindowID = 0,
-    bool aPrivileged = true);
+                               const dom::MediaStreamConstraints& aConstraints,
+                               nsIGetUserMediaDevicesSuccessCallback* onSuccess,
+                               nsIDOMGetUserMediaErrorCallback* onError,
+                               uint64_t aInnerWindowID = 0);
 
   nsresult EnumerateDevices(nsPIDOMWindow* aWindow,
                             nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
                             nsIDOMGetUserMediaErrorCallback* aOnFailure);
 
   nsresult EnumerateDevices(nsPIDOMWindow* aWindow, dom::Promise& aPromise);
   void OnNavigation(uint64_t aWindowID);
   bool IsWindowActivelyCapturing(uint64_t aWindowId);
 
   MediaEnginePrefs mPrefs;
 
 private:
+  typedef nsTArray<nsRefPtr<MediaDevice>> SourceSet;
+  typedef media::Pledge<SourceSet*, dom::MediaStreamError> PledgeSourceSet;
+
+  static nsresult AnonymizeId(nsAString& aId, const nsACString& aOriginKey);
+public: // TODO: make private once we upgrade to GCC 4.8+ on linux.
+  static void AnonymizeDevices(SourceSet& aDevices, const nsACString& aOriginKey);
+  static already_AddRefed<nsIWritableVariant> ToJSArray(SourceSet& aDevices);
+private:
+  already_AddRefed<PledgeSourceSet>
+  EnumerateRawDevices(uint64_t aWindowId,
+                      const dom::MediaStreamConstraints& aConstraints);
+  already_AddRefed<PledgeSourceSet>
+  EnumerateDevicesImpl(uint64_t aWindowId,
+                       const dom::MediaStreamConstraints& aConstraints);
+
   StreamListeners* AddWindowID(uint64_t aWindowId);
   WindowTable *GetActiveWindows() {
     NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
     return &mActiveWindows;
   }
 
   void GetPref(nsIPrefBranch *aBranch, const char *aPref,
                const char *aData, int32_t *aVal);
@@ -605,16 +620,20 @@ private:
   nsAutoPtr<base::Thread> mMediaThread;
 
   Mutex mMutex;
   // protected with mMutex:
   RefPtr<MediaEngine> mBackend;
 
   static StaticRefPtr<MediaManager> sSingleton;
 
+  media::CoatCheck<PledgeSourceSet> mOutstandingPledges;
 #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
   nsRefPtr<nsDOMCameraManager> mCameraManager;
 #endif
+public:
+  media::CoatCheck<media::Pledge<nsCString>> mGetOriginKeyPledges;
+  ScopedDeletePtr<media::Parent<media::NonE10s>> mNonE10sParent;
 };
 
 } // namespace mozilla
 
 #endif // MOZILLA_MEDIAMANAGER_H
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -999,16 +999,17 @@ RTCPeerConnection.prototype = {
       dict.maxRetransmits = dict.maxRetransmitNum;
       this.logWarning("Deprecated RTCDataChannelInit dictionary entry maxRetransmitNum used!", null, 0);
     }
     if (dict.outOfOrderAllowed != undefined) {
       dict.ordered = !dict.outOfOrderAllowed; // the meaning is swapped with
                                               // the name change
       this.logWarning("Deprecated RTCDataChannelInit dictionary entry outOfOrderAllowed used!", null, 0);
     }
+
     if (dict.preset != undefined) {
       dict.negotiated = dict.preset;
       this.logWarning("Deprecated RTCDataChannelInit dictionary entry preset used!", null, 0);
     }
     if (dict.stream != undefined) {
       dict.id = dict.stream;
       this.logWarning("Deprecated RTCDataChannelInit dictionary entry stream used!", null, 0);
     }
--- a/dom/media/nsIDOMNavigatorUserMedia.idl
+++ b/dom/media/nsIDOMNavigatorUserMedia.idl
@@ -1,22 +1,21 @@
 /* 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 "nsISupports.idl"
 #include "nsIVariant.idl"
 
-[scriptable, builtinclass, uuid(bbfebbc6-76eb-407c-b77d-363a69bc5c30)]
+[scriptable, builtinclass, uuid(cebcefca-2de1-460d-b253-d0582c50b40f)]
 interface nsIMediaDevice : nsISupports
 {
   readonly attribute DOMString type;
   readonly attribute DOMString name;
   readonly attribute DOMString id;
-  readonly attribute DOMString facingMode;
   readonly attribute DOMString mediaSource;
 };
 
 [scriptable, function, uuid(24544878-d35e-4962-8c5f-fb84e97bdfee)]
 interface nsIGetUserMediaDevicesSuccessCallback : nsISupports
 {
   void onSuccess(in nsIVariant devices);
 };
--- a/dom/media/systemservices/MediaChild.cpp
+++ b/dom/media/systemservices/MediaChild.cpp
@@ -1,154 +1,116 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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 "MediaChild.h"
+#include "MediaParent.h"
 
-#include "mozilla/ipc/BackgroundChild.h"
-#include "mozilla/ipc/PBackgroundChild.h"
 #include "nsGlobalWindow.h"
 #include "mozilla/MediaManager.h"
 #include "mozilla/Logging.h"
 #include "nsQueryObject.h"
 
 #undef LOG
 PRLogModuleInfo *gMediaChildLog;
 #define LOG(args) MOZ_LOG(gMediaChildLog, mozilla::LogLevel::Debug, args)
 
 namespace mozilla {
 namespace media {
 
-static Child* sChild;
-
-template<typename ValueType> void
-ChildPledge<ValueType>::ActorCreated(PBackgroundChild* aActor)
-{
-  if (!sChild) {
-    // Create PMedia by sending a message to the parent
-    sChild = static_cast<Child*>(aActor->SendPMediaConstructor());
-  }
-  Run(sChild);
-}
-
-template<typename ValueType> void
-ChildPledge<ValueType>::ActorFailed()
-{
-  Pledge<ValueType>::Reject(NS_ERROR_UNEXPECTED);
-}
-
-template<typename ValueType> NS_IMPL_ADDREF(ChildPledge<ValueType>)
-template<typename ValueType> NS_IMPL_RELEASE(ChildPledge<ValueType>)
-template<typename ValueType> NS_INTERFACE_MAP_BEGIN(ChildPledge<ValueType>)
-NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
-NS_INTERFACE_MAP_END
-
-already_AddRefed<ChildPledge<nsCString>>
+already_AddRefed<Pledge<nsCString>>
 GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing)
 {
-  class Pledge : public ChildPledge<nsCString>
-  {
-  public:
-    explicit Pledge(const nsCString& aOrigin, bool aPrivateBrowsing)
-    : mOrigin(aOrigin), mPrivateBrowsing(aPrivateBrowsing) {}
-  private:
-    ~Pledge() {}
-    void Run(PMediaChild* aChild)
-    {
-      Child* child = static_cast<Child*>(aChild);
+  nsRefPtr<MediaManager> mgr = MediaManager::GetInstance();
+  MOZ_ASSERT(mgr);
+
+  nsRefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
+  uint32_t id = mgr->mGetOriginKeyPledges.Append(*p);
 
-      uint32_t id = child->AddRequestPledge(*this);
-      child->SendGetOriginKey(id, mOrigin, mPrivateBrowsing);
-    }
-    const nsCString mOrigin;
-    const bool mPrivateBrowsing;
-  };
-
-  nsRefPtr<ChildPledge<nsCString>> p = new Pledge(aOrigin, aPrivateBrowsing);
-  nsCOMPtr<nsIIPCBackgroundChildCreateCallback> cb = do_QueryObject(p);
-  bool ok = ipc::BackgroundChild::GetOrCreateForCurrentThread(cb);
-  MOZ_RELEASE_ASSERT(ok);
+  if (XRE_GetProcessType() == GeckoProcessType_Default) {
+    mgr->GetNonE10sParent()->RecvGetOriginKey(id, aOrigin, aPrivateBrowsing);
+  } else {
+    Child::Get()->SendGetOriginKey(id, aOrigin, aPrivateBrowsing);
+  }
   return p.forget();
 }
 
-already_AddRefed<ChildPledge<bool>>
+void
 SanitizeOriginKeys(const uint64_t& aSinceWhen)
 {
-  class Pledge : public ChildPledge<bool>
-  {
-  public:
-    explicit Pledge(const uint64_t& aSinceWhen) : mSinceWhen(aSinceWhen) {}
-  private:
-    void Run(PMediaChild* aMedia)
-    {
-      aMedia->SendSanitizeOriginKeys(mSinceWhen);
-      mValue = true;
-      LOG(("SanitizeOriginKeys since %llu", mSinceWhen));
-      Resolve();
-    }
-    const uint64_t mSinceWhen;
-  };
+  LOG(("SanitizeOriginKeys since %llu", aSinceWhen));
 
-  nsRefPtr<ChildPledge<bool>> p = new Pledge(aSinceWhen);
-  nsCOMPtr<nsIIPCBackgroundChildCreateCallback> cb = do_QueryObject(p);
-  bool ok = ipc::BackgroundChild::GetOrCreateForCurrentThread(cb);
-  MOZ_RELEASE_ASSERT(ok);
-  return p.forget();
+  if (XRE_GetProcessType() == GeckoProcessType_Default) {
+    // Avoid opening MediaManager in this case, since this is called by
+    // sanitize.js when cookies are cleared, which can happen on startup.
+    ScopedDeletePtr<Parent<NonE10s>> tmpParent(new Parent<NonE10s>(true));
+    tmpParent->RecvSanitizeOriginKeys(aSinceWhen);
+  } else {
+    Child::Get()->SendSanitizeOriginKeys(aSinceWhen);
+  }
+}
+
+static Child* sChild;
+
+Child* Child::Get()
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!sChild) {
+    sChild = static_cast<Child*>(dom::ContentChild::GetSingleton()->SendPMediaConstructor());
+  }
+  return sChild;
 }
 
 Child::Child()
+  : mActorDestroyed(false)
 {
   if (!gMediaChildLog) {
     gMediaChildLog = PR_NewLogModule("MediaChild");
   }
   LOG(("media::Child: %p", this));
   MOZ_COUNT_CTOR(Child);
 }
 
 Child::~Child()
 {
   LOG(("~media::Child: %p", this));
   sChild = nullptr;
   MOZ_COUNT_DTOR(Child);
 }
 
-uint32_t
-Child::AddRequestPledge(ChildPledge<nsCString>& aPledge)
+void Child::ActorDestroy(ActorDestroyReason aWhy)
 {
-  return mRequestPledges.Append(aPledge);
-}
-
-already_AddRefed<ChildPledge<nsCString>>
-Child::RemoveRequestPledge(uint32_t aRequestId)
-{
-  return mRequestPledges.Remove(aRequestId);
+  mActorDestroyed = true;
 }
 
 bool
 Child::RecvGetOriginKeyResponse(const uint32_t& aRequestId, const nsCString& aKey)
 {
-  nsRefPtr<ChildPledge<nsCString>> pledge = RemoveRequestPledge(aRequestId);
+  nsRefPtr<MediaManager> mgr = MediaManager::GetInstance();
+  if (!mgr) {
+    return false;
+  }
+  nsRefPtr<Pledge<nsCString>> pledge = mgr->mGetOriginKeyPledges.Remove(aRequestId);
   if (pledge) {
     pledge->Resolve(aKey);
   }
   return true;
 }
 
 PMediaChild*
 AllocPMediaChild()
 {
-  Child* obj = new Child();
-  obj->AddRef();
-  return obj;
+  return new Child();
 }
 
 bool
 DeallocPMediaChild(media::PMediaChild *aActor)
 {
-  static_cast<Child*>(aActor)->Release();
+  delete static_cast<Child*>(aActor);
   return true;
 }
 
 }
 }
--- a/dom/media/systemservices/MediaChild.h
+++ b/dom/media/systemservices/MediaChild.h
@@ -5,67 +5,50 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_MediaChild_h
 #define mozilla_MediaChild_h
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/media/PMediaChild.h"
 #include "mozilla/media/PMediaParent.h"
-#include "nsIIPCBackgroundChildCreateCallback.h"
 #include "MediaUtils.h"
 
 namespace mozilla {
 namespace media {
 
 // media::Child implements proxying to the chrome process for some media-related
 // functions, for the moment just:
 //
 // GetOriginKey() - get a cookie-like persisted unique key for a given origin.
 // SanitizeOriginKeys() - reset persisted unique keys.
 
 // GetOriginKey and SanitizeOriginKeys are asynchronous APIs that return pledges
 // (promise-like objects) with the future value. Use pledge.Then(func) to access.
 
-class Child;
-
-template<typename ValueType>
-class ChildPledge : public Pledge<ValueType>,
-                    public nsIIPCBackgroundChildCreateCallback
-{
-  friend Child;
-  NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
-  NS_DECL_ISUPPORTS
-public:
-  explicit ChildPledge() {};
-protected:
-  virtual ~ChildPledge() {}
-  virtual void Run(PMediaChild* aMedia) = 0;
-};
-
-already_AddRefed<ChildPledge<nsCString>>
+already_AddRefed<Pledge<nsCString>>
 GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing);
 
-already_AddRefed<ChildPledge<bool>>
+void
 SanitizeOriginKeys(const uint64_t& aSinceWhen);
 
 class Child : public PMediaChild
 {
-  NS_INLINE_DECL_REFCOUNTING(Child)
 public:
+  static Child* Get();
+
   Child();
 
   bool RecvGetOriginKeyResponse(const uint32_t& aRequestId, const nsCString& aKey);
 
-  uint32_t AddRequestPledge(ChildPledge<nsCString>& aPledge);
-  already_AddRefed<ChildPledge<nsCString>> RemoveRequestPledge(uint32_t aRequestId);
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+  virtual ~Child();
 private:
-  virtual ~Child();
 
-  CoatCheck<ChildPledge<nsCString>> mRequestPledges;
+  bool mActorDestroyed;
 };
 
 PMediaChild* AllocPMediaChild();
 bool DeallocPMediaChild(PMediaChild *aActor);
 
 } // namespace media
 } // namespace mozilla
 
--- a/dom/media/systemservices/MediaParent.cpp
+++ b/dom/media/systemservices/MediaParent.cpp
@@ -27,23 +27,23 @@ PRLogModuleInfo *gMediaParentLog;
 // deviceIds to be unique per origin, to avoid them being supercookies.
 
 #define ORIGINKEYS_FILE "enumerate_devices.txt"
 #define ORIGINKEYS_VERSION "1"
 
 namespace mozilla {
 namespace media {
 
-static StaticMutex gMutex;
-static ParentSingleton* sParentSingleton = nullptr;
+static Parent<PMediaParent>* sIPCServingParent;
 
-class ParentSingleton : public nsISupports
+static OriginKeyStore* sOriginKeyStore = nullptr;
+
+class OriginKeyStore : public nsISupports
 {
   NS_DECL_THREADSAFE_ISUPPORTS
-
   class OriginKey
   {
   public:
     static const size_t DecodedLength = 18;
     static const size_t EncodedLength = DecodedLength * 4 / 3;
 
     OriginKey(const nsACString& aKey, int64_t aSecondsStamp)
     : mKey(aKey)
@@ -319,200 +319,220 @@ class ParentSingleton : public nsISuppor
         Load();
       }
     }
   private:
     nsCOMPtr<nsIFile> mProfileDir;
   };
 
 private:
-  virtual ~ParentSingleton()
+  virtual ~OriginKeyStore()
   {
-    sParentSingleton = nullptr;
+    sOriginKeyStore = nullptr;
     LOG((__FUNCTION__));
   }
 
 public:
-  static ParentSingleton* Get()
+  static OriginKeyStore* Get()
   {
-    // Protect creation of singleton and access from multiple Background threads.
-    //
-    // Multiple Background threads happen because sanitize.js calls us from the
-    // chrome process and gets a thread separate from the one servicing ipc from
-    // the content process.
-
-    StaticMutexAutoLock lock(gMutex);
-    if (!sParentSingleton) {
-      sParentSingleton = new ParentSingleton();
+    MOZ_ASSERT(NS_IsMainThread());
+    if (!sOriginKeyStore) {
+      sOriginKeyStore = new OriginKeyStore();
     }
-    return sParentSingleton;
+    return sOriginKeyStore;
   }
 
   // Only accessed on StreamTS thread
   OriginKeysLoader mOriginKeys;
   OriginKeysTable mPrivateBrowsingOriginKeys;
-
-  // Only accessed on return thread
-  CoatCheck<Pledge<nsCString>> mOutstandingPledges;
 };
 
-NS_IMPL_ISUPPORTS0(ParentSingleton)
+NS_IMPL_ISUPPORTS0(OriginKeyStore)
+
+template<> /* static */
+Parent<PMediaParent>* Parent<PMediaParent>::GetSingleton()
+{
+  return sIPCServingParent;
+}
 
-bool
-Parent::RecvGetOriginKey(const uint32_t& aRequestId,
+template<> /* static */
+Parent<NonE10s>* Parent<NonE10s>::GetSingleton()
+{
+  nsRefPtr<MediaManager> mgr = MediaManager::GetInstance();
+  if (!mgr) {
+    return nullptr;
+  }
+  return mgr->GetNonE10sParent();
+}
+
+// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func:
+// error: 'this' was not captured for this lambda function
+
+template<class Super> static
+Parent<Super>* GccGetSingleton() { return Parent<Super>::GetSingleton(); };
+
+
+template<class Super> bool
+Parent<Super>::RecvGetOriginKey(const uint32_t& aRequestId,
                          const nsCString& aOrigin,
                          const bool& aPrivateBrowsing)
 {
-  // TODO: Replace all this when moving MediaParent to PContent soon (1037389)
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // First, get profile dir.
 
-  nsRefPtr<ParentSingleton> singleton(mSingleton);
-  nsCOMPtr<nsIThread> returnThread = NS_GetCurrentThread();
-  nsRefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
-  nsresult rv;
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIFile> profileDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                       getter_AddRefs(profileDir));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
 
-  // First, over to main thread to get profile dir.
+  // Then over to stream-transport thread to do the actual file io.
+  // Stash a pledge to hold the answer and get an id for this request.
 
-  // Pledges are non-threadsafe by design, so check them and pass an id instead.
-  uint32_t id = singleton->mOutstandingPledges.Append(*p);
+  nsRefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
+  uint32_t id = mOutstandingPledges.Append(*p);
+
+  nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+  MOZ_ASSERT(sts);
+  nsRefPtr<OriginKeyStore> store(mOriginKeyStore);
+  bool sameProcess = mSameProcess;
 
-  rv = NS_DispatchToMainThread(NewRunnableFrom([id, returnThread,
-                                                singleton, aOrigin,
-                                                aPrivateBrowsing]() -> nsresult {
-    MOZ_ASSERT(NS_IsMainThread());
-    nsCOMPtr<nsIFile> profileDir;
-    nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                                         getter_AddRefs(profileDir));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+  rv = sts->Dispatch(NewRunnableFrom([id, profileDir, store, sameProcess,
+                                      aOrigin, aPrivateBrowsing]() -> nsresult {
+    MOZ_ASSERT(!NS_IsMainThread());
+    store->mOriginKeys.SetProfileDir(profileDir);
+    nsCString result;
+    if (aPrivateBrowsing) {
+      store->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, result);
+    } else {
+      store->mOriginKeys.GetOriginKey(aOrigin, result);
     }
 
-    // Then from there over to stream-transport thread to do the actual file io.
-
-    nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
-    MOZ_ASSERT(sts);
-    rv = sts->Dispatch(NewRunnableFrom([profileDir, id, returnThread, singleton,
-                                        aOrigin, aPrivateBrowsing]() -> nsresult {
-      MOZ_ASSERT(!NS_IsMainThread());
-      singleton->mOriginKeys.SetProfileDir(profileDir);
-      nsCString result;
-      if (aPrivateBrowsing) {
-        singleton->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, result);
-      } else {
-        singleton->mOriginKeys.GetOriginKey(aOrigin, result);
+    // Pass result back to main thread.
+    nsresult rv;
+    rv = NS_DispatchToMainThread(NewRunnableFrom([id, store, sameProcess,
+                                                  result]() -> nsresult {
+      Parent* parent = GccGetSingleton<Super>(); // GetSingleton();
+      if (!parent) {
+        return NS_OK;
       }
-
-      // Pass result back to original thread.
-      nsresult rv;
-      rv = returnThread->Dispatch(NewRunnableFrom([id, singleton,
-                                                   result]() -> nsresult {
-        nsRefPtr<Pledge<nsCString>> p = singleton->mOutstandingPledges.Remove(id);
-        if (!p) {
-          return NS_ERROR_UNEXPECTED;
-        }
-        p->Resolve(result);
-        return NS_OK;
-      }), NS_DISPATCH_NORMAL);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
+      nsRefPtr<Pledge<nsCString>> p = parent->mOutstandingPledges.Remove(id);
+      if (!p) {
+        return NS_ERROR_UNEXPECTED;
       }
+      p->Resolve(result);
       return NS_OK;
     }), NS_DISPATCH_NORMAL);
+
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     return NS_OK;
-  }));
+  }), NS_DISPATCH_NORMAL);
+
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
-  nsRefPtr<media::Parent> keepAlive(this);
-  p->Then([this, keepAlive, aRequestId](const nsCString& aKey) mutable {
-    if (!mDestroyed) {
-      unused << SendGetOriginKeyResponse(aRequestId, aKey);
+  p->Then([aRequestId, sameProcess](const nsCString& aKey) mutable {
+    if (!sameProcess) {
+      if (!sIPCServingParent) {
+        return NS_OK;
+      }
+      unused << sIPCServingParent->SendGetOriginKeyResponse(aRequestId, aKey);
+    } else {
+      nsRefPtr<MediaManager> mgr = MediaManager::GetInstance();
+      if (!mgr) {
+        return NS_OK;
+      }
+      nsRefPtr<Pledge<nsCString>> pledge =
+          mgr->mGetOriginKeyPledges.Remove(aRequestId);
+      if (pledge) {
+        pledge->Resolve(aKey);
+      }
     }
     return NS_OK;
   });
   return true;
 }
 
-bool
-Parent::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen)
+template<class Super> bool
+Parent<Super>::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen)
 {
-  nsRefPtr<ParentSingleton> singleton(mSingleton);
-
-  // First, over to main to get profile dir.
-  nsresult rv;
-
-  rv = NS_DispatchToMainThread(NewRunnableFrom([singleton,
-                                                aSinceWhen]() -> nsresult {
-    MOZ_ASSERT(NS_IsMainThread());
-    nsCOMPtr<nsIFile> profileDir;
-    nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIFile> profileDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
                                          getter_AddRefs(profileDir));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    // Then from there over to stream-transport thread to do the file io.
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+  // Over to stream-transport thread to do the file io.
 
-    nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
-    MOZ_ASSERT(sts);
-    rv = sts->Dispatch(NewRunnableFrom([profileDir, singleton, aSinceWhen]() -> nsresult {
-      MOZ_ASSERT(!NS_IsMainThread());
-      singleton->mOriginKeys.SetProfileDir(profileDir);
-      singleton->mPrivateBrowsingOriginKeys.Clear(aSinceWhen);
-      singleton->mOriginKeys.Clear(aSinceWhen);
-      return NS_OK;
-    }), NS_DISPATCH_NORMAL);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+  nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+  MOZ_ASSERT(sts);
+  nsRefPtr<OriginKeyStore> store(mOriginKeyStore);
+
+  rv = sts->Dispatch(NewRunnableFrom([profileDir, store, aSinceWhen]() -> nsresult {
+    MOZ_ASSERT(!NS_IsMainThread());
+    store->mOriginKeys.SetProfileDir(profileDir);
+    store->mPrivateBrowsingOriginKeys.Clear(aSinceWhen);
+    store->mOriginKeys.Clear(aSinceWhen);
     return NS_OK;
-  }));
+  }), NS_DISPATCH_NORMAL);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
   return true;
 }
 
-void
-Parent::ActorDestroy(ActorDestroyReason aWhy)
+template<class Super> void
+Parent<Super>::ActorDestroy(ActorDestroyReason aWhy)
 {
   // No more IPC from here
   mDestroyed = true;
   LOG((__FUNCTION__));
 }
 
-Parent::Parent()
-  : mSingleton(ParentSingleton::Get())
+template<class Super>
+Parent<Super>::Parent(bool aSameProcess)
+  : mOriginKeyStore(OriginKeyStore::Get())
   , mDestroyed(false)
+  , mSameProcess(aSameProcess)
 {
   if (!gMediaParentLog)
     gMediaParentLog = PR_NewLogModule("MediaParent");
   LOG(("media::Parent: %p", this));
 
   MOZ_COUNT_CTOR(Parent);
 }
 
-Parent::~Parent()
+template<class Super>
+Parent<Super>::~Parent()
 {
   LOG(("~media::Parent: %p", this));
 
   MOZ_COUNT_DTOR(Parent);
 }
 
 PMediaParent*
 AllocPMediaParent()
 {
-  Parent* obj = new Parent();
-  obj->AddRef();
-  return obj;
+  MOZ_ASSERT(!sIPCServingParent);
+  sIPCServingParent = new Parent<PMediaParent>();
+  return sIPCServingParent;
 }
 
 bool
 DeallocPMediaParent(media::PMediaParent *aActor)
 {
-  static_cast<Parent*>(aActor)->Release();
+  MOZ_ASSERT(sIPCServingParent == static_cast<Parent<PMediaParent>*>(aActor));
+  delete sIPCServingParent;
   return true;
 }
 
 }
 }
+
+// Instantiate templates to satisfy linker
+template class mozilla::media::Parent<mozilla::media::NonE10s>;
--- a/dom/media/systemservices/MediaParent.h
+++ b/dom/media/systemservices/MediaParent.h
@@ -11,35 +11,58 @@
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/media/PMediaParent.h"
 
 namespace mozilla {
 namespace media {
 
 // media::Parent implements the chrome-process side of ipc for media::Child APIs
+// A "SameProcess" version may also be created to service non-e10s calls.
 
-class ParentSingleton;
+class OriginKeyStore;
 
-class Parent : public PMediaParent
+class NonE10s
 {
-  NS_INLINE_DECL_REFCOUNTING(Parent)
+  typedef mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason
+      ActorDestroyReason;
+protected:
+  virtual bool RecvGetOriginKey(const uint32_t& aRequestId,
+                                const nsCString& aOrigin,
+                                const bool& aPrivateBrowsing) = 0;
+  virtual bool RecvSanitizeOriginKeys(const uint64_t& aSinceWhen) = 0;
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) = 0;
+};
+
+// Super = PMediaParent or NonE10s
+
+template<class Super>
+class Parent : public Super
+{
+  typedef mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason
+      ActorDestroyReason;
 public:
+  static Parent* GetSingleton();
+
   virtual bool RecvGetOriginKey(const uint32_t& aRequestId,
                                 const nsCString& aOrigin,
                                 const bool& aPrivateBrowsing) override;
   virtual bool RecvSanitizeOriginKeys(const uint64_t& aSinceWhen) override;
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
-  Parent();
-private:
+  explicit Parent(bool aSameProcess = false);
   virtual ~Parent();
+private:
 
-  nsRefPtr<ParentSingleton> mSingleton;
+  nsRefPtr<OriginKeyStore> mOriginKeyStore;
   bool mDestroyed;
+  bool mSameProcess;
+
+  CoatCheck<Pledge<nsCString>> mOutstandingPledges;
 };
 
 PMediaParent* AllocPMediaParent();
 bool DeallocPMediaParent(PMediaParent *aActor);
 
 } // namespace media
 } // namespace mozilla
 
--- a/dom/media/systemservices/MediaUtils.h
+++ b/dom/media/systemservices/MediaUtils.h
@@ -35,110 +35,212 @@ namespace media {
  *   nsRefPtr<media::Pledge<Foo>> p = GetFooAsynchronously(); // returns a pledge
  *   p->Then([](const Foo& foo) {
  *     // use foo here (same thread. Need not be thread-safe!)
  *   });
  *
  * See media::CoatCheck below for an example of GetFooAsynchronously().
  */
 
-template<typename ValueType>
-class Pledge
+class PledgeBase
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(PledgeBase);
+protected:
+  virtual ~PledgeBase() {};
+};
+
+template<typename ValueType, typename ErrorType = nsresult>
+class Pledge : public PledgeBase
 {
   // TODO: Remove workaround once mozilla allows std::function from <functional>
   // wo/std::function support, do template + virtual trick to accept lambdas
   class FunctorsBase
   {
   public:
     FunctorsBase() {}
-    virtual void Succeed(const ValueType& result) = 0;
-    virtual void Fail(nsresult rv) = 0;
+    virtual void Succeed(ValueType& result) = 0;
+    virtual void Fail(ErrorType& error) = 0;
     virtual ~FunctorsBase() {};
   };
 
 public:
-  NS_INLINE_DECL_REFCOUNTING(Pledge);
-  explicit Pledge() : mDone(false), mResult(NS_OK) {}
+  explicit Pledge() : mDone(false), mError(nullptr) {}
+  Pledge(const Pledge& aOther) = delete;
+  Pledge& operator = (const Pledge&) = delete;
 
   template<typename OnSuccessType>
   void Then(OnSuccessType aOnSuccess)
   {
-    Then(aOnSuccess, [](nsresult){});
+    Then(aOnSuccess, [](ErrorType&){});
   }
 
   template<typename OnSuccessType, typename OnFailureType>
   void Then(OnSuccessType aOnSuccess, OnFailureType aOnFailure)
   {
-    class F : public FunctorsBase
+    class Functors : public FunctorsBase
     {
     public:
-      F(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure)
+      Functors(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure)
         : mOnSuccess(aOnSuccess), mOnFailure(aOnFailure) {}
 
-      void Succeed(const ValueType& result)
+      void Succeed(ValueType& result)
       {
         mOnSuccess(result);
       }
-      void Fail(nsresult rv)
+      void Fail(ErrorType& error)
       {
-        mOnFailure(rv);
+        mOnFailure(error);
       };
 
       OnSuccessType mOnSuccess;
       OnFailureType mOnFailure;
     };
-    mFunctors = new F(aOnSuccess, aOnFailure);
+    mFunctors = new Functors(aOnSuccess, aOnFailure);
 
     if (mDone) {
-      if (mResult == NS_OK) {
+      if (!mError) {
         mFunctors->Succeed(mValue);
       } else {
-        mFunctors->Fail(mResult);
+        mFunctors->Fail(*mError);
       }
     }
   }
 
   void Resolve(const ValueType& aValue)
   {
     mValue = aValue;
     Resolve();
   }
 protected:
   void Resolve()
   {
     if (!mDone) {
       mDone = true;
-      MOZ_ASSERT(mResult == NS_OK);
+      MOZ_ASSERT(!mError);
       if (mFunctors) {
         mFunctors->Succeed(mValue);
       }
     }
   }
 
-  void Reject(nsresult rv)
+  void Reject(ErrorType rv)
   {
     if (!mDone) {
       mDone = true;
-      mResult = rv;
+      mError = rv;
       if (mFunctors) {
-        mFunctors->Fail(mResult);
+        mFunctors->Fail(mError);
       }
     }
   }
 
   ValueType mValue;
-protected:
+private:
   ~Pledge() {};
   bool mDone;
-  nsresult mResult;
+  nsRefPtr<ErrorType> mError;
+  ScopedDeletePtr<FunctorsBase> mFunctors;
+};
+
+template<typename ValueType>
+class Pledge<ValueType, nsresult>  : public PledgeBase
+{
+  // TODO: Remove workaround once mozilla allows std::function from <functional>
+  // wo/std::function support, do template + virtual trick to accept lambdas
+  class FunctorsBase
+  {
+  public:
+    FunctorsBase() {}
+    virtual void Succeed(ValueType& result) = 0;
+    virtual void Fail(nsresult error) = 0;
+    virtual ~FunctorsBase() {};
+  };
+
+public:
+  explicit Pledge() : mDone(false), mError(NS_OK) {}
+  Pledge(const Pledge& aOther) = delete;
+  Pledge& operator = (const Pledge&) = delete;
+
+  template<typename OnSuccessType>
+  void Then(OnSuccessType aOnSuccess)
+  {
+    Then(aOnSuccess, [](nsresult){});
+  }
+
+  template<typename OnSuccessType, typename OnFailureType>
+  void Then(OnSuccessType aOnSuccess, OnFailureType aOnFailure)
+  {
+    class Functors : public FunctorsBase
+    {
+    public:
+      Functors(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure)
+        : mOnSuccess(aOnSuccess), mOnFailure(aOnFailure) {}
+
+      void Succeed(ValueType& result)
+      {
+        mOnSuccess(result);
+      }
+      void Fail(nsresult rv)
+      {
+        mOnFailure(rv);
+      };
+
+      OnSuccessType mOnSuccess;
+      OnFailureType mOnFailure;
+    };
+    mFunctors = new Functors(aOnSuccess, aOnFailure);
+
+    if (mDone) {
+      if (mError == NS_OK) {
+        mFunctors->Succeed(mValue);
+      } else {
+        mFunctors->Fail(mError);
+      }
+    }
+  }
+
+  void Resolve(const ValueType& aValue)
+  {
+    mValue = aValue;
+    Resolve();
+  }
+protected:
+  void Resolve()
+  {
+    if (!mDone) {
+      mDone = true;
+      MOZ_ASSERT(mError == NS_OK);
+      if (mFunctors) {
+        mFunctors->Succeed(mValue);
+      }
+    }
+  }
+
+  void Reject(nsresult error)
+  {
+    if (!mDone) {
+      mDone = true;
+      mError = error;
+      if (mFunctors) {
+        mFunctors->Fail(mError);
+      }
+    }
+  }
+
+  ValueType mValue;
 private:
-  nsAutoPtr<FunctorsBase> mFunctors;
+  ~Pledge() {};
+  bool mDone;
+  nsresult mError;
+  ScopedDeletePtr<FunctorsBase> mFunctors;
 };
 
 /* media::NewRunnableFrom() - Create an nsRunnable from a lambda.
+ * media::NewTaskFrom()     - Create a Task from a lambda.
  *
  * Passing variables (closures) to an async function is clunky with nsRunnable:
  *
  *   void Foo()
  *   {
  *     class FooRunnable : public nsRunnable
  *     {
  *     public:
@@ -187,16 +289,37 @@ private:
 
 template<typename OnRunType>
 LambdaRunnable<OnRunType>*
 NewRunnableFrom(OnRunType aOnRun)
 {
   return new LambdaRunnable<OnRunType>(aOnRun);
 }
 
+template<typename OnRunType>
+class LambdaTask : public Task
+{
+public:
+  explicit LambdaTask(OnRunType& aOnRun) : mOnRun(aOnRun) {}
+private:
+  void
+  Run()
+  {
+    return mOnRun();
+  }
+  OnRunType mOnRun;
+};
+
+template<typename OnRunType>
+LambdaTask<OnRunType>*
+NewTaskFrom(OnRunType aOnRun)
+{
+  return new LambdaTask<OnRunType>(aOnRun);
+}
+
 /* media::CoatCheck - There and back again. Park an object in exchange for an id.
  *
  * A common problem with calling asynchronous functions that do work on other
  * threads or processes is how to pass in a heap object for use once the
  * function completes, without requiring that object to have threadsafe
  * refcounting, contain mutexes, be marshaled, or leak if things fail
  * (or worse, intermittent use-after-free because of lifetime issues).
  *
@@ -208,40 +331,40 @@ NewRunnableFrom(OnRunType aOnRun)
  *   class FooDoer
  *   {
  *     CoatCheck<Foo> mOutstandingFoos;
  *
  *   public:
  *     void DoFoo()
  *     {
  *       nsRefPtr<Foo> foo = new Foo();
- *       uint32_t requestId = mOutstandingFoos.Append(foo);
+ *       uint32_t requestId = mOutstandingFoos.Append(*foo);
  *       sChild->SendFoo(requestId);
  *     }
  *
  *     void RecvFooResponse(uint32_t requestId)
  *     {
  *       nsRefPtr<Foo> foo = mOutstandingFoos.Remove(requestId);
  *       if (foo) {
  *         // use foo
  *       }
  *     }
  *   };
  *
  * If you read media::Pledge earlier, here's how this is useful for pledges:
  *
  *   class FooGetter
  *   {
- *     CoatCheck<Foo> mOutstandingPledges;
+ *     CoatCheck<Pledge<Foo>> mOutstandingPledges;
  *
  *   public:
  *     already_addRefed<Pledge<Foo>> GetFooAsynchronously()
  *     {
  *       nsRefPtr<Pledge<Foo>> p = new Pledge<Foo>();
- *       uint32_t requestId = mOutstandingPledges.Append(p);
+ *       uint32_t requestId = mOutstandingPledges.Append(*p);
  *       sChild->SendFoo(requestId);
  *       return p.forget();
  *     }
  *
  *     void RecvFooResponse(uint32_t requestId, const Foo& fooResult)
  *     {
  *       nsRefPtr<Foo> p = mOutstandingPledges.Remove(requestId);
  *       if (p) {
--- a/dom/media/systemservices/PMedia.ipdl
+++ b/dom/media/systemservices/PMedia.ipdl
@@ -1,21 +1,20 @@
 /* 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 protocol PContent;
-include protocol PBackground;
 
 namespace mozilla {
 namespace media {
 
 protocol PMedia
 {
-  manager PBackground;
+  manager PContent;
 
 parent:
   /**
    * Requests a persistent unique secret key for each origin.
    * Has no expiry, but is cleared by age along with cookies.
    * This is needed by mediaDevices.enumerateDevices() to produce persistent
    * deviceIds that wont work cross-origin.
    */
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html
@@ -18,24 +18,16 @@ var tests = [
   { message: "unknown required constraint on video ignored",
     constraints: { video: { somethingUnknown: { exact: 0 } },
                    fake: true },
     error: null },
   { message: "unknown required constraint on audio ignored",
     constraints: { audio: { somethingUnknown: { exact: 0 } },
                    fake: true },
     error: null },
-  { message: "video overconstrained by facingMode fails",
-    constraints: { video: { facingMode:{ exact: 'left' } },
-                   fake: true },
-    error: "NotFoundError" },
-  { message: "video overconstrained by facingMode array fails",
-    constraints: { video: { facingMode:{ exact: ['left', 'right'] } },
-                   fake: true },
-    error: "NotFoundError" },
   { message: "audio overconstrained by facingMode ignored",
     constraints: { audio: { facingMode: { exact: 'left' } },
                    fake: true },
     error: null },
   { message: "full screensharing requires permission",
     constraints: { video: { mediaSource: 'screen' } },
     error: "PermissionDeniedError" },
   { message: "application screensharing requires permission",
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -83,18 +83,18 @@ public:
 
   virtual ~MediaEngineSource() {}
 
   virtual void Shutdown() = 0;
 
   /* Populate the human readable name of this device in the nsAString */
   virtual void GetName(nsAString&) = 0;
 
-  /* Populate the UUID of this device in the nsAString */
-  virtual void GetUUID(nsAString&) = 0;
+  /* Populate the UUID of this device in the nsACString */
+  virtual void GetUUID(nsACString&) = 0;
 
   /* Release the device back to the system. */
   virtual nsresult Deallocate() = 0;
 
   /* Start the device and add the track to the provided SourceMediaStream, with
    * the provided TrackID. You may start appending data to the track
    * immediately after. */
   virtual nsresult Start(SourceMediaStream*, TrackID) = 0;
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
@@ -4,21 +4,17 @@
 
 #include "MediaEngineCameraVideoSource.h"
 
 #include <limits>
 
 namespace mozilla {
 
 using namespace mozilla::gfx;
-using dom::OwningLongOrConstrainLongRange;
-using dom::ConstrainLongRange;
-using dom::OwningDoubleOrConstrainDoubleRange;
-using dom::ConstrainDoubleRange;
-using dom::MediaTrackConstraintSet;
+using namespace mozilla::dom;
 
 extern PRLogModuleInfo* GetMediaManagerLog();
 #define LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg)
 #define LOGFRAME(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg)
 
 // guts for appending data to the MSG track
 bool MediaEngineCameraVideoSource::AppendToTrack(SourceMediaStream* aSource,
                                                  layers::Image* aImage,
@@ -57,69 +53,125 @@ MediaEngineCameraVideoSource::GetCapabil
 
 // The full algorithm for all cameras. Sources that don't list capabilities
 // need to fake it and hardcode some by populating mHardcodedCapabilities above.
 
 // Fitness distance returned as integer math * 1000. Infinity = UINT32_MAX
 
 template<class ValueType, class ConstrainRange>
 /* static */ uint32_t
-MediaEngineCameraVideoSource::FitnessDistance(ValueType n,
+MediaEngineCameraVideoSource::FitnessDistance(ValueType aN,
                                               const ConstrainRange& aRange)
 {
-  if ((aRange.mExact.WasPassed() && aRange.mExact.Value() != n) ||
-      (aRange.mMin.WasPassed() && aRange.mMin.Value() > n) ||
-      (aRange.mMax.WasPassed() && aRange.mMax.Value() < n)) {
+  if ((aRange.mExact.WasPassed() && aRange.mExact.Value() != aN) ||
+      (aRange.mMin.WasPassed() && aRange.mMin.Value() > aN) ||
+      (aRange.mMax.WasPassed() && aRange.mMax.Value() < aN)) {
     return UINT32_MAX;
   }
-  if (!aRange.mIdeal.WasPassed() || n == aRange.mIdeal.Value()) {
+  if (!aRange.mIdeal.WasPassed() || aN == aRange.mIdeal.Value()) {
     return 0;
   }
-  return uint32_t(ValueType((std::abs(n - aRange.mIdeal.Value()) * 1000) /
-                            std::max(std::abs(n), std::abs(aRange.mIdeal.Value()))));
+  return uint32_t(ValueType((std::abs(aN - aRange.mIdeal.Value()) * 1000) /
+                            std::max(std::abs(aN), std::abs(aRange.mIdeal.Value()))));
 }
 
 // Binding code doesn't templatize well...
 
 /*static*/ uint32_t
-MediaEngineCameraVideoSource::FitnessDistance(int32_t n,
+MediaEngineCameraVideoSource::FitnessDistance(int32_t aN,
     const OwningLongOrConstrainLongRange& aConstraint, bool aAdvanced)
 {
   if (aConstraint.IsLong()) {
     ConstrainLongRange range;
     (aAdvanced ? range.mExact : range.mIdeal).Construct(aConstraint.GetAsLong());
-    return FitnessDistance(n, range);
+    return FitnessDistance(aN, range);
   } else {
-    return FitnessDistance(n, aConstraint.GetAsConstrainLongRange());
+    return FitnessDistance(aN, aConstraint.GetAsConstrainLongRange());
   }
 }
 
 /*static*/ uint32_t
-MediaEngineCameraVideoSource::FitnessDistance(double n,
+MediaEngineCameraVideoSource::FitnessDistance(double aN,
     const OwningDoubleOrConstrainDoubleRange& aConstraint,
     bool aAdvanced)
 {
   if (aConstraint.IsDouble()) {
     ConstrainDoubleRange range;
     (aAdvanced ? range.mExact : range.mIdeal).Construct(aConstraint.GetAsDouble());
-    return FitnessDistance(n, range);
+    return FitnessDistance(aN, range);
   } else {
-    return FitnessDistance(n, aConstraint.GetAsConstrainDoubleRange());
+    return FitnessDistance(aN, aConstraint.GetAsConstrainDoubleRange());
   }
 }
 
-/*static*/ uint32_t
+// Fitness distance returned as integer math * 1000. Infinity = UINT32_MAX
+
+/* static */ uint32_t
+MediaEngineCameraVideoSource::FitnessDistance(nsString aN,
+                             const ConstrainDOMStringParameters& aParams)
+{
+  struct Func
+  {
+    static bool
+    Contains(const OwningStringOrStringSequence& aStrings, nsString aN)
+    {
+      return aStrings.IsString() ? aStrings.GetAsString() == aN
+                                 : aStrings.GetAsStringSequence().Contains(aN);
+    }
+  };
+
+  if (aParams.mExact.WasPassed() && !Func::Contains(aParams.mExact.Value(), aN)) {
+    return UINT32_MAX;
+  }
+  if (aParams.mIdeal.WasPassed() && !Func::Contains(aParams.mIdeal.Value(), aN)) {
+    return 1000;
+  }
+  return 0;
+}
+
+/* static */ uint32_t
+MediaEngineCameraVideoSource::FitnessDistance(nsString aN,
+    const OwningStringOrStringSequenceOrConstrainDOMStringParameters& aConstraint,
+    bool aAdvanced)
+{
+  if (aConstraint.IsString()) {
+    ConstrainDOMStringParameters params;
+    if (aAdvanced) {
+      params.mExact.Construct();
+      params.mExact.Value().SetAsString() = aConstraint.GetAsString();
+    } else {
+      params.mIdeal.Construct();
+      params.mIdeal.Value().SetAsString() = aConstraint.GetAsString();
+    }
+    return FitnessDistance(aN, params);
+  } else if (aConstraint.IsStringSequence()) {
+    ConstrainDOMStringParameters params;
+    if (aAdvanced) {
+      params.mExact.Construct();
+      params.mExact.Value().SetAsStringSequence() = aConstraint.GetAsStringSequence();
+    } else {
+      params.mIdeal.Construct();
+      params.mIdeal.Value().SetAsStringSequence() = aConstraint.GetAsStringSequence();
+    }
+    return FitnessDistance(aN, params);
+  } else {
+    return FitnessDistance(aN, aConstraint.GetAsConstrainDOMStringParameters());
+  }
+}
+
+uint32_t
 MediaEngineCameraVideoSource::GetFitnessDistance(const webrtc::CaptureCapability& aCandidate,
                                                  const MediaTrackConstraintSet &aConstraints,
                                                  bool aAdvanced)
 {
   // Treat width|height|frameRate == 0 on capability as "can do any".
   // This allows for orthogonal capabilities that are not in discrete steps.
 
   uint64_t distance =
+    uint64_t(FitnessDistance(mFacingMode, aConstraints.mFacingMode, aAdvanced)) +
     uint64_t(aCandidate.width? FitnessDistance(int32_t(aCandidate.width),
                                                aConstraints.mWidth,
                                                aAdvanced) : 0) +
     uint64_t(aCandidate.height? FitnessDistance(int32_t(aCandidate.height),
                                                 aConstraints.mHeight,
                                                 aAdvanced) : 0) +
     uint64_t(aCandidate.maxFPS? FitnessDistance(double(aCandidate.maxFPS),
                                                 aConstraints.mFrameRate,
@@ -210,17 +262,17 @@ MediaEngineCameraVideoSource::LogConstra
         "             frameRate: { min: %f, max: %f, ideal: %f }" :
         "             frameRate: { min: %f, max: %f }"),
        c.mFrameRate.mMin, c.mFrameRate.mMax,
        c.mFrameRate.mIdeal.WasPassed()? c.mFrameRate.mIdeal.Value() : 0));
 }
 
 bool
 MediaEngineCameraVideoSource::ChooseCapability(
-    const dom::MediaTrackConstraints &aConstraints,
+    const MediaTrackConstraints &aConstraints,
     const MediaEnginePrefs &aPrefs)
 {
   if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
     LOG(("ChooseCapability: prefs: %dx%d @%d-%dfps",
          aPrefs.GetWidth(), aPrefs.GetHeight(),
          aPrefs.mFPS, aPrefs.mMinFPS));
     LogConstraints(aConstraints, false);
     if (aConstraints.mAdvanced.WasPassed()) {
@@ -320,27 +372,86 @@ MediaEngineCameraVideoSource::ChooseCapa
 
   LOG(("chose cap %dx%d @%dfps codec %d raw %d",
        mCapability.width, mCapability.height, mCapability.maxFPS,
        mCapability.codecType, mCapability.rawType));
   return true;
 }
 
 void
+MediaEngineCameraVideoSource::SetName(nsString aName)
+{
+  mDeviceName = aName;
+  bool hasFacingMode = false;
+  VideoFacingModeEnum facingMode = VideoFacingModeEnum::User;
+
+  // Set facing mode based on device name.
+#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
+  if (aName.EqualsLiteral("back")) {
+    hasFacingMode = true;
+    facingMode = VideoFacingModeEnum::Environment;
+  } else if (aName.EqualsLiteral("front")) {
+    hasFacingMode = true;
+    facingMode = VideoFacingModeEnum::User;
+  }
+#endif // MOZ_B2G_CAMERA
+#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
+  // Names are generated. Example: "Camera 0, Facing back, Orientation 90"
+  //
+  // See media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/
+  // webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
+
+  if (aName.Find(NS_LITERAL_STRING("Facing back")) != kNotFound) {
+    hasFacingMode = true;
+    facingMode = VideoFacingModeEnum::Environment;
+  } else if (aName.Find(NS_LITERAL_STRING("Facing front")) != kNotFound) {
+    hasFacingMode = true;
+    facingMode = VideoFacingModeEnum::User;
+  }
+#endif // ANDROID
+#ifdef XP_MACOSX
+  // Kludge to test user-facing cameras on OSX.
+  if (aName.Find(NS_LITERAL_STRING("Face")) != -1) {
+    hasFacingMode = true;
+    facingMode = VideoFacingModeEnum::User;
+  }
+#endif
+  if (hasFacingMode) {
+    mFacingMode.Assign(NS_ConvertUTF8toUTF16(
+        VideoFacingModeEnumValues::strings[uint32_t(facingMode)].value));
+  } else {
+    mFacingMode.Truncate();
+  }
+}
+
+void
 MediaEngineCameraVideoSource::GetName(nsAString& aName)
 {
   aName = mDeviceName;
 }
 
 void
-MediaEngineCameraVideoSource::GetUUID(nsAString& aUUID)
+MediaEngineCameraVideoSource::SetUUID(const char* aUUID)
+{
+  mUniqueId.Assign(aUUID);
+}
+
+void
+MediaEngineCameraVideoSource::GetUUID(nsACString& aUUID)
 {
   aUUID = mUniqueId;
 }
 
+const nsCString&
+MediaEngineCameraVideoSource::GetUUID()
+{
+  return mUniqueId;
+}
+
+
 void
 MediaEngineCameraVideoSource::SetDirectListeners(bool aHasDirectListeners)
 {
   LOG((__FUNCTION__));
   mHasDirectListeners = aHasDirectListeners;
 }
 
 } // namespace mozilla
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -29,17 +29,17 @@ public:
     , mHasDirectListeners(false)
     , mCaptureIndex(aIndex)
     , mTrackID(0)
     , mFps(-1)
   {}
 
 
   virtual void GetName(nsAString& aName) override;
-  virtual void GetUUID(nsAString& aUUID) override;
+  virtual void GetUUID(nsACString& aUUID) override;
   virtual void SetDirectListeners(bool aHasListeners) override;
   virtual nsresult Config(bool aEchoOn, uint32_t aEcho,
                           bool aAgcOn, uint32_t aAGC,
                           bool aNoiseOn, uint32_t aNoise,
                           int32_t aPlayoutDelay) override
   {
     return NS_OK;
   };
@@ -76,32 +76,40 @@ protected:
   ~MediaEngineCameraVideoSource() {}
 
   // guts for appending data to the MSG track
   virtual bool AppendToTrack(SourceMediaStream* aSource,
                              layers::Image* aImage,
                              TrackID aID,
                              StreamTime delta);
   template<class ValueType, class ConstrainRange>
-  static uint32_t FitnessDistance(ValueType n, const ConstrainRange& aRange);
-  static uint32_t FitnessDistance(int32_t n,
+  static uint32_t FitnessDistance(ValueType aN, const ConstrainRange& aRange);
+  static uint32_t FitnessDistance(int32_t aN,
       const dom::OwningLongOrConstrainLongRange& aConstraint, bool aAdvanced);
-  static uint32_t FitnessDistance(double n,
+  static uint32_t FitnessDistance(double aN,
       const dom::OwningDoubleOrConstrainDoubleRange& aConstraint, bool aAdvanced);
+  static uint32_t FitnessDistance(nsString aN,
+    const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters& aConstraint,
+    bool aAdvanced);
+  static uint32_t FitnessDistance(nsString aN,
+      const dom::ConstrainDOMStringParameters& aParams);
 
-  static uint32_t GetFitnessDistance(const webrtc::CaptureCapability& aCandidate,
-                                     const dom::MediaTrackConstraintSet &aConstraints,
-                                     bool aAdvanced);
+  uint32_t GetFitnessDistance(const webrtc::CaptureCapability& aCandidate,
+                              const dom::MediaTrackConstraintSet &aConstraints,
+                              bool aAdvanced);
   static void TrimLessFitCandidates(CapabilitySet& set);
   static void LogConstraints(const dom::MediaTrackConstraintSet& aConstraints,
                              bool aAdvanced);
   virtual size_t NumCapabilities();
   virtual void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut);
   bool ChooseCapability(const dom::MediaTrackConstraints &aConstraints,
                         const MediaEnginePrefs &aPrefs);
+  void SetName(nsString aName);
+  void SetUUID(const char* aUUID);
+  const nsCString& GetUUID(); // protected access
 
   // Engine variables.
 
   // mMonitor protects mImage access/changes, and transitions of mState
   // from kStarted to kStopped (which are combined with EndTrack() and
   // image changes).
   // mMonitor also protects mSources[] access/changes.
   // mSources[] is accessed from webrtc threads.
@@ -119,15 +127,17 @@ protected:
   bool mHasDirectListeners;
   int mCaptureIndex;
   TrackID mTrackID;
   int mFps; // Track rate (30 fps by default)
 
   webrtc::CaptureCapability mCapability; // Doesn't work on OS X.
 
   nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities; // For OSX & B2G
+private:
   nsString mDeviceName;
-  nsString mUniqueId;
+  nsCString mUniqueId;
+  nsString mFacingMode;
 };
 
 
 } // namespace mozilla
 #endif // MediaEngineCameraVideoSource_h
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -57,19 +57,19 @@ MediaEngineDefaultVideoSource::~MediaEng
 void
 MediaEngineDefaultVideoSource::GetName(nsAString& aName)
 {
   aName.AssignLiteral(MOZ_UTF16("Default Video Device"));
   return;
 }
 
 void
-MediaEngineDefaultVideoSource::GetUUID(nsAString& aUUID)
+MediaEngineDefaultVideoSource::GetUUID(nsACString& aUUID)
 {
-  aUUID.AssignLiteral(MOZ_UTF16("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676"));
+  aUUID.AssignLiteral("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676");
   return;
 }
 
 nsresult
 MediaEngineDefaultVideoSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                         const MediaEnginePrefs &aPrefs)
 {
   if (mState != kReleased) {
@@ -337,19 +337,19 @@ MediaEngineDefaultAudioSource::~MediaEng
 void
 MediaEngineDefaultAudioSource::GetName(nsAString& aName)
 {
   aName.AssignLiteral(MOZ_UTF16("Default Audio Device"));
   return;
 }
 
 void
-MediaEngineDefaultAudioSource::GetUUID(nsAString& aUUID)
+MediaEngineDefaultAudioSource::GetUUID(nsACString& aUUID)
 {
-  aUUID.AssignLiteral(MOZ_UTF16("B7CBD7C1-53EF-42F9-8353-73F61C70C092"));
+  aUUID.AssignLiteral("B7CBD7C1-53EF-42F9-8353-73F61C70C092");
   return;
 }
 
 nsresult
 MediaEngineDefaultAudioSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                         const MediaEnginePrefs &aPrefs)
 {
   if (mState != kReleased) {
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -34,17 +34,17 @@ class MediaEngineDefaultVideoSource : pu
                                       public MediaEngineVideoSource
 {
 public:
   MediaEngineDefaultVideoSource();
 
   virtual void Shutdown() override {};
 
   virtual void GetName(nsAString&) override;
-  virtual void GetUUID(nsAString&) override;
+  virtual void GetUUID(nsACString&) override;
 
   virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                             const MediaEnginePrefs &aPrefs) override;
   virtual nsresult Deallocate() override;
   virtual nsresult Start(SourceMediaStream*, TrackID) override;
   virtual nsresult Stop(SourceMediaStream*, TrackID) override;
   virtual void SetDirectListeners(bool aHasDirectListeners) override {};
   virtual nsresult Config(bool aEchoOn, uint32_t aEcho,
@@ -104,17 +104,17 @@ class MediaEngineDefaultAudioSource : pu
                                       public MediaEngineAudioSource
 {
 public:
   MediaEngineDefaultAudioSource();
 
   virtual void Shutdown() override {};
 
   virtual void GetName(nsAString&) override;
-  virtual void GetUUID(nsAString&) override;
+  virtual void GetUUID(nsACString&) override;
 
   virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                             const MediaEnginePrefs &aPrefs) override;
   virtual nsresult Deallocate() override;
   virtual nsresult Start(SourceMediaStream*, TrackID) override;
   virtual nsresult Stop(SourceMediaStream*, TrackID) override;
   virtual void SetDirectListeners(bool aHasDirectListeners) override {};
   virtual nsresult Config(bool aEchoOn, uint32_t aEcho,
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
@@ -332,18 +332,18 @@ MediaEngineGonkVideoSource::Stop(SourceM
 * constructor and destructor respectively.
 */
 
 void
 MediaEngineGonkVideoSource::Init()
 {
   nsAutoCString deviceName;
   ICameraControl::GetCameraName(mCaptureIndex, deviceName);
-  CopyUTF8toUTF16(deviceName, mDeviceName);
-  CopyUTF8toUTF16(deviceName, mUniqueId);
+  SetName(NS_ConvertUTF8toUTF16(deviceName));
+  SetUUID(deviceName.get());
 
   mInitDone = true;
 }
 
 void
 MediaEngineGonkVideoSource::Shutdown()
 {
   LOG((__FUNCTION__));
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -104,19 +104,19 @@ MediaEngineTabVideoSource::InitRunnable:
 
 void
 MediaEngineTabVideoSource::GetName(nsAString_internal& aName)
 {
   aName.AssignLiteral(MOZ_UTF16("&getUserMedia.videoSource.tabShare;"));
 }
 
 void
-MediaEngineTabVideoSource::GetUUID(nsAString_internal& aUuid)
+MediaEngineTabVideoSource::GetUUID(nsACString_internal& aUuid)
 {
-  aUuid.AssignLiteral(MOZ_UTF16("uuid"));
+  aUuid.AssignLiteral("tab");
 }
 
 #define DEFAULT_TABSHARE_VIDEO_MAX_WIDTH 4096
 #define DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT 4096
 #define DEFAULT_TABSHARE_VIDEO_FRAMERATE 30
 
 nsresult
 MediaEngineTabVideoSource::Allocate(const dom::MediaTrackConstraints& aConstraints,
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -15,17 +15,17 @@ class MediaEngineTabVideoSource : public
   public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIDOMEVENTLISTENER
     NS_DECL_NSITIMERCALLBACK
     MediaEngineTabVideoSource();
 
     virtual void Shutdown() override {};
     virtual void GetName(nsAString_internal&) override;
-    virtual void GetUUID(nsAString_internal&) override;
+    virtual void GetUUID(nsACString_internal&) override;
     virtual nsresult Allocate(const dom::MediaTrackConstraints &,
                               const mozilla::MediaEnginePrefs&) override;
     virtual nsresult Deallocate() override;
     virtual nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID) override;
     virtual void SetDirectListeners(bool aHasDirectListeners) override {};
     virtual void NotifyPull(mozilla::MediaStreamGraph*, mozilla::SourceMediaStream*, mozilla::TrackID, mozilla::StreamTime) override;
     virtual nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID) override;
     virtual nsresult Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t) override;
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -148,22 +148,22 @@ public:
     , mEchoOn(false), mAgcOn(false), mNoiseOn(false)
     , mEchoCancel(webrtc::kEcDefault)
     , mAGC(webrtc::kAgcDefault)
     , mNoiseSuppress(webrtc::kNsDefault)
     , mPlayoutDelay(0)
     , mNullTransport(nullptr) {
     MOZ_ASSERT(aVoiceEnginePtr);
     mDeviceName.Assign(NS_ConvertUTF8toUTF16(name));
-    mDeviceUUID.Assign(NS_ConvertUTF8toUTF16(uuid));
+    mDeviceUUID.Assign(uuid);
     Init();
   }
 
   virtual void GetName(nsAString& aName) override;
-  virtual void GetUUID(nsAString& aUUID) override;
+  virtual void GetUUID(nsACString& aUUID) override;
 
   virtual nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                             const MediaEnginePrefs& aPrefs) override;
   virtual nsresult Deallocate() override;
   virtual nsresult Start(SourceMediaStream* aStream, TrackID aID) override;
   virtual nsresult Stop(SourceMediaStream* aSource, TrackID aID) override;
   virtual void SetDirectListeners(bool aHasDirectListeners) override {};
   virtual nsresult Config(bool aEchoOn, uint32_t aEcho,
@@ -218,17 +218,17 @@ private:
   nsCOMPtr<nsIThread> mThread;
   int mCapIndex;
   int mChannel;
   TrackID mTrackID;
   bool mInitDone;
   bool mStarted;
 
   nsString mDeviceName;
-  nsString mDeviceUUID;
+  nsCString mDeviceUUID;
 
   bool mEchoOn, mAgcOn, mNoiseOn;
   webrtc::EcModes  mEchoCancel;
   webrtc::AgcModes mAGC;
   webrtc::NsModes  mNoiseSuppress;
   int32_t mPlayoutDelay;
 
   NullTransport *mNullTransport;
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -182,17 +182,17 @@ MediaEngineWebRTCAudioSource::GetName(ns
   if (mInitDone) {
     aName.Assign(mDeviceName);
   }
 
   return;
 }
 
 void
-MediaEngineWebRTCAudioSource::GetUUID(nsAString& aUUID)
+MediaEngineWebRTCAudioSource::GetUUID(nsACString& aUUID)
 {
   if (mInitDone) {
     aUUID.Assign(mDeviceUUID);
   }
 
   return;
 }
 
--- a/dom/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -146,19 +146,17 @@ MediaEngineWebRTCVideoSource::NotifyPull
     // nullptr images are allowed
     AppendToTrack(aSource, mImage, aID, delta);
   }
 }
 
 size_t
 MediaEngineWebRTCVideoSource::NumCapabilities()
 {
-  NS_ConvertUTF16toUTF8 uniqueId(mUniqueId); // TODO: optimize this?
-
-  int num = mViECapture->NumberOfCapabilities(uniqueId.get(), kMaxUniqueIdLength);
+  int num = mViECapture->NumberOfCapabilities(GetUUID().get(), kMaxUniqueIdLength);
   if (num > 0) {
     return num;
   }
 
   switch (mMediaSource) {
     case dom::MediaSourceEnum::Camera:
 #ifdef XP_MACOSX
       // Mac doesn't support capabilities.
@@ -200,33 +198,32 @@ MediaEngineWebRTCVideoSource::NumCapabil
 
 void
 MediaEngineWebRTCVideoSource::GetCapability(size_t aIndex,
                                             webrtc::CaptureCapability& aOut)
 {
   if (!mHardcodedCapabilities.IsEmpty()) {
     MediaEngineCameraVideoSource::GetCapability(aIndex, aOut);
   }
-  NS_ConvertUTF16toUTF8 uniqueId(mUniqueId); // TODO: optimize this?
-  mViECapture->GetCaptureCapability(uniqueId.get(), kMaxUniqueIdLength, aIndex, aOut);
+  mViECapture->GetCaptureCapability(GetUUID().get(), kMaxUniqueIdLength, aIndex, aOut);
 }
 
 nsresult
 MediaEngineWebRTCVideoSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                        const MediaEnginePrefs &aPrefs)
 {
   LOG((__FUNCTION__));
   if (mState == kReleased && mInitDone) {
     // Note: if shared, we don't allow a later opener to affect the resolution.
     // (This may change depending on spec changes for Constraints/settings)
 
     if (!ChooseCapability(aConstraints, aPrefs)) {
       return NS_ERROR_UNEXPECTED;
     }
-    if (mViECapture->AllocateCaptureDevice(NS_ConvertUTF16toUTF8(mUniqueId).get(),
+    if (mViECapture->AllocateCaptureDevice(GetUUID().get(),
                                            kMaxUniqueIdLength, mCaptureIndex)) {
       return NS_ERROR_FAILURE;
     }
     mState = kAllocated;
     LOG(("Video device %d allocated", mCaptureIndex));
   } else if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
     MonitorAutoLock lock(mMonitor);
     if (mSources.IsEmpty()) {
@@ -382,19 +379,18 @@ MediaEngineWebRTCVideoSource::Init()
 
   char deviceName[kMaxDeviceNameLength];
   char uniqueId[kMaxUniqueIdLength];
   if (mViECapture->GetCaptureDevice(mCaptureIndex,
                                     deviceName, kMaxDeviceNameLength,
                                     uniqueId, kMaxUniqueIdLength)) {
     return;
   }
-
-  CopyUTF8toUTF16(deviceName, mDeviceName);
-  CopyUTF8toUTF16(uniqueId, mUniqueId);
+  SetName(NS_ConvertUTF8toUTF16(deviceName));
+  SetUUID(uniqueId);
 
   mInitDone = true;
 }
 
 void
 MediaEngineWebRTCVideoSource::Shutdown()
 {
   LOG((__FUNCTION__));
@@ -438,17 +434,15 @@ void MediaEngineWebRTCVideoSource::Refre
   char uniqueId[kMaxUniqueIdLength];
 
   if (mViECapture->GetCaptureDevice(aIndex,
                                     deviceName, sizeof(deviceName),
                                     uniqueId, sizeof(uniqueId))) {
     return;
   }
 
-  CopyUTF8toUTF16(deviceName, mDeviceName);
+  SetName(NS_ConvertUTF8toUTF16(deviceName));
 #ifdef DEBUG
-  nsString temp;
-  CopyUTF8toUTF16(uniqueId, temp);
-  MOZ_ASSERT(temp.Equals(mUniqueId));
+  MOZ_ASSERT(GetUUID().Equals(uniqueId));
 #endif
 }
 
 } // namespace mozilla
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -3,17 +3,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BackgroundChildImpl.h"
 
 #include "ActorsChild.h" // IndexedDB
 #include "BroadcastChannelChild.h"
 #include "ServiceWorkerManagerChild.h"
 #include "FileDescriptorSetChild.h"
-#include "mozilla/media/MediaChild.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/PBlobChild.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/MessagePortChild.h"
 #include "mozilla/ipc/PBackgroundTestChild.h"
 #include "mozilla/layout/VsyncChild.h"
@@ -324,28 +323,16 @@ BackgroundChildImpl::AllocPCacheStreamCo
 
 bool
 BackgroundChildImpl::DeallocPCacheStreamControlChild(PCacheStreamControlChild* aActor)
 {
   dom::cache::DeallocPCacheStreamControlChild(aActor);
   return true;
 }
 
-media::PMediaChild*
-BackgroundChildImpl::AllocPMediaChild()
-{
-  return media::AllocPMediaChild();
-}
-
-bool
-BackgroundChildImpl::DeallocPMediaChild(media::PMediaChild *aActor)
-{
-  return media::DeallocPMediaChild(aActor);
-}
-
 // -----------------------------------------------------------------------------
 // MessageChannel/MessagePort API
 // -----------------------------------------------------------------------------
 
 dom::PMessagePortChild*
 BackgroundChildImpl::AllocPMessagePortChild(const nsID& aUUID,
                                             const nsID& aDestinationUUID,
                                             const uint32_t& aSequenceID)
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -66,22 +66,16 @@ protected:
 
   virtual PFileDescriptorSetChild*
   AllocPFileDescriptorSetChild(const FileDescriptor& aFileDescriptor)
                                override;
 
   virtual bool
   DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor) override;
 
-  virtual PMediaChild*
-  AllocPMediaChild() override;
-
-  virtual bool
-  DeallocPMediaChild(PMediaChild* aActor) override;
-
   virtual PVsyncChild*
   AllocPVsyncChild() override;
 
   virtual bool
   DeallocPVsyncChild(PVsyncChild* aActor) override;
 
   virtual PUDPSocketChild*
   AllocPUDPSocketChild(const OptionalPrincipalInfo& aPrincipalInfo,
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -1,17 +1,16 @@
 /* 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 "BackgroundParentImpl.h"
 
 #include "BroadcastChannelParent.h"
 #include "FileDescriptorSetParent.h"
-#include "mozilla/media/MediaParent.h"
 #include "mozilla/AppProcessChecker.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/PBlobParent.h"
 #include "mozilla/dom/MessagePortParent.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
@@ -489,28 +488,16 @@ BackgroundParentImpl::DeallocPServiceWor
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   delete static_cast<ServiceWorkerManagerParent*>(aActor);
   return true;
 }
 
-media::PMediaParent*
-BackgroundParentImpl::AllocPMediaParent()
-{
-  return media::AllocPMediaParent();
-}
-
-bool
-BackgroundParentImpl::DeallocPMediaParent(media::PMediaParent *aActor)
-{
-  return media::DeallocPMediaParent(aActor);
-}
-
 bool
 BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar()
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
 
   if (BackgroundParent::IsOtherProcessActor(this)) {
     return false;
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -87,22 +87,16 @@ protected:
   DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override;
 
   virtual PServiceWorkerManagerParent*
   AllocPServiceWorkerManagerParent() override;
 
   virtual bool
   DeallocPServiceWorkerManagerParent(PServiceWorkerManagerParent* aActor) override;
 
-  virtual PMediaParent*
-  AllocPMediaParent() override;
-
-  virtual bool
-  DeallocPMediaParent(PMediaParent* aActor) override;
-
   virtual bool
   RecvShutdownServiceWorkerRegistrar() override;
 
   virtual dom::cache::PCacheStorageParent*
   AllocPCacheStorageParent(const dom::cache::Namespace& aNamespace,
                            const PrincipalInfo& aPrincipalInfo) override;
 
   virtual bool
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -6,17 +6,16 @@ include protocol PBackgroundIDBFactory;
 include protocol PBackgroundTest;
 include protocol PBlob;
 include protocol PBroadcastChannel;
 include protocol PCache;
 include protocol PCacheStorage;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 include protocol PMessagePort;
-include protocol PMedia;
 include protocol PServiceWorkerManager;
 include protocol PUDPSocket;
 include protocol PVsync;
 
 include DOMTypes;
 include PBackgroundSharedTypes;
 include PBackgroundIDBSharedTypes;
 
@@ -32,29 +31,27 @@ sync protocol PBackground
   manages PBackgroundTest;
   manages PBlob;
   manages PBroadcastChannel;
   manages PCache;
   manages PCacheStorage;
   manages PCacheStreamControl;
   manages PFileDescriptorSet;
   manages PMessagePort;
-  manages PMedia;
   manages PServiceWorkerManager;
   manages PUDPSocket;
   manages PVsync;
 
 parent:
   // Only called at startup during mochitests to check the basic infrastructure.
   PBackgroundTest(nsCString testArg);
 
   PBackgroundIDBFactory(LoggingInfo loggingInfo);
 
   PVsync();
-  PMedia();
 
   PUDPSocket(OptionalPrincipalInfo pInfo, nsCString filter);
   PBroadcastChannel(PrincipalInfo pInfo, nsString origin, nsString channel,
                     bool privateBrowsing);
 
   PServiceWorkerManager();
 
   ShutdownServiceWorkerRegistrar();