Backed out changesets 7b161e9fe25e and 2548deff272b (bug 1104055) for B2G debug mochitest asserts.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 16 Dec 2014 18:12:21 -0500
changeset 221527 ddecea83ce6e893acbf3a97dd0ec7f415d839fa6
parent 221526 e0427ee6175ce2080be9f23d76acf047ec27c62e
child 221528 21b8f945c193e6650fbee13c480fc78dc55422e0
push id274
push userryanvm@gmail.com
push dateTue, 16 Dec 2014 23:12:57 +0000
treeherdermozilla-b2g34_v2_1@ddecea83ce6e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1104055
milestone34.0
backs out7b161e9fe25e6836df06fc3fe5a8c493267ba50d
2548deff272b40a55f8c7bc8ee95a851589abb2d
Backed out changesets 7b161e9fe25e and 2548deff272b (bug 1104055) for B2G debug mochitest asserts.
dom/camera/CameraControlImpl.cpp
dom/camera/CameraControlImpl.h
dom/camera/CameraPreviewMediaStream.cpp
dom/camera/CameraPreviewMediaStream.h
dom/camera/DOMCameraControl.cpp
dom/camera/DOMCameraControl.h
dom/camera/DOMCameraControlListener.cpp
dom/camera/DOMCameraControlListener.h
dom/camera/DOMCameraManager.cpp
dom/camera/DOMCameraManager.h
dom/camera/FallbackCameraControl.cpp
dom/camera/GonkCameraControl.cpp
dom/camera/GonkCameraControl.h
dom/camera/ICameraControl.h
dom/camera/test/test_bug975472.html
dom/camera/test/test_camera.html
--- a/dom/camera/CameraControlImpl.cpp
+++ b/dom/camera/CameraControlImpl.cpp
@@ -11,37 +11,38 @@
 #include "CameraRecorderProfiles.h"
 #include "CameraCommon.h"
 #include "nsGlobalWindow.h"
 #include "DeviceStorageFileDescriptor.h"
 #include "CameraControlListener.h"
 
 using namespace mozilla;
 
-/* static */ StaticRefPtr<nsIThread> CameraControlImpl::sCameraThread;
+nsWeakPtr CameraControlImpl::sCameraThread;
 
-CameraControlImpl::CameraControlImpl()
+CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
   : mListenerLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"))
+  , mCameraId(aCameraId)
   , mPreviewState(CameraControlListener::kPreviewStopped)
   , mHardwareState(CameraControlListener::kHardwareClosed)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 
   // reuse the same camera thread to conserve resources
-  nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
+  nsCOMPtr<nsIThread> ct = do_QueryReferent(sCameraThread);
   if (ct) {
     mCameraThread = ct.forget();
   } else {
     nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
     if (NS_FAILED(rv)) {
       MOZ_CRASH("Failed to create new Camera Thread");
     }
 
     // keep a weak reference to the new thread
-    sCameraThread = mCameraThread;
+    sCameraThread = do_GetWeakReference(mCameraThread);
   }
 
   // Care must be taken with the mListenerLock read-write lock to prevent
   // deadlocks. Currently this is handled by ensuring that any attempts to
   // acquire the lock for writing (as in Add/RemoveListener()) happen in a
   // runnable dispatched to the Camera Thread--even if the method is being
   // called from that thread. This ensures that if a registered listener
   // (which is invoked with a read-lock) tries to call Add/RemoveListener(),
@@ -52,32 +53,36 @@ CameraControlImpl::CameraControlImpl()
   // the read-write lock allows multiple simultaneous read-locks.
   if (!mListenerLock) {
     MOZ_CRASH("Out of memory getting new PRRWLock");
   }
 }
 
 CameraControlImpl::~CameraControlImpl()
 {
-  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
-
   MOZ_ASSERT(mListenerLock, "mListenerLock missing in ~CameraControlImpl()");
   if (mListenerLock) {
     PR_DestroyRWLock(mListenerLock);
     mListenerLock = nullptr;
   }
 }
 
 already_AddRefed<RecorderProfileManager>
 CameraControlImpl::GetRecorderProfileManager()
 {
   return GetRecorderProfileManagerImpl();
 }
 
 void
+CameraControlImpl::Shutdown()
+{
+  DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
+}
+
+void
 CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState)
 {
   // This callback can run on threads other than the Main Thread and
   //  the Camera Thread. On Gonk, it may be called from the camera's
   //  local binder thread, should the mediaserver process die.
   RwLockAutoEnterRead lock(mListenerLock);
 
   if (aNewState == mHardwareState) {
--- a/dom/camera/CameraControlImpl.h
+++ b/dom/camera/CameraControlImpl.h
@@ -25,17 +25,17 @@ namespace layers {
   class Image;
 }
 
 class RecorderProfileManager;
 
 class CameraControlImpl : public ICameraControl
 {
 public:
-  CameraControlImpl();
+  CameraControlImpl(uint32_t aCameraId);
   virtual void AddListener(CameraControlListener* aListener) MOZ_OVERRIDE;
   virtual void RemoveListener(CameraControlListener* aListener) MOZ_OVERRIDE;
 
   // See ICameraControl.h for these methods' return values.
   virtual nsresult Start(const Configuration* aConfig = nullptr) MOZ_OVERRIDE;
   virtual nsresult Stop() MOZ_OVERRIDE;
   virtual nsresult SetConfiguration(const Configuration& aConfig) MOZ_OVERRIDE;
   virtual nsresult StartPreview() MOZ_OVERRIDE;
@@ -45,16 +45,19 @@ public:
   virtual nsresult StopFaceDetection() MOZ_OVERRIDE;
   virtual nsresult TakePicture() MOZ_OVERRIDE;
   virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
                                   const StartRecordingOptions* aOptions) MOZ_OVERRIDE;
   virtual nsresult StopRecording() MOZ_OVERRIDE;
   virtual nsresult ResumeContinuousFocus() MOZ_OVERRIDE;
 
   already_AddRefed<RecorderProfileManager> GetRecorderProfileManager();
+  uint32_t GetCameraId() { return mCameraId; }
+
+  virtual void Shutdown() MOZ_OVERRIDE;
 
   // Event handlers called directly from outside this class.
   void OnShutter();
   void OnClosed();
   void OnUserError(CameraControlListener::UserContext aContext, nsresult aError);
   void OnSystemError(CameraControlListener::SystemContext aContext, nsresult aError);
   void OnAutoFocusMoving(bool aIsMoving);
 
@@ -72,17 +75,17 @@ protected:
   void OnHardwareStateChange(CameraControlListener::HardwareState aState);
   void OnConfigurationChange();
 
   // When we create a new CameraThread, we keep a static reference to it so
   // that multiple CameraControl instances can find and reuse it; but we
   // don't want that reference to keep the thread object around unnecessarily,
   // so we make it a weak reference. The strong dynamic references will keep
   // the thread object alive as needed.
-  static StaticRefPtr<nsIThread> sCameraThread;
+  static nsWeakPtr sCameraThread;
   nsCOMPtr<nsIThread> mCameraThread;
 
   virtual ~CameraControlImpl();
 
   virtual void BeginBatchParameterSet() MOZ_OVERRIDE { }
   virtual void EndBatchParameterSet() MOZ_OVERRIDE { }
 
   // Manage camera event listeners.
@@ -125,16 +128,18 @@ protected:
   virtual nsresult PushParametersImpl() = 0;
   virtual nsresult PullParametersImpl() = 0;
 
   virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() = 0;
 
   void OnShutterInternal();
   void OnClosedInternal();
 
+  uint32_t mCameraId;
+
   CameraControlListener::CameraListenerConfiguration mCurrentConfiguration;
 
   CameraControlListener::PreviewState   mPreviewState;
   CameraControlListener::HardwareState  mHardwareState;
 
 private:
   CameraControlImpl(const CameraControlImpl&) MOZ_DELETE;
   CameraControlImpl& operator=(const CameraControlImpl&) MOZ_DELETE;
--- a/dom/camera/CameraPreviewMediaStream.cpp
+++ b/dom/camera/CameraPreviewMediaStream.cpp
@@ -105,17 +105,16 @@ CameraPreviewMediaStream::RemoveListener
   mListeners.RemoveElement(aListener);
   listener->NotifyEvent(gm, MediaStreamListener::EVENT_REMOVED);
 }
 
 void
 CameraPreviewMediaStream::Destroy()
 {
   MutexAutoLock lock(mMutex);
-  mMainThreadDestroyed = true;
   DestroyImpl();
 }
 
 void
 CameraPreviewMediaStream::Invalidate()
 {
   MutexAutoLock lock(mMutex);
   --mInvalidatePending;
--- a/dom/camera/CameraPreviewMediaStream.h
+++ b/dom/camera/CameraPreviewMediaStream.h
@@ -10,35 +10,35 @@
 #include "mozilla/Mutex.h"
 
 namespace mozilla {
 
 /**
  * This is a stream for camera preview.
  *
  * XXX It is a temporary fix of SourceMediaStream.
- * A camera preview requests no delay and no buffering streamn
- * but the SourceMediaStream does not support it.
+ * A camera preview requests no delay and no buffering stream.
+ * But the SourceMediaStream do not support it.
  */
 class CameraPreviewMediaStream : public MediaStream
 {
   typedef mozilla::layers::Image Image;
 
 public:
   CameraPreviewMediaStream(DOMMediaStream* aWrapper);
 
   virtual void AddAudioOutput(void* aKey) MOZ_OVERRIDE;
   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() MOZ_OVERRIDE;
+  virtual void Destroy();
 
   void Invalidate();
 
   // Call these on any thread.
   void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage);
   void ClearCurrentFrame();
   void RateLimit(bool aLimit);
 
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -34,30 +34,24 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream)
-  // nsISupports is an ambiguous base of nsDOMCameraControl
-  // so we need to work around that.
-  if (aIID.Equals(NS_GET_IID(nsDOMCameraControl)))
-    foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
-  else
 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream)
 NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream,
-                                   mAudioChannelAgent,
                                    mCapabilities,
                                    mWindow,
                                    mGetCameraOnSuccessCb,
                                    mGetCameraOnErrorCb,
                                    mAutoFocusOnSuccessCb,
                                    mAutoFocusOnErrorCb,
                                    mTakePictureOnSuccessCb,
                                    mTakePictureOnErrorCb,
@@ -227,49 +221,34 @@ nsDOMCameraControl::nsDOMCameraControl(u
   if (NS_FAILED(rv)) {
     mListener->OnUserError(DOMCameraControlListener::kInStartCamera, rv);
   }
 }
 
 nsDOMCameraControl::~nsDOMCameraControl()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
-  mStream = nullptr;
-  mInput = nullptr;
 }
 
 JSObject*
 nsDOMCameraControl::WrapObject(JSContext* aCx)
 {
   return CameraControlBinding::Wrap(aCx, this);
 }
 
 bool
 nsDOMCameraControl::IsWindowStillActive()
 {
   return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID());
 }
 
-#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)
-
 // Setter for weighted regions: { top, bottom, left, right, weight }
 nsresult
 nsDOMCameraControl::Set(uint32_t aKey, const Optional<Sequence<CameraRegion> >& aValue, uint32_t aLimit)
 {
-  if (!mCameraControl) {
-    DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
-    return NS_ERROR_NOT_AVAILABLE;
-  }
   if (aLimit == 0) {
     DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
     return NS_OK;
   }
 
   nsTArray<ICameraControl::Region> regionArray;
   if (aValue.WasPassed()) {
     const Sequence<CameraRegion>& regions = aValue.Value();
@@ -306,21 +285,16 @@ nsDOMCameraControl::Set(uint32_t aKey, c
   }
   return mCameraControl->Set(aKey, regionArray);
 }
 
 // Getter for weighted regions: { top, bottom, left, right, weight }
 nsresult
 nsDOMCameraControl::Get(uint32_t aKey, nsTArray<CameraRegion>& aValue)
 {
-  if (!mCameraControl) {
-    DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
   nsTArray<ICameraControl::Region> regionArray;
 
   nsresult rv = mCameraControl->Get(aKey, regionArray);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t length = regionArray.Length();
   DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
   aValue.SetLength(length);
@@ -345,121 +319,121 @@ nsDOMCameraControl::Get(uint32_t aKey, n
   }
 
   return NS_OK;
 }
 
 void
 nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
 }
 void
 nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
 }
 
 void
 nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
 }
 void
 nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
 }
 
 void
 nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
 }
 void
 nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
 }
 
 void
 nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
 }
 void
 nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
 }
 
 void
 nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
 }
 void
 nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
 }
 
 void
 nsDOMCameraControl::GetIsoMode(nsString& aIsoMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Get(CAMERA_PARAM_ISOMODE, aIsoMode);
 }
 void
 nsDOMCameraControl::SetIsoMode(const nsAString& aIsoMode, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_ISOMODE, aIsoMode);
 }
 
 double
 nsDOMCameraControl::GetPictureQuality(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL(1.0);
+  MOZ_ASSERT(mCameraControl);
 
   double quality;
   aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_QUALITY, quality);
   return quality;
 }
 void
 nsDOMCameraControl::SetPictureQuality(double aQuality, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_QUALITY, aQuality);
 }
 
 double
 nsDOMCameraControl::GetZoom(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL(1.0);
+  MOZ_ASSERT(mCameraControl);
 
   double zoom = 1.0;
   aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, zoom);
   return zoom;
 }
 
 void
 nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
 }
 
 void
 nsDOMCameraControl::GetMeteringAreas(nsTArray<CameraRegion>& aAreas, ErrorResult& aRv)
 {
   aRv = Get(CAMERA_PARAM_METERINGAREAS, aAreas);
 }
@@ -480,125 +454,117 @@ nsDOMCameraControl::SetFocusAreas(const 
 {
   aRv = Set(CAMERA_PARAM_FOCUSAREAS, aFocusAreas,
             mCurrentConfiguration->mMaxFocusAreas);
 }
 
 void
 nsDOMCameraControl::GetPictureSize(CameraSize& aSize, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
-
   ICameraControl::Size size;
   aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size);
   if (aRv.Failed()) {
     return;
   }
 
   aSize.mWidth = size.width;
   aSize.mHeight = size.height;
 }
 
 void
 nsDOMCameraControl::SetPictureSize(const CameraSize& aSize, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
-
   ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
   aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
 }
 
 void
 nsDOMCameraControl::GetThumbnailSize(CameraSize& aSize, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
-
   ICameraControl::Size size;
   aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size);
   if (aRv.Failed()) {
     return;
   }
 
   aSize.mWidth = size.width;
   aSize.mHeight = size.height;
 }
 
 void
 nsDOMCameraControl::SetThumbnailSize(const CameraSize& aSize, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
-
   ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
   aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s);
 }
 
 double
 nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL(0.0);
+  MOZ_ASSERT(mCameraControl);
 
   double focalLength;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, focalLength);
   return focalLength;
 }
 
 double
 nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL(0.0);
+  MOZ_ASSERT(mCameraControl);
 
   double distance;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, distance);
   return distance;
 }
 
 double
 nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL(0.0);
+  MOZ_ASSERT(mCameraControl);
 
   double distance;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, distance);
   return distance;
 }
 
 double
 nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL(0.0);
+  MOZ_ASSERT(mCameraControl);
 
   double distance;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, distance);
   return distance;
 }
 
 void
 nsDOMCameraControl::SetExposureCompensation(double aCompensation, ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation);
 }
 
 double
 nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL(0.0);
+  MOZ_ASSERT(mCameraControl);
 
   double compensation;
   aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
   return compensation;
 }
 
 int32_t
 nsDOMCameraControl::SensorAngle()
 {
+  MOZ_ASSERT(mCameraControl);
+
   int32_t angle = 0;
-  if (mCameraControl) {
-    mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
-  }
+  mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
   return angle;
 }
 
 // Callback attributes
 
 CameraShutterCallback*
 nsDOMCameraControl::GetOnShutter()
 {
@@ -698,16 +664,18 @@ nsDOMCameraControl::Capabilities()
 void
 nsDOMCameraControl::StartRecording(const CameraStartRecordingOptions& aOptions,
                                    nsDOMDeviceStorage& aStorageArea,
                                    const nsAString& aFilename,
                                    CameraStartRecordingCallback& aOnSuccess,
                                    const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
                                    ErrorResult& aRv)
 {
+  MOZ_ASSERT(mCameraControl);
+
   NotifyRecordingStatusChange(NS_LITERAL_STRING("starting"));
 
 #ifdef MOZ_B2G
   if (!mAudioChannelAgent) {
     mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
     if (mAudioChannelAgent) {
       // Camera app will stop recording when it falls to the background, so no callback is necessary.
       mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr);
@@ -737,19 +705,18 @@ nsDOMCameraControl::StartRecording(const
   request->AddEventListener(NS_LITERAL_STRING("success"), listener, false);
   request->AddEventListener(NS_LITERAL_STRING("error"), listener, false);
 }
 
 void
 nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
 {
   nsresult rv = NS_ERROR_FAILURE;
-  if (!mCameraControl) {
-    rv = NS_ERROR_NOT_INITIALIZED;
-  } else if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
+
+  if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
     ICameraControl::StartRecordingOptions o;
 
     o.rotation = mOptions.mRotation;
     o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes;
     o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs;
     o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch;
     rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o);
     if (NS_SUCCEEDED(rv)) {
@@ -767,32 +734,32 @@ nsDOMCameraControl::OnCreatedFileDescrip
       new CloseFileRunnable(mDSFileDescriptor->mFileDescriptor);
     closer->Dispatch();
   }
 }
 
 void
 nsDOMCameraControl::StopRecording(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
 
 #ifdef MOZ_B2G
   if (mAudioChannelAgent) {
     mAudioChannelAgent->StopPlaying();
     mAudioChannelAgent = nullptr;
   }
 #endif
 
   aRv = mCameraControl->StopRecording();
 }
 
 void
 nsDOMCameraControl::ResumePreview(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->StartPreview();
 }
 
 class ImmediateErrorCallback : public nsRunnable
 {
 public:
   ImmediateErrorCallback(CameraErrorCallback* aCallback, const nsAString& aMessage)
     : mCallback(aCallback)
@@ -814,27 +781,17 @@ protected:
 };
 
 void
 nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
                                      const Optional<OwningNonNull<CameraSetConfigurationCallback> >& aOnSuccess,
                                      const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
                                      ErrorResult& aRv)
 {
-  if (!mCameraControl) {
-    DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
-    if (aOnError.WasPassed()) {
-      NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
-                              NS_LITERAL_STRING("HardwareClosed")));
-    } else {
-      // Only throw if we don't have an error callback.
-      aRv = NS_ERROR_NOT_AVAILABLE;
-    }
-    return;
-  }
+  MOZ_ASSERT(mCameraControl);
 
   nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
   if (cb) {
     // We're busy taking a picture, can't change modes right now.
     if (aOnError.WasPassed()) {
       // There is already a call to TakePicture() in progress, abort this
       // call and invoke the error callback (if one was passed in).
       NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
@@ -867,27 +824,17 @@ nsDOMCameraControl::SetConfiguration(con
   aRv = mCameraControl->SetConfiguration(config);
 }
 
 void
 nsDOMCameraControl::AutoFocus(CameraAutoFocusCallback& aOnSuccess,
                               const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
                               ErrorResult& aRv)
 {
-  if (!mCameraControl) {
-    DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
-    if (aOnError.WasPassed()) {
-      NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
-                              NS_LITERAL_STRING("HardwareClosed")));
-    } else {
-      // Only throw if we don't have an error callback.
-      aRv = NS_ERROR_NOT_AVAILABLE;
-    }
-    return;
-  }
+  MOZ_ASSERT(mCameraControl);
 
   nsRefPtr<CameraErrorCallback> ecb = mAutoFocusOnErrorCb.forget();
   if (ecb) {
     // There is already a call to AutoFocus() in progress, cancel it and
     // invoke the error callback (if one was passed in).
     NS_DispatchToMainThread(new ImmediateErrorCallback(ecb,
                             NS_LITERAL_STRING("AutoFocusInterrupted")));
   }
@@ -899,44 +846,34 @@ nsDOMCameraControl::AutoFocus(CameraAuto
   }
 
   aRv = mCameraControl->AutoFocus();
 }
 
 void
 nsDOMCameraControl::StartFaceDetection(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->StartFaceDetection();
 }
 
 void
 nsDOMCameraControl::StopFaceDetection(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->StopFaceDetection();
 }
 
 void
 nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions,
                                 CameraTakePictureCallback& aOnSuccess,
                                 const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
                                 ErrorResult& aRv)
 {
-  if (!mCameraControl) {
-    DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
-    if (aOnError.WasPassed()) {
-      NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
-                              NS_LITERAL_STRING("HardwareClosed")));
-    } else {
-      // Only throw if we don't have an error callback.
-      aRv = NS_ERROR_NOT_AVAILABLE;
-    }
-    return;
-  }
+  MOZ_ASSERT(mCameraControl);
 
   nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
   if (cb) {
     if (aOnError.WasPassed()) {
       // There is already a call to TakePicture() in progress, abort this new
       // one and invoke the error callback (if one was passed in).
       NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
                               NS_LITERAL_STRING("TakePictureAlreadyInProgress")));
@@ -979,76 +916,42 @@ nsDOMCameraControl::TakePicture(const Ca
   aRv = mCameraControl->TakePicture();
 }
 
 void
 nsDOMCameraControl::ReleaseHardware(const Optional<OwningNonNull<CameraReleaseCallback> >& aOnSuccess,
                                     const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
                                     ErrorResult& aRv)
 {
-  if (!mCameraControl) {
-    // Always succeed if the camera instance is already closed.
-    if (aOnSuccess.WasPassed()) {
-      class Message : public nsRunnable
-      {
-      public:
-        Message(CameraReleaseCallback* aOnSuccess)
-          : mOnSuccess(aOnSuccess)
-        { }
-
-        NS_IMETHODIMP
-        Run()
-        {
-          if (mOnSuccess) {
-            ErrorResult ignored;
-            mOnSuccess->Call(ignored);
-          }
-          return NS_OK;
-        }
-
-      protected:
-        nsRefPtr<CameraReleaseCallback> mOnSuccess;
-      };
-
-      NS_DispatchToMainThread(new Message(&aOnSuccess.Value()));
-    }
-    return;
-  }
+  MOZ_ASSERT(mCameraControl);
 
   mReleaseOnSuccessCb = nullptr;
   if (aOnSuccess.WasPassed()) {
     mReleaseOnSuccessCb = &aOnSuccess.Value();
   }
   mReleaseOnErrorCb = nullptr;
   if (aOnError.WasPassed()) {
     mReleaseOnErrorCb = &aOnError.Value();
   }
 
   aRv = mCameraControl->Stop();
-  if (aRv.Failed()) {
-    return;
-  }
-
-  // Once we stop the camera, there's nothing we can do with it,
-  // so we can throw away this reference. (This won't prevent us
-  // from receiving the last underlying events.)
-  mCameraControl = nullptr;
 }
 
 void
 nsDOMCameraControl::ResumeContinuousFocus(ErrorResult& aRv)
 {
-  THROW_IF_NO_CAMERACONTROL();
+  MOZ_ASSERT(mCameraControl);
   aRv = mCameraControl->ResumeContinuousFocus();
 }
 
 void
 nsDOMCameraControl::Shutdown()
 {
   DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+  MOZ_ASSERT(mCameraControl);
 
   // Remove any pending solicited event handlers; these
   // reference our window object, which in turn references
   // us. If we don't remove them, we can leak DOM objects.
   mGetCameraOnSuccessCb = nullptr;
   mGetCameraOnErrorCb = nullptr;
   mAutoFocusOnSuccessCb = nullptr;
   mAutoFocusOnErrorCb = nullptr;
@@ -1065,20 +968,17 @@ nsDOMCameraControl::Shutdown()
   mOnShutterCb = nullptr;
   mOnClosedCb = nullptr;
   mOnRecorderStateChangeCb = nullptr;
   mOnPreviewStateChangeCb = nullptr;
   mOnAutoFocusMovingCb = nullptr;
   mOnAutoFocusCompletedCb = nullptr;
   mOnFacesDetectedCb = nullptr;
 
-  if (mCameraControl) {
-    mCameraControl->Stop();
-    mCameraControl = nullptr;
-  }
+  mCameraControl->Shutdown();
 }
 
 nsresult
 nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
 {
   NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
 
   return MediaManager::NotifyRecordingStatusChange(mWindow,
@@ -1298,17 +1198,17 @@ nsDOMCameraControl::OnFacesDetected(cons
   }
 
   Sequence<OwningNonNull<DOMCameraDetectedFace> > faces;
   uint32_t len = aFaces.Length();
 
   if (faces.SetCapacity(len)) {
     nsRefPtr<DOMCameraDetectedFace> f;
     for (uint32_t i = 0; i < len; ++i) {
-      f = new DOMCameraDetectedFace(static_cast<DOMMediaStream*>(this), aFaces[i]);
+      f = new DOMCameraDetectedFace(this, aFaces[i]);
       *faces.AppendElement() = f.forget().take();
     }
   }
 
   ErrorResult ignored;
   cb->Call(faces, ignored);
 }
 
--- a/dom/camera/DOMCameraControl.h
+++ b/dom/camera/DOMCameraControl.h
@@ -12,17 +12,16 @@
 #include "ICameraControl.h"
 #include "CameraCommon.h"
 #include "DOMMediaStream.h"
 #include "AudioChannelAgent.h"
 #include "nsProxyRelease.h"
 #include "nsHashPropertyBag.h"
 #include "DeviceStorage.h"
 #include "DOMCameraControlListener.h"
-#include "nsWeakReference.h"
 
 class nsDOMDeviceStorage;
 class nsPIDOMWindow;
 class nsIDOMBlob;
 
 namespace mozilla {
 
 namespace dom {
@@ -31,27 +30,20 @@ namespace dom {
   struct CameraStartRecordingOptions;
   struct CameraRegion;
   struct CameraSize;
   template<typename T> class Optional;
 }
 class ErrorResult;
 class StartRecordingHelper;
 
-#define NS_DOM_CAMERA_CONTROL_CID \
-{ 0x2eb67ab6, 0x2d7c, 0x4831, \
-  { 0x9c, 0x0f, 0xb5, 0xea, 0x4d, 0x58, 0x5f, 0xf0 } }
-
 // Main camera control.
 class nsDOMCameraControl MOZ_FINAL : public DOMMediaStream
-                                   , public nsSupportsWeakReference
 {
 public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_CAMERA_CONTROL_CID)
-
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMCameraControl, DOMMediaStream)
   NS_DECL_ISUPPORTS_INHERITED
 
   // Because this header's filename doesn't match its C++ or DOM-facing
   // classname, we can't rely on the [Func="..."] WebIDL tag to implicitly
   // include the right header for us; instead we must explicitly include a
   // HasSupport() method in each header. We can get rid of these with the
   // Great Renaming proposed in bug 983177.
@@ -141,18 +133,16 @@ public:
   void ResumePreview(ErrorResult& aRv);
   void ReleaseHardware(const dom::Optional<dom::OwningNonNull<dom::CameraReleaseCallback> >& aOnSuccess,
                        const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
                        ErrorResult& aRv);
   void ResumeContinuousFocus(ErrorResult& aRv);
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
-  operator nsISupports*() { return static_cast<DOMMediaStream*>(this); }
-
 protected:
   virtual ~nsDOMCameraControl();
 
   class DOMCameraConfiguration MOZ_FINAL : public dom::CameraConfiguration
   {
   public:
     NS_INLINE_DECL_REFCOUNTING(DOMCameraConfiguration)
 
@@ -237,13 +227,11 @@ protected:
   dom::CameraStartRecordingOptions mOptions;
   nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
 
 private:
   nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
   nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMCameraControl, NS_DOM_CAMERA_CONTROL_CID)
-
 } // namespace mozilla
 
 #endif // DOM_CAMERA_DOMCAMERACONTROL_H
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -10,33 +10,33 @@
 #include "CameraPreviewMediaStream.h"
 #include "mozilla/dom/CameraManagerBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl,
                                                    CameraPreviewMediaStream* aStream)
-  : mDOMCameraControl(new nsMainThreadPtrHolder<nsISupports>(static_cast<DOMMediaStream*>(aDOMCameraControl)))
+  : mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(aDOMCameraControl))
   , mStream(aStream)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, camera=%p, stream=%p\n",
     __func__, __LINE__, this, aDOMCameraControl, aStream);
 }
 
 DOMCameraControlListener::~DOMCameraControlListener()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 }
 
 // Boilerplate callback runnable
 class DOMCameraControlListener::DOMCallback : public nsRunnable
 {
 public:
-  DOMCallback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
+  DOMCallback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
     : mDOMCameraControl(aDOMCameraControl)
   {
     MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback);
   }
 
 protected:
   virtual ~DOMCallback()
   {
@@ -46,37 +46,35 @@ protected:
 public:
   virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0;
 
   NS_IMETHOD
   Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    nsRefPtr<nsDOMCameraControl> camera = do_QueryObject(mDOMCameraControl.get());
-    if (!camera) {
-      DOM_CAMERA_LOGE("do_QueryObject failed to get an nsDOMCameraControl\n");
-      return NS_ERROR_INVALID_ARG;
+    nsRefPtr<nsDOMCameraControl> camera = mDOMCameraControl.get();
+    if (camera) {
+      RunCallback(camera);
     }
-    RunCallback(camera);
     return NS_OK;
   }
 
 protected:
-  nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
+  nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
 };
 
 // Specific callback handlers
 void
 DOMCameraControlListener::OnHardwareStateChange(HardwareState aState)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              HardwareState aState)
       : DOMCallback(aDOMCameraControl)
       , mState(aState)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -91,17 +89,17 @@ DOMCameraControlListener::OnHardwareStat
 }
 
 void
 DOMCameraControlListener::OnPreviewStateChange(PreviewState aState)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              PreviewState aState)
       : DOMCallback(aDOMCameraControl)
       , mState(aState)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -144,17 +142,17 @@ DOMCameraControlListener::OnPreviewState
 
 void
 DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
                                                 int32_t aStatus, int32_t aTrackNum)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              RecorderState aState,
              int32_t aStatus,
              int32_t aTrackNum)
       : DOMCallback(aDOMCameraControl)
       , mState(aState)
       , mStatus(aStatus)
       , mTrackNum(aTrackNum)
     { }
@@ -175,17 +173,17 @@ DOMCameraControlListener::OnRecorderStat
 }
 
 void
 DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              const CameraListenerConfiguration& aConfiguration)
       : DOMCallback(aDOMCameraControl)
       , mConfiguration(aConfiguration)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -224,17 +222,17 @@ DOMCameraControlListener::OnConfiguratio
 }
 
 void
 DOMCameraControlListener::OnAutoFocusMoving(bool aIsMoving)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl, bool aIsMoving)
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, bool aIsMoving)
       : DOMCallback(aDOMCameraControl)
       , mIsMoving(aIsMoving)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
       aDOMCameraControl->OnAutoFocusMoving(mIsMoving);
@@ -248,17 +246,17 @@ DOMCameraControlListener::OnAutoFocusMov
 }
 
 void
 DOMCameraControlListener::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              const nsTArray<ICameraControl::Face>& aFaces)
       : DOMCallback(aDOMCameraControl)
       , mFaces(aFaces)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -273,17 +271,17 @@ DOMCameraControlListener::OnFacesDetecte
 }
 
 void
 DOMCameraControlListener::OnShutter()
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
       : DOMCallback(aDOMCameraControl)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
       aDOMCameraControl->OnShutter();
     }
@@ -308,17 +306,17 @@ DOMCameraControlListener::OnNewPreviewFr
 }
 
 void
 DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              bool aAutoFocusSucceeded)
       : DOMCallback(aDOMCameraControl)
       , mAutoFocusSucceeded(aAutoFocusSucceeded)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -333,17 +331,17 @@ DOMCameraControlListener::OnAutoFocusCom
 }
 
 void
 DOMCameraControlListener::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
       : DOMCallback(aDOMCameraControl)
       , mData(aData)
       , mLength(aLength)
       , mMimeType(aMimeType)
     { }
 
     void
@@ -366,17 +364,17 @@ DOMCameraControlListener::OnTakePictureC
 }
 
 void
 DOMCameraControlListener::OnUserError(UserContext aContext, nsresult aError)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
              UserContext aContext,
              nsresult aError)
       : DOMCallback(aDOMCameraControl)
       , mContext(aContext)
       , mError(aError)
     { }
 
     virtual void
--- a/dom/camera/DOMCameraControlListener.h
+++ b/dom/camera/DOMCameraControlListener.h
@@ -30,17 +30,17 @@ public:
   virtual void OnShutter() MOZ_OVERRIDE;
   virtual void OnRateLimitPreview(bool aLimit) MOZ_OVERRIDE;
   virtual bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) MOZ_OVERRIDE;
   virtual void OnUserError(UserContext aContext, nsresult aError) MOZ_OVERRIDE;
 
 protected:
   virtual ~DOMCameraControlListener();
 
-  nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
+  nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
   CameraPreviewMediaStream* mStream;
 
   class DOMCallback;
 
 private:
   DOMCameraControlListener(const DOMCameraControlListener&) MOZ_DELETE;
   DOMCameraControlListener& operator=(const DOMCameraControlListener&) MOZ_DELETE;
 };
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -39,17 +39,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCa
  * Global camera logging object
  *
  * Set the NSPR_LOG_MODULES environment variable to enable logging
  * in a debug build, e.g. NSPR_LOG_MODULES=Camera:5
  */
 PRLogModuleInfo*
 GetCameraLog()
 {
-  static PRLogModuleInfo* sLog;
+  static PRLogModuleInfo *sLog;
   if (!sLog) {
     sLog = PR_NewLogModule("Camera");
   }
   return sLog;
 }
 
 WindowTable* nsDOMCameraManager::sActiveWindows = nullptr;
 
@@ -332,56 +332,37 @@ void
 nsDOMCameraManager::Register(nsDOMCameraControl* aDOMCameraControl)
 {
   DOM_CAMERA_LOGI(">>> Register( aDOMCameraControl = %p ) mWindowId = 0x%llx\n", aDOMCameraControl, mWindowId);
   MOZ_ASSERT(NS_IsMainThread());
 
   // Put the camera control into the hash table
   CameraControls* controls = sActiveWindows->Get(mWindowId);
   if (!controls) {
-    controls = new CameraControls();
+    controls = new CameraControls;
     sActiveWindows->Put(mWindowId, controls);
   }
-
-  // Remove any stale CameraControl objects to limit our memory usage
-  uint32_t i = controls->Length();
-  while (i > 0) {
-    --i;
-    nsRefPtr<nsDOMCameraControl> cameraControl =
-      do_QueryObject(controls->ElementAt(i));
-    if (!cameraControl) {
-      controls->RemoveElementAt(i);
-    }
-  }
-
-  // Put the camera control into the hash table
-  nsWeakPtr cameraControl =
-    do_GetWeakReference(static_cast<DOMMediaStream*>(aDOMCameraControl));
-  controls->AppendElement(cameraControl);
+  controls->AppendElement(aDOMCameraControl);
 }
 
 void
 nsDOMCameraManager::Shutdown(uint64_t aWindowId)
 {
   DOM_CAMERA_LOGI(">>> Shutdown( aWindowId = 0x%llx )\n", aWindowId);
   MOZ_ASSERT(NS_IsMainThread());
 
   CameraControls* controls = sActiveWindows->Get(aWindowId);
   if (!controls) {
     return;
   }
 
-  uint32_t i = controls->Length();
-  while (i > 0) {
-    --i;
-    nsRefPtr<nsDOMCameraControl> cameraControl =
-      do_QueryObject(controls->ElementAt(i));
-    if (cameraControl) {
-      cameraControl->Shutdown();
-    }
+  uint32_t length = controls->Length();
+  for (uint32_t i = 0; i < length; i++) {
+    nsRefPtr<nsDOMCameraControl> cameraControl = controls->ElementAt(i);
+    cameraControl->Shutdown();
   }
   controls->Clear();
 
   sActiveWindows->Remove(aWindowId);
 }
 
 void
 nsDOMCameraManager::XpComShutdown()
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -5,17 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DOM_CAMERA_DOMCAMERAMANAGER_H
 #define DOM_CAMERA_DOMCAMERAMANAGER_H
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
-#include "nsWeakPtr.h"
 #include "nsIObserver.h"
 #include "nsHashKeys.h"
 #include "nsWrapperCache.h"
 #include "nsWeakReference.h"
 #include "nsClassHashtable.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
@@ -26,17 +25,17 @@ namespace mozilla {
   class nsDOMCameraControl;
   namespace dom {
     struct CameraConfiguration;
     class GetCameraCallback;
     class CameraErrorCallback;
   }
 }
 
-typedef nsTArray<nsWeakPtr> CameraControls;
+typedef nsTArray<nsRefPtr<mozilla::nsDOMCameraControl> > CameraControls;
 typedef nsClassHashtable<nsUint64HashKey, CameraControls> WindowTable;
 typedef mozilla::dom::Optional<mozilla::dom::OwningNonNull<mozilla::dom::CameraErrorCallback>>
           OptionalNonNullCameraErrorCallback;
 
 class nsDOMCameraManager MOZ_FINAL
   : public nsIObserver
   , public nsSupportsWeakReference
   , public nsWrapperCache
--- a/dom/camera/FallbackCameraControl.cpp
+++ b/dom/camera/FallbackCameraControl.cpp
@@ -17,17 +17,17 @@ namespace mozilla {
 
 /**
  * Fallback camera control subclass. Can be used as a template for the
  * definition of new camera support classes.
  */
 class FallbackCameraControl : public CameraControlImpl
 {
 public:
-  FallbackCameraControl() { }
+  FallbackCameraControl(uint32_t aCameraId) : CameraControlImpl(aCameraId) { }
 
   virtual nsresult Set(uint32_t aKey, const nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Get(uint32_t aKey, nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Set(uint32_t aKey, double aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Get(uint32_t aKey, double& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Set(uint32_t aKey, int32_t aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Get(uint32_t aKey, int32_t& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Set(uint32_t aKey, int64_t aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -56,17 +56,17 @@ using namespace android;
       NS_WARNING("Camera hardware is not initialized");                   \
       DOM_CAMERA_LOGE("%s:%d : mCameraHw is null\n", __func__, __LINE__); \
       return NS_ERROR_NOT_INITIALIZED;                                    \
     }                                                                     \
   } while(0)
 
 // Construct nsGonkCameraControl on the main thread.
 nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
-  : mCameraId(aCameraId)
+  : CameraControlImpl(aCameraId)
   , mLastPictureSize({0, 0})
   , mLastThumbnailSize({0, 0})
   , mPreviewFps(30)
   , mResumePreviewAfterTakingPicture(false) // XXXmikeh - see bug 950102
   , mFlashSupported(false)
   , mLuminanceSupported(false)
   , mAutoFlashModeOverridden(false)
   , mSeparateVideoAndPreviewSizesSupported(false)
--- a/dom/camera/GonkCameraControl.h
+++ b/dom/camera/GonkCameraControl.h
@@ -136,17 +136,16 @@ protected:
   nsresult SetPictureSize(const Size& aSize);
   nsresult SetPictureSizeImpl(const Size& aSize);
   nsresult SetThumbnailSize(const Size& aSize);
   nsresult UpdateThumbnailSize();
   nsresult SetThumbnailSizeImpl(const Size& aSize);
 
   int32_t RationalizeRotation(int32_t aRotation);
 
-  uint32_t mCameraId;
   android::sp<android::GonkCameraHardware> mCameraHw;
 
   Size                      mLastPictureSize;
   Size                      mLastThumbnailSize;
   Size                      mLastRecorderSize;
   uint32_t                  mPreviewFps;
   bool                      mResumePreviewAfterTakingPicture;
   bool                      mFlashSupported;
--- a/dom/camera/ICameraControl.h
+++ b/dom/camera/ICameraControl.h
@@ -216,16 +216,19 @@ public:
 
   virtual nsresult SetLocation(const Position& aLocation) = 0;
 
   virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) = 0;
   virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) = 0;
   virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) = 0;
 
   virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManager() = 0;
+  virtual uint32_t GetCameraId() = 0;
+
+  virtual void Shutdown() = 0;
 
 protected:
   virtual ~ICameraControl() { }
 
   friend class ICameraControlParameterSetAutoEnter;
 
   virtual void BeginBatchParameterSet() = 0;
   virtual void EndBatchParameterSet() = 0;
--- a/dom/camera/test/test_bug975472.html
+++ b/dom/camera/test/test_bug975472.html
@@ -50,51 +50,39 @@ var tests = [
         ok(false, "release() failed with: " + error);
       }
       camera.release(onSuccess, onError);
     }
   },
   {
     key: "set-picture-size-after-release",
     func: function testSetPictureSize(camera) {
-      try {
-        camera.setPictureSize({ width: 0, height: 0 });
-      } catch(e) {
-        ok(e.name === "NS_ERROR_NOT_AVAILABLE", "Error: " + e.name);
-        next();
-      }
+      camera.setPictureSize({ width: 0, height: 0 });
+      next();
     }
   },
   {
     key: "set-thumbnail-size-after-release",
     func: function testSetThumbnailSize(camera) {
-      try {
-        camera.setThumbnailSize({ width: 0, height: 0 });
-      } catch(e) {
-        ok(e.name === "NS_ERROR_NOT_AVAILABLE", "Error: " + e.name);
-        next();
-      }
+      camera.setThumbnailSize({ width: 0, height: 0 });
+      next();
     }
   },
   {
     key: "get-sensor-angle-after-release",
     func: function testGetSensorAngle(camera) {
       ok(camera.sensorAngle == 0, "camera.sensorAngle = " + camera.sensorAngle);
       next();
     }
   },
   {
     key: "resume-preview-after-release",
     func: function testResumePreview(camera) {
-      try {
-        camera.resumePreview();
-      } catch(e) {
-        ok(e.name === "NS_ERROR_NOT_AVAILABLE", "Error: " + e.name);
-        next();
-      }
+      camera.resumePreview();
+      next();
     }
   },
   {
     key: "auto-focus-after-release",
     func: function testAutoFocus(camera) {
       function onSuccess(success) {
         ok(false, "autoFocus() succeeded incorrectly");
       }
@@ -120,38 +108,34 @@ var tests = [
   },
   {
     key: "start-recording-after-release",
     func: function testStartRecording(camera) {
       function onSuccess(picture) {
         ok(false, "startRecording() process succeeded incorrectly");
       }
       function onError(error) {
-        ok(error === "HardwareClosed", "startRecording() failed with: " + error);
+        ok(error === "GeneralFailure", "startRecording() failed with: " + error);
         next();
       }
       var recordingOptions = {
         profile: 'cif',
         rotation: 0
       };
       camera.startRecording(recordingOptions,
                             navigator.getDeviceStorage('videos'),
                             'bug975472.mp4',
                             onSuccess, onError);
     }
   },
   {
     key: "stop-recording-after-release",
     func: function testStopRecording(camera) {
-      try {
-        camera.stopRecording();
-      } catch(e) {
-        ok(e.name === "NS_ERROR_NOT_AVAILABLE", "Error: " + e.name);
-        next();
-      }
+      camera.stopRecording();
+      next();
     }
   },
   {
     key: "set-configuration-after-release",
     func: function testSetConfiguration(camera) {
       function onSuccess(picture) {
         ok(false, "setConfiguration() process succeeded incorrectly");
       }
@@ -187,18 +171,18 @@ var Camera = {
           CameraTest.end();
         } else {
           throw e;
         }
       }
     };
     // Release the camera hardware, and call all of the asynchronous methods
     // to make sure they properly handle being in this state.
-    Camera.cameraObj.release(next, onError);
-    // next();
+    Camera.cameraObj.release();
+    next();
   },
   release: function release() {
     cameraObj = null;
   },
   start: function run_test() {
     function onSuccess(camera, config) {
       Camera.cameraObj = camera;
       Camera.viewfinder.mozSrcObject = camera;
--- a/dom/camera/test/test_camera.html
+++ b/dom/camera/test/test_camera.html
@@ -225,20 +225,18 @@ var Camera = {
     navigator.mozCameras.getCamera(whichCamera, null, onSuccess, onError);
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 
 window.addEventListener('beforeunload', function() {
   Camera.viewfinder.mozSrcObject = null;
-  if (Camera.cameraObj) {
-    Camera.cameraObj.release();
-    Camera.cameraObj = null;
-  }
+  Camera.cameraObj.release();
+  Camera.cameraObj = null;
 });
 
 Camera.setUp();
 
 </script>
 </body>
 
 </html>