Bug 949907 - GetUserMediaDevices cleanup + untie GetUserMediaRequest obj from DOM. r=jesup
☠☠ backed out by 4609a7efae47 ☠ ☠
authorJan-Ivar Bruaroey <jib@mozilla.com>
Thu, 13 Feb 2014 15:32:17 -0800
changeset 168792 e1d1542ff35c165ce55efbcc62cf7cecf3b774c2
parent 168791 4081bcbf92852885796f1f5a7c8cc6e2843ecfed
child 168793 fffb200a94bcf686819f877526817218c11fd2ce
push id39796
push userryanvm@gmail.com
push dateFri, 14 Feb 2014 16:15:39 +0000
treeherdermozilla-inbound@e1d1542ff35c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs949907
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 949907 - GetUserMediaDevices cleanup + untie GetUserMediaRequest obj from DOM. r=jesup
browser/modules/webrtcUI.jsm
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/media/GetUserMediaRequest.cpp
dom/media/GetUserMediaRequest.h
dom/media/MediaManager.cpp
dom/media/MediaManager.h
dom/media/MediaPermissionGonk.cpp
dom/webidl/GetUserMediaRequest.webidl
dom/webidl/Navigator.webidl
mobile/android/chrome/content/WebrtcUI.js
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -61,41 +61,42 @@ function getBrowserForWindow(aContentWin
   return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIWebNavigation)
                        .QueryInterface(Ci.nsIDocShell)
                        .chromeEventHandler;
 }
 
 function handleRequest(aSubject, aTopic, aData) {
   let constraints = aSubject.getConstraints();
+  let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
 
-  Services.wm.getMostRecentWindow(null).navigator.mozGetUserMediaDevices(
+  contentWindow.navigator.mozGetUserMediaDevices(
     constraints,
     function (devices) {
-      prompt(aSubject.windowID, aSubject.callID, constraints.audio,
+      prompt(contentWindow, aSubject.callID, constraints.audio,
              constraints.video || constraints.picture, devices);
     },
     function (error) {
       // bug 827146 -- In the future, the UI should catch NO_DEVICES_FOUND
       // and allow the user to plug in a device, instead of immediately failing.
       denyRequest(aSubject.callID, error);
-    }
-  );
+    },
+    aSubject.innerWindowID);
 }
 
 function denyRequest(aCallID, aError) {
   let msg = null;
   if (aError) {
     msg = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
     msg.data = aError;
   }
   Services.obs.notifyObservers(msg, "getUserMedia:response:deny", aCallID);
 }
 
-function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices) {
+function prompt(aContentWindow, aCallID, aAudioRequested, aVideoRequested, aDevices) {
   let audioDevices = [];
   let videoDevices = [];
   for (let device of aDevices) {
     device = device.QueryInterface(Ci.nsIMediaDevice);
     switch (device.type) {
       case "audio":
         if (aAudioRequested)
           audioDevices.push(device);
@@ -114,19 +115,18 @@ function prompt(aWindowID, aCallID, aAud
     requestType = "Microphone";
   else if (videoDevices.length)
     requestType = "Camera";
   else {
     denyRequest(aCallID, "NO_DEVICES_FOUND");
     return;
   }
 
-  let contentWindow = Services.wm.getOuterWindowWithId(aWindowID);
-  let host = contentWindow.document.documentURIObject.host;
-  let browser = getBrowserForWindow(contentWindow);
+  let host = aContentWindow.document.documentURIObject.host;
+  let browser = getBrowserForWindow(aContentWindow);
   let chromeDoc = browser.ownerDocument;
   let chromeWin = chromeDoc.defaultView;
   let stringBundle = chromeWin.gNavigatorBundle;
   let message = stringBundle.getFormattedString("getUserMedia.share" + requestType + ".message",
                                                 [ host ]);
 
   let mainAction = {
     label: PluralForm.get(requestType == "CameraAndMicrophone" ? 2 : 1,
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1017,16 +1017,17 @@ Navigator::MozGetUserMedia(JSContext* aC
   aRv = manager->GetUserMedia(aCx, privileged, mWindow, aConstraints,
                               onsuccess, onerror);
 }
 
 void
 Navigator::MozGetUserMediaDevices(const MediaStreamConstraintsInternal& aConstraints,
                                   MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
                                   NavigatorUserMediaErrorCallback& aOnError,
+                                  uint64_t aInnerWindowID,
                                   ErrorResult& aRv)
 {
   CallbackObjectHolder<MozGetUserMediaDevicesSuccessCallback,
                        nsIGetUserMediaDevicesSuccessCallback> holder1(&aOnSuccess);
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onsuccess =
     holder1.ToXPCOMCallback();
 
   CallbackObjectHolder<NavigatorUserMediaErrorCallback,
@@ -1035,17 +1036,18 @@ Navigator::MozGetUserMediaDevices(const 
 
   if (!mWindow || !mWindow->GetOuterWindow() ||
       mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return;
   }
 
   MediaManager* manager = MediaManager::Get();
-  aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror);
+  aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror,
+                                     aInnerWindowID);
 }
 #endif
 
 DesktopNotificationCenter*
 Navigator::GetMozNotification(ErrorResult& aRv)
 {
   if (mNotification) {
     return mNotification;
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -225,16 +225,17 @@ public:
   void MozGetUserMedia(JSContext* aCx,
                        const MediaStreamConstraints& aConstraints,
                        NavigatorUserMediaSuccessCallback& aOnSuccess,
                        NavigatorUserMediaErrorCallback& aOnError,
                        ErrorResult& aRv);
   void MozGetUserMediaDevices(const MediaStreamConstraintsInternal& aConstraints,
                               MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
                               NavigatorUserMediaErrorCallback& aOnError,
+                              uint64_t aInnerWindowID,
                               ErrorResult& aRv);
 #endif // MOZ_MEDIA_NAVIGATOR
   bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                     JS::Handle<jsid> aId,
                     JS::MutableHandle<JSPropertyDescriptor> aDesc);
   void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
                            ErrorResult& aRv);
 
--- a/dom/media/GetUserMediaRequest.cpp
+++ b/dom/media/GetUserMediaRequest.cpp
@@ -12,51 +12,56 @@
 
 namespace mozilla {
 namespace dom {
 
 GetUserMediaRequest::GetUserMediaRequest(
     nsPIDOMWindow* aInnerWindow,
     const nsAString& aCallID,
     const MediaStreamConstraintsInternal& aConstraints)
-  : mInnerWindow(aInnerWindow)
-  , mWindowID(aInnerWindow->GetOuterWindow()->WindowID())
+  : mInnerWindowID(aInnerWindow->WindowID())
+  , mOuterWindowID(aInnerWindow->GetOuterWindow()->WindowID())
   , mCallID(aCallID)
   , mConstraints(aConstraints)
 {
   SetIsDOMBinding();
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(GetUserMediaRequest, mInnerWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(GetUserMediaRequest)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(GetUserMediaRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(GetUserMediaRequest)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GetUserMediaRequest)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 JSObject*
 GetUserMediaRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return GetUserMediaRequestBinding::Wrap(aCx, aScope, this);
 }
 
 nsISupports* GetUserMediaRequest::GetParentObject()
 {
-  return mInnerWindow;
+  return nullptr;
 }
 
 void GetUserMediaRequest::GetCallID(nsString& retval)
 {
   retval = mCallID;
 }
 
 uint64_t GetUserMediaRequest::WindowID()
 {
-  return mWindowID;
+  return mOuterWindowID;
+}
+
+uint64_t GetUserMediaRequest::InnerWindowID()
+{
+  return mInnerWindowID;
 }
 
 void
 GetUserMediaRequest::GetConstraints(MediaStreamConstraintsInternal &result)
 {
   result = mConstraints;
 }
 
--- a/dom/media/GetUserMediaRequest.h
+++ b/dom/media/GetUserMediaRequest.h
@@ -15,34 +15,35 @@
 
 namespace mozilla {
 namespace dom {
 class MediaStreamConstraintsInternal;
 
 class GetUserMediaRequest : public nsISupports, public nsWrapperCache
 {
 public:
-  GetUserMediaRequest(nsPIDOMWindow* aInnerWindow, const nsAString& aCallID,
+  GetUserMediaRequest(nsPIDOMWindow* aInnerWindow,
+                      const nsAString& aCallID,
                       const MediaStreamConstraintsInternal& aConstraints);
   virtual ~GetUserMediaRequest() {};
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GetUserMediaRequest)
 
   virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> scope)
     MOZ_OVERRIDE;
   nsISupports* GetParentObject();
 
   uint64_t WindowID();
+  uint64_t InnerWindowID();
   void GetCallID(nsString& retval);
   void GetConstraints(MediaStreamConstraintsInternal &result);
 
 private:
-  nsCOMPtr<nsPIDOMWindow> mInnerWindow;
-  uint64_t mWindowID;
+  uint64_t mInnerWindowID, mOuterWindowID;
   const nsString mCallID;
   MediaStreamConstraintsInternal mConstraints;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // GetUserMediaRequest_h__
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -220,31 +220,39 @@ private:
  * 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,
     already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aSuccess,
     already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
     nsTArray<nsCOMPtr<nsIMediaDevice> >* aDevices)
     : mSuccess(aSuccess)
     , mError(aError)
-    , mDevices(aDevices) {}
+    , mDevices(aDevices)
+    , mWindowID(aWindowID)
+    , mManager(MediaManager::GetInstance()) {}
 
   NS_IMETHOD
   Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
     nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> success(mSuccess);
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
+    // 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");
 
     int32_t len = mDevices->Length();
     if (len == 0) {
       // XXX
       // We should in the future return an empty array, and dynamically add
       // devices to the dropdowns if things are hotplugged while the
@@ -268,16 +276,18 @@ public:
     success->OnSuccess(devices);
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsAutoPtr<nsTArray<nsCOMPtr<nsIMediaDevice> > > mDevices;
+  uint64_t mWindowID;
+  nsRefPtr<MediaManager> mManager;
 };
 
 // Handle removing GetUserMediaCallbackMediaStreamListener from main thread
 class GetUserMediaListenerRemove: public nsRunnable
 {
 public:
   GetUserMediaListenerRemove(uint64_t aWindowID,
     GetUserMediaCallbackMediaStreamListener *aListener)
@@ -1071,27 +1081,29 @@ public:
                                           &MediaEngine::EnumerateVideoDevices,
                                           mLoopbackVideoDevice));
     {
       ScopedDeletePtr<SourceSet> s (GetSources(backend, mConstraints.mAudiom,
                                         &MediaEngine::EnumerateAudioDevices,
                                         mLoopbackAudioDevice));
       final->MoveElementsFrom(*s);
     }
-    NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mSuccess, mError,
+    NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId,
+                                                              mSuccess, mError,
                                                               final.forget()));
     return NS_OK;
   }
 
 private:
   MediaStreamConstraintsInternal mConstraints;
   already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   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.
   char* mLoopbackAudioDevice;
   char* mLoopbackVideoDevice;
 };
 
 MediaManager::MediaManager()
@@ -1444,17 +1456,18 @@ MediaManager::GetUserMedia(JSContext* aC
 
   return NS_OK;
 }
 
 nsresult
 MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
   const MediaStreamConstraintsInternal& aConstraints,
   nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
-  nsIDOMGetUserMediaErrorCallback* aOnError)
+  nsIDOMGetUserMediaErrorCallback* aOnError,
+  uint64_t aInnerWindowID)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
@@ -1469,19 +1482,19 @@ MediaManager::GetUserMediaDevices(nsPIDO
     if (branch) {
       branch->GetCharPref("media.audio_loopback_dev", &loopbackAudioDevice);
       branch->GetCharPref("media.video_loopback_dev", &loopbackVideoDevice);
     }
   }
 #endif
 
   nsCOMPtr<nsIRunnable> gUMDRunnable = new GetUserMediaDevicesRunnable(
-    aConstraints, onSuccess.forget(), onError.forget(), aWindow->WindowID(),
-    loopbackAudioDevice, loopbackVideoDevice
-  );
+    aConstraints, onSuccess.forget(), onError.forget(),
+    (aInnerWindowID ? aInnerWindowID : aWindow->WindowID()),
+    loopbackAudioDevice, loopbackVideoDevice);
 
   nsCOMPtr<nsIThread> deviceThread;
   rv = NS_NewThread(getter_AddRefs(deviceThread));
   NS_ENSURE_SUCCESS(rv, rv);
 
 
   deviceThread->Dispatch(gUMDRunnable, NS_DISPATCH_NORMAL);
   return NS_OK;
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -489,17 +489,18 @@ public:
     nsPIDOMWindow* aWindow,
     const dom::MediaStreamConstraints& aRawConstraints,
     nsIDOMGetUserMediaSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
 
   nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
     const dom::MediaStreamConstraintsInternal& aConstraints,
     nsIGetUserMediaDevicesSuccessCallback* onSuccess,
-    nsIDOMGetUserMediaErrorCallback* onError);
+    nsIDOMGetUserMediaErrorCallback* onError,
+    uint64_t aInnerWindowID = 0);
   void OnNavigation(uint64_t aWindowID);
 
   MediaEnginePrefs mPrefs;
 
 private:
   WindowTable *GetActiveWindows() {
     NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
     return &mActiveWindows;
--- a/dom/media/MediaPermissionGonk.cpp
+++ b/dom/media/MediaPermissionGonk.cpp
@@ -168,31 +168,33 @@ MediaPermissionRequest::GetTypes(nsIArra
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
 {
   NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
 
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mRequest->GetParentObject());
+  nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*>
+      (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID()));
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
   NS_ADDREF(*aRequestingPrincipal = doc->NodePrincipal());
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
 {
   NS_ENSURE_ARG_POINTER(aRequestingWindow);
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mRequest->GetParentObject());
+  nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*>
+      (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID()));
   window.forget(aRequestingWindow);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaPermissionRequest::GetElement(nsIDOMElement** aRequestingElement)
 {
   NS_ENSURE_ARG_POINTER(aRequestingElement);
@@ -216,17 +218,18 @@ MediaPermissionRequest::Allow()
   mRequest->GetCallID(callID);
   NotifyPermissionAllow(callID, mDevices);
   return NS_OK;
 }
 
 already_AddRefed<nsPIDOMWindow>
 MediaPermissionRequest::GetOwner()
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mRequest->GetParentObject());
+  nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*>
+      (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID()));
   return window.forget();
 }
 
 //PCOMContentPermissionRequestChild
 bool
 MediaPermissionRequest::Recv__delete__(const bool& allow)
 {
   if (allow) {
@@ -429,17 +432,18 @@ MediaPermissionManager::Observe(nsISuppo
 
 // Handle GetUserMediaRequest, query available media device first.
 nsresult
 MediaPermissionManager::HandleRequest(nsRefPtr<dom::GetUserMediaRequest> &req)
 {
   nsString callID;
   req->GetCallID(callID);
 
-  nsCOMPtr<nsPIDOMWindow> innerWindow = do_QueryInterface(req->GetParentObject());
+  nsCOMPtr<nsPIDOMWindow> innerWindow = static_cast<nsPIDOMWindow*>
+      (nsGlobalWindow::GetInnerWindowWithId(req->InnerWindowID()));
   if (!innerWindow) {
     MOZ_ASSERT(false, "No inner window");
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess =
       new MediaDeviceSuccessCallback(req);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError =
--- a/dom/webidl/GetUserMediaRequest.webidl
+++ b/dom/webidl/GetUserMediaRequest.webidl
@@ -4,11 +4,12 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * This is an internal IDL file
  */
 
 [NoInterfaceObject]
 interface GetUserMediaRequest {
   readonly attribute unsigned long long windowID;
+  readonly attribute unsigned long long innerWindowID;
   readonly attribute DOMString callID;
   MediaStreamConstraintsInternal getConstraints();
 };
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -335,11 +335,15 @@ partial interface Navigator {
 };
 
 // nsINavigatorUserMedia
 callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices);
 partial interface Navigator {
   [Throws, ChromeOnly]
   void mozGetUserMediaDevices(MediaStreamConstraintsInternal constraints,
                               MozGetUserMediaDevicesSuccessCallback onsuccess,
-                              NavigatorUserMediaErrorCallback onerror);
+                              NavigatorUserMediaErrorCallback onerror,
+                              // The originating innerWindowID is needed to
+                              // avoid calling the callbacks if the window has
+                              // navigated away. It is optional only as legacy.
+                              optional unsigned long long innerWindowID = 0);
 };
 #endif // MOZ_MEDIA_NAVIGATOR
--- a/mobile/android/chrome/content/WebrtcUI.js
+++ b/mobile/android/chrome/content/WebrtcUI.js
@@ -69,27 +69,28 @@ var WebrtcUI = {
         this._notificationId = Notifications.create(notificationOptions);
       if (count > 1)
         msg.count = count;
     }
   },
 
   handleRequest: function handleRequest(aSubject, aTopic, aData) {
     let constraints = aSubject.getConstraints();
+    let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
 
-    Services.wm.getMostRecentWindow(null).navigator.mozGetUserMediaDevices(
+    contentWindow.navigator.mozGetUserMediaDevices(
       constraints,
       function (devices) {
-        WebrtcUI.prompt(aSubject.windowID, aSubject.callID, constraints.audio,
+        WebrtcUI.prompt(contentWindow, aSubject.callID, constraints.audio,
                         constraints.video, devices);
       },
       function (error) {
         Cu.reportError(error);
-      }
-    );
+      },
+      aSubject.innerWindowID);
   },
 
   getDeviceButtons: function(audioDevices, videoDevices, aCallID) {
     return [{
       label: Strings.browser.GetStringFromName("getUserMedia.denyRequest.label"),
       callback: function() {
         Services.obs.notifyObservers(null, "getUserMedia:response:deny", aCallID);
       }
@@ -148,17 +149,18 @@ var WebrtcUI = {
           label: Strings.browser.GetStringFromName("getUserMedia." + aType + ".prompt"),
           values: list
         });
 
       }
     }
   },
 
-  prompt: function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices) {
+  prompt: function prompt(contentWindow, aCallID, aAudioRequested,
+                          aVideoRequested, aDevices) {
     let audioDevices = [];
     let videoDevices = [];
     for (let device of aDevices) {
       device = device.QueryInterface(Ci.nsIMediaDevice);
       switch (device.type) {
       case "audio":
         if (aAudioRequested)
           audioDevices.push(device);
@@ -175,18 +177,17 @@ var WebrtcUI = {
       requestType = "CameraAndMicrophone";
     else if (audioDevices.length)
       requestType = "Microphone";
     else if (videoDevices.length)
       requestType = "Camera";
     else
       return;
 
-    let contentWindow = Services.wm.getOuterWindowWithId(aWindowID);
-    let host = contentWindow.document.documentURIObject.host;
+    let host = aContentWindow.document.documentURIObject.host;
     let requestor = BrowserApp.manifest ? "'" + BrowserApp.manifest.name  + "'" : host;
     let message = Strings.browser.formatStringFromName("getUserMedia.share" + requestType + ".message", [ requestor ], 1);
 
     let options = { inputs: [] };
     // if the users only option would be to select "No Audio" or "No Video"
     // i.e. we're only showing audio or only video and there is only one device for that type
     // don't bother showing a menulist to select from
     var extraItems = null;