dom/camera/CameraControlImpl.cpp

changeset 0
6474c204b198
     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 +}

mercurial