dom/camera/CameraControlImpl.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "CameraControlImpl.h"
michael@0 6 #include "base/basictypes.h"
michael@0 7 #include "mozilla/Assertions.h"
michael@0 8 #include "mozilla/unused.h"
michael@0 9 #include "nsIWeakReferenceUtils.h"
michael@0 10 #include "CameraRecorderProfiles.h"
michael@0 11 #include "CameraCommon.h"
michael@0 12 #include "nsGlobalWindow.h"
michael@0 13 #include "DeviceStorageFileDescriptor.h"
michael@0 14 #include "CameraControlListener.h"
michael@0 15
michael@0 16 using namespace mozilla;
michael@0 17
michael@0 18 nsWeakPtr CameraControlImpl::sCameraThread;
michael@0 19
michael@0 20 CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
michael@0 21 : mCameraId(aCameraId)
michael@0 22 , mPreviewState(CameraControlListener::kPreviewStopped)
michael@0 23 , mHardwareState(CameraControlListener::kHardwareClosed)
michael@0 24 {
michael@0 25 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
michael@0 26
michael@0 27 // reuse the same camera thread to conserve resources
michael@0 28 nsCOMPtr<nsIThread> ct = do_QueryReferent(sCameraThread);
michael@0 29 if (ct) {
michael@0 30 mCameraThread = ct.forget();
michael@0 31 } else {
michael@0 32 nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
michael@0 33 unused << rv; // swallow rv to suppress a compiler warning when the macro
michael@0 34 // is #defined to nothing (i.e. in non-DEBUG builds).
michael@0 35 MOZ_ASSERT(NS_SUCCEEDED(rv));
michael@0 36
michael@0 37 // keep a weak reference to the new thread
michael@0 38 sCameraThread = do_GetWeakReference(mCameraThread);
michael@0 39 }
michael@0 40
michael@0 41 // Care must be taken with the mListenerLock read-write lock to prevent
michael@0 42 // deadlocks. Currently this is handled by ensuring that any attempts to
michael@0 43 // acquire the lock for writing (as in Add/RemoveListener()) happen in a
michael@0 44 // runnable dispatched to the Camera Thread--even if the method is being
michael@0 45 // called from that thread. This ensures that if a registered listener
michael@0 46 // (which is invoked with a read-lock) tries to call Add/RemoveListener(),
michael@0 47 // the lock-for-writing attempt won't happen until the listener has
michael@0 48 // completed.
michael@0 49 //
michael@0 50 // Multiple parallel listeners being invoked are not a problem because
michael@0 51 // the read-write lock allows multiple simultaneous read-locks.
michael@0 52 mListenerLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock");
michael@0 53 }
michael@0 54
michael@0 55 CameraControlImpl::~CameraControlImpl()
michael@0 56 {
michael@0 57 if (mListenerLock) {
michael@0 58 PR_DestroyRWLock(mListenerLock);
michael@0 59 mListenerLock = nullptr;
michael@0 60 }
michael@0 61 }
michael@0 62
michael@0 63 already_AddRefed<RecorderProfileManager>
michael@0 64 CameraControlImpl::GetRecorderProfileManager()
michael@0 65 {
michael@0 66 return GetRecorderProfileManagerImpl();
michael@0 67 }
michael@0 68
michael@0 69 void
michael@0 70 CameraControlImpl::Shutdown()
michael@0 71 {
michael@0 72 DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
michael@0 73 }
michael@0 74
michael@0 75 void
michael@0 76 CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState)
michael@0 77 {
michael@0 78 // This callback can run on threads other than the Main Thread and
michael@0 79 // the Camera Thread. On Gonk, it may be called from the camera's
michael@0 80 // local binder thread, should the mediaserver process die.
michael@0 81 RwLockAutoEnterRead lock(mListenerLock);
michael@0 82
michael@0 83 if (aNewState == mHardwareState) {
michael@0 84 DOM_CAMERA_LOGI("OnHardwareStateChange: state did not change from %d\n", mHardwareState);
michael@0 85 return;
michael@0 86 }
michael@0 87
michael@0 88 #ifdef PR_LOGGING
michael@0 89 const char* state[] = { "open", "closed", "failed" };
michael@0 90 MOZ_ASSERT(aNewState >= 0);
michael@0 91 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
michael@0 92 DOM_CAMERA_LOGI("New hardware state is '%s'\n", state[aNewState]);
michael@0 93 } else {
michael@0 94 DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState);
michael@0 95 }
michael@0 96 #endif
michael@0 97
michael@0 98 mHardwareState = aNewState;
michael@0 99
michael@0 100 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 101 CameraControlListener* l = mListeners[i];
michael@0 102 l->OnHardwareStateChange(mHardwareState);
michael@0 103 }
michael@0 104 }
michael@0 105
michael@0 106 void
michael@0 107 CameraControlImpl::OnConfigurationChange()
michael@0 108 {
michael@0 109 MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
michael@0 110 RwLockAutoEnterRead lock(mListenerLock);
michael@0 111
michael@0 112 DOM_CAMERA_LOGI("OnConfigurationChange : %d listeners\n", mListeners.Length());
michael@0 113
michael@0 114 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 115 CameraControlListener* l = mListeners[i];
michael@0 116 l->OnConfigurationChange(mCurrentConfiguration);
michael@0 117 }
michael@0 118 }
michael@0 119
michael@0 120 void
michael@0 121 CameraControlImpl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
michael@0 122 {
michael@0 123 // This callback can run on threads other than the Main Thread and
michael@0 124 // the Camera Thread. On Gonk, it is called from the camera
michael@0 125 // library's auto focus thread.
michael@0 126 RwLockAutoEnterRead lock(mListenerLock);
michael@0 127
michael@0 128 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 129 CameraControlListener* l = mListeners[i];
michael@0 130 l->OnAutoFocusComplete(aAutoFocusSucceeded);
michael@0 131 }
michael@0 132 }
michael@0 133
michael@0 134 void
michael@0 135 CameraControlImpl::OnAutoFocusMoving(bool aIsMoving)
michael@0 136 {
michael@0 137 RwLockAutoEnterRead lock(mListenerLock);
michael@0 138
michael@0 139 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 140 CameraControlListener* l = mListeners[i];
michael@0 141 l->OnAutoFocusMoving(aIsMoving);
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 void
michael@0 146 CameraControlImpl::OnFacesDetected(const nsTArray<Face>& aFaces)
michael@0 147 {
michael@0 148 // This callback can run on threads other than the Main Thread and
michael@0 149 // the Camera Thread. On Gonk, it is called from the camera
michael@0 150 // library's face detection thread.
michael@0 151 RwLockAutoEnterRead lock(mListenerLock);
michael@0 152
michael@0 153 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 154 CameraControlListener* l = mListeners[i];
michael@0 155 l->OnFacesDetected(aFaces);
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 void
michael@0 160 CameraControlImpl::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
michael@0 161 {
michael@0 162 // This callback can run on threads other than the Main Thread and
michael@0 163 // the Camera Thread. On Gonk, it is called from the camera
michael@0 164 // library's snapshot thread.
michael@0 165 RwLockAutoEnterRead lock(mListenerLock);
michael@0 166
michael@0 167 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 168 CameraControlListener* l = mListeners[i];
michael@0 169 l->OnTakePictureComplete(aData, aLength, aMimeType);
michael@0 170 }
michael@0 171 }
michael@0 172
michael@0 173 void
michael@0 174 CameraControlImpl::OnShutter()
michael@0 175 {
michael@0 176 // This callback can run on threads other than the Main Thread and
michael@0 177 // the Camera Thread. On Gonk, it is called from the camera driver's
michael@0 178 // preview thread.
michael@0 179 RwLockAutoEnterRead lock(mListenerLock);
michael@0 180
michael@0 181 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 182 CameraControlListener* l = mListeners[i];
michael@0 183 l->OnShutter();
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 void
michael@0 188 CameraControlImpl::OnClosed()
michael@0 189 {
michael@0 190 // This callback can run on threads other than the Main Thread and
michael@0 191 // the Camera Thread.
michael@0 192 RwLockAutoEnterRead lock(mListenerLock);
michael@0 193
michael@0 194 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 195 CameraControlListener* l = mListeners[i];
michael@0 196 l->OnHardwareStateChange(CameraControlListener::kHardwareClosed);
michael@0 197 }
michael@0 198 }
michael@0 199
michael@0 200 void
michael@0 201 CameraControlImpl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
michael@0 202 int32_t aStatus, int32_t aTrackNumber)
michael@0 203 {
michael@0 204 // This callback can run on threads other than the Main Thread and
michael@0 205 // the Camera Thread. On Gonk, it is called from the media encoder
michael@0 206 // thread.
michael@0 207 RwLockAutoEnterRead lock(mListenerLock);
michael@0 208
michael@0 209 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 210 CameraControlListener* l = mListeners[i];
michael@0 211 l->OnRecorderStateChange(aState, aStatus, aTrackNumber);
michael@0 212 }
michael@0 213 }
michael@0 214
michael@0 215 void
michael@0 216 CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNewState)
michael@0 217 {
michael@0 218 // This callback runs on the Main Thread and the Camera Thread, and
michael@0 219 // may run on the local binder thread, should the mediaserver
michael@0 220 // process die.
michael@0 221 RwLockAutoEnterRead lock(mListenerLock);
michael@0 222
michael@0 223 if (aNewState == mPreviewState) {
michael@0 224 DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState);
michael@0 225 return;
michael@0 226 }
michael@0 227
michael@0 228 #ifdef PR_LOGGING
michael@0 229 const char* state[] = { "stopped", "paused", "started" };
michael@0 230 MOZ_ASSERT(aNewState >= 0);
michael@0 231 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
michael@0 232 DOM_CAMERA_LOGI("New preview state is '%s'\n", state[aNewState]);
michael@0 233 } else {
michael@0 234 DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState);
michael@0 235 }
michael@0 236 #endif
michael@0 237
michael@0 238 mPreviewState = aNewState;
michael@0 239
michael@0 240 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 241 CameraControlListener* l = mListeners[i];
michael@0 242 l->OnPreviewStateChange(mPreviewState);
michael@0 243 }
michael@0 244 }
michael@0 245
michael@0 246 bool
michael@0 247 CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
michael@0 248 {
michael@0 249 // This function runs on neither the Main Thread nor the Camera Thread.
michael@0 250 // On Gonk, it is called from the camera driver's preview thread.
michael@0 251 RwLockAutoEnterRead lock(mListenerLock);
michael@0 252
michael@0 253 DOM_CAMERA_LOGI("OnNewPreviewFrame: we have %d preview frame listener(s)\n",
michael@0 254 mListeners.Length());
michael@0 255
michael@0 256 bool consumed = false;
michael@0 257
michael@0 258 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 259 CameraControlListener* l = mListeners[i];
michael@0 260 consumed = l->OnNewPreviewFrame(aImage, aWidth, aHeight) || consumed;
michael@0 261 }
michael@0 262 return consumed;
michael@0 263 }
michael@0 264
michael@0 265 void
michael@0 266 CameraControlImpl::OnError(CameraControlListener::CameraErrorContext aContext,
michael@0 267 CameraControlListener::CameraError aError)
michael@0 268 {
michael@0 269 // This callback can run on threads other than the Main Thread and
michael@0 270 // the Camera Thread.
michael@0 271 RwLockAutoEnterRead lock(mListenerLock);
michael@0 272
michael@0 273 #ifdef PR_LOGGING
michael@0 274 const char* error[] = {
michael@0 275 "api-failed",
michael@0 276 "init-failed",
michael@0 277 "invalid-configuration",
michael@0 278 "service-failed",
michael@0 279 "set-picture-size-failed",
michael@0 280 "set-thumbnail-size-failed",
michael@0 281 "unknown"
michael@0 282 };
michael@0 283 const char* context[] = {
michael@0 284 "StartCamera",
michael@0 285 "StopCamera",
michael@0 286 "AutoFocus",
michael@0 287 "StartFaceDetection",
michael@0 288 "StopFaceDetection",
michael@0 289 "TakePicture",
michael@0 290 "StartRecording",
michael@0 291 "StopRecording",
michael@0 292 "SetConfiguration",
michael@0 293 "StartPreview",
michael@0 294 "StopPreview",
michael@0 295 "ResumeContinuousFocus",
michael@0 296 "Unspecified"
michael@0 297 };
michael@0 298 if (static_cast<unsigned int>(aError) < sizeof(error) / sizeof(error[0]) &&
michael@0 299 static_cast<unsigned int>(aContext) < sizeof(context) / sizeof(context[0])) {
michael@0 300 DOM_CAMERA_LOGW("CameraControlImpl::OnError : aContext='%s' (%u), aError='%s' (%u)\n",
michael@0 301 context[aContext], aContext, error[aError], aError);
michael@0 302 } else {
michael@0 303 DOM_CAMERA_LOGE("CameraControlImpl::OnError : aContext=%u, aError=%d\n",
michael@0 304 aContext, aError);
michael@0 305 }
michael@0 306 #endif
michael@0 307
michael@0 308 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
michael@0 309 CameraControlListener* l = mListeners[i];
michael@0 310 l->OnError(aContext, aError);
michael@0 311 }
michael@0 312 }
michael@0 313
michael@0 314 // Camera control asynchronous message; these are dispatched from
michael@0 315 // the Main Thread to the Camera Thread, where they are consumed.
michael@0 316
michael@0 317 class CameraControlImpl::ControlMessage : public nsRunnable
michael@0 318 {
michael@0 319 public:
michael@0 320 ControlMessage(CameraControlImpl* aCameraControl,
michael@0 321 CameraControlListener::CameraErrorContext aContext)
michael@0 322 : mCameraControl(aCameraControl)
michael@0 323 , mContext(aContext)
michael@0 324 {
michael@0 325 MOZ_COUNT_CTOR(CameraControlImpl::ControlMessage);
michael@0 326 }
michael@0 327
michael@0 328 virtual ~ControlMessage()
michael@0 329 {
michael@0 330 MOZ_COUNT_DTOR(CameraControlImpl::ControlMessage);
michael@0 331 }
michael@0 332
michael@0 333 virtual nsresult RunImpl() = 0;
michael@0 334
michael@0 335 NS_IMETHOD
michael@0 336 Run() MOZ_OVERRIDE
michael@0 337 {
michael@0 338 MOZ_ASSERT(mCameraControl);
michael@0 339 MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl->mCameraThread);
michael@0 340
michael@0 341 nsresult rv = RunImpl();
michael@0 342 if (NS_FAILED(rv)) {
michael@0 343 DOM_CAMERA_LOGW("Camera control API failed at %d with 0x%x\n", mContext, rv);
michael@0 344 // XXXmikeh - do we want to report a more specific error code?
michael@0 345 mCameraControl->OnError(mContext, CameraControlListener::kErrorApiFailed);
michael@0 346 }
michael@0 347
michael@0 348 return NS_OK;
michael@0 349 }
michael@0 350
michael@0 351 protected:
michael@0 352 nsRefPtr<CameraControlImpl> mCameraControl;
michael@0 353 CameraControlListener::CameraErrorContext mContext;
michael@0 354 };
michael@0 355
michael@0 356 nsresult
michael@0 357 CameraControlImpl::Start(const Configuration* aConfig)
michael@0 358 {
michael@0 359 class Message : public ControlMessage
michael@0 360 {
michael@0 361 public:
michael@0 362 Message(CameraControlImpl* aCameraControl,
michael@0 363 CameraControlListener::CameraErrorContext aContext,
michael@0 364 const Configuration* aConfig)
michael@0 365 : ControlMessage(aCameraControl, aContext)
michael@0 366 , mHaveInitialConfig(false)
michael@0 367 {
michael@0 368 if (aConfig) {
michael@0 369 mConfig = *aConfig;
michael@0 370 mHaveInitialConfig = true;
michael@0 371 }
michael@0 372 }
michael@0 373
michael@0 374 nsresult
michael@0 375 RunImpl() MOZ_OVERRIDE
michael@0 376 {
michael@0 377 if (mHaveInitialConfig) {
michael@0 378 return mCameraControl->StartImpl(&mConfig);
michael@0 379 }
michael@0 380 return mCameraControl->StartImpl();
michael@0 381 }
michael@0 382
michael@0 383 protected:
michael@0 384 bool mHaveInitialConfig;
michael@0 385 Configuration mConfig;
michael@0 386 };
michael@0 387
michael@0 388 return mCameraThread->Dispatch(
michael@0 389 new Message(this, CameraControlListener::kInStartCamera, aConfig), NS_DISPATCH_NORMAL);
michael@0 390 }
michael@0 391
michael@0 392 nsresult
michael@0 393 CameraControlImpl::SetConfiguration(const Configuration& aConfig)
michael@0 394 {
michael@0 395 class Message : public ControlMessage
michael@0 396 {
michael@0 397 public:
michael@0 398 Message(CameraControlImpl* aCameraControl,
michael@0 399 CameraControlListener::CameraErrorContext aContext,
michael@0 400 const Configuration& aConfig)
michael@0 401 : ControlMessage(aCameraControl, aContext)
michael@0 402 , mConfig(aConfig)
michael@0 403 { }
michael@0 404
michael@0 405 nsresult
michael@0 406 RunImpl() MOZ_OVERRIDE
michael@0 407 {
michael@0 408 return mCameraControl->SetConfigurationImpl(mConfig);
michael@0 409 }
michael@0 410
michael@0 411 protected:
michael@0 412 Configuration mConfig;
michael@0 413 };
michael@0 414
michael@0 415 return mCameraThread->Dispatch(
michael@0 416 new Message(this, CameraControlListener::kInSetConfiguration, aConfig), NS_DISPATCH_NORMAL);
michael@0 417 }
michael@0 418
michael@0 419 nsresult
michael@0 420 CameraControlImpl::AutoFocus()
michael@0 421 {
michael@0 422 class Message : public ControlMessage
michael@0 423 {
michael@0 424 public:
michael@0 425 Message(CameraControlImpl* aCameraControl,
michael@0 426 CameraControlListener::CameraErrorContext aContext)
michael@0 427 : ControlMessage(aCameraControl, aContext)
michael@0 428 { }
michael@0 429
michael@0 430 nsresult
michael@0 431 RunImpl() MOZ_OVERRIDE
michael@0 432 {
michael@0 433 return mCameraControl->AutoFocusImpl();
michael@0 434 }
michael@0 435 };
michael@0 436
michael@0 437 return mCameraThread->Dispatch(
michael@0 438 new Message(this, CameraControlListener::kInAutoFocus), NS_DISPATCH_NORMAL);
michael@0 439 }
michael@0 440
michael@0 441 nsresult
michael@0 442 CameraControlImpl::StartFaceDetection()
michael@0 443 {
michael@0 444 class Message : public ControlMessage
michael@0 445 {
michael@0 446 public:
michael@0 447 Message(CameraControlImpl* aCameraControl,
michael@0 448 CameraControlListener::CameraErrorContext aContext)
michael@0 449 : ControlMessage(aCameraControl, aContext)
michael@0 450 { }
michael@0 451
michael@0 452 nsresult
michael@0 453 RunImpl() MOZ_OVERRIDE
michael@0 454 {
michael@0 455 return mCameraControl->StartFaceDetectionImpl();
michael@0 456 }
michael@0 457 };
michael@0 458
michael@0 459 return mCameraThread->Dispatch(
michael@0 460 new Message(this, CameraControlListener::kInStartFaceDetection), NS_DISPATCH_NORMAL);
michael@0 461 }
michael@0 462
michael@0 463 nsresult
michael@0 464 CameraControlImpl::StopFaceDetection()
michael@0 465 {
michael@0 466 class Message : public ControlMessage
michael@0 467 {
michael@0 468 public:
michael@0 469 Message(CameraControlImpl* aCameraControl,
michael@0 470 CameraControlListener::CameraErrorContext aContext)
michael@0 471 : ControlMessage(aCameraControl, aContext)
michael@0 472 { }
michael@0 473
michael@0 474 nsresult
michael@0 475 RunImpl() MOZ_OVERRIDE
michael@0 476 {
michael@0 477 return mCameraControl->StopFaceDetectionImpl();
michael@0 478 }
michael@0 479 };
michael@0 480
michael@0 481 return mCameraThread->Dispatch(
michael@0 482 new Message(this, CameraControlListener::kInStopFaceDetection), NS_DISPATCH_NORMAL);
michael@0 483 }
michael@0 484
michael@0 485 nsresult
michael@0 486 CameraControlImpl::TakePicture()
michael@0 487 {
michael@0 488 class Message : public ControlMessage
michael@0 489 {
michael@0 490 public:
michael@0 491 Message(CameraControlImpl* aCameraControl,
michael@0 492 CameraControlListener::CameraErrorContext aContext)
michael@0 493 : ControlMessage(aCameraControl, aContext)
michael@0 494 { }
michael@0 495
michael@0 496 nsresult
michael@0 497 RunImpl() MOZ_OVERRIDE
michael@0 498 {
michael@0 499 return mCameraControl->TakePictureImpl();
michael@0 500 }
michael@0 501 };
michael@0 502
michael@0 503 return mCameraThread->Dispatch(
michael@0 504 new Message(this, CameraControlListener::kInTakePicture), NS_DISPATCH_NORMAL);
michael@0 505 }
michael@0 506
michael@0 507 nsresult
michael@0 508 CameraControlImpl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
michael@0 509 const StartRecordingOptions* aOptions)
michael@0 510 {
michael@0 511 class Message : public ControlMessage
michael@0 512 {
michael@0 513 public:
michael@0 514 Message(CameraControlImpl* aCameraControl,
michael@0 515 CameraControlListener::CameraErrorContext aContext,
michael@0 516 const StartRecordingOptions* aOptions,
michael@0 517 DeviceStorageFileDescriptor* aFileDescriptor)
michael@0 518 : ControlMessage(aCameraControl, aContext)
michael@0 519 , mOptionsPassed(false)
michael@0 520 , mFileDescriptor(aFileDescriptor)
michael@0 521 {
michael@0 522 if (aOptions) {
michael@0 523 mOptions = *aOptions;
michael@0 524 mOptionsPassed = true;
michael@0 525 }
michael@0 526 }
michael@0 527
michael@0 528 nsresult
michael@0 529 RunImpl() MOZ_OVERRIDE
michael@0 530 {
michael@0 531 return mCameraControl->StartRecordingImpl(mFileDescriptor,
michael@0 532 mOptionsPassed ? &mOptions : nullptr);
michael@0 533 }
michael@0 534
michael@0 535 protected:
michael@0 536 StartRecordingOptions mOptions;
michael@0 537 bool mOptionsPassed;
michael@0 538 nsRefPtr<DeviceStorageFileDescriptor> mFileDescriptor;
michael@0 539 };
michael@0 540
michael@0 541
michael@0 542 return mCameraThread->Dispatch(new Message(this, CameraControlListener::kInStartRecording,
michael@0 543 aOptions, aFileDescriptor), NS_DISPATCH_NORMAL);
michael@0 544 }
michael@0 545
michael@0 546 nsresult
michael@0 547 CameraControlImpl::StopRecording()
michael@0 548 {
michael@0 549 class Message : public ControlMessage
michael@0 550 {
michael@0 551 public:
michael@0 552 Message(CameraControlImpl* aCameraControl,
michael@0 553 CameraControlListener::CameraErrorContext aContext)
michael@0 554 : ControlMessage(aCameraControl, aContext)
michael@0 555 { }
michael@0 556
michael@0 557 nsresult
michael@0 558 RunImpl() MOZ_OVERRIDE
michael@0 559 {
michael@0 560 return mCameraControl->StopRecordingImpl();
michael@0 561 }
michael@0 562 };
michael@0 563
michael@0 564 return mCameraThread->Dispatch(
michael@0 565 new Message(this, CameraControlListener::kInStopRecording), NS_DISPATCH_NORMAL);
michael@0 566 }
michael@0 567
michael@0 568 nsresult
michael@0 569 CameraControlImpl::StartPreview()
michael@0 570 {
michael@0 571 class Message : public ControlMessage
michael@0 572 {
michael@0 573 public:
michael@0 574 Message(CameraControlImpl* aCameraControl,
michael@0 575 CameraControlListener::CameraErrorContext aContext)
michael@0 576 : ControlMessage(aCameraControl, aContext)
michael@0 577 { }
michael@0 578
michael@0 579 nsresult
michael@0 580 RunImpl() MOZ_OVERRIDE
michael@0 581 {
michael@0 582 return mCameraControl->StartPreviewImpl();
michael@0 583 }
michael@0 584 };
michael@0 585
michael@0 586 return mCameraThread->Dispatch(
michael@0 587 new Message(this, CameraControlListener::kInStartPreview), NS_DISPATCH_NORMAL);
michael@0 588 }
michael@0 589
michael@0 590 nsresult
michael@0 591 CameraControlImpl::StopPreview()
michael@0 592 {
michael@0 593 class Message : public ControlMessage
michael@0 594 {
michael@0 595 public:
michael@0 596 Message(CameraControlImpl* aCameraControl,
michael@0 597 CameraControlListener::CameraErrorContext aContext)
michael@0 598 : ControlMessage(aCameraControl, aContext)
michael@0 599 { }
michael@0 600
michael@0 601 nsresult
michael@0 602 RunImpl() MOZ_OVERRIDE
michael@0 603 {
michael@0 604 return mCameraControl->StopPreviewImpl();
michael@0 605 }
michael@0 606 };
michael@0 607
michael@0 608 return mCameraThread->Dispatch(
michael@0 609 new Message(this, CameraControlListener::kInStopPreview), NS_DISPATCH_NORMAL);
michael@0 610 }
michael@0 611
michael@0 612 nsresult
michael@0 613 CameraControlImpl::ResumeContinuousFocus()
michael@0 614 {
michael@0 615 class Message : public ControlMessage
michael@0 616 {
michael@0 617 public:
michael@0 618 Message(CameraControlImpl* aCameraControl,
michael@0 619 CameraControlListener::CameraErrorContext aContext)
michael@0 620 : ControlMessage(aCameraControl, aContext)
michael@0 621 { }
michael@0 622
michael@0 623 nsresult
michael@0 624 RunImpl() MOZ_OVERRIDE
michael@0 625 {
michael@0 626 return mCameraControl->ResumeContinuousFocusImpl();
michael@0 627 }
michael@0 628 };
michael@0 629
michael@0 630 return mCameraThread->Dispatch(
michael@0 631 new Message(this, CameraControlListener::kInResumeContinuousFocus), NS_DISPATCH_NORMAL);
michael@0 632 }
michael@0 633
michael@0 634 nsresult
michael@0 635 CameraControlImpl::Stop()
michael@0 636 {
michael@0 637 class Message : public ControlMessage
michael@0 638 {
michael@0 639 public:
michael@0 640 Message(CameraControlImpl* aCameraControl,
michael@0 641 CameraControlListener::CameraErrorContext aContext)
michael@0 642 : ControlMessage(aCameraControl, aContext)
michael@0 643 { }
michael@0 644
michael@0 645 nsresult
michael@0 646 RunImpl() MOZ_OVERRIDE
michael@0 647 {
michael@0 648 return mCameraControl->StopImpl();
michael@0 649 }
michael@0 650 };
michael@0 651
michael@0 652 return mCameraThread->Dispatch(
michael@0 653 new Message(this, CameraControlListener::kInStopCamera), NS_DISPATCH_NORMAL);
michael@0 654 }
michael@0 655
michael@0 656 class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage
michael@0 657 {
michael@0 658 public:
michael@0 659 ListenerMessage(CameraControlImpl* aCameraControl,
michael@0 660 CameraControlListener* aListener)
michael@0 661 : ControlMessage(aCameraControl, CameraControlListener::kInUnspecified)
michael@0 662 , mListener(aListener)
michael@0 663 { }
michael@0 664
michael@0 665 protected:
michael@0 666 nsRefPtr<CameraControlListener> mListener;
michael@0 667 };
michael@0 668
michael@0 669 void
michael@0 670 CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aListener)
michael@0 671 {
michael@0 672 RwLockAutoEnterWrite lock(mListenerLock);
michael@0 673
michael@0 674 CameraControlListener* l = *mListeners.AppendElement() = aListener;
michael@0 675 DOM_CAMERA_LOGI("Added camera control listener %p\n", l);
michael@0 676
michael@0 677 // Update the newly-added listener's state
michael@0 678 l->OnConfigurationChange(mCurrentConfiguration);
michael@0 679 l->OnHardwareStateChange(mHardwareState);
michael@0 680 l->OnPreviewStateChange(mPreviewState);
michael@0 681 }
michael@0 682
michael@0 683 void
michael@0 684 CameraControlImpl::AddListener(CameraControlListener* aListener)
michael@0 685 {
michael@0 686 class Message : public ListenerMessage
michael@0 687 {
michael@0 688 public:
michael@0 689 Message(CameraControlImpl* aCameraControl,
michael@0 690 CameraControlListener* aListener)
michael@0 691 : ListenerMessage(aCameraControl, aListener)
michael@0 692 { }
michael@0 693
michael@0 694 nsresult
michael@0 695 RunImpl() MOZ_OVERRIDE
michael@0 696 {
michael@0 697 mCameraControl->AddListenerImpl(mListener.forget());
michael@0 698 return NS_OK;
michael@0 699 }
michael@0 700 };
michael@0 701
michael@0 702 mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL);
michael@0 703 }
michael@0 704
michael@0 705 void
michael@0 706 CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener)
michael@0 707 {
michael@0 708 RwLockAutoEnterWrite lock(mListenerLock);
michael@0 709
michael@0 710 nsRefPtr<CameraControlListener> l(aListener);
michael@0 711 mListeners.RemoveElement(l);
michael@0 712 DOM_CAMERA_LOGI("Removed camera control listener %p\n", l.get());
michael@0 713 // XXXmikeh - do we want to notify the listener that it has been removed?
michael@0 714 }
michael@0 715
michael@0 716 void
michael@0 717 CameraControlImpl::RemoveListener(CameraControlListener* aListener)
michael@0 718 {
michael@0 719 class Message : public ListenerMessage
michael@0 720 {
michael@0 721 public:
michael@0 722 Message(CameraControlImpl* aCameraControl, CameraControlListener* aListener)
michael@0 723 : ListenerMessage(aCameraControl, aListener)
michael@0 724 { }
michael@0 725
michael@0 726 nsresult
michael@0 727 RunImpl() MOZ_OVERRIDE
michael@0 728 {
michael@0 729 mCameraControl->RemoveListenerImpl(mListener);
michael@0 730 return NS_OK;
michael@0 731 }
michael@0 732 };
michael@0 733
michael@0 734 mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL);
michael@0 735 }

mercurial