Bumping manifests a=b2g-bump
[gecko.git] / dom / camera / DOMCameraControl.cpp
blob03542ee5c1f445189c81d14f2286c11b1cad8dba
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"
35 #include "nsPrintfCString.h"
37 using namespace mozilla;
38 using namespace mozilla::dom;
39 using namespace mozilla::ipc;
41 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
42 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
43 NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream)
44 // nsISupports is an ambiguous base of nsDOMCameraControl
45 // so we need to work around that.
46 if (aIID.Equals(NS_GET_IID(nsDOMCameraControl)))
47 foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
48 else
49 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
51 NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream)
52 NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream)
54 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream,
55 mAudioChannelAgent,
56 mCapabilities,
57 mWindow,
58 mGetCameraOnSuccessCb,
59 mGetCameraOnErrorCb,
60 mAutoFocusOnSuccessCb,
61 mAutoFocusOnErrorCb,
62 mTakePictureOnSuccessCb,
63 mTakePictureOnErrorCb,
64 mStartRecordingOnSuccessCb,
65 mStartRecordingOnErrorCb,
66 mReleaseOnSuccessCb,
67 mReleaseOnErrorCb,
68 mSetConfigurationOnSuccessCb,
69 mSetConfigurationOnErrorCb,
70 mOnShutterCb,
71 mOnClosedCb,
72 mOnRecorderStateChangeCb,
73 mOnPreviewStateChangeCb,
74 mOnAutoFocusMovingCb,
75 mOnAutoFocusCompletedCb,
76 mOnFacesDetectedCb)
78 /* static */
79 bool
80 nsDOMCameraControl::HasSupport(JSContext* aCx, JSObject* aGlobal)
82 return Navigator::HasCameraSupport(aCx, aGlobal);
85 class mozilla::StartRecordingHelper : public nsIDOMEventListener
87 public:
88 NS_DECL_ISUPPORTS
89 NS_DECL_NSIDOMEVENTLISTENER
91 StartRecordingHelper(nsDOMCameraControl* aDOMCameraControl)
92 : mDOMCameraControl(aDOMCameraControl)
94 MOZ_COUNT_CTOR(StartRecordingHelper);
97 protected:
98 virtual ~StartRecordingHelper()
100 MOZ_COUNT_DTOR(StartRecordingHelper);
103 protected:
104 nsRefPtr<nsDOMCameraControl> mDOMCameraControl;
107 NS_IMETHODIMP
108 StartRecordingHelper::HandleEvent(nsIDOMEvent* aEvent)
110 nsString eventType;
111 aEvent->GetType(eventType);
113 mDOMCameraControl->OnCreatedFileDescriptor(eventType.EqualsLiteral("success"));
114 return NS_OK;
117 NS_IMPL_ISUPPORTS(mozilla::StartRecordingHelper, nsIDOMEventListener)
119 nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration()
120 : CameraConfiguration()
121 , mMaxFocusAreas(0)
122 , mMaxMeteringAreas(0)
124 MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration);
127 nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration(const CameraConfiguration& aConfiguration)
128 : CameraConfiguration(aConfiguration)
129 , mMaxFocusAreas(0)
130 , mMaxMeteringAreas(0)
132 MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration);
135 nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration()
137 MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration);
140 nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
141 const CameraConfiguration& aInitialConfig,
142 GetCameraCallback* aOnSuccess,
143 CameraErrorCallback* aOnError,
144 nsPIDOMWindow* aWindow)
145 : DOMMediaStream()
146 , mCameraControl(nullptr)
147 , mAudioChannelAgent(nullptr)
148 , mGetCameraOnSuccessCb(aOnSuccess)
149 , mGetCameraOnErrorCb(aOnError)
150 , mAutoFocusOnSuccessCb(nullptr)
151 , mAutoFocusOnErrorCb(nullptr)
152 , mTakePictureOnSuccessCb(nullptr)
153 , mTakePictureOnErrorCb(nullptr)
154 , mStartRecordingOnSuccessCb(nullptr)
155 , mStartRecordingOnErrorCb(nullptr)
156 , mReleaseOnSuccessCb(nullptr)
157 , mReleaseOnErrorCb(nullptr)
158 , mSetConfigurationOnSuccessCb(nullptr)
159 , mSetConfigurationOnErrorCb(nullptr)
160 , mOnShutterCb(nullptr)
161 , mOnClosedCb(nullptr)
162 , mOnRecorderStateChangeCb(nullptr)
163 , mOnPreviewStateChangeCb(nullptr)
164 , mOnAutoFocusMovingCb(nullptr)
165 , mOnAutoFocusCompletedCb(nullptr)
166 , mOnFacesDetectedCb(nullptr)
167 , mWindow(aWindow)
169 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
170 mInput = new CameraPreviewMediaStream(this);
172 SetIsDOMBinding();
174 nsRefPtr<DOMCameraConfiguration> initialConfig =
175 new DOMCameraConfiguration(aInitialConfig);
177 // Create and initialize the underlying camera.
178 ICameraControl::Configuration config;
179 bool haveInitialConfig = false;
180 nsresult rv;
182 switch (aInitialConfig.mMode) {
183 case CameraMode::Picture:
184 config.mMode = ICameraControl::kPictureMode;
185 haveInitialConfig = true;
186 break;
188 case CameraMode::Video:
189 config.mMode = ICameraControl::kVideoMode;
190 haveInitialConfig = true;
191 break;
193 case CameraMode::Unspecified:
194 break;
196 default:
197 MOZ_ASSERT_UNREACHABLE("Unanticipated camera mode!");
198 break;
201 if (haveInitialConfig) {
202 config.mPreviewSize.width = aInitialConfig.mPreviewSize.mWidth;
203 config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
204 config.mRecorderProfile = aInitialConfig.mRecorderProfile;
207 mCameraControl = ICameraControl::Create(aCameraId);
208 mCurrentConfiguration = initialConfig.forget();
210 // Attach our DOM-facing media stream to our viewfinder stream.
211 SetHintContents(HINT_CONTENTS_VIDEO);
212 InitStreamCommon(mInput);
213 MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
214 if (mWindow->GetExtantDoc()) {
215 CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
218 // Register a listener for camera events.
219 mListener = new DOMCameraControlListener(this, mInput);
220 mCameraControl->AddListener(mListener);
222 // Start the camera...
223 if (haveInitialConfig) {
224 rv = mCameraControl->Start(&config);
225 } else {
226 rv = mCameraControl->Start();
228 if (NS_FAILED(rv)) {
229 mListener->OnUserError(DOMCameraControlListener::kInStartCamera, rv);
233 nsDOMCameraControl::~nsDOMCameraControl()
235 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
238 JSObject*
239 nsDOMCameraControl::WrapObject(JSContext* aCx)
241 return CameraControlBinding::Wrap(aCx, this);
244 bool
245 nsDOMCameraControl::IsWindowStillActive()
247 return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID());
250 #define THROW_IF_NO_CAMERACONTROL(...) \
251 do { \
252 if (!mCameraControl) { \
253 DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__); \
254 aRv = NS_ERROR_NOT_AVAILABLE; \
255 return __VA_ARGS__; \
257 } while (0)
259 // Setter for weighted regions: { top, bottom, left, right, weight }
260 nsresult
261 nsDOMCameraControl::Set(uint32_t aKey, const Optional<Sequence<CameraRegion> >& aValue, uint32_t aLimit)
263 if (!mCameraControl) {
264 DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
265 return NS_ERROR_NOT_AVAILABLE;
267 if (aLimit == 0) {
268 DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
269 return NS_OK;
272 nsTArray<ICameraControl::Region> regionArray;
273 if (aValue.WasPassed()) {
274 const Sequence<CameraRegion>& regions = aValue.Value();
275 uint32_t length = regions.Length();
277 DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
278 if (length > aLimit) {
279 length = aLimit;
282 // aLimit supplied by camera library provides sane ceiling (i.e. <10)
283 regionArray.SetCapacity(length);
285 for (uint32_t i = 0; i < length; ++i) {
286 ICameraControl::Region* r = regionArray.AppendElement();
287 const CameraRegion &region = regions[i];
288 r->top = region.mTop;
289 r->left = region.mLeft;
290 r->bottom = region.mBottom;
291 r->right = region.mRight;
292 r->weight = region.mWeight;
294 DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n",
296 r->top,
297 r->left,
298 r->bottom,
299 r->right,
300 r->weight
303 } else {
304 DOM_CAMERA_LOGI("%s:%d : clear regions\n", __func__, __LINE__);
306 return mCameraControl->Set(aKey, regionArray);
309 // Getter for weighted regions: { top, bottom, left, right, weight }
310 nsresult
311 nsDOMCameraControl::Get(uint32_t aKey, nsTArray<CameraRegion>& aValue)
313 if (!mCameraControl) {
314 DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
315 return NS_ERROR_NOT_AVAILABLE;
318 nsTArray<ICameraControl::Region> regionArray;
320 nsresult rv = mCameraControl->Get(aKey, regionArray);
321 NS_ENSURE_SUCCESS(rv, rv);
323 uint32_t length = regionArray.Length();
324 DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
325 aValue.SetLength(length);
327 for (uint32_t i = 0; i < length; ++i) {
328 ICameraControl::Region& r = regionArray[i];
329 CameraRegion& v = aValue[i];
330 v.mTop = r.top;
331 v.mLeft = r.left;
332 v.mBottom = r.bottom;
333 v.mRight = r.right;
334 v.mWeight = r.weight;
336 DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n",
338 v.mTop,
339 v.mLeft,
340 v.mBottom,
341 v.mRight,
342 v.mWeight
346 return NS_OK;
349 void
350 nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv)
352 THROW_IF_NO_CAMERACONTROL();
353 aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
355 void
356 nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv)
358 THROW_IF_NO_CAMERACONTROL();
359 aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
362 void
363 nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv)
365 THROW_IF_NO_CAMERACONTROL();
366 aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
368 void
369 nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv)
371 THROW_IF_NO_CAMERACONTROL();
372 aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
375 void
376 nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv)
378 THROW_IF_NO_CAMERACONTROL();
379 aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
381 void
382 nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv)
384 THROW_IF_NO_CAMERACONTROL();
385 aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
388 void
389 nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv)
391 THROW_IF_NO_CAMERACONTROL();
392 aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
394 void
395 nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv)
397 THROW_IF_NO_CAMERACONTROL();
398 aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
401 void
402 nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv)
404 THROW_IF_NO_CAMERACONTROL();
405 aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
407 void
408 nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv)
410 THROW_IF_NO_CAMERACONTROL();
411 aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
414 void
415 nsDOMCameraControl::GetIsoMode(nsString& aIsoMode, ErrorResult& aRv)
417 THROW_IF_NO_CAMERACONTROL();
418 aRv = mCameraControl->Get(CAMERA_PARAM_ISOMODE, aIsoMode);
420 void
421 nsDOMCameraControl::SetIsoMode(const nsAString& aIsoMode, ErrorResult& aRv)
423 THROW_IF_NO_CAMERACONTROL();
424 aRv = mCameraControl->Set(CAMERA_PARAM_ISOMODE, aIsoMode);
427 double
428 nsDOMCameraControl::GetPictureQuality(ErrorResult& aRv)
430 THROW_IF_NO_CAMERACONTROL(1.0);
432 double quality;
433 aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_QUALITY, quality);
434 return quality;
436 void
437 nsDOMCameraControl::SetPictureQuality(double aQuality, ErrorResult& aRv)
439 THROW_IF_NO_CAMERACONTROL();
440 aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_QUALITY, aQuality);
443 double
444 nsDOMCameraControl::GetZoom(ErrorResult& aRv)
446 THROW_IF_NO_CAMERACONTROL(1.0);
448 double zoom = 1.0;
449 aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, zoom);
450 return zoom;
453 void
454 nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv)
456 THROW_IF_NO_CAMERACONTROL();
457 aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
460 void
461 nsDOMCameraControl::GetMeteringAreas(nsTArray<CameraRegion>& aAreas, ErrorResult& aRv)
463 aRv = Get(CAMERA_PARAM_METERINGAREAS, aAreas);
465 void
466 nsDOMCameraControl::SetMeteringAreas(const Optional<Sequence<CameraRegion> >& aMeteringAreas, ErrorResult& aRv)
468 aRv = Set(CAMERA_PARAM_METERINGAREAS, aMeteringAreas,
469 mCurrentConfiguration->mMaxMeteringAreas);
472 void
473 nsDOMCameraControl::GetFocusAreas(nsTArray<CameraRegion>& aAreas, ErrorResult& aRv)
475 aRv = Get(CAMERA_PARAM_FOCUSAREAS, aAreas);
477 void
478 nsDOMCameraControl::SetFocusAreas(const Optional<Sequence<CameraRegion> >& aFocusAreas, ErrorResult& aRv)
480 aRv = Set(CAMERA_PARAM_FOCUSAREAS, aFocusAreas,
481 mCurrentConfiguration->mMaxFocusAreas);
484 void
485 nsDOMCameraControl::GetPictureSize(CameraSize& aSize, ErrorResult& aRv)
487 THROW_IF_NO_CAMERACONTROL();
489 ICameraControl::Size size;
490 aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size);
491 if (aRv.Failed()) {
492 return;
495 aSize.mWidth = size.width;
496 aSize.mHeight = size.height;
499 void
500 nsDOMCameraControl::SetPictureSize(const CameraSize& aSize, ErrorResult& aRv)
502 THROW_IF_NO_CAMERACONTROL();
504 ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
505 aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
508 void
509 nsDOMCameraControl::GetThumbnailSize(CameraSize& aSize, ErrorResult& aRv)
511 THROW_IF_NO_CAMERACONTROL();
513 ICameraControl::Size size;
514 aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size);
515 if (aRv.Failed()) {
516 return;
519 aSize.mWidth = size.width;
520 aSize.mHeight = size.height;
523 void
524 nsDOMCameraControl::SetThumbnailSize(const CameraSize& aSize, ErrorResult& aRv)
526 THROW_IF_NO_CAMERACONTROL();
528 ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
529 aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s);
532 double
533 nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
535 THROW_IF_NO_CAMERACONTROL(0.0);
537 double focalLength;
538 aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, focalLength);
539 return focalLength;
542 double
543 nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv)
545 THROW_IF_NO_CAMERACONTROL(0.0);
547 double distance;
548 aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, distance);
549 return distance;
552 double
553 nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv)
555 THROW_IF_NO_CAMERACONTROL(0.0);
557 double distance;
558 aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, distance);
559 return distance;
562 double
563 nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv)
565 THROW_IF_NO_CAMERACONTROL(0.0);
567 double distance;
568 aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, distance);
569 return distance;
572 void
573 nsDOMCameraControl::SetExposureCompensation(double aCompensation, ErrorResult& aRv)
575 THROW_IF_NO_CAMERACONTROL();
576 aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation);
579 double
580 nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
582 THROW_IF_NO_CAMERACONTROL(0.0);
584 double compensation;
585 aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
586 return compensation;
589 int32_t
590 nsDOMCameraControl::SensorAngle()
592 int32_t angle = 0;
593 if (mCameraControl) {
594 mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
596 return angle;
599 // Callback attributes
601 CameraShutterCallback*
602 nsDOMCameraControl::GetOnShutter()
604 return mOnShutterCb;
606 void
607 nsDOMCameraControl::SetOnShutter(CameraShutterCallback* aCb)
609 mOnShutterCb = aCb;
612 CameraClosedCallback*
613 nsDOMCameraControl::GetOnClosed()
615 return mOnClosedCb;
617 void
618 nsDOMCameraControl::SetOnClosed(CameraClosedCallback* aCb)
620 mOnClosedCb = aCb;
623 CameraRecorderStateChange*
624 nsDOMCameraControl::GetOnRecorderStateChange()
626 return mOnRecorderStateChangeCb;
628 void
629 nsDOMCameraControl::SetOnRecorderStateChange(CameraRecorderStateChange* aCb)
631 mOnRecorderStateChangeCb = aCb;
634 CameraPreviewStateChange*
635 nsDOMCameraControl::GetOnPreviewStateChange()
637 return mOnPreviewStateChangeCb;
639 void
640 nsDOMCameraControl::SetOnPreviewStateChange(CameraPreviewStateChange* aCb)
642 mOnPreviewStateChangeCb = aCb;
645 CameraAutoFocusMovingCallback*
646 nsDOMCameraControl::GetOnAutoFocusMoving()
648 return mOnAutoFocusMovingCb;
650 void
651 nsDOMCameraControl::SetOnAutoFocusMoving(CameraAutoFocusMovingCallback* aCb)
653 mOnAutoFocusMovingCb = aCb;
656 CameraAutoFocusCallback*
657 nsDOMCameraControl::GetOnAutoFocusCompleted()
659 return mOnAutoFocusCompletedCb;
661 void
662 nsDOMCameraControl::SetOnAutoFocusCompleted(CameraAutoFocusCallback* aCb)
664 mOnAutoFocusCompletedCb = aCb;
667 CameraFaceDetectionCallback*
668 nsDOMCameraControl::GetOnFacesDetected()
670 return mOnFacesDetectedCb;
672 void
673 nsDOMCameraControl::SetOnFacesDetected(CameraFaceDetectionCallback* aCb)
675 mOnFacesDetectedCb = aCb;
678 already_AddRefed<dom::CameraCapabilities>
679 nsDOMCameraControl::Capabilities()
681 nsRefPtr<CameraCapabilities> caps = mCapabilities;
683 if (!caps) {
684 caps = new CameraCapabilities(mWindow);
685 nsresult rv = caps->Populate(mCameraControl);
686 if (NS_FAILED(rv)) {
687 DOM_CAMERA_LOGW("Failed to populate camera capabilities (%d)\n", rv);
688 return nullptr;
690 mCapabilities = caps;
693 return caps.forget();
696 // Methods.
697 void
698 nsDOMCameraControl::StartRecording(const CameraStartRecordingOptions& aOptions,
699 nsDOMDeviceStorage& aStorageArea,
700 const nsAString& aFilename,
701 CameraStartRecordingCallback& aOnSuccess,
702 const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
703 ErrorResult& aRv)
705 NotifyRecordingStatusChange(NS_LITERAL_STRING("starting"));
707 #ifdef MOZ_B2G
708 if (!mAudioChannelAgent) {
709 mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
710 if (mAudioChannelAgent) {
711 // Camera app will stop recording when it falls to the background, so no callback is necessary.
712 mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr);
713 // Video recording doesn't output any sound, so it's not necessary to check canPlay.
714 int32_t canPlay;
715 mAudioChannelAgent->StartPlaying(&canPlay);
718 #endif
720 nsCOMPtr<nsIDOMDOMRequest> request;
721 mDSFileDescriptor = new DeviceStorageFileDescriptor();
722 aRv = aStorageArea.CreateFileDescriptor(aFilename, mDSFileDescriptor.get(),
723 getter_AddRefs(request));
724 if (aRv.Failed()) {
725 return;
728 mOptions = aOptions;
729 mStartRecordingOnSuccessCb = &aOnSuccess;
730 mStartRecordingOnErrorCb = nullptr;
731 if (aOnError.WasPassed()) {
732 mStartRecordingOnErrorCb = &aOnError.Value();
735 nsCOMPtr<nsIDOMEventListener> listener = new StartRecordingHelper(this);
736 request->AddEventListener(NS_LITERAL_STRING("success"), listener, false);
737 request->AddEventListener(NS_LITERAL_STRING("error"), listener, false);
740 void
741 nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
743 nsresult rv = NS_ERROR_FAILURE;
744 if (!mCameraControl) {
745 rv = NS_ERROR_NOT_INITIALIZED;
746 } else if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
747 ICameraControl::StartRecordingOptions o;
749 o.rotation = mOptions.mRotation;
750 o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes;
751 o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs;
752 o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch;
753 rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o);
754 if (NS_SUCCEEDED(rv)) {
755 return;
759 OnUserError(CameraControlListener::kInStartRecording, rv);
761 if (mDSFileDescriptor->mFileDescriptor.IsValid()) {
762 // An error occured. We need to manually close the file associated with the
763 // FileDescriptor, and we shouldn't do this on the main thread, so we
764 // use a little helper.
765 nsRefPtr<CloseFileRunnable> closer =
766 new CloseFileRunnable(mDSFileDescriptor->mFileDescriptor);
767 closer->Dispatch();
771 void
772 nsDOMCameraControl::StopRecording(ErrorResult& aRv)
774 THROW_IF_NO_CAMERACONTROL();
776 #ifdef MOZ_B2G
777 if (mAudioChannelAgent) {
778 mAudioChannelAgent->StopPlaying();
779 mAudioChannelAgent = nullptr;
781 #endif
783 aRv = mCameraControl->StopRecording();
786 void
787 nsDOMCameraControl::ResumePreview(ErrorResult& aRv)
789 THROW_IF_NO_CAMERACONTROL();
790 aRv = mCameraControl->StartPreview();
793 class ImmediateErrorCallback : public nsRunnable
795 public:
796 ImmediateErrorCallback(CameraErrorCallback* aCallback, const nsAString& aMessage)
797 : mCallback(aCallback)
798 , mMessage(aMessage)
801 NS_IMETHODIMP
802 Run()
804 MOZ_ASSERT(NS_IsMainThread());
805 ErrorResult ignored;
806 mCallback->Call(mMessage, ignored);
807 return NS_OK;
810 protected:
811 nsRefPtr<CameraErrorCallback> mCallback;
812 nsString mMessage;
815 void
816 nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
817 const Optional<OwningNonNull<CameraSetConfigurationCallback> >& aOnSuccess,
818 const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
819 ErrorResult& aRv)
821 if (!mCameraControl) {
822 DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
823 if (aOnError.WasPassed()) {
824 NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
825 NS_LITERAL_STRING("HardwareClosed")));
826 } else {
827 // Only throw if we don't have an error callback.
828 aRv = NS_ERROR_NOT_AVAILABLE;
830 return;
833 nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
834 if (cb) {
835 // We're busy taking a picture, can't change modes right now.
836 if (aOnError.WasPassed()) {
837 // There is already a call to TakePicture() in progress, abort this
838 // call and invoke the error callback (if one was passed in).
839 NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
840 NS_LITERAL_STRING("TakePictureInProgress")));
841 } else {
842 // Only throw if no error callback was passed in.
843 aRv = NS_ERROR_FAILURE;
845 return;
848 ICameraControl::Configuration config;
849 config.mRecorderProfile = aConfiguration.mRecorderProfile;
850 config.mPreviewSize.width = aConfiguration.mPreviewSize.mWidth;
851 config.mPreviewSize.height = aConfiguration.mPreviewSize.mHeight;
852 config.mMode = ICameraControl::kPictureMode;
853 if (aConfiguration.mMode == CameraMode::Video) {
854 config.mMode = ICameraControl::kVideoMode;
857 mSetConfigurationOnSuccessCb = nullptr;
858 if (aOnSuccess.WasPassed()) {
859 mSetConfigurationOnSuccessCb = &aOnSuccess.Value();
861 mSetConfigurationOnErrorCb = nullptr;
862 if (aOnError.WasPassed()) {
863 mSetConfigurationOnErrorCb = &aOnError.Value();
866 aRv = mCameraControl->SetConfiguration(config);
869 void
870 nsDOMCameraControl::AutoFocus(CameraAutoFocusCallback& aOnSuccess,
871 const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
872 ErrorResult& aRv)
874 if (!mCameraControl) {
875 DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
876 if (aOnError.WasPassed()) {
877 NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
878 NS_LITERAL_STRING("HardwareClosed")));
879 } else {
880 // Only throw if we don't have an error callback.
881 aRv = NS_ERROR_NOT_AVAILABLE;
883 return;
886 nsRefPtr<CameraErrorCallback> ecb = mAutoFocusOnErrorCb.forget();
887 if (ecb) {
888 // There is already a call to AutoFocus() in progress, cancel it and
889 // invoke the error callback (if one was passed in).
890 NS_DispatchToMainThread(new ImmediateErrorCallback(ecb,
891 NS_LITERAL_STRING("AutoFocusInterrupted")));
894 mAutoFocusOnSuccessCb = &aOnSuccess;
895 mAutoFocusOnErrorCb = nullptr;
896 if (aOnError.WasPassed()) {
897 mAutoFocusOnErrorCb = &aOnError.Value();
900 aRv = mCameraControl->AutoFocus();
903 void
904 nsDOMCameraControl::StartFaceDetection(ErrorResult& aRv)
906 THROW_IF_NO_CAMERACONTROL();
907 aRv = mCameraControl->StartFaceDetection();
910 void
911 nsDOMCameraControl::StopFaceDetection(ErrorResult& aRv)
913 THROW_IF_NO_CAMERACONTROL();
914 aRv = mCameraControl->StopFaceDetection();
917 void
918 nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions,
919 CameraTakePictureCallback& aOnSuccess,
920 const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
921 ErrorResult& aRv)
923 if (!mCameraControl) {
924 DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
925 if (aOnError.WasPassed()) {
926 NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
927 NS_LITERAL_STRING("HardwareClosed")));
928 } else {
929 // Only throw if we don't have an error callback.
930 aRv = NS_ERROR_NOT_AVAILABLE;
932 return;
935 nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
936 if (cb) {
937 if (aOnError.WasPassed()) {
938 // There is already a call to TakePicture() in progress, abort this new
939 // one and invoke the error callback (if one was passed in).
940 NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
941 NS_LITERAL_STRING("TakePictureAlreadyInProgress")));
942 } else {
943 // Only throw if no error callback was passed in.
944 aRv = NS_ERROR_FAILURE;
946 return;
950 ICameraControlParameterSetAutoEnter batch(mCameraControl);
952 // XXXmikeh - remove this: see bug 931155
953 ICameraControl::Size s;
954 s.width = aOptions.mPictureSize.mWidth;
955 s.height = aOptions.mPictureSize.mHeight;
957 ICameraControl::Position p;
958 p.latitude = aOptions.mPosition.mLatitude;
959 p.longitude = aOptions.mPosition.mLongitude;
960 p.altitude = aOptions.mPosition.mAltitude;
961 p.timestamp = aOptions.mPosition.mTimestamp;
963 if (s.width && s.height) {
964 mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
966 mCameraControl->Set(CAMERA_PARAM_PICTURE_ROTATION, aOptions.mRotation);
967 mCameraControl->Set(CAMERA_PARAM_PICTURE_FILEFORMAT, aOptions.mFileFormat);
968 mCameraControl->Set(CAMERA_PARAM_PICTURE_DATETIME, aOptions.mDateTime);
969 mCameraControl->SetLocation(p);
972 mTakePictureOnSuccessCb = &aOnSuccess;
973 mTakePictureOnErrorCb = nullptr;
974 if (aOnError.WasPassed()) {
975 mTakePictureOnErrorCb = &aOnError.Value();
978 aRv = mCameraControl->TakePicture();
981 void
982 nsDOMCameraControl::ReleaseHardware(const Optional<OwningNonNull<CameraReleaseCallback> >& aOnSuccess,
983 const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
984 ErrorResult& aRv)
986 if (!mCameraControl) {
987 // Always succeed if the camera instance is already closed.
988 if (aOnSuccess.WasPassed()) {
989 class Message : public nsRunnable
991 public:
992 Message(CameraReleaseCallback* aOnSuccess)
993 : mOnSuccess(aOnSuccess)
996 NS_IMETHODIMP
997 Run()
999 if (mOnSuccess) {
1000 ErrorResult ignored;
1001 mOnSuccess->Call(ignored);
1003 return NS_OK;
1006 protected:
1007 nsRefPtr<CameraReleaseCallback> mOnSuccess;
1010 NS_DispatchToMainThread(new Message(&aOnSuccess.Value()));
1012 return;
1015 mReleaseOnSuccessCb = nullptr;
1016 if (aOnSuccess.WasPassed()) {
1017 mReleaseOnSuccessCb = &aOnSuccess.Value();
1019 mReleaseOnErrorCb = nullptr;
1020 if (aOnError.WasPassed()) {
1021 mReleaseOnErrorCb = &aOnError.Value();
1024 aRv = mCameraControl->Stop();
1025 if (aRv.Failed()) {
1026 return;
1029 // Once we stop the camera, there's nothing we can do with it,
1030 // so we can throw away this reference. (This won't prevent us
1031 // from receiving the last underlying events.)
1032 mCameraControl = nullptr;
1035 void
1036 nsDOMCameraControl::ResumeContinuousFocus(ErrorResult& aRv)
1038 THROW_IF_NO_CAMERACONTROL();
1039 aRv = mCameraControl->ResumeContinuousFocus();
1042 void
1043 nsDOMCameraControl::Shutdown()
1045 DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
1047 // Remove any pending solicited event handlers; these
1048 // reference our window object, which in turn references
1049 // us. If we don't remove them, we can leak DOM objects.
1050 mGetCameraOnSuccessCb = nullptr;
1051 mGetCameraOnErrorCb = nullptr;
1052 mAutoFocusOnSuccessCb = nullptr;
1053 mAutoFocusOnErrorCb = nullptr;
1054 mTakePictureOnSuccessCb = nullptr;
1055 mTakePictureOnErrorCb = nullptr;
1056 mStartRecordingOnSuccessCb = nullptr;
1057 mStartRecordingOnErrorCb = nullptr;
1058 mReleaseOnSuccessCb = nullptr;
1059 mReleaseOnErrorCb = nullptr;
1060 mSetConfigurationOnSuccessCb = nullptr;
1061 mSetConfigurationOnErrorCb = nullptr;
1063 // Remove all of the unsolicited event handlers too.
1064 mOnShutterCb = nullptr;
1065 mOnClosedCb = nullptr;
1066 mOnRecorderStateChangeCb = nullptr;
1067 mOnPreviewStateChangeCb = nullptr;
1068 mOnAutoFocusMovingCb = nullptr;
1069 mOnAutoFocusCompletedCb = nullptr;
1070 mOnFacesDetectedCb = nullptr;
1072 if (mCameraControl) {
1073 mCameraControl->Stop();
1074 mCameraControl = nullptr;
1078 nsresult
1079 nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
1081 NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
1083 return MediaManager::NotifyRecordingStatusChange(mWindow,
1084 aMsg,
1085 true /* aIsAudio */,
1086 true /* aIsVideo */);
1089 // Camera Control event handlers--must only be called from the Main Thread!
1090 void
1091 nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState)
1093 MOZ_ASSERT(NS_IsMainThread());
1094 ErrorResult ignored;
1096 DOM_CAMERA_LOGI("DOM OnHardwareStateChange(%d)\n", aState);
1098 switch (aState) {
1099 case CameraControlListener::kHardwareOpen:
1100 // The hardware is open, so we can return a camera to JS, even if
1101 // the preview hasn't started yet.
1102 if (mGetCameraOnSuccessCb) {
1103 nsRefPtr<GetCameraCallback> cb = mGetCameraOnSuccessCb.forget();
1104 ErrorResult ignored;
1105 mGetCameraOnErrorCb = nullptr;
1106 cb->Call(*this, *mCurrentConfiguration, ignored);
1108 break;
1110 case CameraControlListener::kHardwareClosed:
1111 if (mReleaseOnSuccessCb) {
1112 // If we have this event handler, this was a solicited hardware close.
1113 nsRefPtr<CameraReleaseCallback> cb = mReleaseOnSuccessCb.forget();
1114 mReleaseOnErrorCb = nullptr;
1115 cb->Call(ignored);
1116 } else if(mOnClosedCb) {
1117 // If not, something else closed the hardware.
1118 nsRefPtr<CameraClosedCallback> cb = mOnClosedCb;
1119 cb->Call(ignored);
1121 break;
1123 default:
1124 MOZ_ASSERT_UNREACHABLE("Unanticipated camera hardware state");
1128 void
1129 nsDOMCameraControl::OnShutter()
1131 MOZ_ASSERT(NS_IsMainThread());
1133 DOM_CAMERA_LOGI("DOM ** SNAP **\n");
1135 nsRefPtr<CameraShutterCallback> cb = mOnShutterCb;
1136 if (cb) {
1137 ErrorResult ignored;
1138 cb->Call(ignored);
1142 void
1143 nsDOMCameraControl::OnPreviewStateChange(CameraControlListener::PreviewState aState)
1145 MOZ_ASSERT(NS_IsMainThread());
1147 if (!mOnPreviewStateChangeCb) {
1148 return;
1151 nsString state;
1152 switch (aState) {
1153 case CameraControlListener::kPreviewStarted:
1154 state = NS_LITERAL_STRING("started");
1155 break;
1157 default:
1158 state = NS_LITERAL_STRING("stopped");
1159 break;
1162 nsRefPtr<CameraPreviewStateChange> cb = mOnPreviewStateChangeCb;
1163 ErrorResult ignored;
1164 cb->Call(state, ignored);
1167 void
1168 nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
1169 int32_t aArg, int32_t aTrackNum)
1171 // For now, we do nothing with 'aStatus' and 'aTrackNum'.
1172 MOZ_ASSERT(NS_IsMainThread());
1174 ErrorResult ignored;
1175 nsString state;
1177 switch (aState) {
1178 case CameraControlListener::kRecorderStarted:
1179 if (mStartRecordingOnSuccessCb) {
1180 nsRefPtr<CameraStartRecordingCallback> cb = mStartRecordingOnSuccessCb.forget();
1181 mStartRecordingOnErrorCb = nullptr;
1182 cb->Call(ignored);
1184 state = NS_LITERAL_STRING("Started");
1185 break;
1187 case CameraControlListener::kRecorderStopped:
1188 NotifyRecordingStatusChange(NS_LITERAL_STRING("shutdown"));
1189 state = NS_LITERAL_STRING("Stopped");
1190 break;
1192 #ifdef MOZ_B2G_CAMERA
1193 case CameraControlListener::kFileSizeLimitReached:
1194 state = NS_LITERAL_STRING("FileSizeLimitReached");
1195 break;
1197 case CameraControlListener::kVideoLengthLimitReached:
1198 state = NS_LITERAL_STRING("VideoLengthLimitReached");
1199 break;
1201 case CameraControlListener::kTrackCompleted:
1202 state = NS_LITERAL_STRING("TrackCompleted");
1203 break;
1205 case CameraControlListener::kTrackFailed:
1206 state = NS_LITERAL_STRING("TrackFailed");
1207 break;
1209 case CameraControlListener::kMediaRecorderFailed:
1210 state = NS_LITERAL_STRING("MediaRecorderFailed");
1211 break;
1213 case CameraControlListener::kMediaServerFailed:
1214 state = NS_LITERAL_STRING("MediaServerFailed");
1215 break;
1216 #endif
1218 default:
1219 MOZ_ASSERT_UNREACHABLE("Unanticipated video recorder error");
1220 return;
1223 nsRefPtr<CameraRecorderStateChange> cb = mOnRecorderStateChangeCb;
1224 if (cb) {
1225 cb->Call(state, ignored);
1229 void
1230 nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration)
1232 MOZ_ASSERT(NS_IsMainThread());
1234 // Update our record of the current camera configuration
1235 mCurrentConfiguration = aConfiguration;
1237 DOM_CAMERA_LOGI("DOM OnConfigurationChange: this=%p\n", this);
1238 DOM_CAMERA_LOGI(" mode : %s\n",
1239 mCurrentConfiguration->mMode == CameraMode::Video ? "video" : "picture");
1240 DOM_CAMERA_LOGI(" maximum focus areas : %d\n",
1241 mCurrentConfiguration->mMaxFocusAreas);
1242 DOM_CAMERA_LOGI(" maximum metering areas : %d\n",
1243 mCurrentConfiguration->mMaxMeteringAreas);
1244 DOM_CAMERA_LOGI(" preview size (w x h) : %d x %d\n",
1245 mCurrentConfiguration->mPreviewSize.mWidth, mCurrentConfiguration->mPreviewSize.mHeight);
1246 DOM_CAMERA_LOGI(" recorder profile : %s\n",
1247 NS_ConvertUTF16toUTF8(mCurrentConfiguration->mRecorderProfile).get());
1249 nsRefPtr<CameraSetConfigurationCallback> cb = mSetConfigurationOnSuccessCb.forget();
1250 mSetConfigurationOnErrorCb = nullptr;
1251 if (cb) {
1252 ErrorResult ignored;
1253 cb->Call(*mCurrentConfiguration, ignored);
1257 void
1258 nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
1260 MOZ_ASSERT(NS_IsMainThread());
1262 nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.forget();
1263 mAutoFocusOnErrorCb = nullptr;
1264 if (cb) {
1265 ErrorResult ignored;
1266 cb->Call(aAutoFocusSucceeded, ignored);
1269 cb = mOnAutoFocusCompletedCb;
1270 if (cb) {
1271 ErrorResult ignored;
1272 cb->Call(aAutoFocusSucceeded, ignored);
1276 void
1277 nsDOMCameraControl::OnAutoFocusMoving(bool aIsMoving)
1279 MOZ_ASSERT(NS_IsMainThread());
1281 nsRefPtr<CameraAutoFocusMovingCallback> cb = mOnAutoFocusMovingCb;
1282 if (cb) {
1283 ErrorResult ignored;
1284 cb->Call(aIsMoving, ignored);
1288 void
1289 nsDOMCameraControl::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces)
1291 DOM_CAMERA_LOGI("DOM OnFacesDetected %u face(s)\n", aFaces.Length());
1292 MOZ_ASSERT(NS_IsMainThread());
1294 nsRefPtr<CameraFaceDetectionCallback> cb = mOnFacesDetectedCb;
1295 if (!cb) {
1296 return;
1299 Sequence<OwningNonNull<DOMCameraDetectedFace> > faces;
1300 uint32_t len = aFaces.Length();
1302 if (faces.SetCapacity(len)) {
1303 nsRefPtr<DOMCameraDetectedFace> f;
1304 for (uint32_t i = 0; i < len; ++i) {
1305 f = new DOMCameraDetectedFace(static_cast<DOMMediaStream*>(this), aFaces[i]);
1306 *faces.AppendElement() = f.forget().take();
1310 ErrorResult ignored;
1311 cb->Call(faces, ignored);
1314 void
1315 nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
1317 MOZ_ASSERT(NS_IsMainThread());
1319 nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget();
1320 mTakePictureOnErrorCb = nullptr;
1321 if (!cb) {
1322 // Warn because it shouldn't be possible to get here without
1323 // having passed a success callback into takePicture(), even
1324 // though we guard against a nullptr dereference.
1325 NS_WARNING("DOM Null success callback in OnTakePictureComplete()");
1326 return;
1329 ErrorResult ignored;
1330 cb->Call(aPicture, ignored);
1333 void
1334 nsDOMCameraControl::OnUserError(CameraControlListener::UserContext aContext, nsresult aError)
1336 MOZ_ASSERT(NS_IsMainThread());
1338 nsRefPtr<CameraErrorCallback> errorCb;
1340 switch (aContext) {
1341 case CameraControlListener::kInStartCamera:
1342 mGetCameraOnSuccessCb = nullptr;
1343 errorCb = mGetCameraOnErrorCb.forget();
1344 break;
1346 case CameraControlListener::kInStopCamera:
1347 mReleaseOnSuccessCb = nullptr;
1348 errorCb = mReleaseOnErrorCb.forget();
1349 break;
1351 case CameraControlListener::kInSetConfiguration:
1352 mSetConfigurationOnSuccessCb = nullptr;
1353 errorCb = mSetConfigurationOnErrorCb.forget();
1354 break;
1356 case CameraControlListener::kInAutoFocus:
1357 mAutoFocusOnSuccessCb = nullptr;
1358 errorCb = mAutoFocusOnErrorCb.forget();
1359 break;
1361 case CameraControlListener::kInTakePicture:
1362 mTakePictureOnSuccessCb = nullptr;
1363 errorCb = mTakePictureOnErrorCb.forget();
1364 break;
1366 case CameraControlListener::kInStartRecording:
1367 mStartRecordingOnSuccessCb = nullptr;
1368 errorCb = mStartRecordingOnErrorCb.forget();
1369 break;
1371 case CameraControlListener::kInStartFaceDetection:
1372 // This method doesn't have any callbacks, so all we can do is log the
1373 // failure. This only happens after the hardware has been released.
1374 NS_WARNING("Failed to start face detection");
1375 return;
1377 case CameraControlListener::kInStopFaceDetection:
1378 // This method doesn't have any callbacks, so all we can do is log the
1379 // failure. This only happens after the hardware has been released.
1380 NS_WARNING("Failed to stop face detection");
1381 return;
1383 case CameraControlListener::kInResumeContinuousFocus:
1384 // This method doesn't have any callbacks, so all we can do is log the
1385 // failure. This only happens after the hardware has been released.
1386 NS_WARNING("Failed to resume continuous focus");
1387 return;
1389 case CameraControlListener::kInStopRecording:
1390 // This method doesn't have any callbacks, so all we can do is log the
1391 // failure. This only happens after the hardware has been released.
1392 NS_WARNING("Failed to stop recording");
1393 return;
1395 case CameraControlListener::kInStartPreview:
1396 // This method doesn't have any callbacks, so all we can do is log the
1397 // failure. This only happens after the hardware has been released.
1398 NS_WARNING("Failed to (re)start preview");
1399 return;
1401 case CameraControlListener::kInStopPreview:
1402 // This method doesn't have any callbacks, so all we can do is log the
1403 // failure. This only happens after the hardware has been released.
1404 NS_WARNING("Failed to stop preview");
1405 return;
1407 case CameraControlListener::kInSetPictureSize:
1408 // This method doesn't have any callbacks, so all we can do is log the
1409 // failure. This only happens after the hardware has been released.
1410 NS_WARNING("Failed to set picture size");
1411 return;
1413 case CameraControlListener::kInSetThumbnailSize:
1414 // This method doesn't have any callbacks, so all we can do is log the
1415 // failure. This only happens after the hardware has been released.
1416 NS_WARNING("Failed to set thumbnail size");
1417 return;
1419 default:
1421 nsPrintfCString msg("Unhandled aContext=%u, aError=0x%x\n", aContext, aError);
1422 NS_WARNING(msg.get());
1424 MOZ_ASSERT_UNREACHABLE("Unhandled user error");
1425 return;
1428 if (!errorCb) {
1429 DOM_CAMERA_LOGW("DOM No error handler for aError=0x%x in aContext=%u\n",
1430 aError, aContext);
1431 return;
1434 nsString error;
1435 switch (aError) {
1436 case NS_ERROR_INVALID_ARG:
1437 error = NS_LITERAL_STRING("InvalidArgument");
1438 break;
1440 case NS_ERROR_NOT_AVAILABLE:
1441 error = NS_LITERAL_STRING("NotAvailable");
1442 break;
1444 case NS_ERROR_NOT_IMPLEMENTED:
1445 error = NS_LITERAL_STRING("NotImplemented");
1446 break;
1448 case NS_ERROR_NOT_INITIALIZED:
1449 error = NS_LITERAL_STRING("HardwareClosed");
1450 break;
1452 case NS_ERROR_ALREADY_INITIALIZED:
1453 error = NS_LITERAL_STRING("HardwareAlreadyOpen");
1454 break;
1456 case NS_ERROR_OUT_OF_MEMORY:
1457 error = NS_LITERAL_STRING("OutOfMemory");
1458 break;
1460 default:
1462 nsPrintfCString msg("Reporting aError=0x%x as generic\n", aError);
1463 NS_WARNING(msg.get());
1465 // fallthrough
1467 case NS_ERROR_FAILURE:
1468 error = NS_LITERAL_STRING("GeneralFailure");
1469 break;
1472 DOM_CAMERA_LOGI("DOM OnUserError aContext=%u, error='%s'\n", aContext,
1473 NS_ConvertUTF16toUTF8(error).get());
1474 ErrorResult ignored;
1475 errorCb->Call(error, ignored);