Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / camera / CameraControlImpl.cpp
blobc0de63f5ed2f5167a66a7b3ab1747baf847583b4
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 "CameraRecorderProfiles.h"
12 #include "CameraCommon.h"
13 #include "nsGlobalWindow.h"
14 #include "DeviceStorageFileDescriptor.h"
15 #include "CameraControlListener.h"
17 using namespace mozilla;
19 /* static */ StaticRefPtr<nsIThread> CameraControlImpl::sCameraThread;
21 CameraControlImpl::CameraControlImpl()
22 : mListenerLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"))
23 , mPreviewState(CameraControlListener::kPreviewStopped)
24 , mHardwareState(CameraControlListener::kHardwareClosed)
26 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
28 // reuse the same camera thread to conserve resources
29 nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
30 if (ct) {
31 mCameraThread = ct.forget();
32 } else {
33 nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
34 if (NS_FAILED(rv)) {
35 MOZ_CRASH("Failed to create new Camera Thread");
38 // keep a weak reference to the new thread
39 sCameraThread = mCameraThread;
42 // Care must be taken with the mListenerLock read-write lock to prevent
43 // deadlocks. Currently this is handled by ensuring that any attempts to
44 // acquire the lock for writing (as in Add/RemoveListener()) happen in a
45 // runnable dispatched to the Camera Thread--even if the method is being
46 // called from that thread. This ensures that if a registered listener
47 // (which is invoked with a read-lock) tries to call Add/RemoveListener(),
48 // the lock-for-writing attempt won't happen until the listener has
49 // completed.
51 // Multiple parallel listeners being invoked are not a problem because
52 // the read-write lock allows multiple simultaneous read-locks.
53 if (!mListenerLock) {
54 MOZ_CRASH("Out of memory getting new PRRWLock");
58 CameraControlImpl::~CameraControlImpl()
60 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
62 MOZ_ASSERT(mListenerLock, "mListenerLock missing in ~CameraControlImpl()");
63 if (mListenerLock) {
64 PR_DestroyRWLock(mListenerLock);
65 mListenerLock = nullptr;
69 already_AddRefed<RecorderProfileManager>
70 CameraControlImpl::GetRecorderProfileManager()
72 return GetRecorderProfileManagerImpl();
75 void
76 CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState)
78 // This callback can run on threads other than the Main Thread and
79 // the Camera Thread. On Gonk, it may be called from the camera's
80 // local binder thread, should the mediaserver process die.
81 RwLockAutoEnterRead lock(mListenerLock);
83 if (aNewState == mHardwareState) {
84 DOM_CAMERA_LOGI("OnHardwareStateChange: state did not change from %d\n", mHardwareState);
85 return;
88 #ifdef PR_LOGGING
89 const char* state[] = { "open", "closed", "failed" };
90 MOZ_ASSERT(aNewState >= 0);
91 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
92 DOM_CAMERA_LOGI("New hardware state is '%s'\n", state[aNewState]);
93 } else {
94 DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState);
96 #endif
98 mHardwareState = aNewState;
100 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
101 CameraControlListener* l = mListeners[i];
102 l->OnHardwareStateChange(mHardwareState);
106 void
107 CameraControlImpl::OnConfigurationChange()
109 MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
110 RwLockAutoEnterRead lock(mListenerLock);
112 DOM_CAMERA_LOGI("OnConfigurationChange : %d listeners\n", mListeners.Length());
114 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
115 CameraControlListener* l = mListeners[i];
116 l->OnConfigurationChange(mCurrentConfiguration);
120 void
121 CameraControlImpl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
123 // This callback can run on threads other than the Main Thread and
124 // the Camera Thread. On Gonk, it is called from the camera
125 // library's auto focus thread.
126 RwLockAutoEnterRead lock(mListenerLock);
128 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
129 CameraControlListener* l = mListeners[i];
130 l->OnAutoFocusComplete(aAutoFocusSucceeded);
134 void
135 CameraControlImpl::OnAutoFocusMoving(bool aIsMoving)
137 RwLockAutoEnterRead lock(mListenerLock);
139 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
140 CameraControlListener* l = mListeners[i];
141 l->OnAutoFocusMoving(aIsMoving);
145 void
146 CameraControlImpl::OnFacesDetected(const nsTArray<Face>& aFaces)
148 // This callback can run on threads other than the Main Thread and
149 // the Camera Thread. On Gonk, it is called from the camera
150 // library's face detection thread.
151 RwLockAutoEnterRead lock(mListenerLock);
153 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
154 CameraControlListener* l = mListeners[i];
155 l->OnFacesDetected(aFaces);
159 void
160 CameraControlImpl::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
162 // This callback can run on threads other than the Main Thread and
163 // the Camera Thread. On Gonk, it is called from the camera
164 // library's snapshot thread.
165 RwLockAutoEnterRead lock(mListenerLock);
167 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
168 CameraControlListener* l = mListeners[i];
169 l->OnTakePictureComplete(aData, aLength, aMimeType);
173 void
174 CameraControlImpl::OnShutter()
176 // This callback can run on threads other than the Main Thread and
177 // the Camera Thread. On Gonk, it is called from the camera driver's
178 // preview thread.
179 RwLockAutoEnterRead lock(mListenerLock);
181 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
182 CameraControlListener* l = mListeners[i];
183 l->OnShutter();
187 void
188 CameraControlImpl::OnClosed()
190 // This callback can run on threads other than the Main Thread and
191 // the Camera Thread.
192 RwLockAutoEnterRead lock(mListenerLock);
194 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
195 CameraControlListener* l = mListeners[i];
196 l->OnHardwareStateChange(CameraControlListener::kHardwareClosed);
200 void
201 CameraControlImpl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
202 int32_t aStatus, int32_t aTrackNumber)
204 // This callback can run on threads other than the Main Thread and
205 // the Camera Thread. On Gonk, it is called from the media encoder
206 // thread.
207 RwLockAutoEnterRead lock(mListenerLock);
209 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
210 CameraControlListener* l = mListeners[i];
211 l->OnRecorderStateChange(aState, aStatus, aTrackNumber);
215 void
216 CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNewState)
218 // This callback runs on the Main Thread and the Camera Thread, and
219 // may run on the local binder thread, should the mediaserver
220 // process die.
221 RwLockAutoEnterRead lock(mListenerLock);
223 if (aNewState == mPreviewState) {
224 DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState);
225 return;
228 #ifdef PR_LOGGING
229 const char* state[] = { "stopped", "paused", "started" };
230 MOZ_ASSERT(aNewState >= 0);
231 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
232 DOM_CAMERA_LOGI("New preview state is '%s'\n", state[aNewState]);
233 } else {
234 DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState);
236 #endif
238 mPreviewState = aNewState;
240 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
241 CameraControlListener* l = mListeners[i];
242 l->OnPreviewStateChange(mPreviewState);
246 void
247 CameraControlImpl::OnRateLimitPreview(bool aLimit)
249 // This function runs on neither the Main Thread nor the Camera Thread.
250 RwLockAutoEnterRead lock(mListenerLock);
252 DOM_CAMERA_LOGI("OnRateLimitPreview: %d\n", aLimit);
254 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
255 CameraControlListener* l = mListeners[i];
256 l->OnRateLimitPreview(aLimit);
260 bool
261 CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
263 // This function runs on neither the Main Thread nor the Camera Thread.
264 // On Gonk, it is called from the camera driver's preview thread.
265 RwLockAutoEnterRead lock(mListenerLock);
267 DOM_CAMERA_LOGI("OnNewPreviewFrame: we have %d preview frame listener(s)\n",
268 mListeners.Length());
270 bool consumed = false;
272 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
273 CameraControlListener* l = mListeners[i];
274 consumed = l->OnNewPreviewFrame(aImage, aWidth, aHeight) || consumed;
276 return consumed;
279 void
280 CameraControlImpl::OnUserError(CameraControlListener::UserContext aContext,
281 nsresult aError)
283 // This callback can run on threads other than the Main Thread and
284 // the Camera Thread.
285 RwLockAutoEnterRead lock(mListenerLock);
287 #ifdef PR_LOGGING
288 const char* context[] = {
289 "StartCamera",
290 "StopCamera",
291 "AutoFocus",
292 "StartFaceDetection",
293 "StopFaceDetection",
294 "TakePicture",
295 "StartRecording",
296 "StopRecording",
297 "SetConfiguration",
298 "StartPreview",
299 "StopPreview",
300 "SetPictureSize",
301 "SetThumbnailSize",
302 "ResumeContinuousFocus",
303 "Unspecified"
305 if (static_cast<size_t>(aContext) < sizeof(context) / sizeof(context[0])) {
306 DOM_CAMERA_LOGW("CameraControlImpl::OnUserError : aContext='%s' (%d), aError=0x%x\n",
307 context[aContext], aContext, aError);
308 } else {
309 DOM_CAMERA_LOGE("CameraControlImpl::OnUserError : aContext=%d, aError=0x%x\n",
310 aContext, aError);
312 #endif
314 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
315 CameraControlListener* l = mListeners[i];
316 l->OnUserError(aContext, aError);
320 void
321 CameraControlImpl::OnSystemError(CameraControlListener::SystemContext aContext,
322 nsresult aError)
324 // This callback can run on threads other than the Main Thread and
325 // the Camera Thread.
326 RwLockAutoEnterRead lock(mListenerLock);
328 #ifdef PR_LOGGING
329 const char* context[] = {
330 "Camera Service"
332 if (static_cast<size_t>(aContext) < sizeof(context) / sizeof(context[0])) {
333 DOM_CAMERA_LOGW("CameraControlImpl::OnSystemError : aContext='%s' (%d), aError=0x%x\n",
334 context[aContext], aContext, aError);
335 } else {
336 DOM_CAMERA_LOGE("CameraControlImpl::OnSystemError : aContext=%d, aError=0x%x\n",
337 aContext, aError);
339 #endif
341 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
342 CameraControlListener* l = mListeners[i];
343 l->OnSystemError(aContext, aError);
347 // Camera control asynchronous message; these are dispatched from
348 // the Main Thread to the Camera Thread, where they are consumed.
350 class CameraControlImpl::ControlMessage : public nsRunnable
352 public:
353 ControlMessage(CameraControlImpl* aCameraControl,
354 CameraControlListener::UserContext aContext)
355 : mCameraControl(aCameraControl)
356 , mContext(aContext)
359 virtual nsresult RunImpl() = 0;
361 NS_IMETHOD
362 Run() MOZ_OVERRIDE
364 MOZ_ASSERT(mCameraControl);
365 MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl->mCameraThread);
367 nsresult rv = RunImpl();
368 if (NS_FAILED(rv)) {
369 nsPrintfCString msg("Camera control API(%d) failed with 0x%x", mContext, rv);
370 NS_WARNING(msg.get());
371 mCameraControl->OnUserError(mContext, rv);
374 return NS_OK;
377 protected:
378 virtual ~ControlMessage() { }
380 nsRefPtr<CameraControlImpl> mCameraControl;
381 CameraControlListener::UserContext mContext;
384 nsresult
385 CameraControlImpl::Dispatch(ControlMessage* aMessage)
387 nsresult rv = mCameraThread->Dispatch(aMessage, NS_DISPATCH_NORMAL);
388 if (NS_SUCCEEDED(rv)) {
389 return NS_OK;
392 nsPrintfCString msg("Failed to dispatch camera control message (0x%x)", rv);
393 NS_WARNING(msg.get());
394 return NS_ERROR_FAILURE;
397 nsresult
398 CameraControlImpl::Start(const Configuration* aConfig)
400 class Message : public ControlMessage
402 public:
403 Message(CameraControlImpl* aCameraControl,
404 CameraControlListener::UserContext aContext,
405 const Configuration* aConfig)
406 : ControlMessage(aCameraControl, aContext)
407 , mHaveInitialConfig(false)
409 if (aConfig) {
410 mConfig = *aConfig;
411 mHaveInitialConfig = true;
415 nsresult
416 RunImpl() MOZ_OVERRIDE
418 if (mHaveInitialConfig) {
419 return mCameraControl->StartImpl(&mConfig);
421 return mCameraControl->StartImpl();
424 protected:
425 bool mHaveInitialConfig;
426 Configuration mConfig;
429 return Dispatch(new Message(this, CameraControlListener::kInStartCamera, aConfig));
432 nsresult
433 CameraControlImpl::SetConfiguration(const Configuration& aConfig)
435 class Message : public ControlMessage
437 public:
438 Message(CameraControlImpl* aCameraControl,
439 CameraControlListener::UserContext aContext,
440 const Configuration& aConfig)
441 : ControlMessage(aCameraControl, aContext)
442 , mConfig(aConfig)
445 nsresult
446 RunImpl() MOZ_OVERRIDE
448 return mCameraControl->SetConfigurationImpl(mConfig);
451 protected:
452 Configuration mConfig;
455 return Dispatch(new Message(this, CameraControlListener::kInSetConfiguration, aConfig));
458 nsresult
459 CameraControlImpl::AutoFocus()
461 class Message : public ControlMessage
463 public:
464 Message(CameraControlImpl* aCameraControl,
465 CameraControlListener::UserContext aContext)
466 : ControlMessage(aCameraControl, aContext)
469 nsresult
470 RunImpl() MOZ_OVERRIDE
472 return mCameraControl->AutoFocusImpl();
476 return Dispatch(new Message(this, CameraControlListener::kInAutoFocus));
479 nsresult
480 CameraControlImpl::StartFaceDetection()
482 class Message : public ControlMessage
484 public:
485 Message(CameraControlImpl* aCameraControl,
486 CameraControlListener::UserContext aContext)
487 : ControlMessage(aCameraControl, aContext)
490 nsresult
491 RunImpl() MOZ_OVERRIDE
493 return mCameraControl->StartFaceDetectionImpl();
497 return Dispatch(new Message(this, CameraControlListener::kInStartFaceDetection));
500 nsresult
501 CameraControlImpl::StopFaceDetection()
503 class Message : public ControlMessage
505 public:
506 Message(CameraControlImpl* aCameraControl,
507 CameraControlListener::UserContext aContext)
508 : ControlMessage(aCameraControl, aContext)
511 nsresult
512 RunImpl() MOZ_OVERRIDE
514 return mCameraControl->StopFaceDetectionImpl();
518 return Dispatch(new Message(this, CameraControlListener::kInStopFaceDetection));
521 nsresult
522 CameraControlImpl::TakePicture()
524 class Message : public ControlMessage
526 public:
527 Message(CameraControlImpl* aCameraControl,
528 CameraControlListener::UserContext aContext)
529 : ControlMessage(aCameraControl, aContext)
532 nsresult
533 RunImpl() MOZ_OVERRIDE
535 return mCameraControl->TakePictureImpl();
539 return Dispatch(new Message(this, CameraControlListener::kInTakePicture));
542 nsresult
543 CameraControlImpl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
544 const StartRecordingOptions* aOptions)
546 class Message : public ControlMessage
548 public:
549 Message(CameraControlImpl* aCameraControl,
550 CameraControlListener::UserContext aContext,
551 const StartRecordingOptions* aOptions,
552 DeviceStorageFileDescriptor* aFileDescriptor)
553 : ControlMessage(aCameraControl, aContext)
554 , mOptionsPassed(false)
555 , mFileDescriptor(aFileDescriptor)
557 if (aOptions) {
558 mOptions = *aOptions;
559 mOptionsPassed = true;
563 nsresult
564 RunImpl() MOZ_OVERRIDE
566 return mCameraControl->StartRecordingImpl(mFileDescriptor,
567 mOptionsPassed ? &mOptions : nullptr);
570 protected:
571 StartRecordingOptions mOptions;
572 bool mOptionsPassed;
573 nsRefPtr<DeviceStorageFileDescriptor> mFileDescriptor;
576 if (!aFileDescriptor) {
577 return NS_ERROR_INVALID_ARG;
579 return Dispatch(new Message(this, CameraControlListener::kInStartRecording,
580 aOptions, aFileDescriptor));
583 nsresult
584 CameraControlImpl::StopRecording()
586 class Message : public ControlMessage
588 public:
589 Message(CameraControlImpl* aCameraControl,
590 CameraControlListener::UserContext aContext)
591 : ControlMessage(aCameraControl, aContext)
594 nsresult
595 RunImpl() MOZ_OVERRIDE
597 return mCameraControl->StopRecordingImpl();
601 return Dispatch(new Message(this, CameraControlListener::kInStopRecording));
604 nsresult
605 CameraControlImpl::StartPreview()
607 class Message : public ControlMessage
609 public:
610 Message(CameraControlImpl* aCameraControl,
611 CameraControlListener::UserContext aContext)
612 : ControlMessage(aCameraControl, aContext)
615 nsresult
616 RunImpl() MOZ_OVERRIDE
618 return mCameraControl->StartPreviewImpl();
622 return Dispatch(new Message(this, CameraControlListener::kInStartPreview));
625 nsresult
626 CameraControlImpl::StopPreview()
628 class Message : public ControlMessage
630 public:
631 Message(CameraControlImpl* aCameraControl,
632 CameraControlListener::UserContext aContext)
633 : ControlMessage(aCameraControl, aContext)
636 nsresult
637 RunImpl() MOZ_OVERRIDE
639 return mCameraControl->StopPreviewImpl();
643 return Dispatch(new Message(this, CameraControlListener::kInStopPreview));
646 nsresult
647 CameraControlImpl::ResumeContinuousFocus()
649 class Message : public ControlMessage
651 public:
652 Message(CameraControlImpl* aCameraControl,
653 CameraControlListener::UserContext aContext)
654 : ControlMessage(aCameraControl, aContext)
657 nsresult
658 RunImpl() MOZ_OVERRIDE
660 return mCameraControl->ResumeContinuousFocusImpl();
664 return Dispatch(new Message(this, CameraControlListener::kInResumeContinuousFocus));
667 nsresult
668 CameraControlImpl::Stop()
670 class Message : public ControlMessage
672 public:
673 Message(CameraControlImpl* aCameraControl,
674 CameraControlListener::UserContext aContext)
675 : ControlMessage(aCameraControl, aContext)
678 nsresult
679 RunImpl() MOZ_OVERRIDE
681 return mCameraControl->StopImpl();
685 return Dispatch(new Message(this, CameraControlListener::kInStopCamera));
688 class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage
690 public:
691 ListenerMessage(CameraControlImpl* aCameraControl,
692 CameraControlListener* aListener)
693 : ControlMessage(aCameraControl, CameraControlListener::kInUnspecified)
694 , mListener(aListener)
697 protected:
698 nsRefPtr<CameraControlListener> mListener;
701 void
702 CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aListener)
704 RwLockAutoEnterWrite lock(mListenerLock);
706 CameraControlListener* l = *mListeners.AppendElement() = aListener;
707 DOM_CAMERA_LOGI("Added camera control listener %p\n", l);
709 // Update the newly-added listener's state
710 l->OnConfigurationChange(mCurrentConfiguration);
711 l->OnHardwareStateChange(mHardwareState);
712 l->OnPreviewStateChange(mPreviewState);
715 void
716 CameraControlImpl::AddListener(CameraControlListener* aListener)
718 class Message : public ListenerMessage
720 public:
721 Message(CameraControlImpl* aCameraControl,
722 CameraControlListener* aListener)
723 : ListenerMessage(aCameraControl, aListener)
726 nsresult
727 RunImpl() MOZ_OVERRIDE
729 mCameraControl->AddListenerImpl(mListener.forget());
730 return NS_OK;
734 if (aListener) {
735 Dispatch(new Message(this, aListener));
739 void
740 CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener)
742 RwLockAutoEnterWrite lock(mListenerLock);
744 nsRefPtr<CameraControlListener> l(aListener);
745 mListeners.RemoveElement(l);
746 DOM_CAMERA_LOGI("Removed camera control listener %p\n", l.get());
747 // XXXmikeh - do we want to notify the listener that it has been removed?
750 void
751 CameraControlImpl::RemoveListener(CameraControlListener* aListener)
753 class Message : public ListenerMessage
755 public:
756 Message(CameraControlImpl* aCameraControl, CameraControlListener* aListener)
757 : ListenerMessage(aCameraControl, aListener)
760 nsresult
761 RunImpl() MOZ_OVERRIDE
763 mCameraControl->RemoveListenerImpl(mListener);
764 return NS_OK;
768 if (aListener) {
769 Dispatch(new Message(this, aListener));