Bug 1177242 - Verify whether sandboxed Content process has permissions to access the camera/mic. r=jesup
authorGian-Carlo Pascutto <gcp@mozilla.com>
Wed, 17 Feb 2016 18:57:26 +0100
changeset 331627 c5d6c3e00c91dd0595a12b145c66cf4f2a890591
parent 331626 1ef77d653c4f7f5ea0452b010a9c6a85c9e87b5d
child 331628 93e0395f69fbe1242899b5e54610f4ad2d80ad27
push id11020
push userjolesen@mozilla.com
push dateWed, 17 Feb 2016 18:16:38 +0000
reviewersjesup
bugs1177242
milestone47.0a1
Bug 1177242 - Verify whether sandboxed Content process has permissions to access the camera/mic. r=jesup
browser/modules/webrtcUI.jsm
dom/media/MediaManager.cpp
dom/media/MediaManager.h
dom/media/systemservices/CamerasChild.cpp
dom/media/systemservices/CamerasChild.h
dom/media/systemservices/CamerasParent.cpp
dom/media/systemservices/CamerasParent.h
dom/media/systemservices/PCameras.ipdl
dom/media/webrtc/MediaEngine.h
dom/media/webrtc/MediaEngineDefault.cpp
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
dom/media/webrtc/MediaEngineRemoteVideoSource.h
dom/media/webrtc/MediaEngineTabVideoSource.cpp
dom/media/webrtc/MediaEngineTabVideoSource.h
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -274,16 +274,17 @@ function getHost(uri, href) {
 }
 
 function prompt(aBrowser, aRequest) {
   let {audioDevices: audioDevices, videoDevices: videoDevices,
        sharingScreen: sharingScreen, sharingAudio: sharingAudio,
        requestTypes: requestTypes} = aRequest;
   let uri = Services.io.newURI(aRequest.documentURI, null, null);
   let host = getHost(uri);
+  let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
   let chromeDoc = aBrowser.ownerDocument;
   let chromeWin = chromeDoc.defaultView;
   let stringBundle = chromeWin.gNavigatorBundle;
   let stringId = "getUserMedia.share" + requestTypes.join("And") + ".message";
   let message = stringBundle.getFormattedString(stringId, [host]);
 
   let mainLabel;
   if (sharingScreen || sharingAudio) {
@@ -369,17 +370,26 @@ function prompt(aBrowser, aRequest) {
       // to avoid granting permissions automatically to background tabs.
       if (aRequest.secure) {
         let perms = Services.perms;
 
         let micPerm = perms.testExactPermission(uri, "microphone");
         if (micPerm == perms.PROMPT_ACTION)
           micPerm = perms.UNKNOWN_ACTION;
 
+        let camPermanentPerm = perms.testExactPermanentPermission(principal, "camera");
         let camPerm = perms.testExactPermission(uri, "camera");
+
+        // Session approval given but never used to allocate a camera, remove
+        // and ask again
+        if (camPerm && !camPermanentPerm) {
+          perms.remove(uri, "camera");
+          camPerm = perms.UNKNOWN_ACTION;
+        }
+
         if (camPerm == perms.PROMPT_ACTION)
           camPerm = perms.UNKNOWN_ACTION;
 
         // Screen sharing shouldn't follow the camera permissions.
         if (videoDevices.length && sharingScreen)
           camPerm = perms.UNKNOWN_ACTION;
 
         // We don't check that permissions are set to ALLOW_ACTION in this
@@ -510,21 +520,24 @@ function prompt(aBrowser, aRequest) {
 
       this.mainAction.callback = function(aRemember) {
         let allowedDevices = [];
         let perms = Services.perms;
         if (videoDevices.length) {
           let listId = "webRTC-select" + (sharingScreen ? "Window" : "Camera") + "-menulist";
           let videoDeviceIndex = chromeDoc.getElementById(listId).value;
           let allowCamera = videoDeviceIndex != "-1";
-          if (allowCamera)
+          if (allowCamera) {
             allowedDevices.push(videoDeviceIndex);
-          if (aRemember) {
-            perms.add(uri, "camera",
-                      allowCamera ? perms.ALLOW_ACTION : perms.DENY_ACTION);
+            // Session permission will be removed after use
+            // (it's really one-shot, not for the entire session)
+            perms.add(uri, "camera", perms.ALLOW_ACTION,
+                      aRemember ? perms.EXPIRE_NEVER : perms.EXPIRE_SESSION);
+          } else if (aRemember) {
+            perms.add(uri, "camera", perms.DENY_ACTION);
           }
         }
         if (audioDevices.length) {
           if (!sharingAudio) {
             let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value;
             let allowMic = audioDeviceIndex != "-1";
             if (allowMic)
               allowedDevices.push(audioDeviceIndex);
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -629,23 +629,25 @@ VideoDevice::GetSource()
 
 AudioDevice::Source*
 AudioDevice::GetSource()
 {
   return static_cast<Source*>(&*mSource);
 }
 
 nsresult VideoDevice::Allocate(const dom::MediaTrackConstraints &aConstraints,
-                               const MediaEnginePrefs &aPrefs) {
-  return GetSource()->Allocate(aConstraints, aPrefs, mID);
+                               const MediaEnginePrefs &aPrefs,
+                               const nsACString& aOrigin) {
+  return GetSource()->Allocate(aConstraints, aPrefs, mID, aOrigin);
 }
 
 nsresult AudioDevice::Allocate(const dom::MediaTrackConstraints &aConstraints,
-                               const MediaEnginePrefs &aPrefs) {
-  return GetSource()->Allocate(aConstraints, aPrefs, mID);
+                               const MediaEnginePrefs &aPrefs,
+                               const nsACString& aOrigin) {
+  return GetSource()->Allocate(aConstraints, aPrefs, mID, aOrigin);
 }
 
 nsresult VideoDevice::Restart(const dom::MediaTrackConstraints &aConstraints,
                               const MediaEnginePrefs &aPrefs) {
   return GetSource()->Restart(aConstraints, aPrefs, mID);
 }
 
 nsresult AudioDevice::Restart(const dom::MediaTrackConstraints &aConstraints,
@@ -1198,26 +1200,28 @@ public:
     MOZ_ASSERT(mDeviceChosen);
 
     // Allocate a video or audio device and return a MediaStream via
     // a GetUserMediaStreamRunnable.
 
     nsresult rv;
 
     if (mAudioDevice) {
-      rv = mAudioDevice->Allocate(GetInvariant(mConstraints.mAudio), mPrefs);
+      rv = mAudioDevice->Allocate(GetInvariant(mConstraints.mAudio),
+                                  mPrefs, mOrigin);
       if (NS_FAILED(rv)) {
         LOG(("Failed to allocate audiosource %d",rv));
         Fail(NS_LITERAL_STRING("SourceUnavailableError"),
              NS_LITERAL_STRING("Failed to allocate audiosource"));
         return;
       }
     }
     if (mVideoDevice) {
-      rv = mVideoDevice->Allocate(GetInvariant(mConstraints.mVideo), mPrefs);
+      rv = mVideoDevice->Allocate(GetInvariant(mConstraints.mVideo),
+                                  mPrefs, mOrigin);
       if (NS_FAILED(rv)) {
         LOG(("Failed to allocate videosource %d\n",rv));
         if (mAudioDevice) {
           mAudioDevice->GetSource()->Deallocate();
         }
         Fail(NS_LITERAL_STRING("SourceUnavailableError"),
              NS_LITERAL_STRING("Failed to allocate videosource"));
         return;
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -89,31 +89,33 @@ class VideoDevice : public MediaDevice
 {
 public:
   typedef MediaEngineVideoSource Source;
 
   explicit VideoDevice(Source* aSource);
   NS_IMETHOD GetType(nsAString& aType);
   Source* GetSource();
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
-                    const MediaEnginePrefs &aPrefs);
+                    const MediaEnginePrefs &aPrefs,
+                    const nsACString& aOrigin);
   nsresult Restart(const dom::MediaTrackConstraints &aConstraints,
                    const MediaEnginePrefs &aPrefs);
 };
 
 class AudioDevice : public MediaDevice
 {
 public:
   typedef MediaEngineAudioSource Source;
 
   explicit AudioDevice(Source* aSource);
   NS_IMETHOD GetType(nsAString& aType);
   Source* GetSource();
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
-                    const MediaEnginePrefs &aPrefs);
+                    const MediaEnginePrefs &aPrefs,
+                    const nsACString& aOrigin);
   nsresult Restart(const dom::MediaTrackConstraints &aConstraints,
                    const MediaEnginePrefs &aPrefs);
 };
 
 /**
  * This class is an implementation of MediaStreamListener. This is used
  * to Start() and Stop() the underlying MediaEngineSource when MediaStreams
  * are assigned and deassigned in content.
--- a/dom/media/systemservices/CamerasChild.cpp
+++ b/dom/media/systemservices/CamerasChild.cpp
@@ -346,23 +346,25 @@ CamerasChild::RecvReplyGetCaptureDevice(
   monitor.Notify();
   return true;
 }
 
 int
 CamerasChild::AllocateCaptureDevice(CaptureEngine aCapEngine,
                                     const char* unique_idUTF8,
                                     const unsigned int unique_idUTF8Length,
-                                    int& capture_id)
+                                    int& capture_id,
+                                    const nsACString& aOrigin)
 {
   LOG((__PRETTY_FUNCTION__));
   nsCString unique_id(unique_idUTF8);
+  nsCString origin(aOrigin);
   nsCOMPtr<nsIRunnable> runnable =
-    media::NewRunnableFrom([this, aCapEngine, unique_id]() -> nsresult {
-      if (this->SendAllocateCaptureDevice(aCapEngine, unique_id)) {
+    media::NewRunnableFrom([this, aCapEngine, unique_id, origin]() -> nsresult {
+      if (this->SendAllocateCaptureDevice(aCapEngine, unique_id, origin)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
   LockAndDispatch<> dispatcher(this, __func__, runnable);
   if (dispatcher.Success()) {
     LOG(("Capture Device allocated: %d", mReplyInteger));
     capture_id = mReplyInteger;
--- a/dom/media/systemservices/CamerasChild.h
+++ b/dom/media/systemservices/CamerasChild.h
@@ -176,17 +176,18 @@ public:
                            const int capture_id);
   int StartCapture(CaptureEngine aCapEngine,
                    const int capture_id, webrtc::CaptureCapability& capability,
                    webrtc::ExternalRenderer* func);
   int StopCapture(CaptureEngine aCapEngine, const int capture_id);
   int AllocateCaptureDevice(CaptureEngine aCapEngine,
                             const char* unique_idUTF8,
                             const unsigned int unique_idUTF8Length,
-                            int& capture_id);
+                            int& capture_id,
+                            const nsACString& aOrigin);
   int GetCaptureCapability(CaptureEngine aCapEngine,
                            const char* unique_idUTF8,
                            const unsigned int capability_number,
                            webrtc::CaptureCapability& capability);
   int GetCaptureDevice(CaptureEngine aCapEngine,
                        unsigned int list_number, char* device_nameUTF8,
                        const unsigned int device_nameUTF8Length,
                        char* unique_idUTF8,
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -6,20 +6,24 @@
 
 #include "CamerasParent.h"
 #include "CamerasUtils.h"
 #include "MediaEngine.h"
 #include "MediaUtils.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/unused.h"
+#include "mozilla/Services.h"
 #include "mozilla/Logging.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/Preferences.h"
+#include "nsIPermissionManager.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
+#include "nsNetUtil.h"
 
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
 
 #undef LOG
 #undef LOG_ENABLED
 mozilla::LazyLogModule gCamerasParentLog("CamerasParent");
 #define LOG(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Debug, args)
 #define LOG_ENABLED() MOZ_LOG_TEST(gCamerasParentLog, mozilla::LogLevel::Debug)
@@ -636,49 +640,137 @@ CamerasParent::RecvGetCaptureDevice(cons
         });
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
   DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
+static nsresult
+GetPrincipalFromOrigin(const nsACString& aOrigin, nsIPrincipal** aPrincipal)
+{
+  nsAutoCString originNoSuffix;
+  mozilla::PrincipalOriginAttributes attrs;
+  if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
+  principal.forget(aPrincipal);
+  return NS_OK;
+}
+
+// Find out whether the given origin has permission to use the
+// camera. If the permission is not persistent, we'll make it
+// a one-shot by removing the (session) permission.
+static bool
+HasCameraPermission(const nsCString& aOrigin)
+{
+  // Name used with nsIPermissionManager
+  static const char* cameraPermission = "camera";
+  bool allowed = false;
+  bool permanent = false;
+  nsresult rv;
+  nsCOMPtr<nsIPermissionManager> mgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
+  if (NS_SUCCEEDED(rv)) {
+    nsCOMPtr<nsIIOService> ioServ(do_GetIOService());
+    nsCOMPtr<nsIURI> uri;
+    rv = ioServ->NewURI(aOrigin, nullptr, nullptr, getter_AddRefs(uri));
+    if (NS_SUCCEEDED(rv)) {
+      // Permanent permissions are only retrievable via principal, not uri
+      nsCOMPtr<nsIPrincipal> principal;
+      rv = GetPrincipalFromOrigin(aOrigin, getter_AddRefs(principal));
+      if (NS_SUCCEEDED(rv)) {
+        uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
+        rv = mgr->TestExactPermissionFromPrincipal(principal,
+                                                   cameraPermission,
+                                                   &video);
+        if (NS_SUCCEEDED(rv)) {
+          allowed = (video == nsIPermissionManager::ALLOW_ACTION);
+          // Was allowed, now see if this is a persistent permission
+          // or a session one.
+          if (allowed) {
+            rv = mgr->TestExactPermanentPermission(principal,
+                                                   cameraPermission,
+                                                   &video);
+            if (NS_SUCCEEDED(rv)) {
+              permanent = (video == nsIPermissionManager::ALLOW_ACTION);
+            }
+          }
+        }
+        // Session permissions are removed after one use.
+        if (allowed && !permanent) {
+          mgr->RemoveFromPrincipal(principal, cameraPermission);
+        }
+      }
+    }
+  }
+  return allowed;
+}
+
 bool
 CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine,
-                                         const nsCString& unique_id)
+                                         const nsCString& unique_id,
+                                         const nsCString& aOrigin)
 {
-  LOG((__PRETTY_FUNCTION__));
-
+  LOG(("%s: Verifying permissions for %s", __PRETTY_FUNCTION__, aOrigin.get()));
   RefPtr<CamerasParent> self(this);
-  RefPtr<nsRunnable> webrtc_runnable =
-    media::NewRunnableFrom([self, aCapEngine, unique_id]() -> nsresult {
-      int numdev = -1;
-      int error = -1;
-      if (self->EnsureInitialized(aCapEngine)) {
-        error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice(
-          unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev);
+  RefPtr<nsRunnable> mainthread_runnable =
+    media::NewRunnableFrom([self, aCapEngine, unique_id, aOrigin]() -> nsresult {
+      // Verify whether the claimed origin has received permission
+      // to use the camera, either persistently or this session (one shot).
+      bool allowed = HasCameraPermission(aOrigin);
+      if (!allowed) {
+        // Developer preference for turning off permission check.
+        if (Preferences::GetBool("media.navigator.permission.disabled", false)
+            || Preferences::GetBool("media.navigator.permission.fake")) {
+          allowed = true;
+          LOG(("No permission but checks are disabled or fake sources active"));
+        } else {
+          LOG(("No camera permission for this origin"));
+        }
       }
-      RefPtr<nsIRunnable> ipc_runnable =
-        media::NewRunnableFrom([self, numdev, error]() -> nsresult {
-          if (self->IsShuttingDown()) {
-            return NS_ERROR_FAILURE;
-          }
-          if (error) {
-            Unused << self->SendReplyFailure();
-            return NS_ERROR_FAILURE;
-          } else {
-            LOG(("Allocated device nr %d", numdev));
-            Unused << self->SendReplyAllocateCaptureDevice(numdev);
-            return NS_OK;
-          }
+      // After retrieving the permission (or not) on the main thread,
+      // bounce to the WebRTC thread to allocate the device (or not),
+      // then bounce back to the IPC thread for the reply to content.
+      RefPtr<nsRunnable> webrtc_runnable =
+      media::NewRunnableFrom([self, allowed, aCapEngine, unique_id]() -> nsresult {
+        int numdev = -1;
+        int error = -1;
+        if (allowed && self->EnsureInitialized(aCapEngine)) {
+          error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice(
+                    unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev);
+        }
+        RefPtr<nsIRunnable> ipc_runnable =
+          media::NewRunnableFrom([self, numdev, error]() -> nsresult {
+            if (self->IsShuttingDown()) {
+              return NS_ERROR_FAILURE;
+            }
+            if (error) {
+              Unused << self->SendReplyFailure();
+              return NS_ERROR_FAILURE;
+            } else {
+              LOG(("Allocated device nr %d", numdev));
+              Unused << self->SendReplyAllocateCaptureDevice(numdev);
+              return NS_OK;
+            }
+          });
+        self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
+        return NS_OK;
         });
-      self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
+      self->DispatchToVideoCaptureThread(webrtc_runnable);
       return NS_OK;
     });
-  DispatchToVideoCaptureThread(webrtc_runnable);
+  NS_DispatchToMainThread(mainthread_runnable);
   return true;
 }
 
 int
 CamerasParent::ReleaseCaptureDevice(const int& aCapEngine,
                                     const int& capnum)
 {
   int error = -1;
--- a/dom/media/systemservices/CamerasParent.h
+++ b/dom/media/systemservices/CamerasParent.h
@@ -81,17 +81,17 @@ class CamerasParent :  public PCamerasPa
 {
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
 public:
   static already_AddRefed<CamerasParent> Create();
 
   // Messages received form the child. These run on the IPC/PBackground thread.
-  virtual bool RecvAllocateCaptureDevice(const int&, const nsCString&) override;
+  virtual bool RecvAllocateCaptureDevice(const int&, const nsCString&, const nsCString&) override;
   virtual bool RecvReleaseCaptureDevice(const int&, const int &) override;
   virtual bool RecvNumberOfCaptureDevices(const int&) override;
   virtual bool RecvNumberOfCapabilities(const int&, const nsCString&) override;
   virtual bool RecvGetCaptureCapability(const int&, const nsCString&, const int&) override;
   virtual bool RecvGetCaptureDevice(const int&, const int&) override;
   virtual bool RecvStartCapture(const int&, const int&, const CaptureCapability&) override;
   virtual bool RecvStopCapture(const int&, const int&) override;
   virtual bool RecvReleaseFrame(mozilla::ipc::Shmem&&) override;
--- a/dom/media/systemservices/PCameras.ipdl
+++ b/dom/media/systemservices/PCameras.ipdl
@@ -40,17 +40,17 @@ child:
 
 parent:
   async NumberOfCaptureDevices(int engine);
   async NumberOfCapabilities(int engine, nsCString deviceUniqueIdUTF8);
 
   async GetCaptureCapability(int engine, nsCString unique_idUTF8, int capability_number);
   async GetCaptureDevice(int engine, int num);
 
-  async AllocateCaptureDevice(int engine, nsCString unique_idUTF8);
+  async AllocateCaptureDevice(int engine, nsCString unique_idUTF8, nsCString origin);
   async ReleaseCaptureDevice(int engine, int numdev);
   async StartCapture(int engine, int numdev, CaptureCapability capability);
   async StopCapture(int engine, int numdev);
   // transfers frame back
   async ReleaseFrame(Shmem s);
 
   // Ask parent to delete us
   async AllDone();
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -166,17 +166,18 @@ public:
 
   void SetHasFakeTracks(bool aHasFakeTracks) {
     mHasFakeTracks = aHasFakeTracks;
   }
 
   /* This call reserves but does not start the device. */
   virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                             const MediaEnginePrefs &aPrefs,
-                            const nsString& aDeviceId) = 0;
+                            const nsString& aDeviceId,
+                            const nsACString& aOrigin) = 0;
 
   virtual uint32_t GetBestFitnessDistance(
       const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets,
       const nsString& aDeviceId) = 0;
 
 protected:
   // Only class' own members can be initialized in constructor initializer list.
   explicit MediaEngineSource(MediaEngineState aState)
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -82,17 +82,18 @@ MediaEngineDefaultVideoSource::GetBestFi
   }
 #endif
   return distance;
 }
 
 nsresult
 MediaEngineDefaultVideoSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                         const MediaEnginePrefs &aPrefs,
-                                        const nsString& aDeviceId)
+                                        const nsString& aDeviceId,
+                                        const nsACString& aOrigin)
 {
   if (mState != kReleased) {
     return NS_ERROR_FAILURE;
   }
 
   mOpts = aPrefs;
   mOpts.mWidth = mOpts.mWidth ? mOpts.mWidth : MediaEngine::DEFAULT_43_VIDEO_WIDTH;
   mOpts.mHeight = mOpts.mHeight ? mOpts.mHeight : MediaEngine::DEFAULT_43_VIDEO_HEIGHT;
@@ -391,17 +392,18 @@ MediaEngineDefaultAudioSource::GetBestFi
   }
 #endif
   return distance;
 }
 
 nsresult
 MediaEngineDefaultAudioSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                         const MediaEnginePrefs &aPrefs,
-                                        const nsString& aDeviceId)
+                                        const nsString& aDeviceId,
+                                        const nsACString& aOrigin)
 {
   if (mState != kReleased) {
     return NS_ERROR_FAILURE;
   }
 
   mState = kAllocated;
   // generate sine wave (default 1KHz)
   mSineGenerator = new SineWaveGenerator(AUDIO_RATE,
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -40,17 +40,18 @@ public:
 
   void Shutdown() override {};
 
   void GetName(nsAString&) override;
   void GetUUID(nsACString&) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;
   nsresult Start(SourceMediaStream*, TrackID) override;
   nsresult Stop(SourceMediaStream*, TrackID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void SetDirectListeners(bool aHasDirectListeners) override {};
   void NotifyPull(MediaStreamGraph* aGraph,
@@ -109,17 +110,18 @@ public:
 
   void Shutdown() override {};
 
   void GetName(nsAString&) override;
   void GetUUID(nsACString&) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;
   nsresult Start(SourceMediaStream*, TrackID) override;
   nsresult Stop(SourceMediaStream*, TrackID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void SetDirectListeners(bool aHasDirectListeners) override {};
   void AppendToSegment(AudioSegment& aSegment, TrackTicks aSamples);
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -95,17 +95,18 @@ MediaEngineRemoteVideoSource::Shutdown()
   mState = kReleased;
   mInitDone = false;
   return;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Allocate(const dom::MediaTrackConstraints& aConstraints,
                                        const MediaEnginePrefs& aPrefs,
-                                       const nsString& aDeviceId)
+                                       const nsString& aDeviceId,
+                                       const nsACString& aOrigin)
 {
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
 
   if (!mInitDone) {
     LOG(("Init not done"));
     return NS_ERROR_FAILURE;
   }
@@ -115,21 +116,22 @@ MediaEngineRemoteVideoSource::Allocate(c
     // (This may change depending on spec changes for Constraints/settings)
 
     if (!ChooseCapability(aConstraints, aPrefs, aDeviceId)) {
       return NS_ERROR_UNEXPECTED;
     }
 
     if (mozilla::camera::GetChildAndCall(
       &mozilla::camera::CamerasChild::AllocateCaptureDevice,
-      mCapEngine, GetUUID().get(), kMaxUniqueIdLength, mCaptureIndex)) {
+      mCapEngine, GetUUID().get(), kMaxUniqueIdLength, mCaptureIndex, aOrigin)) {
       return NS_ERROR_FAILURE;
     }
     mState = kAllocated;
-    LOG(("Video device %d allocated", mCaptureIndex));
+    LOG(("Video device %d allocated for %s", mCaptureIndex,
+         PromiseFlatCString(aOrigin).get()));
   } else if (MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
     MonitorAutoLock lock(mMonitor);
     if (mSources.IsEmpty()) {
       LOG(("Video device %d reallocated", mCaptureIndex));
     } else {
       LOG(("Video device %d allocated shared", mCaptureIndex));
     }
   }
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -68,17 +68,18 @@ public:
 
   // MediaEngineCameraVideoSource
   MediaEngineRemoteVideoSource(int aIndex, mozilla::camera::CaptureEngine aCapEngine,
                                dom::MediaSourceEnum aMediaSource,
                                const char* aMonitorName = "RemoteVideo.Monitor");
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;;
   nsresult Start(SourceMediaStream*, TrackID) override;
   nsresult Stop(SourceMediaStream*, TrackID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void NotifyPull(MediaStreamGraph* aGraph,
                   SourceMediaStream* aSource,
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -123,17 +123,18 @@ MediaEngineTabVideoSource::GetUUID(nsACS
 
 #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,
                                     const MediaEnginePrefs& aPrefs,
-                                    const nsString& aDeviceId)
+                                    const nsString& aDeviceId,
+                                    const nsACString& aOrigin)
 {
   // windowId is not a proper constraint, so just read it.
   // It has no well-defined behavior in advanced, so ignore it there.
 
   mWindowId = aConstraints.mBrowserWindow.WasPassed() ?
               aConstraints.mBrowserWindow.Value() : -1;
 
   return Restart(aConstraints, aPrefs, aDeviceId);
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -18,17 +18,18 @@ class MediaEngineTabVideoSource : public
     NS_DECL_NSITIMERCALLBACK
     MediaEngineTabVideoSource();
 
     void Shutdown() override {};
     void GetName(nsAString_internal&) override;
     void GetUUID(nsACString_internal&) override;
     nsresult Allocate(const dom::MediaTrackConstraints &,
                       const mozilla::MediaEnginePrefs&,
-                      const nsString& aDeviceId) override;
+                      const nsString& aDeviceId,
+                      const nsACString& aOrigin) override;
     nsresult Deallocate() override;
     nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID) override;
     void SetDirectListeners(bool aHasDirectListeners) override {};
     void NotifyPull(mozilla::MediaStreamGraph*, mozilla::SourceMediaStream*, mozilla::TrackID, mozilla::StreamTime) override;
     nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID) override;
     nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                      const mozilla::MediaEnginePrefs& aPrefs,
                      const nsString& aDeviceId) override;
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -67,17 +67,18 @@ public:
   explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid)
     : MediaEngineAudioSource(kReleased)
   {
   }
   void GetName(nsAString& aName) override;
   void GetUUID(nsACString& aUUID) override;
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
-                    const nsString& aDeviceId) override
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
     return NS_OK;
   }
   nsresult Deallocate() override
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
     return NS_OK;
@@ -430,17 +431,18 @@ public:
     Init();
   }
 
   void GetName(nsAString& aName) override;
   void GetUUID(nsACString& aUUID) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;
   nsresult Start(SourceMediaStream* aStream, TrackID aID) override;
   nsresult Stop(SourceMediaStream* aSource, TrackID aID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void SetDirectListeners(bool aHasDirectListeners) override {};
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -215,17 +215,18 @@ uint32_t MediaEngineWebRTCMicrophoneSour
     break; // distance is read from first entry only
   }
   return distance;
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                             const MediaEnginePrefs &aPrefs,
-                                            const nsString& aDeviceId)
+                                            const nsString& aDeviceId,
+                                            const nsACString& aOrigin)
 {
   AssertIsOnOwningThread();
   if (mState == kReleased) {
     if (mInitDone) {
       if (mAudioInput->SetRecordingDevice(mCapIndex)) {
         return NS_ERROR_FAILURE;
       }
       mState = kAllocated;