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
);
31 mCameraThread
= ct
.forget();
33 nsresult rv
= NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread
));
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
51 // Multiple parallel listeners being invoked are not a problem because
52 // the read-write lock allows multiple simultaneous read-locks.
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()");
64 PR_DestroyRWLock(mListenerLock
);
65 mListenerLock
= nullptr;
69 already_AddRefed
<RecorderProfileManager
>
70 CameraControlImpl::GetRecorderProfileManager()
72 return GetRecorderProfileManagerImpl();
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
);
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
]);
94 DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState
);
98 mHardwareState
= aNewState
;
100 for (uint32_t i
= 0; i
< mListeners
.Length(); ++i
) {
101 CameraControlListener
* l
= mListeners
[i
];
102 l
->OnHardwareStateChange(mHardwareState
);
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
);
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
);
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
);
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
);
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
);
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
179 RwLockAutoEnterRead
lock(mListenerLock
);
181 for (uint32_t i
= 0; i
< mListeners
.Length(); ++i
) {
182 CameraControlListener
* l
= mListeners
[i
];
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
);
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
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
);
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
221 RwLockAutoEnterRead
lock(mListenerLock
);
223 if (aNewState
== mPreviewState
) {
224 DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState
);
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
]);
234 DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState
);
238 mPreviewState
= aNewState
;
240 for (uint32_t i
= 0; i
< mListeners
.Length(); ++i
) {
241 CameraControlListener
* l
= mListeners
[i
];
242 l
->OnPreviewStateChange(mPreviewState
);
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
);
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
;
280 CameraControlImpl::OnUserError(CameraControlListener::UserContext aContext
,
283 // This callback can run on threads other than the Main Thread and
284 // the Camera Thread.
285 RwLockAutoEnterRead
lock(mListenerLock
);
288 const char* context
[] = {
292 "StartFaceDetection",
302 "ResumeContinuousFocus",
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
);
309 DOM_CAMERA_LOGE("CameraControlImpl::OnUserError : aContext=%d, aError=0x%x\n",
314 for (uint32_t i
= 0; i
< mListeners
.Length(); ++i
) {
315 CameraControlListener
* l
= mListeners
[i
];
316 l
->OnUserError(aContext
, aError
);
321 CameraControlImpl::OnSystemError(CameraControlListener::SystemContext aContext
,
324 // This callback can run on threads other than the Main Thread and
325 // the Camera Thread.
326 RwLockAutoEnterRead
lock(mListenerLock
);
329 const char* context
[] = {
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
);
336 DOM_CAMERA_LOGE("CameraControlImpl::OnSystemError : aContext=%d, aError=0x%x\n",
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
353 ControlMessage(CameraControlImpl
* aCameraControl
,
354 CameraControlListener::UserContext aContext
)
355 : mCameraControl(aCameraControl
)
359 virtual nsresult
RunImpl() = 0;
364 MOZ_ASSERT(mCameraControl
);
365 MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl
->mCameraThread
);
367 nsresult rv
= RunImpl();
369 nsPrintfCString
msg("Camera control API(%d) failed with 0x%x", mContext
, rv
);
370 NS_WARNING(msg
.get());
371 mCameraControl
->OnUserError(mContext
, rv
);
378 virtual ~ControlMessage() { }
380 nsRefPtr
<CameraControlImpl
> mCameraControl
;
381 CameraControlListener::UserContext mContext
;
385 CameraControlImpl::Dispatch(ControlMessage
* aMessage
)
387 nsresult rv
= mCameraThread
->Dispatch(aMessage
, NS_DISPATCH_NORMAL
);
388 if (NS_SUCCEEDED(rv
)) {
392 nsPrintfCString
msg("Failed to dispatch camera control message (0x%x)", rv
);
393 NS_WARNING(msg
.get());
394 return NS_ERROR_FAILURE
;
398 CameraControlImpl::Start(const Configuration
* aConfig
)
400 class Message
: public ControlMessage
403 Message(CameraControlImpl
* aCameraControl
,
404 CameraControlListener::UserContext aContext
,
405 const Configuration
* aConfig
)
406 : ControlMessage(aCameraControl
, aContext
)
407 , mHaveInitialConfig(false)
411 mHaveInitialConfig
= true;
416 RunImpl() MOZ_OVERRIDE
418 if (mHaveInitialConfig
) {
419 return mCameraControl
->StartImpl(&mConfig
);
421 return mCameraControl
->StartImpl();
425 bool mHaveInitialConfig
;
426 Configuration mConfig
;
429 return Dispatch(new Message(this, CameraControlListener::kInStartCamera
, aConfig
));
433 CameraControlImpl::SetConfiguration(const Configuration
& aConfig
)
435 class Message
: public ControlMessage
438 Message(CameraControlImpl
* aCameraControl
,
439 CameraControlListener::UserContext aContext
,
440 const Configuration
& aConfig
)
441 : ControlMessage(aCameraControl
, aContext
)
446 RunImpl() MOZ_OVERRIDE
448 return mCameraControl
->SetConfigurationImpl(mConfig
);
452 Configuration mConfig
;
455 return Dispatch(new Message(this, CameraControlListener::kInSetConfiguration
, aConfig
));
459 CameraControlImpl::AutoFocus()
461 class Message
: public ControlMessage
464 Message(CameraControlImpl
* aCameraControl
,
465 CameraControlListener::UserContext aContext
)
466 : ControlMessage(aCameraControl
, aContext
)
470 RunImpl() MOZ_OVERRIDE
472 return mCameraControl
->AutoFocusImpl();
476 return Dispatch(new Message(this, CameraControlListener::kInAutoFocus
));
480 CameraControlImpl::StartFaceDetection()
482 class Message
: public ControlMessage
485 Message(CameraControlImpl
* aCameraControl
,
486 CameraControlListener::UserContext aContext
)
487 : ControlMessage(aCameraControl
, aContext
)
491 RunImpl() MOZ_OVERRIDE
493 return mCameraControl
->StartFaceDetectionImpl();
497 return Dispatch(new Message(this, CameraControlListener::kInStartFaceDetection
));
501 CameraControlImpl::StopFaceDetection()
503 class Message
: public ControlMessage
506 Message(CameraControlImpl
* aCameraControl
,
507 CameraControlListener::UserContext aContext
)
508 : ControlMessage(aCameraControl
, aContext
)
512 RunImpl() MOZ_OVERRIDE
514 return mCameraControl
->StopFaceDetectionImpl();
518 return Dispatch(new Message(this, CameraControlListener::kInStopFaceDetection
));
522 CameraControlImpl::TakePicture()
524 class Message
: public ControlMessage
527 Message(CameraControlImpl
* aCameraControl
,
528 CameraControlListener::UserContext aContext
)
529 : ControlMessage(aCameraControl
, aContext
)
533 RunImpl() MOZ_OVERRIDE
535 return mCameraControl
->TakePictureImpl();
539 return Dispatch(new Message(this, CameraControlListener::kInTakePicture
));
543 CameraControlImpl::StartRecording(DeviceStorageFileDescriptor
* aFileDescriptor
,
544 const StartRecordingOptions
* aOptions
)
546 class Message
: public ControlMessage
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
)
558 mOptions
= *aOptions
;
559 mOptionsPassed
= true;
564 RunImpl() MOZ_OVERRIDE
566 return mCameraControl
->StartRecordingImpl(mFileDescriptor
,
567 mOptionsPassed
? &mOptions
: nullptr);
571 StartRecordingOptions mOptions
;
573 nsRefPtr
<DeviceStorageFileDescriptor
> mFileDescriptor
;
576 if (!aFileDescriptor
) {
577 return NS_ERROR_INVALID_ARG
;
579 return Dispatch(new Message(this, CameraControlListener::kInStartRecording
,
580 aOptions
, aFileDescriptor
));
584 CameraControlImpl::StopRecording()
586 class Message
: public ControlMessage
589 Message(CameraControlImpl
* aCameraControl
,
590 CameraControlListener::UserContext aContext
)
591 : ControlMessage(aCameraControl
, aContext
)
595 RunImpl() MOZ_OVERRIDE
597 return mCameraControl
->StopRecordingImpl();
601 return Dispatch(new Message(this, CameraControlListener::kInStopRecording
));
605 CameraControlImpl::StartPreview()
607 class Message
: public ControlMessage
610 Message(CameraControlImpl
* aCameraControl
,
611 CameraControlListener::UserContext aContext
)
612 : ControlMessage(aCameraControl
, aContext
)
616 RunImpl() MOZ_OVERRIDE
618 return mCameraControl
->StartPreviewImpl();
622 return Dispatch(new Message(this, CameraControlListener::kInStartPreview
));
626 CameraControlImpl::StopPreview()
628 class Message
: public ControlMessage
631 Message(CameraControlImpl
* aCameraControl
,
632 CameraControlListener::UserContext aContext
)
633 : ControlMessage(aCameraControl
, aContext
)
637 RunImpl() MOZ_OVERRIDE
639 return mCameraControl
->StopPreviewImpl();
643 return Dispatch(new Message(this, CameraControlListener::kInStopPreview
));
647 CameraControlImpl::ResumeContinuousFocus()
649 class Message
: public ControlMessage
652 Message(CameraControlImpl
* aCameraControl
,
653 CameraControlListener::UserContext aContext
)
654 : ControlMessage(aCameraControl
, aContext
)
658 RunImpl() MOZ_OVERRIDE
660 return mCameraControl
->ResumeContinuousFocusImpl();
664 return Dispatch(new Message(this, CameraControlListener::kInResumeContinuousFocus
));
668 CameraControlImpl::Stop()
670 class Message
: public ControlMessage
673 Message(CameraControlImpl
* aCameraControl
,
674 CameraControlListener::UserContext aContext
)
675 : ControlMessage(aCameraControl
, aContext
)
679 RunImpl() MOZ_OVERRIDE
681 return mCameraControl
->StopImpl();
685 return Dispatch(new Message(this, CameraControlListener::kInStopCamera
));
688 class CameraControlImpl::ListenerMessage
: public CameraControlImpl::ControlMessage
691 ListenerMessage(CameraControlImpl
* aCameraControl
,
692 CameraControlListener
* aListener
)
693 : ControlMessage(aCameraControl
, CameraControlListener::kInUnspecified
)
694 , mListener(aListener
)
698 nsRefPtr
<CameraControlListener
> mListener
;
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
);
716 CameraControlImpl::AddListener(CameraControlListener
* aListener
)
718 class Message
: public ListenerMessage
721 Message(CameraControlImpl
* aCameraControl
,
722 CameraControlListener
* aListener
)
723 : ListenerMessage(aCameraControl
, aListener
)
727 RunImpl() MOZ_OVERRIDE
729 mCameraControl
->AddListenerImpl(mListener
.forget());
735 Dispatch(new Message(this, aListener
));
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?
751 CameraControlImpl::RemoveListener(CameraControlListener
* aListener
)
753 class Message
: public ListenerMessage
756 Message(CameraControlImpl
* aCameraControl
, CameraControlListener
* aListener
)
757 : ListenerMessage(aCameraControl
, aListener
)
761 RunImpl() MOZ_OVERRIDE
763 mCameraControl
->RemoveListenerImpl(mListener
);
769 Dispatch(new Message(this, aListener
));