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