Bug 926289 - Part 2: Carry recording type and request URL in recording-device-events in gUM API. r=jesup, a=koi+
authorShih-Chiang Chien <schien@mozilla.com>
Wed, 23 Oct 2013 19:10:42 +0800
changeset 160895 a56ccf8675e0ae3c1adb3d2d9fa63508e56cd779
parent 160894 e7922b4a6decb7ad2107d40b6a029538170d997d
child 160896 a5a671061a34ad436898c010fcacbf31e1d4fa22
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, koi
bugs926289
milestone26.0a2
Bug 926289 - Part 2: Carry recording type and request URL in recording-device-events in gUM API. r=jesup, a=koi+
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1,30 +1,33 @@
 /* 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 "MediaManager.h"
 
 #include "MediaStreamGraph.h"
 #include "GetUserMediaRequest.h"
+#include "nsHashPropertyBag.h"
 #ifdef MOZ_WIDGET_GONK
 #include "nsIAudioManager.h"
 #endif
+#include "nsIAppsService.h"
 #include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIPopupWindowManager.h"
 #include "nsISupportsArray.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "mozilla/dom/ContentChild.h"
+#include "nsIScriptSecurityManager.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/GetUserMediaRequestBinding.h"
 
 // For PR_snprintf
 #include "prprf.h"
 
 #include "nsJSUtils.h"
 #include "nsDOMFile.h"
@@ -133,16 +136,55 @@ static nsresult ValidateTrackConstraints
     nsresult rv = CompareDictionaries(aCx, track.mMandatory.Value(),
                                       aNormalized.mMandatory,
                                       aOutUnknownConstraint);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
+static already_AddRefed<nsHashPropertyBag>
+CreateRecordingDeviceEventsSubject(nsPIDOMWindow* aWindow,
+                                   const bool aIsAudio,
+                                   const bool aIsVideo)
+{
+  MOZ_ASSERT(aWindow);
+
+  nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
+  props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio);
+  props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo);
+
+  nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
+  if (docShell) {
+    bool isApp;
+    DebugOnly<nsresult> rv = docShell->GetIsApp(&isApp);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+    nsString requestURL;
+    if (isApp) {
+      rv = docShell->GetAppManifestURL(requestURL);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
+    } else {
+      nsCString pageURL;
+      nsCOMPtr<nsIURI> docURI = aWindow->GetDocumentURI();
+      MOZ_ASSERT(docURI);
+
+      rv = docURI->GetSpec(pageURL);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+      requestURL = NS_ConvertUTF8toUTF16(pageURL);
+    }
+
+    props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
+    props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), isApp);
+  }
+
+  return props.forget();
+}
+
 /**
  * Send an error back to content. The error is the form a string.
  * Do this only on the main thread. The success callback is also passed here
  * so it can be released correctly.
  */
 class ErrorCallbackRunnable : public nsRunnable
 {
 public:
@@ -569,17 +611,17 @@ public:
     // Dispatch to the media thread to ask it to start the sources,
     // because that can take a while.
     // Pass ownership of trackunion to the MediaOperationRunnable
     // to ensure it's kept alive until the MediaOperationRunnable runs (at least).
     nsIThread *mediaThread = MediaManager::GetThread();
     nsRefPtr<MediaOperationRunnable> runnable(
       new MediaOperationRunnable(MEDIA_START, mListener, trackunion,
                                  tracksAvailableCallback,
-                                 mAudioSource, mVideoSource, false));
+                                 mAudioSource, mVideoSource, false, mWindowID));
     mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
 
 #ifdef MOZ_WEBRTC
     // Right now these configs are only of use if webrtc is available
     nsresult rv;
     nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
     if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
@@ -1715,17 +1757,17 @@ GetUserMediaCallbackMediaStreamListener:
   nsRefPtr<MediaOperationRunnable> runnable;
   // We can't take a chance on blocking here, so proxy this to another
   // thread.
   // Pass a ref to us (which is threadsafe) so it can query us for the
   // source stream info.
   runnable = new MediaOperationRunnable(MEDIA_STOP,
                                         this, nullptr, nullptr,
                                         mAudioSource, mVideoSource,
-                                        mFinished);
+                                        mFinished, mWindowID);
   mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
 }
 
 // Called from the MediaStreamGraph thread
 void
 GetUserMediaCallbackMediaStreamListener::NotifyFinished(MediaStreamGraph* aGraph)
 {
   mFinished = true;
@@ -1772,20 +1814,27 @@ GetUserMediaNotificationEvent::Run()
     break;
   case STOPPING:
     msg = NS_LITERAL_STRING("shutdown");
     if (mListener) {
       mListener->SetStopped();
     }
     break;
   }
-  obs->NotifyObservers(nullptr,
+
+  nsCOMPtr<nsPIDOMWindow> window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+  MOZ_ASSERT(window);
+
+  nsRefPtr<nsHashPropertyBag> props = 
+    CreateRecordingDeviceEventsSubject(window, mIsAudio, mIsVideo);
+
+  obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
 		       "recording-device-events",
 		       msg.get());
   // Forward recording events to parent process.
   // The events are gathered in chrome process and used for recording indicator
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
-    unused << dom::ContentChild::GetSingleton()->SendRecordingDeviceEvents(msg);
+    unused << dom::TabChild::GetFrom(window)->SendRecordingDeviceEvents(msg, mIsAudio, mIsVideo);
   }
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -199,36 +199,42 @@ private:
 class GetUserMediaNotificationEvent: public nsRunnable
 {
   public:
     enum GetUserMediaStatus {
       STARTING,
       STOPPING
     };
     GetUserMediaNotificationEvent(GetUserMediaCallbackMediaStreamListener* aListener,
-                                  GetUserMediaStatus aStatus)
-    : mListener(aListener), mStatus(aStatus) {}
+                                  GetUserMediaStatus aStatus,
+                                  bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
+    : mListener(aListener) , mStatus(aStatus) , mIsAudio(aIsAudio)
+    , mIsVideo(aIsVideo), mWindowID(aWindowID) {}
 
     GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
                                   already_AddRefed<DOMMediaStream> aStream,
-                                  DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback)
+                                  DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
+                                  bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
     : mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
-      mStatus(aStatus) {}
+      mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID) {}
     virtual ~GetUserMediaNotificationEvent()
     {
 
     }
 
     NS_IMETHOD Run() MOZ_OVERRIDE;
 
   protected:
     nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
     nsRefPtr<DOMMediaStream> mStream;
     nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
     GetUserMediaStatus mStatus;
+    bool mIsAudio;
+    bool mIsVideo;
+    uint64_t mWindowID;
 };
 
 typedef enum {
   MEDIA_START,
   MEDIA_STOP
 } MediaOperation;
 
 // Generic class for running long media operations like Start off the main
@@ -239,24 +245,26 @@ class MediaOperationRunnable : public ns
 public:
   // so we can send Stop without AddRef()ing from the MSG thread
   MediaOperationRunnable(MediaOperation aType,
     GetUserMediaCallbackMediaStreamListener* aListener,
     DOMMediaStream* aStream,
     DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource,
-    bool aNeedsFinish)
+    bool aNeedsFinish,
+    uint64_t aWindowID)
     : mType(aType)
     , mStream(aStream)
     , mOnTracksAvailableCallback(aOnTracksAvailableCallback)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mListener(aListener)
     , mFinish(aNeedsFinish)
+    , mWindowID(aWindowID)
     {}
 
   ~MediaOperationRunnable()
   {
     // MediaStreams can be released on any thread.
   }
 
   NS_IMETHOD
@@ -298,17 +306,20 @@ public:
 
           MM_LOG(("started all sources"));
           // Forward mOnTracksAvailableCallback to GetUserMediaNotificationEvent,
           // because mOnTracksAvailableCallback needs to be added to mStream
           // on the main thread.
           nsRefPtr<GetUserMediaNotificationEvent> event =
             new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING,
                                               mStream.forget(),
-                                              mOnTracksAvailableCallback.forget());
+                                              mOnTracksAvailableCallback.forget(),
+                                              mAudioSource != nullptr,
+                                              mVideoSource != nullptr,
+                                              mWindowID);
           NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
         }
         break;
 
       case MEDIA_STOP:
         {
           NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
           if (mAudioSource) {
@@ -319,17 +330,21 @@ public:
             mVideoSource->Stop(source, kVideoTrack);
             mVideoSource->Deallocate();
           }
           // Do this after stopping all tracks with EndTrack()
           if (mFinish) {
             source->Finish();
           }
           nsRefPtr<GetUserMediaNotificationEvent> event =
-            new GetUserMediaNotificationEvent(mListener, GetUserMediaNotificationEvent::STOPPING);
+            new GetUserMediaNotificationEvent(mListener,
+                                              GetUserMediaNotificationEvent::STOPPING,
+                                              mAudioSource != nullptr,
+                                              mVideoSource != nullptr,
+                                              mWindowID);
 
           NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
         }
         break;
 
       default:
         MOZ_ASSERT(false,"invalid MediaManager operation");
         break;
@@ -340,16 +355,17 @@ public:
 private:
   MediaOperation mType;
   nsRefPtr<DOMMediaStream> mStream;
   nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
   nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe
   nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
   bool mFinish;
+  uint64_t mWindowID;
 };
 
 typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
 
 class MediaDevice : public nsIMediaDevice
 {
 public: