Bug 1212783 - Add a MediaStreamTrack to DOMCameraControl. r=aosmond
authorAndreas Pehrson <pehrsons@gmail.com>
Thu, 22 Oct 2015 12:36:23 +0800
changeset 304348 cfd7882e6f70d4d824e4af91fa3ac0591c884ebb
parent 304347 34f53b05a578fa60e13ea6c117bc48f1413df3aa
child 304349 0ed4298f0cc674c174d6c3a292f76855ad470149
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaosmond
bugs1212783
milestone44.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 1212783 - Add a MediaStreamTrack to DOMCameraControl. r=aosmond Without this, HTMLMediaElement cannot see that the camera stream contains video so it won't hold the screen wake lock.
dom/camera/DOMCameraControl.cpp
dom/camera/DOMCameraControl.h
dom/media/DOMMediaStream.cpp
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -32,25 +32,65 @@
 #include "mozilla/dom/CameraManagerBinding.h"
 #include "mozilla/dom/CameraCapabilitiesBinding.h"
 #include "mozilla/dom/CameraConfigurationEvent.h"
 #include "mozilla/dom/CameraConfigurationEventBinding.h"
 #include "mozilla/dom/CameraFacesDetectedEvent.h"
 #include "mozilla/dom/CameraFacesDetectedEventBinding.h"
 #include "mozilla/dom/CameraStateChangeEvent.h"
 #include "mozilla/dom/CameraClosedEvent.h"
+#include "mozilla/dom/VideoStreamTrack.h"
 #include "mozilla/dom/BlobEvent.h"
 #include "DOMCameraDetectedFace.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
+class mozilla::TrackCreatedListener : public MediaStreamListener
+{
+public:
+  explicit TrackCreatedListener(nsDOMCameraControl* aCameraControl)
+    : mCameraControl(aCameraControl) {}
+
+  void Forget() { mCameraControl = nullptr; }
+
+  void DoNotifyTrackCreated(TrackID aTrackID)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (!mCameraControl) {
+      return;
+    }
+
+    mCameraControl->TrackCreated(aTrackID);
+  }
+
+  void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
+                                StreamTime aTrackOffset, uint32_t aTrackEvents,
+                                const MediaSegment& aQueuedMedia,
+                                MediaStream* aInputStream,
+                                TrackID aInputTrackID) override
+  {
+    if (aTrackEvents & TRACK_EVENT_CREATED) {
+      nsCOMPtr<nsIRunnable> runnable =
+        NS_NewRunnableMethodWithArgs<TrackID>(
+          this, &TrackCreatedListener::DoNotifyTrackCreated, aID);
+      aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget());
+    }
+  }
+
+protected:
+  ~TrackCreatedListener() {}
+
+  nsDOMCameraControl* mCameraControl;
+};
+
 #ifdef MOZ_WIDGET_GONK
 StaticRefPtr<ICameraControl> nsDOMCameraControl::sCachedCameraControl;
 /* static */ nsresult nsDOMCameraControl::sCachedCameraControlStartResult = NS_OK;
 /* static */ nsCOMPtr<nsITimer> nsDOMCameraControl::sDiscardCachedCameraControlTimer;
 #endif
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
@@ -274,16 +314,21 @@ nsDOMCameraControl::nsDOMCameraControl(u
     sCachedCameraControl = nullptr;
 #endif
     mCameraControl = ICameraControl::Create(aCameraId);
 #ifdef MOZ_WIDGET_GONK
   }
 #endif
   mCurrentConfiguration = initialConfig.forget();
 
+  // Register a TrackCreatedListener directly on CameraPreviewMediaStream
+  // so we can know the TrackID of the video track.
+  mTrackCreatedListener = new TrackCreatedListener(this);
+  mInput->AddListener(mTrackCreatedListener);
+
   // Register the playback listener directly on the camera input stream.
   // We want as low latency as possible for the camera, thus avoiding
   // MediaStreamGraph altogether. Don't do the regular InitStreamCommon()
   // to avoid initializing the Owned and Playback streams. This is OK since
   // we are not user/DOM facing anyway.
   CreateAndAddPlaybackStreamListener(mInput);
 
   MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
@@ -329,16 +374,20 @@ nsDOMCameraControl::~nsDOMCameraControl(
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   /*invoke DOMMediaStream destroy*/
   Destroy();
 
   if (mInput) {
     mInput->Destroy();
     mInput = nullptr;
   }
+  if (mTrackCreatedListener) {
+    mTrackCreatedListener->Forget();
+    mTrackCreatedListener = nullptr;
+  }
 }
 
 JSObject*
 nsDOMCameraControl::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CameraControlBinding::Wrap(aCx, this, aGivenProto);
 }
 
@@ -470,16 +519,29 @@ nsDOMCameraControl::Get(uint32_t aKey, n
 }
 
 MediaStream*
 nsDOMCameraControl::GetCameraStream() const
 {
   return mInput;
 }
 
+void
+nsDOMCameraControl::TrackCreated(TrackID aTrackID) {
+  // This track is not connected through a port.
+  MediaInputPort* inputPort = nullptr;
+  dom::VideoStreamTrack* track =
+    new dom::VideoStreamTrack(this, aTrackID);
+  RefPtr<TrackPort> port =
+    new TrackPort(inputPort, track,
+                  TrackPort::InputPortOwnership::OWNED);
+  mTracks.AppendElement(port.forget());
+  NotifyTrackAdded(track);
+}
+
 #define THROW_IF_NO_CAMERACONTROL(...)                                          \
   do {                                                                          \
     if (!mCameraControl) {                                                      \
       DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__); \
       aRv = NS_ERROR_NOT_AVAILABLE;                                             \
       return __VA_ARGS__;                                                       \
     }                                                                           \
   } while (0)
--- a/dom/camera/DOMCameraControl.h
+++ b/dom/camera/DOMCameraControl.h
@@ -35,16 +35,17 @@ namespace dom {
   struct CameraStartRecordingOptions;
   struct CameraRegion;
   struct CameraSize;
   template<typename T> class Optional;
 } // namespace dom
 class ErrorResult;
 class StartRecordingHelper;
 class RecorderPosterHelper;
+class TrackCreatedListener;
 
 #define NS_DOM_CAMERA_CONTROL_CID \
 { 0x3700c096, 0xf920, 0x438d, \
   { 0x8b, 0x3f, 0x15, 0xb3, 0xc9, 0x96, 0x23, 0x62 } }
 
 // Main camera control.
 class nsDOMCameraControl final : public DOMMediaStream
                                , public nsSupportsWeakReference
@@ -68,16 +69,20 @@ public:
                      nsPIDOMWindow* aWindow);
 
   void Shutdown();
 
   nsPIDOMWindow* GetParentObject() const { return mWindow; }
 
   MediaStream* GetCameraStream() const override;
 
+  // Called by TrackCreatedListener when the underlying track has been created.
+  // XXX Bug 1124630. This can be removed with CameraPreviewMediaStream.
+  void TrackCreated(TrackID aTrackID);
+
   // Attributes.
   void GetEffect(nsString& aEffect, ErrorResult& aRv);
   void SetEffect(const nsAString& aEffect, ErrorResult& aRv);
   void GetWhiteBalanceMode(nsString& aMode, ErrorResult& aRv);
   void SetWhiteBalanceMode(const nsAString& aMode, ErrorResult& aRv);
   void GetSceneMode(nsString& aMode, ErrorResult& aRv);
   void SetSceneMode(const nsAString& aMode, ErrorResult& aRv);
   void GetFlashMode(nsString& aMode, ErrorResult& aRv);
@@ -221,16 +226,19 @@ protected:
   // Camera event listener; we only need this weak reference so that
   //  we can remove the listener from the camera when we're done
   //  with it.
   DOMCameraControlListener* mListener;
 
   // our viewfinder stream
   RefPtr<CameraPreviewMediaStream> mInput;
 
+  // A listener on mInput for adding tracks to the DOM side.
+  RefPtr<TrackCreatedListener> mTrackCreatedListener;
+
   // set once when this object is created
   nsCOMPtr<nsPIDOMWindow>   mWindow;
 
   dom::CameraStartRecordingOptions mOptions;
   RefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
   DOMCameraControlListener::PreviewState mPreviewState;
   bool mRecording;
   bool mRecordingStoppedDeferred;
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -39,17 +39,19 @@ const TrackID TRACK_VIDEO_PRIMARY = 1;
 
 DOMMediaStream::TrackPort::TrackPort(MediaInputPort* aInputPort,
                                      MediaStreamTrack* aTrack,
                                      const InputPortOwnership aOwnership)
   : mInputPort(aInputPort)
   , mTrack(aTrack)
   , mOwnership(aOwnership)
 {
-  MOZ_ASSERT(mInputPort);
+  // XXX Bug 1124630. nsDOMCameraControl requires adding a track without and
+  // input port.
+  // MOZ_ASSERT(mInputPort);
   MOZ_ASSERT(mTrack);
 
   MOZ_COUNT_CTOR(TrackPort);
 }
 
 DOMMediaStream::TrackPort::~TrackPort()
 {
   MOZ_COUNT_DTOR(TrackPort);