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 234591 f749e3f70ffc956291c4738140c896d1a9e718c0
parent 234590 ecd54a3fbfddd0260566ff8a0269e3bca3223a2c
child 234592 0e9a6298a2022e0d4c3a2d14ce6a4924bb0f735f
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs879717
milestone35.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 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++;