Bug 879717: Part 3: Fix camera preview stream and wake locks from lock screen. r=roc
☠☠ backed out by 189ac924dfa6 ☠ ☠
authorAndrew Osmond <aosmond@mozilla.com>
Mon, 13 Oct 2014 00:01:25 -0400
changeset 225496 f749e3f70ffc956291c4738140c896d1a9e718c0
parent 225495 ecd54a3fbfddd0260566ff8a0269e3bca3223a2c
child 225497 0e9a6298a2022e0d4c3a2d14ce6a4924bb0f735f
push id7107
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 17:43:31 +0000
treeherdermozilla-aurora@b4b34e0acc75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs879717
milestone35.0a1
Bug 879717: Part 3: Fix camera preview stream and wake locks from lock screen. r=roc
dom/camera/CameraPreviewMediaStream.cpp
dom/camera/CameraPreviewMediaStream.h
dom/camera/DOMCameraControl.cpp
dom/camera/DOMCameraControlListener.cpp
dom/camera/test/test_camera.html
--- a/dom/camera/CameraPreviewMediaStream.cpp
+++ b/dom/camera/CameraPreviewMediaStream.cpp
@@ -12,31 +12,34 @@
  * either very busy or the device is busy elsewhere (e.g. encoding or
  * persisting video data).
  */
 #define MAX_INVALIDATE_PENDING 4
 
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
+static const TrackID TRACK_VIDEO = 2;
+
 namespace mozilla {
 
 void
 FakeMediaStreamGraph::DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
 {
   nsRefPtr<nsIRunnable> task = aRunnable;
   NS_DispatchToMainThread(task);
 }
 
 CameraPreviewMediaStream::CameraPreviewMediaStream(DOMMediaStream* aWrapper)
   : MediaStream(aWrapper)
   , mMutex("mozilla::camera::CameraPreviewMediaStream")
   , mInvalidatePending(0)
   , mDiscardedFrames(0)
   , mRateLimit(false)
+  , mTrackCreated(false)
 {
   SetGraphImpl(MediaStreamGraph::GetInstance());
   mFakeMediaStreamGraph = new FakeMediaStreamGraph();
   mIsConsumed = false;
 }
 
 void
 CameraPreviewMediaStream::AddAudioOutput(void* aKey)
@@ -107,16 +110,32 @@ CameraPreviewMediaStream::RemoveListener
   MutexAutoLock lock(mMutex);
 
   nsRefPtr<MediaStreamListener> listener(aListener);
   mListeners.RemoveElement(aListener);
   listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamListener::EVENT_REMOVED);
 }
 
 void
+CameraPreviewMediaStream::OnPreviewStateChange(bool aActive)
+{
+  MutexAutoLock lock(mMutex);
+  if (!mTrackCreated && aActive) {
+    mTrackCreated = true;
+    VideoSegment tmpSegment;
+    uint32_t trackEvent = aActive ? MediaStreamListener::TRACK_EVENT_CREATED
+                                  : MediaStreamListener::TRACK_EVENT_ENDED;
+    for (uint32_t j = 0; j < mListeners.Length(); ++j) {
+      MediaStreamListener* l = mListeners[j];
+      l->NotifyQueuedTrackChanges(mFakeMediaStreamGraph, TRACK_VIDEO, 0, 0, trackEvent, tmpSegment);
+    }
+  }
+}
+
+void
 CameraPreviewMediaStream::Destroy()
 {
   MutexAutoLock lock(mMutex);
   DestroyImpl();
 }
 
 void
 CameraPreviewMediaStream::Invalidate()
--- a/dom/camera/CameraPreviewMediaStream.h
+++ b/dom/camera/CameraPreviewMediaStream.h
@@ -46,30 +46,32 @@ public:
   virtual void SetAudioOutputVolume(void* aKey, float aVolume) MOZ_OVERRIDE;
   virtual void RemoveAudioOutput(void* aKey) MOZ_OVERRIDE;
   virtual void AddVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void RemoveVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void ChangeExplicitBlockerCount(int32_t aDelta) MOZ_OVERRIDE;
   virtual void AddListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
   virtual void RemoveListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
   virtual void Destroy();
+  void OnPreviewStateChange(bool aActive);
 
   void Invalidate();
 
   // Call these on any thread.
   void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage);
   void ClearCurrentFrame();
   void RateLimit(bool aLimit);
 
 protected:
   // mMutex protects all the class' fields.
   // This class is not registered to MediaStreamGraph.
   // It needs to protect all the fields.
   Mutex mMutex;
   int32_t mInvalidatePending;
   uint32_t mDiscardedFrames;
   bool mRateLimit;
+  bool mTrackCreated;
   nsRefPtr<FakeMediaStreamGraph> mFakeMediaStreamGraph;
 };
 
 }
 
 #endif // DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -213,17 +213,18 @@ nsDOMCameraControl::nsDOMCameraControl(u
     config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
     config.mRecorderProfile = aInitialConfig.mRecorderProfile;
   }
 
   mCameraControl = ICameraControl::Create(aCameraId);
   mCurrentConfiguration = initialConfig.forget();
 
   // Attach our DOM-facing media stream to our viewfinder stream.
-  mStream = mInput;
+  SetHintContents(HINT_CONTENTS_VIDEO);
+  InitStreamCommon(mInput);
   MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
   if (mWindow->GetExtantDoc()) {
     CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
   }
 
   // Register a listener for camera events.
   mListener = new DOMCameraControlListener(this, mInput);
   mCameraControl->AddListener(mListener);
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -132,16 +132,17 @@ DOMCameraControlListener::OnPreviewState
       DOM_CAMERA_LOGI("Preview started\n");
       break;
 
     default:
       DOM_CAMERA_LOGE("Unknown preview state %d\n", aState);
       MOZ_ASSERT_UNREACHABLE("Invalid preview state");
       return;
   }
+  mStream->OnPreviewStateChange(aState == kPreviewStarted);
   NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState));
 }
 
 void
 DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
                                                 int32_t aStatus, int32_t aTrackNum)
 {
   class Callback : public DOMCallback
--- a/dom/camera/test/test_camera.html
+++ b/dom/camera/test/test_camera.html
@@ -104,28 +104,36 @@ var Camera = {
   takePictureSuccess: function taken_foto(blob) {
     ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
     ok("image/" + test.fileFormat ==  blob.type, "Blob Type = " + blob.type);
   },
   takePictureEvent: function taken_foto_evt(e) {
     var blob = e.data;
     var img = new Image();
     var test = this._currentTest;
+    var onPreviewStateChange = function(e) {
+      if (e.newState === 'started') {
+        ok(true, "viewfinder is ready and playing after resume");
+        Camera.cameraObj.removeEventListener('previewstatechange', onPreviewStateChange);
+        Camera._testsCompleted++;
+        if(Camera._testsCompleted == Camera._tests.length) {
+          ok(true, "test finishing");
+          SimpleTest.finish();
+        } else {
+          Camera.runTests();
+        }
+      }
+    }
+    Camera.cameraObj.addEventListener('previewstatechange', onPreviewStateChange);
     img.onload = function Imgsize() {
       ok(this.width == test.pictureSize.width, "The image taken has the width " +
                                               this.width + " pictureSize width = " + test.pictureSize.width);
       ok(this.height == test.pictureSize.height, "The image taken has the height " +
                                               this.height + " picturesize height = " + test.pictureSize.height);
-      Camera._testsCompleted++;
-      if(Camera._testsCompleted == Camera._tests.length) {
-        ok(true, "test finishing");
-        SimpleTest.finish();
-      } else {
-        Camera.runTests();
-      }
+      Camera.cameraObj.resumePreview();
     }
     ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
     ok("image/" + test.fileFormat ==  blob.type, "Blob Type = " + blob.type);
     img.src = window.URL.createObjectURL(blob);
   },
   shutter: function onShutter () {
     Camera._shutter++;