1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/CameraControlImpl.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,735 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "CameraControlImpl.h" 1.9 +#include "base/basictypes.h" 1.10 +#include "mozilla/Assertions.h" 1.11 +#include "mozilla/unused.h" 1.12 +#include "nsIWeakReferenceUtils.h" 1.13 +#include "CameraRecorderProfiles.h" 1.14 +#include "CameraCommon.h" 1.15 +#include "nsGlobalWindow.h" 1.16 +#include "DeviceStorageFileDescriptor.h" 1.17 +#include "CameraControlListener.h" 1.18 + 1.19 +using namespace mozilla; 1.20 + 1.21 +nsWeakPtr CameraControlImpl::sCameraThread; 1.22 + 1.23 +CameraControlImpl::CameraControlImpl(uint32_t aCameraId) 1.24 + : mCameraId(aCameraId) 1.25 + , mPreviewState(CameraControlListener::kPreviewStopped) 1.26 + , mHardwareState(CameraControlListener::kHardwareClosed) 1.27 +{ 1.28 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.29 + 1.30 + // reuse the same camera thread to conserve resources 1.31 + nsCOMPtr<nsIThread> ct = do_QueryReferent(sCameraThread); 1.32 + if (ct) { 1.33 + mCameraThread = ct.forget(); 1.34 + } else { 1.35 + nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread)); 1.36 + unused << rv; // swallow rv to suppress a compiler warning when the macro 1.37 + // is #defined to nothing (i.e. in non-DEBUG builds). 1.38 + MOZ_ASSERT(NS_SUCCEEDED(rv)); 1.39 + 1.40 + // keep a weak reference to the new thread 1.41 + sCameraThread = do_GetWeakReference(mCameraThread); 1.42 + } 1.43 + 1.44 + // Care must be taken with the mListenerLock read-write lock to prevent 1.45 + // deadlocks. Currently this is handled by ensuring that any attempts to 1.46 + // acquire the lock for writing (as in Add/RemoveListener()) happen in a 1.47 + // runnable dispatched to the Camera Thread--even if the method is being 1.48 + // called from that thread. This ensures that if a registered listener 1.49 + // (which is invoked with a read-lock) tries to call Add/RemoveListener(), 1.50 + // the lock-for-writing attempt won't happen until the listener has 1.51 + // completed. 1.52 + // 1.53 + // Multiple parallel listeners being invoked are not a problem because 1.54 + // the read-write lock allows multiple simultaneous read-locks. 1.55 + mListenerLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"); 1.56 +} 1.57 + 1.58 +CameraControlImpl::~CameraControlImpl() 1.59 +{ 1.60 + if (mListenerLock) { 1.61 + PR_DestroyRWLock(mListenerLock); 1.62 + mListenerLock = nullptr; 1.63 + } 1.64 +} 1.65 + 1.66 +already_AddRefed<RecorderProfileManager> 1.67 +CameraControlImpl::GetRecorderProfileManager() 1.68 +{ 1.69 + return GetRecorderProfileManagerImpl(); 1.70 +} 1.71 + 1.72 +void 1.73 +CameraControlImpl::Shutdown() 1.74 +{ 1.75 + DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__); 1.76 +} 1.77 + 1.78 +void 1.79 +CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState) 1.80 +{ 1.81 + // This callback can run on threads other than the Main Thread and 1.82 + // the Camera Thread. On Gonk, it may be called from the camera's 1.83 + // local binder thread, should the mediaserver process die. 1.84 + RwLockAutoEnterRead lock(mListenerLock); 1.85 + 1.86 + if (aNewState == mHardwareState) { 1.87 + DOM_CAMERA_LOGI("OnHardwareStateChange: state did not change from %d\n", mHardwareState); 1.88 + return; 1.89 + } 1.90 + 1.91 +#ifdef PR_LOGGING 1.92 + const char* state[] = { "open", "closed", "failed" }; 1.93 + MOZ_ASSERT(aNewState >= 0); 1.94 + if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) { 1.95 + DOM_CAMERA_LOGI("New hardware state is '%s'\n", state[aNewState]); 1.96 + } else { 1.97 + DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState); 1.98 + } 1.99 +#endif 1.100 + 1.101 + mHardwareState = aNewState; 1.102 + 1.103 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.104 + CameraControlListener* l = mListeners[i]; 1.105 + l->OnHardwareStateChange(mHardwareState); 1.106 + } 1.107 +} 1.108 + 1.109 +void 1.110 +CameraControlImpl::OnConfigurationChange() 1.111 +{ 1.112 + MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread); 1.113 + RwLockAutoEnterRead lock(mListenerLock); 1.114 + 1.115 + DOM_CAMERA_LOGI("OnConfigurationChange : %d listeners\n", mListeners.Length()); 1.116 + 1.117 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.118 + CameraControlListener* l = mListeners[i]; 1.119 + l->OnConfigurationChange(mCurrentConfiguration); 1.120 + } 1.121 +} 1.122 + 1.123 +void 1.124 +CameraControlImpl::OnAutoFocusComplete(bool aAutoFocusSucceeded) 1.125 +{ 1.126 + // This callback can run on threads other than the Main Thread and 1.127 + // the Camera Thread. On Gonk, it is called from the camera 1.128 + // library's auto focus thread. 1.129 + RwLockAutoEnterRead lock(mListenerLock); 1.130 + 1.131 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.132 + CameraControlListener* l = mListeners[i]; 1.133 + l->OnAutoFocusComplete(aAutoFocusSucceeded); 1.134 + } 1.135 +} 1.136 + 1.137 +void 1.138 +CameraControlImpl::OnAutoFocusMoving(bool aIsMoving) 1.139 +{ 1.140 + RwLockAutoEnterRead lock(mListenerLock); 1.141 + 1.142 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.143 + CameraControlListener* l = mListeners[i]; 1.144 + l->OnAutoFocusMoving(aIsMoving); 1.145 + } 1.146 +} 1.147 + 1.148 +void 1.149 +CameraControlImpl::OnFacesDetected(const nsTArray<Face>& aFaces) 1.150 +{ 1.151 + // This callback can run on threads other than the Main Thread and 1.152 + // the Camera Thread. On Gonk, it is called from the camera 1.153 + // library's face detection thread. 1.154 + RwLockAutoEnterRead lock(mListenerLock); 1.155 + 1.156 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.157 + CameraControlListener* l = mListeners[i]; 1.158 + l->OnFacesDetected(aFaces); 1.159 + } 1.160 +} 1.161 + 1.162 +void 1.163 +CameraControlImpl::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) 1.164 +{ 1.165 + // This callback can run on threads other than the Main Thread and 1.166 + // the Camera Thread. On Gonk, it is called from the camera 1.167 + // library's snapshot thread. 1.168 + RwLockAutoEnterRead lock(mListenerLock); 1.169 + 1.170 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.171 + CameraControlListener* l = mListeners[i]; 1.172 + l->OnTakePictureComplete(aData, aLength, aMimeType); 1.173 + } 1.174 +} 1.175 + 1.176 +void 1.177 +CameraControlImpl::OnShutter() 1.178 +{ 1.179 + // This callback can run on threads other than the Main Thread and 1.180 + // the Camera Thread. On Gonk, it is called from the camera driver's 1.181 + // preview thread. 1.182 + RwLockAutoEnterRead lock(mListenerLock); 1.183 + 1.184 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.185 + CameraControlListener* l = mListeners[i]; 1.186 + l->OnShutter(); 1.187 + } 1.188 +} 1.189 + 1.190 +void 1.191 +CameraControlImpl::OnClosed() 1.192 +{ 1.193 + // This callback can run on threads other than the Main Thread and 1.194 + // the Camera Thread. 1.195 + RwLockAutoEnterRead lock(mListenerLock); 1.196 + 1.197 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.198 + CameraControlListener* l = mListeners[i]; 1.199 + l->OnHardwareStateChange(CameraControlListener::kHardwareClosed); 1.200 + } 1.201 +} 1.202 + 1.203 +void 1.204 +CameraControlImpl::OnRecorderStateChange(CameraControlListener::RecorderState aState, 1.205 + int32_t aStatus, int32_t aTrackNumber) 1.206 +{ 1.207 + // This callback can run on threads other than the Main Thread and 1.208 + // the Camera Thread. On Gonk, it is called from the media encoder 1.209 + // thread. 1.210 + RwLockAutoEnterRead lock(mListenerLock); 1.211 + 1.212 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.213 + CameraControlListener* l = mListeners[i]; 1.214 + l->OnRecorderStateChange(aState, aStatus, aTrackNumber); 1.215 + } 1.216 +} 1.217 + 1.218 +void 1.219 +CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNewState) 1.220 +{ 1.221 + // This callback runs on the Main Thread and the Camera Thread, and 1.222 + // may run on the local binder thread, should the mediaserver 1.223 + // process die. 1.224 + RwLockAutoEnterRead lock(mListenerLock); 1.225 + 1.226 + if (aNewState == mPreviewState) { 1.227 + DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState); 1.228 + return; 1.229 + } 1.230 + 1.231 +#ifdef PR_LOGGING 1.232 + const char* state[] = { "stopped", "paused", "started" }; 1.233 + MOZ_ASSERT(aNewState >= 0); 1.234 + if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) { 1.235 + DOM_CAMERA_LOGI("New preview state is '%s'\n", state[aNewState]); 1.236 + } else { 1.237 + DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState); 1.238 + } 1.239 +#endif 1.240 + 1.241 + mPreviewState = aNewState; 1.242 + 1.243 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.244 + CameraControlListener* l = mListeners[i]; 1.245 + l->OnPreviewStateChange(mPreviewState); 1.246 + } 1.247 +} 1.248 + 1.249 +bool 1.250 +CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) 1.251 +{ 1.252 + // This function runs on neither the Main Thread nor the Camera Thread. 1.253 + // On Gonk, it is called from the camera driver's preview thread. 1.254 + RwLockAutoEnterRead lock(mListenerLock); 1.255 + 1.256 + DOM_CAMERA_LOGI("OnNewPreviewFrame: we have %d preview frame listener(s)\n", 1.257 + mListeners.Length()); 1.258 + 1.259 + bool consumed = false; 1.260 + 1.261 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.262 + CameraControlListener* l = mListeners[i]; 1.263 + consumed = l->OnNewPreviewFrame(aImage, aWidth, aHeight) || consumed; 1.264 + } 1.265 + return consumed; 1.266 +} 1.267 + 1.268 +void 1.269 +CameraControlImpl::OnError(CameraControlListener::CameraErrorContext aContext, 1.270 + CameraControlListener::CameraError aError) 1.271 +{ 1.272 + // This callback can run on threads other than the Main Thread and 1.273 + // the Camera Thread. 1.274 + RwLockAutoEnterRead lock(mListenerLock); 1.275 + 1.276 +#ifdef PR_LOGGING 1.277 + const char* error[] = { 1.278 + "api-failed", 1.279 + "init-failed", 1.280 + "invalid-configuration", 1.281 + "service-failed", 1.282 + "set-picture-size-failed", 1.283 + "set-thumbnail-size-failed", 1.284 + "unknown" 1.285 + }; 1.286 + const char* context[] = { 1.287 + "StartCamera", 1.288 + "StopCamera", 1.289 + "AutoFocus", 1.290 + "StartFaceDetection", 1.291 + "StopFaceDetection", 1.292 + "TakePicture", 1.293 + "StartRecording", 1.294 + "StopRecording", 1.295 + "SetConfiguration", 1.296 + "StartPreview", 1.297 + "StopPreview", 1.298 + "ResumeContinuousFocus", 1.299 + "Unspecified" 1.300 + }; 1.301 + if (static_cast<unsigned int>(aError) < sizeof(error) / sizeof(error[0]) && 1.302 + static_cast<unsigned int>(aContext) < sizeof(context) / sizeof(context[0])) { 1.303 + DOM_CAMERA_LOGW("CameraControlImpl::OnError : aContext='%s' (%u), aError='%s' (%u)\n", 1.304 + context[aContext], aContext, error[aError], aError); 1.305 + } else { 1.306 + DOM_CAMERA_LOGE("CameraControlImpl::OnError : aContext=%u, aError=%d\n", 1.307 + aContext, aError); 1.308 + } 1.309 +#endif 1.310 + 1.311 + for (uint32_t i = 0; i < mListeners.Length(); ++i) { 1.312 + CameraControlListener* l = mListeners[i]; 1.313 + l->OnError(aContext, aError); 1.314 + } 1.315 +} 1.316 + 1.317 +// Camera control asynchronous message; these are dispatched from 1.318 +// the Main Thread to the Camera Thread, where they are consumed. 1.319 + 1.320 +class CameraControlImpl::ControlMessage : public nsRunnable 1.321 +{ 1.322 +public: 1.323 + ControlMessage(CameraControlImpl* aCameraControl, 1.324 + CameraControlListener::CameraErrorContext aContext) 1.325 + : mCameraControl(aCameraControl) 1.326 + , mContext(aContext) 1.327 + { 1.328 + MOZ_COUNT_CTOR(CameraControlImpl::ControlMessage); 1.329 + } 1.330 + 1.331 + virtual ~ControlMessage() 1.332 + { 1.333 + MOZ_COUNT_DTOR(CameraControlImpl::ControlMessage); 1.334 + } 1.335 + 1.336 + virtual nsresult RunImpl() = 0; 1.337 + 1.338 + NS_IMETHOD 1.339 + Run() MOZ_OVERRIDE 1.340 + { 1.341 + MOZ_ASSERT(mCameraControl); 1.342 + MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl->mCameraThread); 1.343 + 1.344 + nsresult rv = RunImpl(); 1.345 + if (NS_FAILED(rv)) { 1.346 + DOM_CAMERA_LOGW("Camera control API failed at %d with 0x%x\n", mContext, rv); 1.347 + // XXXmikeh - do we want to report a more specific error code? 1.348 + mCameraControl->OnError(mContext, CameraControlListener::kErrorApiFailed); 1.349 + } 1.350 + 1.351 + return NS_OK; 1.352 + } 1.353 + 1.354 +protected: 1.355 + nsRefPtr<CameraControlImpl> mCameraControl; 1.356 + CameraControlListener::CameraErrorContext mContext; 1.357 +}; 1.358 + 1.359 +nsresult 1.360 +CameraControlImpl::Start(const Configuration* aConfig) 1.361 +{ 1.362 + class Message : public ControlMessage 1.363 + { 1.364 + public: 1.365 + Message(CameraControlImpl* aCameraControl, 1.366 + CameraControlListener::CameraErrorContext aContext, 1.367 + const Configuration* aConfig) 1.368 + : ControlMessage(aCameraControl, aContext) 1.369 + , mHaveInitialConfig(false) 1.370 + { 1.371 + if (aConfig) { 1.372 + mConfig = *aConfig; 1.373 + mHaveInitialConfig = true; 1.374 + } 1.375 + } 1.376 + 1.377 + nsresult 1.378 + RunImpl() MOZ_OVERRIDE 1.379 + { 1.380 + if (mHaveInitialConfig) { 1.381 + return mCameraControl->StartImpl(&mConfig); 1.382 + } 1.383 + return mCameraControl->StartImpl(); 1.384 + } 1.385 + 1.386 + protected: 1.387 + bool mHaveInitialConfig; 1.388 + Configuration mConfig; 1.389 + }; 1.390 + 1.391 + return mCameraThread->Dispatch( 1.392 + new Message(this, CameraControlListener::kInStartCamera, aConfig), NS_DISPATCH_NORMAL); 1.393 +} 1.394 + 1.395 +nsresult 1.396 +CameraControlImpl::SetConfiguration(const Configuration& aConfig) 1.397 +{ 1.398 + class Message : public ControlMessage 1.399 + { 1.400 + public: 1.401 + Message(CameraControlImpl* aCameraControl, 1.402 + CameraControlListener::CameraErrorContext aContext, 1.403 + const Configuration& aConfig) 1.404 + : ControlMessage(aCameraControl, aContext) 1.405 + , mConfig(aConfig) 1.406 + { } 1.407 + 1.408 + nsresult 1.409 + RunImpl() MOZ_OVERRIDE 1.410 + { 1.411 + return mCameraControl->SetConfigurationImpl(mConfig); 1.412 + } 1.413 + 1.414 + protected: 1.415 + Configuration mConfig; 1.416 + }; 1.417 + 1.418 + return mCameraThread->Dispatch( 1.419 + new Message(this, CameraControlListener::kInSetConfiguration, aConfig), NS_DISPATCH_NORMAL); 1.420 +} 1.421 + 1.422 +nsresult 1.423 +CameraControlImpl::AutoFocus() 1.424 +{ 1.425 + class Message : public ControlMessage 1.426 + { 1.427 + public: 1.428 + Message(CameraControlImpl* aCameraControl, 1.429 + CameraControlListener::CameraErrorContext aContext) 1.430 + : ControlMessage(aCameraControl, aContext) 1.431 + { } 1.432 + 1.433 + nsresult 1.434 + RunImpl() MOZ_OVERRIDE 1.435 + { 1.436 + return mCameraControl->AutoFocusImpl(); 1.437 + } 1.438 + }; 1.439 + 1.440 + return mCameraThread->Dispatch( 1.441 + new Message(this, CameraControlListener::kInAutoFocus), NS_DISPATCH_NORMAL); 1.442 +} 1.443 + 1.444 +nsresult 1.445 +CameraControlImpl::StartFaceDetection() 1.446 +{ 1.447 + class Message : public ControlMessage 1.448 + { 1.449 + public: 1.450 + Message(CameraControlImpl* aCameraControl, 1.451 + CameraControlListener::CameraErrorContext aContext) 1.452 + : ControlMessage(aCameraControl, aContext) 1.453 + { } 1.454 + 1.455 + nsresult 1.456 + RunImpl() MOZ_OVERRIDE 1.457 + { 1.458 + return mCameraControl->StartFaceDetectionImpl(); 1.459 + } 1.460 + }; 1.461 + 1.462 + return mCameraThread->Dispatch( 1.463 + new Message(this, CameraControlListener::kInStartFaceDetection), NS_DISPATCH_NORMAL); 1.464 +} 1.465 + 1.466 +nsresult 1.467 +CameraControlImpl::StopFaceDetection() 1.468 +{ 1.469 + class Message : public ControlMessage 1.470 + { 1.471 + public: 1.472 + Message(CameraControlImpl* aCameraControl, 1.473 + CameraControlListener::CameraErrorContext aContext) 1.474 + : ControlMessage(aCameraControl, aContext) 1.475 + { } 1.476 + 1.477 + nsresult 1.478 + RunImpl() MOZ_OVERRIDE 1.479 + { 1.480 + return mCameraControl->StopFaceDetectionImpl(); 1.481 + } 1.482 + }; 1.483 + 1.484 + return mCameraThread->Dispatch( 1.485 + new Message(this, CameraControlListener::kInStopFaceDetection), NS_DISPATCH_NORMAL); 1.486 +} 1.487 + 1.488 +nsresult 1.489 +CameraControlImpl::TakePicture() 1.490 +{ 1.491 + class Message : public ControlMessage 1.492 + { 1.493 + public: 1.494 + Message(CameraControlImpl* aCameraControl, 1.495 + CameraControlListener::CameraErrorContext aContext) 1.496 + : ControlMessage(aCameraControl, aContext) 1.497 + { } 1.498 + 1.499 + nsresult 1.500 + RunImpl() MOZ_OVERRIDE 1.501 + { 1.502 + return mCameraControl->TakePictureImpl(); 1.503 + } 1.504 + }; 1.505 + 1.506 + return mCameraThread->Dispatch( 1.507 + new Message(this, CameraControlListener::kInTakePicture), NS_DISPATCH_NORMAL); 1.508 +} 1.509 + 1.510 +nsresult 1.511 +CameraControlImpl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor, 1.512 + const StartRecordingOptions* aOptions) 1.513 +{ 1.514 + class Message : public ControlMessage 1.515 + { 1.516 + public: 1.517 + Message(CameraControlImpl* aCameraControl, 1.518 + CameraControlListener::CameraErrorContext aContext, 1.519 + const StartRecordingOptions* aOptions, 1.520 + DeviceStorageFileDescriptor* aFileDescriptor) 1.521 + : ControlMessage(aCameraControl, aContext) 1.522 + , mOptionsPassed(false) 1.523 + , mFileDescriptor(aFileDescriptor) 1.524 + { 1.525 + if (aOptions) { 1.526 + mOptions = *aOptions; 1.527 + mOptionsPassed = true; 1.528 + } 1.529 + } 1.530 + 1.531 + nsresult 1.532 + RunImpl() MOZ_OVERRIDE 1.533 + { 1.534 + return mCameraControl->StartRecordingImpl(mFileDescriptor, 1.535 + mOptionsPassed ? &mOptions : nullptr); 1.536 + } 1.537 + 1.538 + protected: 1.539 + StartRecordingOptions mOptions; 1.540 + bool mOptionsPassed; 1.541 + nsRefPtr<DeviceStorageFileDescriptor> mFileDescriptor; 1.542 + }; 1.543 + 1.544 + 1.545 + return mCameraThread->Dispatch(new Message(this, CameraControlListener::kInStartRecording, 1.546 + aOptions, aFileDescriptor), NS_DISPATCH_NORMAL); 1.547 +} 1.548 + 1.549 +nsresult 1.550 +CameraControlImpl::StopRecording() 1.551 +{ 1.552 + class Message : public ControlMessage 1.553 + { 1.554 + public: 1.555 + Message(CameraControlImpl* aCameraControl, 1.556 + CameraControlListener::CameraErrorContext aContext) 1.557 + : ControlMessage(aCameraControl, aContext) 1.558 + { } 1.559 + 1.560 + nsresult 1.561 + RunImpl() MOZ_OVERRIDE 1.562 + { 1.563 + return mCameraControl->StopRecordingImpl(); 1.564 + } 1.565 + }; 1.566 + 1.567 + return mCameraThread->Dispatch( 1.568 + new Message(this, CameraControlListener::kInStopRecording), NS_DISPATCH_NORMAL); 1.569 +} 1.570 + 1.571 +nsresult 1.572 +CameraControlImpl::StartPreview() 1.573 +{ 1.574 + class Message : public ControlMessage 1.575 + { 1.576 + public: 1.577 + Message(CameraControlImpl* aCameraControl, 1.578 + CameraControlListener::CameraErrorContext aContext) 1.579 + : ControlMessage(aCameraControl, aContext) 1.580 + { } 1.581 + 1.582 + nsresult 1.583 + RunImpl() MOZ_OVERRIDE 1.584 + { 1.585 + return mCameraControl->StartPreviewImpl(); 1.586 + } 1.587 + }; 1.588 + 1.589 + return mCameraThread->Dispatch( 1.590 + new Message(this, CameraControlListener::kInStartPreview), NS_DISPATCH_NORMAL); 1.591 +} 1.592 + 1.593 +nsresult 1.594 +CameraControlImpl::StopPreview() 1.595 +{ 1.596 + class Message : public ControlMessage 1.597 + { 1.598 + public: 1.599 + Message(CameraControlImpl* aCameraControl, 1.600 + CameraControlListener::CameraErrorContext aContext) 1.601 + : ControlMessage(aCameraControl, aContext) 1.602 + { } 1.603 + 1.604 + nsresult 1.605 + RunImpl() MOZ_OVERRIDE 1.606 + { 1.607 + return mCameraControl->StopPreviewImpl(); 1.608 + } 1.609 + }; 1.610 + 1.611 + return mCameraThread->Dispatch( 1.612 + new Message(this, CameraControlListener::kInStopPreview), NS_DISPATCH_NORMAL); 1.613 +} 1.614 + 1.615 +nsresult 1.616 +CameraControlImpl::ResumeContinuousFocus() 1.617 +{ 1.618 + class Message : public ControlMessage 1.619 + { 1.620 + public: 1.621 + Message(CameraControlImpl* aCameraControl, 1.622 + CameraControlListener::CameraErrorContext aContext) 1.623 + : ControlMessage(aCameraControl, aContext) 1.624 + { } 1.625 + 1.626 + nsresult 1.627 + RunImpl() MOZ_OVERRIDE 1.628 + { 1.629 + return mCameraControl->ResumeContinuousFocusImpl(); 1.630 + } 1.631 + }; 1.632 + 1.633 + return mCameraThread->Dispatch( 1.634 + new Message(this, CameraControlListener::kInResumeContinuousFocus), NS_DISPATCH_NORMAL); 1.635 +} 1.636 + 1.637 +nsresult 1.638 +CameraControlImpl::Stop() 1.639 +{ 1.640 + class Message : public ControlMessage 1.641 + { 1.642 + public: 1.643 + Message(CameraControlImpl* aCameraControl, 1.644 + CameraControlListener::CameraErrorContext aContext) 1.645 + : ControlMessage(aCameraControl, aContext) 1.646 + { } 1.647 + 1.648 + nsresult 1.649 + RunImpl() MOZ_OVERRIDE 1.650 + { 1.651 + return mCameraControl->StopImpl(); 1.652 + } 1.653 + }; 1.654 + 1.655 + return mCameraThread->Dispatch( 1.656 + new Message(this, CameraControlListener::kInStopCamera), NS_DISPATCH_NORMAL); 1.657 +} 1.658 + 1.659 +class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage 1.660 +{ 1.661 +public: 1.662 + ListenerMessage(CameraControlImpl* aCameraControl, 1.663 + CameraControlListener* aListener) 1.664 + : ControlMessage(aCameraControl, CameraControlListener::kInUnspecified) 1.665 + , mListener(aListener) 1.666 + { } 1.667 + 1.668 +protected: 1.669 + nsRefPtr<CameraControlListener> mListener; 1.670 +}; 1.671 + 1.672 +void 1.673 +CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aListener) 1.674 +{ 1.675 + RwLockAutoEnterWrite lock(mListenerLock); 1.676 + 1.677 + CameraControlListener* l = *mListeners.AppendElement() = aListener; 1.678 + DOM_CAMERA_LOGI("Added camera control listener %p\n", l); 1.679 + 1.680 + // Update the newly-added listener's state 1.681 + l->OnConfigurationChange(mCurrentConfiguration); 1.682 + l->OnHardwareStateChange(mHardwareState); 1.683 + l->OnPreviewStateChange(mPreviewState); 1.684 +} 1.685 + 1.686 +void 1.687 +CameraControlImpl::AddListener(CameraControlListener* aListener) 1.688 + { 1.689 + class Message : public ListenerMessage 1.690 + { 1.691 + public: 1.692 + Message(CameraControlImpl* aCameraControl, 1.693 + CameraControlListener* aListener) 1.694 + : ListenerMessage(aCameraControl, aListener) 1.695 + { } 1.696 + 1.697 + nsresult 1.698 + RunImpl() MOZ_OVERRIDE 1.699 + { 1.700 + mCameraControl->AddListenerImpl(mListener.forget()); 1.701 + return NS_OK; 1.702 + } 1.703 + }; 1.704 + 1.705 + mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL); 1.706 +} 1.707 + 1.708 +void 1.709 +CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener) 1.710 +{ 1.711 + RwLockAutoEnterWrite lock(mListenerLock); 1.712 + 1.713 + nsRefPtr<CameraControlListener> l(aListener); 1.714 + mListeners.RemoveElement(l); 1.715 + DOM_CAMERA_LOGI("Removed camera control listener %p\n", l.get()); 1.716 + // XXXmikeh - do we want to notify the listener that it has been removed? 1.717 +} 1.718 + 1.719 +void 1.720 +CameraControlImpl::RemoveListener(CameraControlListener* aListener) 1.721 + { 1.722 + class Message : public ListenerMessage 1.723 + { 1.724 + public: 1.725 + Message(CameraControlImpl* aCameraControl, CameraControlListener* aListener) 1.726 + : ListenerMessage(aCameraControl, aListener) 1.727 + { } 1.728 + 1.729 + nsresult 1.730 + RunImpl() MOZ_OVERRIDE 1.731 + { 1.732 + mCameraControl->RemoveListenerImpl(mListener); 1.733 + return NS_OK; 1.734 + } 1.735 + }; 1.736 + 1.737 + mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL); 1.738 +}