Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / dom / camera / CameraControlImpl.cpp
blob9a232efc1a08a37cd8b9035aa70d5785eef3f031
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 "CameraControlImpl.h"
6 #include "base/basictypes.h"
7 #include "mozilla/Assertions.h"
8 #include "mozilla/unused.h"
9 #include "nsPrintfCString.h"
10 #include "nsIWeakReferenceUtils.h"
11 #include "CameraCommon.h"
12 #include "nsGlobalWindow.h"
13 #include "DeviceStorageFileDescriptor.h"
14 #include "CameraControlListener.h"
16 using namespace mozilla;
18 /* static */ StaticRefPtr<nsIThread> CameraControlImpl::sCameraThread;
20 CameraControlImpl::CameraControlImpl()
21 : mListenerLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"))
22 , mPreviewState(CameraControlListener::kPreviewStopped)
23 , mHardwareState(CameraControlListener::kHardwareUninitialized)
24 , mHardwareStateChangeReason(NS_OK)
26 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
27 mCurrentConfiguration.mMode = ICameraControl::kUnspecifiedMode;
29 // reuse the same camera thread to conserve resources
30 nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
31 if (ct) {
32 mCameraThread = ct.forget();
33 } else {
34 nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
35 if (NS_FAILED(rv)) {
36 MOZ_CRASH("Failed to create new Camera Thread");
38 sCameraThread = mCameraThread;
41 // Care must be taken with the mListenerLock read-write lock to prevent
42 // deadlocks. Currently this is handled by ensuring that any attempts to
43 // acquire the lock for writing (as in Add/RemoveListener()) happen in a
44 // runnable dispatched to the Camera Thread--even if the method is being
45 // called from that thread. This ensures that if a registered listener
46 // (which is invoked with a read-lock) tries to call Add/RemoveListener(),
47 // the lock-for-writing attempt won't happen until the listener has
48 // completed.
50 // Multiple parallel listeners being invoked are not a problem because
51 // the read-write lock allows multiple simultaneous read-locks.
52 if (!mListenerLock) {
53 MOZ_CRASH("Out of memory getting new PRRWLock");
57 CameraControlImpl::~CameraControlImpl()
59 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
61 MOZ_ASSERT(mListenerLock, "mListenerLock missing in ~CameraControlImpl()");
62 if (mListenerLock) {
63 PR_DestroyRWLock(mListenerLock);
64 mListenerLock = nullptr;
68 void
69 CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState,
70 nsresult aReason)
72 // This callback can run on threads other than the Main Thread and
73 // the Camera Thread. On Gonk, it may be called from the camera's
74 // local binder thread, should the mediaserver process die.
75 RwLockAutoEnterRead lock(mListenerLock);
77 if (aNewState == mHardwareState) {
78 DOM_CAMERA_LOGI("OnHardwareStateChange: state did not change from %d\n", mHardwareState);
79 return;
82 #ifdef PR_LOGGING
83 const char* state[] = { "uninitialized", "closed", "open", "failed" };
84 MOZ_ASSERT(aNewState >= 0);
85 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
86 DOM_CAMERA_LOGI("New hardware state is '%s' (reason=0x%x)\n",
87 state[aNewState], aReason);
88 } else {
89 DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState);
91 #endif
93 mHardwareState = aNewState;
94 mHardwareStateChangeReason = aReason;
96 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
97 CameraControlListener* l = mListeners[i];
98 l->OnHardwareStateChange(mHardwareState, mHardwareStateChangeReason);
102 void
103 CameraControlImpl::OnConfigurationChange()
105 MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
106 RwLockAutoEnterRead lock(mListenerLock);
108 DOM_CAMERA_LOGI("OnConfigurationChange : %zu listeners\n", mListeners.Length());
110 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
111 CameraControlListener* l = mListeners[i];
112 l->OnConfigurationChange(mCurrentConfiguration);
116 void
117 CameraControlImpl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
119 // This callback can run on threads other than the Main Thread and
120 // the Camera Thread. On Gonk, it is called from the camera
121 // library's auto focus thread.
122 RwLockAutoEnterRead lock(mListenerLock);
124 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
125 CameraControlListener* l = mListeners[i];
126 l->OnAutoFocusComplete(aAutoFocusSucceeded);
130 void
131 CameraControlImpl::OnAutoFocusMoving(bool aIsMoving)
133 RwLockAutoEnterRead lock(mListenerLock);
135 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
136 CameraControlListener* l = mListeners[i];
137 l->OnAutoFocusMoving(aIsMoving);
141 void
142 CameraControlImpl::OnFacesDetected(const nsTArray<Face>& aFaces)
144 // This callback can run on threads other than the Main Thread and
145 // the Camera Thread. On Gonk, it is called from the camera
146 // library's face detection thread.
147 RwLockAutoEnterRead lock(mListenerLock);
149 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
150 CameraControlListener* l = mListeners[i];
151 l->OnFacesDetected(aFaces);
155 void
156 CameraControlImpl::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
158 // This callback can run on threads other than the Main Thread and
159 // the Camera Thread. On Gonk, it is called from the camera
160 // library's snapshot thread.
161 RwLockAutoEnterRead lock(mListenerLock);
163 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
164 CameraControlListener* l = mListeners[i];
165 l->OnTakePictureComplete(aData, aLength, aMimeType);
169 void
170 CameraControlImpl::OnShutter()
172 // This callback can run on threads other than the Main Thread and
173 // the Camera Thread. On Gonk, it is called from the camera driver's
174 // preview thread.
175 RwLockAutoEnterRead lock(mListenerLock);
177 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
178 CameraControlListener* l = mListeners[i];
179 l->OnShutter();
183 void
184 CameraControlImpl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
185 int32_t aStatus, int32_t aTrackNumber)
187 // This callback can run on threads other than the Main Thread and
188 // the Camera Thread. On Gonk, it is called from the media encoder
189 // thread.
190 RwLockAutoEnterRead lock(mListenerLock);
192 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
193 CameraControlListener* l = mListeners[i];
194 l->OnRecorderStateChange(aState, aStatus, aTrackNumber);
198 void
199 CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNewState)
201 // This callback runs on the Main Thread and the Camera Thread, and
202 // may run on the local binder thread, should the mediaserver
203 // process die.
204 RwLockAutoEnterRead lock(mListenerLock);
206 if (aNewState == mPreviewState) {
207 DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState);
208 return;
211 #ifdef PR_LOGGING
212 const char* state[] = { "stopped", "paused", "started" };
213 MOZ_ASSERT(aNewState >= 0);
214 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
215 DOM_CAMERA_LOGI("New preview state is '%s'\n", state[aNewState]);
216 } else {
217 DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState);
219 #endif
221 mPreviewState = aNewState;
223 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
224 CameraControlListener* l = mListeners[i];
225 l->OnPreviewStateChange(mPreviewState);
229 void
230 CameraControlImpl::OnRateLimitPreview(bool aLimit)
232 // This function runs on neither the Main Thread nor the Camera Thread.
233 RwLockAutoEnterRead lock(mListenerLock);
235 DOM_CAMERA_LOGI("OnRateLimitPreview: %d\n", aLimit);
237 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
238 CameraControlListener* l = mListeners[i];
239 l->OnRateLimitPreview(aLimit);
243 bool
244 CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
246 // This function runs on neither the Main Thread nor the Camera Thread.
247 // On Gonk, it is called from the camera driver's preview thread.
248 RwLockAutoEnterRead lock(mListenerLock);
250 DOM_CAMERA_LOGI("OnNewPreviewFrame: we have %zu preview frame listener(s)\n",
251 mListeners.Length());
253 bool consumed = false;
255 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
256 CameraControlListener* l = mListeners[i];
257 consumed = l->OnNewPreviewFrame(aImage, aWidth, aHeight) || consumed;
259 return consumed;
262 void
263 CameraControlImpl::OnUserError(CameraControlListener::UserContext aContext,
264 nsresult aError)
266 // This callback can run on threads other than the Main Thread and
267 // the Camera Thread.
268 RwLockAutoEnterRead lock(mListenerLock);
270 #ifdef PR_LOGGING
271 const char* context[] = {
272 "StartCamera",
273 "StopCamera",
274 "AutoFocus",
275 "StartFaceDetection",
276 "StopFaceDetection",
277 "TakePicture",
278 "StartRecording",
279 "StopRecording",
280 "SetConfiguration",
281 "StartPreview",
282 "StopPreview",
283 "SetPictureSize",
284 "SetThumbnailSize",
285 "ResumeContinuousFocus",
286 "Unspecified"
288 if (static_cast<size_t>(aContext) < sizeof(context) / sizeof(context[0])) {
289 DOM_CAMERA_LOGW("CameraControlImpl::OnUserError : aContext='%s' (%d), aError=0x%x\n",
290 context[aContext], aContext, aError);
291 } else {
292 DOM_CAMERA_LOGE("CameraControlImpl::OnUserError : aContext=%d, aError=0x%x\n",
293 aContext, aError);
295 #endif
297 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
298 CameraControlListener* l = mListeners[i];
299 l->OnUserError(aContext, aError);
303 void
304 CameraControlImpl::OnSystemError(CameraControlListener::SystemContext aContext,
305 nsresult aError)
307 // This callback can run on threads other than the Main Thread and
308 // the Camera Thread.
309 RwLockAutoEnterRead lock(mListenerLock);
311 #ifdef PR_LOGGING
312 const char* context[] = {
313 "Camera Service"
315 if (static_cast<size_t>(aContext) < sizeof(context) / sizeof(context[0])) {
316 DOM_CAMERA_LOGW("CameraControlImpl::OnSystemError : aContext='%s' (%d), aError=0x%x\n",
317 context[aContext], aContext, aError);
318 } else {
319 DOM_CAMERA_LOGE("CameraControlImpl::OnSystemError : aContext=%d, aError=0x%x\n",
320 aContext, aError);
322 #endif
324 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
325 CameraControlListener* l = mListeners[i];
326 l->OnSystemError(aContext, aError);
330 // Camera control asynchronous message; these are dispatched from
331 // the Main Thread to the Camera Thread, where they are consumed.
333 class CameraControlImpl::ControlMessage : public nsRunnable
335 public:
336 ControlMessage(CameraControlImpl* aCameraControl,
337 CameraControlListener::UserContext aContext)
338 : mCameraControl(aCameraControl)
339 , mContext(aContext)
342 virtual nsresult RunImpl() = 0;
344 NS_IMETHOD
345 Run() MOZ_OVERRIDE
347 MOZ_ASSERT(mCameraControl);
348 MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl->mCameraThread);
350 nsresult rv = RunImpl();
351 if (NS_FAILED(rv)) {
352 nsPrintfCString msg("Camera control API(%d) failed with 0x%x", mContext, rv);
353 NS_WARNING(msg.get());
354 mCameraControl->OnUserError(mContext, rv);
357 return NS_OK;
360 protected:
361 virtual ~ControlMessage() { }
363 nsRefPtr<CameraControlImpl> mCameraControl;
364 CameraControlListener::UserContext mContext;
367 nsresult
368 CameraControlImpl::Dispatch(ControlMessage* aMessage)
370 nsresult rv = mCameraThread->Dispatch(aMessage, NS_DISPATCH_NORMAL);
371 if (NS_SUCCEEDED(rv)) {
372 return NS_OK;
375 nsPrintfCString msg("Failed to dispatch camera control message (0x%x)", rv);
376 NS_WARNING(msg.get());
377 return NS_ERROR_FAILURE;
380 nsresult
381 CameraControlImpl::Start(const Configuration* aConfig)
383 class Message : public ControlMessage
385 public:
386 Message(CameraControlImpl* aCameraControl,
387 CameraControlListener::UserContext aContext,
388 const Configuration* aConfig)
389 : ControlMessage(aCameraControl, aContext)
390 , mHaveInitialConfig(false)
392 if (aConfig) {
393 mConfig = *aConfig;
394 mHaveInitialConfig = true;
398 nsresult
399 RunImpl() MOZ_OVERRIDE
401 if (mHaveInitialConfig) {
402 return mCameraControl->StartImpl(&mConfig);
404 return mCameraControl->StartImpl();
407 protected:
408 bool mHaveInitialConfig;
409 Configuration mConfig;
412 return Dispatch(new Message(this, CameraControlListener::kInStartCamera, aConfig));
415 nsresult
416 CameraControlImpl::SetConfiguration(const Configuration& aConfig)
418 class Message : public ControlMessage
420 public:
421 Message(CameraControlImpl* aCameraControl,
422 CameraControlListener::UserContext aContext,
423 const Configuration& aConfig)
424 : ControlMessage(aCameraControl, aContext)
425 , mConfig(aConfig)
428 nsresult
429 RunImpl() MOZ_OVERRIDE
431 return mCameraControl->SetConfigurationImpl(mConfig);
434 protected:
435 Configuration mConfig;
438 return Dispatch(new Message(this, CameraControlListener::kInSetConfiguration, aConfig));
441 nsresult
442 CameraControlImpl::AutoFocus()
444 class Message : public ControlMessage
446 public:
447 Message(CameraControlImpl* aCameraControl,
448 CameraControlListener::UserContext aContext)
449 : ControlMessage(aCameraControl, aContext)
452 nsresult
453 RunImpl() MOZ_OVERRIDE
455 return mCameraControl->AutoFocusImpl();
459 return Dispatch(new Message(this, CameraControlListener::kInAutoFocus));
462 nsresult
463 CameraControlImpl::StartFaceDetection()
465 class Message : public ControlMessage
467 public:
468 Message(CameraControlImpl* aCameraControl,
469 CameraControlListener::UserContext aContext)
470 : ControlMessage(aCameraControl, aContext)
473 nsresult
474 RunImpl() MOZ_OVERRIDE
476 return mCameraControl->StartFaceDetectionImpl();
480 return Dispatch(new Message(this, CameraControlListener::kInStartFaceDetection));
483 nsresult
484 CameraControlImpl::StopFaceDetection()
486 class Message : public ControlMessage
488 public:
489 Message(CameraControlImpl* aCameraControl,
490 CameraControlListener::UserContext aContext)
491 : ControlMessage(aCameraControl, aContext)
494 nsresult
495 RunImpl() MOZ_OVERRIDE
497 return mCameraControl->StopFaceDetectionImpl();
501 return Dispatch(new Message(this, CameraControlListener::kInStopFaceDetection));
504 nsresult
505 CameraControlImpl::TakePicture()
507 class Message : public ControlMessage
509 public:
510 Message(CameraControlImpl* aCameraControl,
511 CameraControlListener::UserContext aContext)
512 : ControlMessage(aCameraControl, aContext)
515 nsresult
516 RunImpl() MOZ_OVERRIDE
518 return mCameraControl->TakePictureImpl();
522 return Dispatch(new Message(this, CameraControlListener::kInTakePicture));
525 nsresult
526 CameraControlImpl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
527 const StartRecordingOptions* aOptions)
529 class Message : public ControlMessage
531 public:
532 Message(CameraControlImpl* aCameraControl,
533 CameraControlListener::UserContext aContext,
534 const StartRecordingOptions* aOptions,
535 DeviceStorageFileDescriptor* aFileDescriptor)
536 : ControlMessage(aCameraControl, aContext)
537 , mOptionsPassed(false)
538 , mFileDescriptor(aFileDescriptor)
540 if (aOptions) {
541 mOptions = *aOptions;
542 mOptionsPassed = true;
546 nsresult
547 RunImpl() MOZ_OVERRIDE
549 return mCameraControl->StartRecordingImpl(mFileDescriptor,
550 mOptionsPassed ? &mOptions : nullptr);
553 protected:
554 StartRecordingOptions mOptions;
555 bool mOptionsPassed;
556 nsRefPtr<DeviceStorageFileDescriptor> mFileDescriptor;
559 if (!aFileDescriptor) {
560 return NS_ERROR_INVALID_ARG;
562 return Dispatch(new Message(this, CameraControlListener::kInStartRecording,
563 aOptions, aFileDescriptor));
566 nsresult
567 CameraControlImpl::StopRecording()
569 class Message : public ControlMessage
571 public:
572 Message(CameraControlImpl* aCameraControl,
573 CameraControlListener::UserContext aContext)
574 : ControlMessage(aCameraControl, aContext)
577 nsresult
578 RunImpl() MOZ_OVERRIDE
580 return mCameraControl->StopRecordingImpl();
584 return Dispatch(new Message(this, CameraControlListener::kInStopRecording));
587 nsresult
588 CameraControlImpl::StartPreview()
590 class Message : public ControlMessage
592 public:
593 Message(CameraControlImpl* aCameraControl,
594 CameraControlListener::UserContext aContext)
595 : ControlMessage(aCameraControl, aContext)
598 nsresult
599 RunImpl() MOZ_OVERRIDE
601 return mCameraControl->StartPreviewImpl();
605 return Dispatch(new Message(this, CameraControlListener::kInStartPreview));
608 nsresult
609 CameraControlImpl::StopPreview()
611 class Message : public ControlMessage
613 public:
614 Message(CameraControlImpl* aCameraControl,
615 CameraControlListener::UserContext aContext)
616 : ControlMessage(aCameraControl, aContext)
619 nsresult
620 RunImpl() MOZ_OVERRIDE
622 return mCameraControl->StopPreviewImpl();
626 return Dispatch(new Message(this, CameraControlListener::kInStopPreview));
629 nsresult
630 CameraControlImpl::ResumeContinuousFocus()
632 class Message : public ControlMessage
634 public:
635 Message(CameraControlImpl* aCameraControl,
636 CameraControlListener::UserContext aContext)
637 : ControlMessage(aCameraControl, aContext)
640 nsresult
641 RunImpl() MOZ_OVERRIDE
643 return mCameraControl->ResumeContinuousFocusImpl();
647 return Dispatch(new Message(this, CameraControlListener::kInResumeContinuousFocus));
650 nsresult
651 CameraControlImpl::Stop()
653 class Message : public ControlMessage
655 public:
656 Message(CameraControlImpl* aCameraControl,
657 CameraControlListener::UserContext aContext)
658 : ControlMessage(aCameraControl, aContext)
661 nsresult
662 RunImpl() MOZ_OVERRIDE
664 return mCameraControl->StopImpl();
668 return Dispatch(new Message(this, CameraControlListener::kInStopCamera));
671 class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage
673 public:
674 ListenerMessage(CameraControlImpl* aCameraControl,
675 CameraControlListener* aListener)
676 : ControlMessage(aCameraControl, CameraControlListener::kInUnspecified)
677 , mListener(aListener)
680 protected:
681 nsRefPtr<CameraControlListener> mListener;
684 void
685 CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aListener)
687 RwLockAutoEnterWrite lock(mListenerLock);
689 CameraControlListener* l = *mListeners.AppendElement() = aListener;
690 DOM_CAMERA_LOGI("Added camera control listener %p\n", l);
692 // Update the newly-added listener's state
693 l->OnConfigurationChange(mCurrentConfiguration);
694 l->OnHardwareStateChange(mHardwareState, mHardwareStateChangeReason);
695 l->OnPreviewStateChange(mPreviewState);
698 void
699 CameraControlImpl::AddListener(CameraControlListener* aListener)
701 class Message : public ListenerMessage
703 public:
704 Message(CameraControlImpl* aCameraControl,
705 CameraControlListener* aListener)
706 : ListenerMessage(aCameraControl, aListener)
709 nsresult
710 RunImpl() MOZ_OVERRIDE
712 mCameraControl->AddListenerImpl(mListener.forget());
713 return NS_OK;
717 if (aListener) {
718 Dispatch(new Message(this, aListener));
722 void
723 CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener)
725 RwLockAutoEnterWrite lock(mListenerLock);
727 nsRefPtr<CameraControlListener> l(aListener);
728 mListeners.RemoveElement(l);
729 DOM_CAMERA_LOGI("Removed camera control listener %p\n", l.get());
730 // XXXmikeh - do we want to notify the listener that it has been removed?
733 void
734 CameraControlImpl::RemoveListener(CameraControlListener* aListener)
736 class Message : public ListenerMessage
738 public:
739 Message(CameraControlImpl* aCameraControl, CameraControlListener* aListener)
740 : ListenerMessage(aCameraControl, aListener)
743 nsresult
744 RunImpl() MOZ_OVERRIDE
746 mCameraControl->RemoveListenerImpl(mListener);
747 return NS_OK;
751 if (aListener) {
752 Dispatch(new Message(this, aListener));