Tue, 06 Jan 2015 21:39:09 +0100
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 | } |