dom/camera/DOMCameraControl.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "DOMCameraControl.h"
     6 #include "base/basictypes.h"
     7 #include "nsCOMPtr.h"
     8 #include "nsDOMClassInfo.h"
     9 #include "nsHashPropertyBag.h"
    10 #include "nsThread.h"
    11 #include "DeviceStorage.h"
    12 #include "DeviceStorageFileDescriptor.h"
    13 #include "mozilla/dom/TabChild.h"
    14 #include "mozilla/ipc/FileDescriptorUtils.h"
    15 #include "mozilla/MediaManager.h"
    16 #include "mozilla/Services.h"
    17 #include "mozilla/unused.h"
    18 #include "nsIAppsService.h"
    19 #include "nsIObserverService.h"
    20 #include "nsIDOMDeviceStorage.h"
    21 #include "nsIDOMEventListener.h"
    22 #include "nsIScriptSecurityManager.h"
    23 #include "Navigator.h"
    24 #include "nsXULAppAPI.h"
    25 #include "DOMCameraManager.h"
    26 #include "DOMCameraCapabilities.h"
    27 #include "CameraCommon.h"
    28 #include "nsGlobalWindow.h"
    29 #include "CameraPreviewMediaStream.h"
    30 #include "mozilla/dom/CameraControlBinding.h"
    31 #include "mozilla/dom/CameraManagerBinding.h"
    32 #include "mozilla/dom/CameraCapabilitiesBinding.h"
    33 #include "DOMCameraDetectedFace.h"
    34 #include "mozilla/dom/BindingUtils.h"
    36 using namespace mozilla;
    37 using namespace mozilla::dom;
    38 using namespace mozilla::ipc;
    40 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
    41   NS_INTERFACE_MAP_ENTRY(nsISupports)
    42   NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream)
    43 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
    45 NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream)
    46 NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream)
    48 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream,
    49                                    mCapabilities,
    50                                    mWindow,
    51                                    mGetCameraOnSuccessCb,
    52                                    mGetCameraOnErrorCb,
    53                                    mAutoFocusOnSuccessCb,
    54                                    mAutoFocusOnErrorCb,
    55                                    mTakePictureOnSuccessCb,
    56                                    mTakePictureOnErrorCb,
    57                                    mStartRecordingOnSuccessCb,
    58                                    mStartRecordingOnErrorCb,
    59                                    mReleaseOnSuccessCb,
    60                                    mReleaseOnErrorCb,
    61                                    mSetConfigurationOnSuccessCb,
    62                                    mSetConfigurationOnErrorCb,
    63                                    mOnShutterCb,
    64                                    mOnClosedCb,
    65                                    mOnRecorderStateChangeCb,
    66                                    mOnPreviewStateChangeCb,
    67                                    mOnAutoFocusMovingCb,
    68                                    mOnFacesDetectedCb)
    70 /* static */
    71 bool
    72 nsDOMCameraControl::HasSupport(JSContext* aCx, JSObject* aGlobal)
    73 {
    74   return Navigator::HasCameraSupport(aCx, aGlobal);
    75 }
    77 class mozilla::StartRecordingHelper : public nsIDOMEventListener
    78 {
    79 public:
    80   NS_DECL_ISUPPORTS
    81   NS_DECL_NSIDOMEVENTLISTENER
    83   StartRecordingHelper(nsDOMCameraControl* aDOMCameraControl)
    84     : mDOMCameraControl(aDOMCameraControl)
    85   {
    86     MOZ_COUNT_CTOR(StartRecordingHelper);
    87   }
    89 protected:
    90   virtual ~StartRecordingHelper()
    91   {
    92     MOZ_COUNT_DTOR(StartRecordingHelper);
    93   }
    95 protected:
    96   nsRefPtr<nsDOMCameraControl> mDOMCameraControl;
    97 };
    99 NS_IMETHODIMP
   100 StartRecordingHelper::HandleEvent(nsIDOMEvent* aEvent)
   101 {
   102   nsString eventType;
   103   aEvent->GetType(eventType);
   105   mDOMCameraControl->OnCreatedFileDescriptor(eventType.EqualsLiteral("success"));
   106   return NS_OK;
   107 }
   109 NS_IMPL_ISUPPORTS(mozilla::StartRecordingHelper, nsIDOMEventListener)
   111 nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration()
   112   : CameraConfiguration()
   113   , mMaxFocusAreas(0)
   114   , mMaxMeteringAreas(0)
   115 {
   116   MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration);
   117 }
   119 nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration(const CameraConfiguration& aConfiguration)
   120   : CameraConfiguration(aConfiguration)
   121   , mMaxFocusAreas(0)
   122   , mMaxMeteringAreas(0)
   123 {
   124   MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration);
   125 }
   127 nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration()
   128 {
   129   MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration);
   130 }
   132 nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
   133                                        const CameraConfiguration& aInitialConfig,
   134                                        GetCameraCallback* aOnSuccess,
   135                                        CameraErrorCallback* aOnError,
   136                                        nsPIDOMWindow* aWindow)
   137   : DOMMediaStream()
   138   , mCameraControl(nullptr)
   139   , mAudioChannelAgent(nullptr)
   140   , mGetCameraOnSuccessCb(aOnSuccess)
   141   , mGetCameraOnErrorCb(aOnError)
   142   , mAutoFocusOnSuccessCb(nullptr)
   143   , mAutoFocusOnErrorCb(nullptr)
   144   , mTakePictureOnSuccessCb(nullptr)
   145   , mTakePictureOnErrorCb(nullptr)
   146   , mStartRecordingOnSuccessCb(nullptr)
   147   , mStartRecordingOnErrorCb(nullptr)
   148   , mReleaseOnSuccessCb(nullptr)
   149   , mReleaseOnErrorCb(nullptr)
   150   , mSetConfigurationOnSuccessCb(nullptr)
   151   , mSetConfigurationOnErrorCb(nullptr)
   152   , mOnShutterCb(nullptr)
   153   , mOnClosedCb(nullptr)
   154   , mOnRecorderStateChangeCb(nullptr)
   155   , mOnPreviewStateChangeCb(nullptr)
   156   , mOnAutoFocusMovingCb(nullptr)
   157   , mOnFacesDetectedCb(nullptr)
   158   , mWindow(aWindow)
   159 {
   160   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   161   mInput = new CameraPreviewMediaStream(this);
   163   SetIsDOMBinding();
   165   nsRefPtr<DOMCameraConfiguration> initialConfig =
   166     new DOMCameraConfiguration(aInitialConfig);
   168   // Create and initialize the underlying camera.
   169   ICameraControl::Configuration config;
   171   switch (aInitialConfig.mMode) {
   172     case CameraMode::Picture:
   173       config.mMode = ICameraControl::kPictureMode;
   174       break;
   176     case CameraMode::Video:
   177       config.mMode = ICameraControl::kVideoMode;
   178       break;
   180     default:
   181       MOZ_ASSUME_UNREACHABLE("Unanticipated camera mode!");
   182   }
   184   config.mPreviewSize.width = aInitialConfig.mPreviewSize.mWidth;
   185   config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
   186   config.mRecorderProfile = aInitialConfig.mRecorderProfile;
   188   mCameraControl = ICameraControl::Create(aCameraId);
   189   mCurrentConfiguration = initialConfig.forget();
   191   // Attach our DOM-facing media stream to our viewfinder stream.
   192   mStream = mInput;
   193   MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
   194   if (mWindow->GetExtantDoc()) {
   195     CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
   196   }
   198   // Register a listener for camera events.
   199   mListener = new DOMCameraControlListener(this, mInput);
   200   mCameraControl->AddListener(mListener);
   202   // Start the camera...
   203   nsresult rv = mCameraControl->Start(&config);
   204   if (NS_FAILED(rv)) {
   205     mListener->OnError(DOMCameraControlListener::kInStartCamera,
   206                        DOMCameraControlListener::kErrorApiFailed);
   207   }
   208 }
   210 nsDOMCameraControl::~nsDOMCameraControl()
   211 {
   212   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   213 }
   215 JSObject*
   216 nsDOMCameraControl::WrapObject(JSContext* aCx)
   217 {
   218   return CameraControlBinding::Wrap(aCx, this);
   219 }
   221 bool
   222 nsDOMCameraControl::IsWindowStillActive()
   223 {
   224   return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID());
   225 }
   227 // JS-to-native helpers
   228 // Setter for weighted regions: { top, bottom, left, right, weight }
   229 nsresult
   230 nsDOMCameraControl::Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit)
   231 {
   232   if (aLimit == 0) {
   233     DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
   234     return NS_OK;
   235   }
   237   if (!aValue.isObject()) {
   238     return NS_ERROR_INVALID_ARG;
   239   }
   241   uint32_t length = 0;
   243   JS::Rooted<JSObject*> regions(aCx, &aValue.toObject());
   244   if (!JS_GetArrayLength(aCx, regions, &length)) {
   245     return NS_ERROR_FAILURE;
   246   }
   248   DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
   249   if (length > aLimit) {
   250     length = aLimit;
   251   }
   253   nsTArray<ICameraControl::Region> regionArray;
   254   regionArray.SetCapacity(length);
   256   for (uint32_t i = 0; i < length; ++i) {
   257     JS::Rooted<JS::Value> v(aCx);
   259     if (!JS_GetElement(aCx, regions, i, &v)) {
   260       return NS_ERROR_FAILURE;
   261     }
   263     CameraRegion region;
   264     if (!region.Init(aCx, v)) {
   265       return NS_ERROR_FAILURE;
   266     }
   268     ICameraControl::Region* r = regionArray.AppendElement();
   269     r->top = region.mTop;
   270     r->left = region.mLeft;
   271     r->bottom = region.mBottom;
   272     r->right = region.mRight;
   273     r->weight = region.mWeight;
   275     DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n",
   276       i,
   277       r->top,
   278       r->left,
   279       r->bottom,
   280       r->right,
   281       r->weight
   282     );
   283   }
   284   return mCameraControl->Set(aKey, regionArray);
   285 }
   287 // Getter for weighted regions: { top, bottom, left, right, weight }
   288 nsresult
   289 nsDOMCameraControl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue)
   290 {
   291   nsTArray<ICameraControl::Region> regionArray;
   293   nsresult rv = mCameraControl->Get(aKey, regionArray);
   294   NS_ENSURE_SUCCESS(rv, rv);
   296   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
   297   if (!array) {
   298     return NS_ERROR_OUT_OF_MEMORY;
   299   }
   301   uint32_t length = regionArray.Length();
   302   DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
   304   for (uint32_t i = 0; i < length; ++i) {
   305     ICameraControl::Region* r = &regionArray[i];
   306     JS::Rooted<JS::Value> v(aCx);
   308     JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
   309     if (!o) {
   310       return NS_ERROR_OUT_OF_MEMORY;
   311     }
   313     DOM_CAMERA_LOGI("top=%d\n", r->top);
   314     v = INT_TO_JSVAL(r->top);
   315     if (!JS_SetProperty(aCx, o, "top", v)) {
   316       return NS_ERROR_FAILURE;
   317     }
   318     DOM_CAMERA_LOGI("left=%d\n", r->left);
   319     v = INT_TO_JSVAL(r->left);
   320     if (!JS_SetProperty(aCx, o, "left", v)) {
   321       return NS_ERROR_FAILURE;
   322     }
   323     DOM_CAMERA_LOGI("bottom=%d\n", r->bottom);
   324     v = INT_TO_JSVAL(r->bottom);
   325     if (!JS_SetProperty(aCx, o, "bottom", v)) {
   326       return NS_ERROR_FAILURE;
   327     }
   328     DOM_CAMERA_LOGI("right=%d\n", r->right);
   329     v = INT_TO_JSVAL(r->right);
   330     if (!JS_SetProperty(aCx, o, "right", v)) {
   331       return NS_ERROR_FAILURE;
   332     }
   333     DOM_CAMERA_LOGI("weight=%d\n", r->weight);
   334     v = INT_TO_JSVAL(r->weight);
   335     if (!JS_SetProperty(aCx, o, "weight", v)) {
   336       return NS_ERROR_FAILURE;
   337     }
   339     if (!JS_SetElement(aCx, array, i, o)) {
   340       return NS_ERROR_FAILURE;
   341     }
   342   }
   344   *aValue = JS::ObjectValue(*array);
   345   return NS_OK;
   346 }
   348 void
   349 nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv)
   350 {
   351   MOZ_ASSERT(mCameraControl);
   352   aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
   353 }
   354 void
   355 nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv)
   356 {
   357   MOZ_ASSERT(mCameraControl);
   358   aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
   359 }
   361 void
   362 nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv)
   363 {
   364   MOZ_ASSERT(mCameraControl);
   365   aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
   366 }
   367 void
   368 nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv)
   369 {
   370   MOZ_ASSERT(mCameraControl);
   371   aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
   372 }
   374 void
   375 nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv)
   376 {
   377   MOZ_ASSERT(mCameraControl);
   378   aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
   379 }
   380 void
   381 nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv)
   382 {
   383   MOZ_ASSERT(mCameraControl);
   384   aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
   385 }
   387 void
   388 nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv)
   389 {
   390   MOZ_ASSERT(mCameraControl);
   391   aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
   392 }
   393 void
   394 nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv)
   395 {
   396   MOZ_ASSERT(mCameraControl);
   397   aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
   398 }
   400 void
   401 nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv)
   402 {
   403   MOZ_ASSERT(mCameraControl);
   404   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
   405 }
   406 void
   407 nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv)
   408 {
   409   MOZ_ASSERT(mCameraControl);
   410   aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
   411 }
   413 void
   414 nsDOMCameraControl::GetIsoMode(nsString& aIsoMode, ErrorResult& aRv)
   415 {
   416   MOZ_ASSERT(mCameraControl);
   417   aRv = mCameraControl->Get(CAMERA_PARAM_ISOMODE, aIsoMode);
   418 }
   419 void
   420 nsDOMCameraControl::SetIsoMode(const nsAString& aIsoMode, ErrorResult& aRv)
   421 {
   422   MOZ_ASSERT(mCameraControl);
   423   aRv = mCameraControl->Set(CAMERA_PARAM_ISOMODE, aIsoMode);
   424 }
   426 double
   427 nsDOMCameraControl::GetZoom(ErrorResult& aRv)
   428 {
   429   MOZ_ASSERT(mCameraControl);
   431   double zoom;
   432   aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, zoom);
   433   return zoom;
   434 }
   436 void
   437 nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv)
   438 {
   439   MOZ_ASSERT(mCameraControl);
   440   aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
   441 }
   443 /* attribute jsval meteringAreas; */
   444 void
   445 nsDOMCameraControl::GetMeteringAreas(JSContext* cx,
   446 				     JS::MutableHandle<JS::Value> aMeteringAreas,
   447 				     ErrorResult& aRv)
   448 {
   449   aRv = Get(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas.address());
   450 }
   452 void
   453 nsDOMCameraControl::SetMeteringAreas(JSContext* cx, JS::Handle<JS::Value> aMeteringAreas, ErrorResult& aRv)
   454 {
   455   aRv = Set(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas,
   456             mCurrentConfiguration->mMaxMeteringAreas);
   457 }
   459 void
   460 nsDOMCameraControl::GetFocusAreas(JSContext* cx,
   461 				  JS::MutableHandle<JS::Value> aFocusAreas,
   462 				  ErrorResult& aRv)
   463 {
   464   aRv = Get(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas.address());
   465 }
   466 void
   467 nsDOMCameraControl::SetFocusAreas(JSContext* cx, JS::Handle<JS::Value> aFocusAreas, ErrorResult& aRv)
   468 {
   469   aRv = Set(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas,
   470             mCurrentConfiguration->mMaxFocusAreas);
   471 }
   473 static nsresult
   474 GetSize(JSContext* aCx, JS::Value* aValue, const ICameraControl::Size& aSize)
   475 {
   476   JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
   477   if (!o) {
   478     return NS_ERROR_OUT_OF_MEMORY;
   479   }
   481   JS::Rooted<JS::Value> v(aCx);
   483   v = INT_TO_JSVAL(aSize.width);
   484   if (!JS_SetProperty(aCx, o, "width", v)) {
   485     return NS_ERROR_FAILURE;
   486   }
   487   v = INT_TO_JSVAL(aSize.height);
   488   if (!JS_SetProperty(aCx, o, "height", v)) {
   489     return NS_ERROR_FAILURE;
   490   }
   492   *aValue = JS::ObjectValue(*o);
   493   return NS_OK;
   494 }
   496 /* attribute any pictureSize */
   497 void
   498 nsDOMCameraControl::GetPictureSize(JSContext* cx,
   499 				   JS::MutableHandle<JS::Value> aSize,
   500 				   ErrorResult& aRv)
   501 {
   502   ICameraControl::Size size;
   503   aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size);
   504   if (aRv.Failed()) {
   505     return;
   506   }
   508   aRv = GetSize(cx, aSize.address(), size);
   509 }
   510 void
   511 nsDOMCameraControl::SetPictureSize(JSContext* aCx, JS::Handle<JS::Value> aSize, ErrorResult& aRv)
   512 {
   513   CameraSize size;
   514   if (!size.Init(aCx, aSize)) {
   515     aRv = NS_ERROR_FAILURE;
   516     return;
   517   }
   519   ICameraControl::Size s = { size.mWidth, size.mHeight };
   520   aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
   521 }
   523 /* attribute any thumbnailSize */
   524 void
   525 nsDOMCameraControl::GetThumbnailSize(JSContext* aCx,
   526 				     JS::MutableHandle<JS::Value> aSize,
   527 				     ErrorResult& aRv)
   528 {
   529   ICameraControl::Size size;
   530   aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size);
   531   if (aRv.Failed()) {
   532     return;
   533   }
   535   aRv = GetSize(aCx, aSize.address(), size);
   536 }
   537 void
   538 nsDOMCameraControl::SetThumbnailSize(JSContext* aCx, JS::Handle<JS::Value> aSize, ErrorResult& aRv)
   539 {
   540   CameraSize size;
   541   if (!size.Init(aCx, aSize)) {
   542     aRv = NS_ERROR_FAILURE;
   543     return;
   544   }
   546   ICameraControl::Size s = { size.mWidth, size.mHeight };
   547   aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s);
   548 }
   550 double
   551 nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
   552 {
   553   MOZ_ASSERT(mCameraControl);
   555   double focalLength;
   556   aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, focalLength);
   557   return focalLength;
   558 }
   560 double
   561 nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv)
   562 {
   563   MOZ_ASSERT(mCameraControl);
   565   double distance;
   566   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, distance);
   567   return distance;
   568 }
   570 double
   571 nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv)
   572 {
   573   MOZ_ASSERT(mCameraControl);
   575   double distance;
   576   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, distance);
   577   return distance;
   578 }
   580 double
   581 nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv)
   582 {
   583   MOZ_ASSERT(mCameraControl);
   585   double distance;
   586   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, distance);
   587   return distance;
   588 }
   590 void
   591 nsDOMCameraControl::SetExposureCompensation(const Optional<double>& aCompensation, ErrorResult& aRv)
   592 {
   593   MOZ_ASSERT(mCameraControl);
   595   if (!aCompensation.WasPassed()) {
   596     // use NaN to switch the camera back into auto mode
   597     aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN);
   598     return;
   599   }
   601   aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation.Value());
   602 }
   604 double
   605 nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
   606 {
   607   MOZ_ASSERT(mCameraControl);
   609   double compensation;
   610   aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
   611   return compensation;
   612 }
   614 int32_t
   615 nsDOMCameraControl::SensorAngle()
   616 {
   617   MOZ_ASSERT(mCameraControl);
   619   int32_t angle = 0;
   620   mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
   621   return angle;
   622 }
   624 // Callback attributes
   626 CameraShutterCallback*
   627 nsDOMCameraControl::GetOnShutter()
   628 {
   629   return mOnShutterCb;
   630 }
   631 void
   632 nsDOMCameraControl::SetOnShutter(CameraShutterCallback* aCb)
   633 {
   634   mOnShutterCb = aCb;
   635 }
   637 CameraClosedCallback*
   638 nsDOMCameraControl::GetOnClosed()
   639 {
   640   return mOnClosedCb;
   641 }
   642 void
   643 nsDOMCameraControl::SetOnClosed(CameraClosedCallback* aCb)
   644 {
   645   mOnClosedCb = aCb;
   646 }
   648 CameraRecorderStateChange*
   649 nsDOMCameraControl::GetOnRecorderStateChange()
   650 {
   651   return mOnRecorderStateChangeCb;
   652 }
   653 void
   654 nsDOMCameraControl::SetOnRecorderStateChange(CameraRecorderStateChange* aCb)
   655 {
   656   mOnRecorderStateChangeCb = aCb;
   657 }
   659 CameraPreviewStateChange*
   660 nsDOMCameraControl::GetOnPreviewStateChange()
   661 {
   662   return mOnPreviewStateChangeCb;
   663 }
   664 void
   665 nsDOMCameraControl::SetOnPreviewStateChange(CameraPreviewStateChange* aCb)
   666 {
   667   mOnPreviewStateChangeCb = aCb;
   668 }
   670 CameraAutoFocusMovingCallback*
   671 nsDOMCameraControl::GetOnAutoFocusMoving()
   672 {
   673   return mOnAutoFocusMovingCb;
   674 }
   675 void
   676 nsDOMCameraControl::SetOnAutoFocusMoving(CameraAutoFocusMovingCallback* aCb)
   677 {
   678   mOnAutoFocusMovingCb = aCb;
   679 }
   681 CameraFaceDetectionCallback*
   682 nsDOMCameraControl::GetOnFacesDetected()
   683 {
   684   return mOnFacesDetectedCb;
   685 }
   686 void
   687 nsDOMCameraControl::SetOnFacesDetected(CameraFaceDetectionCallback* aCb)
   688 {
   689   mOnFacesDetectedCb = aCb;
   690 }
   692 already_AddRefed<dom::CameraCapabilities>
   693 nsDOMCameraControl::Capabilities()
   694 {
   695   nsRefPtr<CameraCapabilities> caps = mCapabilities;
   697   if (!caps) {
   698     caps = new CameraCapabilities(mWindow);
   699     nsresult rv = caps->Populate(mCameraControl);
   700     if (NS_FAILED(rv)) {
   701       DOM_CAMERA_LOGW("Failed to populate camera capabilities (%d)\n", rv);
   702       return nullptr;
   703     }
   704     mCapabilities = caps;
   705   }
   707   return caps.forget();
   708 }
   710 // Methods.
   711 void
   712 nsDOMCameraControl::StartRecording(const CameraStartRecordingOptions& aOptions,
   713                                    nsDOMDeviceStorage& aStorageArea,
   714                                    const nsAString& aFilename,
   715                                    CameraStartRecordingCallback& aOnSuccess,
   716                                    const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
   717                                    ErrorResult& aRv)
   718 {
   719   MOZ_ASSERT(mCameraControl);
   721   NotifyRecordingStatusChange(NS_LITERAL_STRING("starting"));
   723 #ifdef MOZ_B2G
   724   if (!mAudioChannelAgent) {
   725     mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
   726     if (mAudioChannelAgent) {
   727       // Camera app will stop recording when it falls to the background, so no callback is necessary.
   728       mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr);
   729       // Video recording doesn't output any sound, so it's not necessary to check canPlay.
   730       int32_t canPlay;
   731       mAudioChannelAgent->StartPlaying(&canPlay);
   732     }
   733   }
   734 #endif
   736   nsCOMPtr<nsIDOMDOMRequest> request;
   737   mDSFileDescriptor = new DeviceStorageFileDescriptor();
   738   aRv = aStorageArea.CreateFileDescriptor(aFilename, mDSFileDescriptor.get(),
   739                                          getter_AddRefs(request));
   740   if (aRv.Failed()) {
   741     return;
   742   }
   744   mOptions = aOptions;
   745   mStartRecordingOnSuccessCb = &aOnSuccess;
   746   mStartRecordingOnErrorCb = nullptr;
   747   if (aOnError.WasPassed()) {
   748     mStartRecordingOnErrorCb = &aOnError.Value();
   749   }
   751   nsCOMPtr<nsIDOMEventListener> listener = new StartRecordingHelper(this);
   752   request->AddEventListener(NS_LITERAL_STRING("success"), listener, false);
   753   request->AddEventListener(NS_LITERAL_STRING("error"), listener, false);
   754 }
   756 void
   757 nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
   758 {
   759   if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
   760     ICameraControl::StartRecordingOptions o;
   762     o.rotation = mOptions.mRotation;
   763     o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes;
   764     o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs;
   765     o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch;
   766     nsresult rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o);
   767     if (NS_SUCCEEDED(rv)) {
   768       return;
   769     }
   770   }
   771   OnError(CameraControlListener::kInStartRecording, NS_LITERAL_STRING("FAILURE"));
   773   if (mDSFileDescriptor->mFileDescriptor.IsValid()) {
   774     // An error occured. We need to manually close the file associated with the
   775     // FileDescriptor, and we shouldn't do this on the main thread, so we
   776     // use a little helper.
   777     nsRefPtr<CloseFileRunnable> closer =
   778       new CloseFileRunnable(mDSFileDescriptor->mFileDescriptor);
   779     closer->Dispatch();
   780   }
   781 }
   783 void
   784 nsDOMCameraControl::StopRecording(ErrorResult& aRv)
   785 {
   786   MOZ_ASSERT(mCameraControl);
   788 #ifdef MOZ_B2G
   789   if (mAudioChannelAgent) {
   790     mAudioChannelAgent->StopPlaying();
   791     mAudioChannelAgent = nullptr;
   792   }
   793 #endif
   795   aRv = mCameraControl->StopRecording();
   796 }
   798 void
   799 nsDOMCameraControl::ResumePreview(ErrorResult& aRv)
   800 {
   801   MOZ_ASSERT(mCameraControl);
   802   aRv = mCameraControl->StartPreview();
   803 }
   805 void
   806 nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
   807                                      const Optional<OwningNonNull<CameraSetConfigurationCallback> >& aOnSuccess,
   808                                      const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
   809                                      ErrorResult& aRv)
   810 {
   811   MOZ_ASSERT(mCameraControl);
   813   nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
   814   if (cb) {
   815     // We're busy taking a picture, can't change modes right now.
   816     if (aOnError.WasPassed()) {
   817       ErrorResult ignored;
   818       aOnError.Value().Call(NS_LITERAL_STRING("Busy"), ignored);
   819     }
   820     aRv = NS_ERROR_FAILURE;
   821     return;
   822   }
   824   ICameraControl::Configuration config;
   825   config.mRecorderProfile = aConfiguration.mRecorderProfile;
   826   config.mPreviewSize.width = aConfiguration.mPreviewSize.mWidth;
   827   config.mPreviewSize.height = aConfiguration.mPreviewSize.mHeight;
   828   config.mMode = ICameraControl::kPictureMode;
   829   if (aConfiguration.mMode == CameraMode::Video) {
   830     config.mMode = ICameraControl::kVideoMode;
   831   }
   833   mSetConfigurationOnSuccessCb = nullptr;
   834   if (aOnSuccess.WasPassed()) {
   835     mSetConfigurationOnSuccessCb = &aOnSuccess.Value();
   836   }
   837   mSetConfigurationOnErrorCb = nullptr;
   838   if (aOnError.WasPassed()) {
   839     mSetConfigurationOnErrorCb = &aOnError.Value();
   840   }
   842   aRv = mCameraControl->SetConfiguration(config);
   843 }
   845 class ImmediateErrorCallback : public nsRunnable
   846 {
   847 public:
   848   ImmediateErrorCallback(CameraErrorCallback* aCallback, const nsAString& aMessage)
   849     : mCallback(aCallback)
   850     , mMessage(aMessage)
   851   { }
   853   NS_IMETHODIMP
   854   Run()
   855   {
   856     MOZ_ASSERT(NS_IsMainThread());
   857     ErrorResult ignored;
   858     mCallback->Call(mMessage, ignored);
   859     return NS_OK;
   860   }
   862 protected:
   863   nsRefPtr<CameraErrorCallback> mCallback;
   864   nsString mMessage;
   865 };
   868 void
   869 nsDOMCameraControl::AutoFocus(CameraAutoFocusCallback& aOnSuccess,
   870                               const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
   871                               ErrorResult& aRv)
   872 {
   873   MOZ_ASSERT(mCameraControl);
   875   nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb;
   876   if (cb) {
   877     if (aOnError.WasPassed()) {
   878       // There is already a call to AutoFocus() in progress, abort this new one
   879       // and invoke the error callback (if one was passed in).
   880       NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
   881                               NS_LITERAL_STRING("AutoFocusAlreadyInProgress")));
   882     }
   883     aRv = NS_ERROR_FAILURE;
   884     return;
   885   }
   887   mAutoFocusOnSuccessCb = &aOnSuccess;
   888   mAutoFocusOnErrorCb = nullptr;
   889   if (aOnError.WasPassed()) {
   890     mAutoFocusOnErrorCb = &aOnError.Value();
   891   }
   893   aRv = mCameraControl->AutoFocus();
   894 }
   896 void
   897 nsDOMCameraControl::StartFaceDetection(ErrorResult& aRv)
   898 {
   899   MOZ_ASSERT(mCameraControl);
   900   aRv = mCameraControl->StartFaceDetection();
   901 }
   903 void
   904 nsDOMCameraControl::StopFaceDetection(ErrorResult& aRv)
   905 {
   906   MOZ_ASSERT(mCameraControl);
   907   aRv = mCameraControl->StopFaceDetection();
   908 }
   910 void
   911 nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions,
   912                                 CameraTakePictureCallback& aOnSuccess,
   913                                 const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
   914                                 ErrorResult& aRv)
   915 {
   916   MOZ_ASSERT(mCameraControl);
   918   nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
   919   if (cb) {
   920     if (aOnError.WasPassed()) {
   921       // There is already a call to TakePicture() in progress, abort this new
   922       // one and invoke the error callback (if one was passed in).
   923       NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
   924                               NS_LITERAL_STRING("TakePictureAlreadyInProgress")));
   925     }
   926     aRv = NS_ERROR_FAILURE;
   927     return;
   928   }
   930   {
   931     ICameraControlParameterSetAutoEnter batch(mCameraControl);
   933     // XXXmikeh - remove this: see bug 931155
   934     ICameraControl::Size s;
   935     s.width = aOptions.mPictureSize.mWidth;
   936     s.height = aOptions.mPictureSize.mHeight;
   938     ICameraControl::Position p;
   939     p.latitude = aOptions.mPosition.mLatitude;
   940     p.longitude = aOptions.mPosition.mLongitude;
   941     p.altitude = aOptions.mPosition.mAltitude;
   942     p.timestamp = aOptions.mPosition.mTimestamp;
   944     if (s.width && s.height) {
   945       mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
   946     }
   947     mCameraControl->Set(CAMERA_PARAM_PICTURE_ROTATION, aOptions.mRotation);
   948     mCameraControl->Set(CAMERA_PARAM_PICTURE_FILEFORMAT, aOptions.mFileFormat);
   949     mCameraControl->Set(CAMERA_PARAM_PICTURE_DATETIME, aOptions.mDateTime);
   950     mCameraControl->SetLocation(p);
   951   }
   953   mTakePictureOnSuccessCb = &aOnSuccess;
   954   mTakePictureOnErrorCb = nullptr;
   955   if (aOnError.WasPassed()) {
   956     mTakePictureOnErrorCb = &aOnError.Value();
   957   }
   959   aRv = mCameraControl->TakePicture();
   960 }
   962 void
   963 nsDOMCameraControl::ReleaseHardware(const Optional<OwningNonNull<CameraReleaseCallback> >& aOnSuccess,
   964                                     const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
   965                                     ErrorResult& aRv)
   966 {
   967   MOZ_ASSERT(mCameraControl);
   969   mReleaseOnSuccessCb = nullptr;
   970   if (aOnSuccess.WasPassed()) {
   971     mReleaseOnSuccessCb = &aOnSuccess.Value();
   972   }
   973   mReleaseOnErrorCb = nullptr;
   974   if (aOnError.WasPassed()) {
   975     mReleaseOnErrorCb = &aOnError.Value();
   976   }
   978   aRv = mCameraControl->Stop();
   979 }
   981 void
   982 nsDOMCameraControl::ResumeContinuousFocus(ErrorResult& aRv)
   983 {
   984   MOZ_ASSERT(mCameraControl);
   985   aRv = mCameraControl->ResumeContinuousFocus();
   986 }
   988 void
   989 nsDOMCameraControl::Shutdown()
   990 {
   991   DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
   992   MOZ_ASSERT(mCameraControl);
   994   // Remove any pending solicited event handlers; these
   995   // reference our window object, which in turn references
   996   // us. If we don't remove them, we can leak DOM objects.
   997   mGetCameraOnSuccessCb = nullptr;
   998   mGetCameraOnErrorCb = nullptr;
   999   mAutoFocusOnSuccessCb = nullptr;
  1000   mAutoFocusOnErrorCb = nullptr;
  1001   mTakePictureOnSuccessCb = nullptr;
  1002   mTakePictureOnErrorCb = nullptr;
  1003   mStartRecordingOnSuccessCb = nullptr;
  1004   mStartRecordingOnErrorCb = nullptr;
  1005   mReleaseOnSuccessCb = nullptr;
  1006   mReleaseOnErrorCb = nullptr;
  1007   mSetConfigurationOnSuccessCb = nullptr;
  1008   mSetConfigurationOnErrorCb = nullptr;
  1010   // Remove all of the unsolicited event handlers too.
  1011   mOnShutterCb = nullptr;
  1012   mOnClosedCb = nullptr;
  1013   mOnRecorderStateChangeCb = nullptr;
  1014   mOnPreviewStateChangeCb = nullptr;
  1015   mOnAutoFocusMovingCb = nullptr;
  1016   mOnFacesDetectedCb = nullptr;
  1018   mCameraControl->Shutdown();
  1021 nsresult
  1022 nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
  1024   NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
  1026   return MediaManager::NotifyRecordingStatusChange(mWindow,
  1027                                                    aMsg,
  1028                                                    true /* aIsAudio */,
  1029                                                    true /* aIsVideo */);
  1032 // Camera Control event handlers--must only be called from the Main Thread!
  1033 void
  1034 nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState)
  1036   MOZ_ASSERT(NS_IsMainThread());
  1037   ErrorResult ignored;
  1039   DOM_CAMERA_LOGI("DOM OnHardwareStateChange(%d)\n", aState);
  1041   switch (aState) {
  1042     case CameraControlListener::kHardwareOpen:
  1043       // The hardware is open, so we can return a camera to JS, even if
  1044       // the preview hasn't started yet.
  1045       if (mGetCameraOnSuccessCb) {
  1046         nsRefPtr<GetCameraCallback> cb = mGetCameraOnSuccessCb.forget();
  1047         ErrorResult ignored;
  1048         mGetCameraOnErrorCb = nullptr;
  1049         cb->Call(*this, *mCurrentConfiguration, ignored);
  1051       break;
  1053     case CameraControlListener::kHardwareClosed:
  1054       if (mReleaseOnSuccessCb) {
  1055         // If we have this event handler, this was a solicited hardware close.
  1056         nsRefPtr<CameraReleaseCallback> cb = mReleaseOnSuccessCb.forget();
  1057         mReleaseOnErrorCb = nullptr;
  1058         cb->Call(ignored);
  1059       } else if(mOnClosedCb) {
  1060         // If not, something else closed the hardware.
  1061         nsRefPtr<CameraClosedCallback> cb = mOnClosedCb;
  1062         cb->Call(ignored);
  1064       break;
  1066     default:
  1067       MOZ_ASSUME_UNREACHABLE("Unanticipated camera hardware state");
  1071 void
  1072 nsDOMCameraControl::OnShutter()
  1074   MOZ_ASSERT(NS_IsMainThread());
  1076   DOM_CAMERA_LOGI("DOM ** SNAP **\n");
  1078   nsRefPtr<CameraShutterCallback> cb = mOnShutterCb;
  1079   if (cb) {
  1080     ErrorResult ignored;
  1081     cb->Call(ignored);
  1085 void
  1086 nsDOMCameraControl::OnPreviewStateChange(CameraControlListener::PreviewState aState)
  1088   MOZ_ASSERT(NS_IsMainThread());
  1090   if (!mOnPreviewStateChangeCb) {
  1091     return;
  1094   nsString state;
  1095   switch (aState) {
  1096     case CameraControlListener::kPreviewStarted:
  1097       state = NS_LITERAL_STRING("started");
  1098       break;
  1100     default:
  1101       state = NS_LITERAL_STRING("stopped");
  1102       break;
  1105   nsRefPtr<CameraPreviewStateChange> cb = mOnPreviewStateChangeCb;
  1106   ErrorResult ignored;
  1107   cb->Call(state, ignored);
  1110 void
  1111 nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
  1112                                           int32_t aArg, int32_t aTrackNum)
  1114   // For now, we do nothing with 'aStatus' and 'aTrackNum'.
  1115   MOZ_ASSERT(NS_IsMainThread());
  1117   ErrorResult ignored;
  1118   nsString state;
  1120   switch (aState) {
  1121     case CameraControlListener::kRecorderStarted:
  1122       if (mStartRecordingOnSuccessCb) {
  1123         nsRefPtr<CameraStartRecordingCallback> cb = mStartRecordingOnSuccessCb.forget();
  1124         mStartRecordingOnErrorCb = nullptr;
  1125         cb->Call(ignored);
  1127       state = NS_LITERAL_STRING("Started");
  1128       break;
  1130     case CameraControlListener::kRecorderStopped:
  1131       NotifyRecordingStatusChange(NS_LITERAL_STRING("shutdown"));
  1132       state = NS_LITERAL_STRING("Stopped");
  1133       break;
  1135 #ifdef MOZ_B2G_CAMERA
  1136     case CameraControlListener::kFileSizeLimitReached:
  1137       state = NS_LITERAL_STRING("FileSizeLimitReached");
  1138       break;
  1140     case CameraControlListener::kVideoLengthLimitReached:
  1141       state = NS_LITERAL_STRING("VideoLengthLimitReached");
  1142       break;
  1144     case CameraControlListener::kTrackCompleted:
  1145       state = NS_LITERAL_STRING("TrackCompleted");
  1146       break;
  1148     case CameraControlListener::kTrackFailed:
  1149       state = NS_LITERAL_STRING("TrackFailed");
  1150       break;
  1152     case CameraControlListener::kMediaRecorderFailed:
  1153       state = NS_LITERAL_STRING("MediaRecorderFailed");
  1154       break;
  1156     case CameraControlListener::kMediaServerFailed:
  1157       state = NS_LITERAL_STRING("MediaServerFailed");
  1158       break;
  1159 #endif
  1161     default:
  1162       MOZ_ASSUME_UNREACHABLE("Unanticipated video recorder error");
  1163       return;
  1166   nsRefPtr<CameraRecorderStateChange> cb = mOnRecorderStateChangeCb;
  1167   if (cb) {
  1168     cb->Call(state, ignored);
  1172 void
  1173 nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration)
  1175   MOZ_ASSERT(NS_IsMainThread());
  1177   // Update our record of the current camera configuration
  1178   mCurrentConfiguration = aConfiguration;
  1180   DOM_CAMERA_LOGI("DOM OnConfigurationChange: this=%p\n", this);
  1181   DOM_CAMERA_LOGI("    mode                   : %s\n",
  1182     mCurrentConfiguration->mMode == CameraMode::Video ? "video" : "picture");
  1183   DOM_CAMERA_LOGI("    maximum focus areas    : %d\n",
  1184     mCurrentConfiguration->mMaxFocusAreas);
  1185   DOM_CAMERA_LOGI("    maximum metering areas : %d\n",
  1186     mCurrentConfiguration->mMaxMeteringAreas);
  1187   DOM_CAMERA_LOGI("    preview size (w x h)   : %d x %d\n",
  1188     mCurrentConfiguration->mPreviewSize.mWidth, mCurrentConfiguration->mPreviewSize.mHeight);
  1189   DOM_CAMERA_LOGI("    recorder profile       : %s\n",
  1190     NS_ConvertUTF16toUTF8(mCurrentConfiguration->mRecorderProfile).get());
  1192   nsRefPtr<CameraSetConfigurationCallback> cb = mSetConfigurationOnSuccessCb.forget();
  1193   mSetConfigurationOnErrorCb = nullptr;
  1194   if (cb) {
  1195     ErrorResult ignored;
  1196     cb->Call(*mCurrentConfiguration, ignored);
  1200 void
  1201 nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
  1203   MOZ_ASSERT(NS_IsMainThread());
  1205   nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.forget();
  1206   mAutoFocusOnErrorCb = nullptr;
  1207   if (cb) {
  1208     ErrorResult ignored;
  1209     cb->Call(aAutoFocusSucceeded, ignored);
  1213 void
  1214 nsDOMCameraControl::OnAutoFocusMoving(bool aIsMoving)
  1216   MOZ_ASSERT(NS_IsMainThread());
  1218   nsRefPtr<CameraAutoFocusMovingCallback> cb = mOnAutoFocusMovingCb;
  1219   if (cb) {
  1220     ErrorResult ignored;
  1221     cb->Call(aIsMoving, ignored);
  1225 void
  1226 nsDOMCameraControl::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces)
  1228   DOM_CAMERA_LOGI("DOM OnFacesDetected %u face(s)\n", aFaces.Length());
  1229   MOZ_ASSERT(NS_IsMainThread());
  1231   nsRefPtr<CameraFaceDetectionCallback> cb = mOnFacesDetectedCb;
  1232   if (!cb) {
  1233     return;
  1236   Sequence<OwningNonNull<DOMCameraDetectedFace> > faces;
  1237   uint32_t len = aFaces.Length();
  1239   if (faces.SetCapacity(len)) {
  1240     nsRefPtr<DOMCameraDetectedFace> f;
  1241     for (uint32_t i = 0; i < len; ++i) {
  1242       f = new DOMCameraDetectedFace(this, aFaces[i]);
  1243       *faces.AppendElement() = f.forget().take();
  1247   ErrorResult ignored;
  1248   cb->Call(faces, ignored);
  1251 void
  1252 nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
  1254   MOZ_ASSERT(NS_IsMainThread());
  1256   nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget();
  1257   mTakePictureOnErrorCb = nullptr;
  1258   if (!cb) {
  1259     // Warn because it shouldn't be possible to get here without
  1260     // having passed a success callback into takePicture(), even
  1261     // though we guard against a nullptr dereference.
  1262     NS_WARNING("DOM Null success callback in OnTakePictureComplete()");
  1263     return;
  1266   ErrorResult ignored;
  1267   cb->Call(aPicture, ignored);
  1270 void
  1271 nsDOMCameraControl::OnError(CameraControlListener::CameraErrorContext aContext, const nsAString& aError)
  1273   DOM_CAMERA_LOGI("DOM OnError context=%d, error='%s'\n", aContext,
  1274     NS_LossyConvertUTF16toASCII(aError).get());
  1275   MOZ_ASSERT(NS_IsMainThread());
  1277   nsRefPtr<CameraErrorCallback> errorCb;
  1279   switch (aContext) {
  1280     case CameraControlListener::kInStartCamera:
  1281       mGetCameraOnSuccessCb = nullptr;
  1282       errorCb = mGetCameraOnErrorCb.forget();
  1283       break;
  1285     case CameraControlListener::kInStopCamera:
  1286       mReleaseOnSuccessCb = nullptr;
  1287       errorCb = mReleaseOnErrorCb.forget();
  1288       break;
  1290     case CameraControlListener::kInSetConfiguration:
  1291       mSetConfigurationOnSuccessCb = nullptr;
  1292       errorCb = mSetConfigurationOnErrorCb.forget();
  1293       break;
  1295     case CameraControlListener::kInAutoFocus:
  1296       mAutoFocusOnSuccessCb = nullptr;
  1297       errorCb = mAutoFocusOnErrorCb.forget();
  1298       break;
  1300     case CameraControlListener::kInTakePicture:
  1301       mTakePictureOnSuccessCb = nullptr;
  1302       errorCb = mTakePictureOnErrorCb.forget();
  1303       break;
  1305     case CameraControlListener::kInStartRecording:
  1306       mStartRecordingOnSuccessCb = nullptr;
  1307       errorCb = mStartRecordingOnErrorCb.forget();
  1308       break;
  1310     case CameraControlListener::kInStopRecording:
  1311       // This method doesn't have any callbacks, so all we can do is log the
  1312       // failure. This only happens after the hardware has been released.
  1313       NS_WARNING("Failed to stop recording");
  1314       return;
  1316     case CameraControlListener::kInStartPreview:
  1317       // This method doesn't have any callbacks, so all we can do is log the
  1318       // failure. This only happens after the hardware has been released.
  1319       NS_WARNING("Failed to (re)start preview");
  1320       return;
  1322     case CameraControlListener::kInUnspecified:
  1323       if (aError.EqualsASCII("ErrorServiceFailed")) {
  1324         // If the camera service fails, we will get preview-stopped and
  1325         // hardware-closed events, so nothing to do here.
  1326         NS_WARNING("Camera service failed");
  1327         return;
  1329       if (aError.EqualsASCII("ErrorSetPictureSizeFailed") ||
  1330           aError.EqualsASCII("ErrorSetThumbnailSizeFailed")) {
  1331         // We currently don't handle attribute setter failure. Practically,
  1332         // this only ever happens if a setter is called after the hardware
  1333         // has gone away before an asynchronous set gets to happen, so we
  1334         // swallow these.
  1335         NS_WARNING("Failed to set either picture or thumbnail size");
  1336         return;
  1338       // fallthrough
  1340     default:
  1341       MOZ_ASSUME_UNREACHABLE("Error occurred in unanticipated camera state");
  1342       return;
  1345   if (!errorCb) {
  1346     DOM_CAMERA_LOGW("DOM No error handler for error '%s' in context=%d\n",
  1347       NS_LossyConvertUTF16toASCII(aError).get(), aContext);
  1348     return;
  1351   ErrorResult ignored;
  1352   errorCb->Call(aError, ignored);

mercurial