Backout a74bd5095902, Bug 959405 - Please update the Buri Moz-central, 1.3, 1.2 with...
[gecko.git] / dom / camera / CameraControlImpl.cpp
blob108ba85553c6781c9c11ad2559847a560ce85129
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/. */
5 #include "base/basictypes.h"
6 #include "mozilla/Assertions.h"
7 #include "DOMCameraPreview.h"
8 #include "CameraRecorderProfiles.h"
9 #include "CameraControlImpl.h"
10 #include "CameraCommon.h"
11 #include "nsGlobalWindow.h"
13 using namespace mozilla;
14 using namespace mozilla::dom;
15 using namespace mozilla::idl;
17 CameraControlImpl::CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread, uint64_t aWindowId)
18 : mCameraId(aCameraId)
19 , mCameraThread(aCameraThread)
20 , mWindowId(aWindowId)
21 , mFileFormat()
22 , mMaxMeteringAreas(0)
23 , mMaxFocusAreas(0)
24 , mPreviewState(PREVIEW_STOPPED)
25 , mDOMPreview(nullptr)
26 , mAutoFocusOnSuccessCb(nullptr)
27 , mAutoFocusOnErrorCb(nullptr)
28 , mTakePictureOnSuccessCb(nullptr)
29 , mTakePictureOnErrorCb(nullptr)
30 , mOnShutterCb(nullptr)
31 , mOnClosedCb(nullptr)
32 , mOnRecorderStateChangeCb(nullptr)
33 , mOnPreviewStateChangeCb(nullptr)
35 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
38 CameraControlImpl::~CameraControlImpl()
40 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
43 // Helpers for string properties.
44 nsresult
45 CameraControlImpl::Set(uint32_t aKey, const nsAString& aValue)
47 SetParameter(aKey, NS_ConvertUTF16toUTF8(aValue).get());
48 return NS_OK;
51 nsresult
52 CameraControlImpl::Get(uint32_t aKey, nsAString& aValue)
54 const char* value = GetParameterConstChar(aKey);
55 if (!value) {
56 return NS_ERROR_FAILURE;
59 aValue.AssignASCII(value);
60 return NS_OK;
63 // Helpers for doubles.
64 nsresult
65 CameraControlImpl::Set(uint32_t aKey, double aValue)
67 SetParameter(aKey, aValue);
68 return NS_OK;
71 nsresult
72 CameraControlImpl::Get(uint32_t aKey, double* aValue)
74 MOZ_ASSERT(aValue);
75 *aValue = GetParameterDouble(aKey);
76 return NS_OK;
79 // Helper for weighted regions.
80 nsresult
81 CameraControlImpl::Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit)
83 if (aLimit == 0) {
84 DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
85 return NS_OK;
88 if (!aValue.isObject()) {
89 return NS_ERROR_INVALID_ARG;
92 uint32_t length = 0;
94 JS::Rooted<JSObject*> regions(aCx, &aValue.toObject());
95 if (!JS_GetArrayLength(aCx, regions, &length)) {
96 return NS_ERROR_FAILURE;
99 DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
100 if (length > aLimit) {
101 length = aLimit;
104 nsTArray<CameraRegion> regionArray;
105 regionArray.SetCapacity(length);
107 for (uint32_t i = 0; i < length; ++i) {
108 JS::Rooted<JS::Value> v(aCx);
110 if (!JS_GetElement(aCx, regions, i, &v)) {
111 return NS_ERROR_FAILURE;
114 CameraRegion* r = regionArray.AppendElement();
116 * These are the default values. We can remove these when the xpidl
117 * dictionary parser gains the ability to grok default values.
119 r->top = -1000;
120 r->left = -1000;
121 r->bottom = 1000;
122 r->right = 1000;
123 r->weight = 1000;
125 nsresult rv = r->Init(aCx, v.address());
126 NS_ENSURE_SUCCESS(rv, rv);
128 DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%d\n",
130 r->top,
131 r->left,
132 r->bottom,
133 r->right,
134 r->weight
137 SetParameter(aKey, regionArray);
138 return NS_OK;
141 nsresult
142 CameraControlImpl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue)
144 nsTArray<CameraRegion> regionArray;
146 GetParameter(aKey, regionArray);
148 JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
149 if (!array) {
150 return NS_ERROR_OUT_OF_MEMORY;
153 uint32_t length = regionArray.Length();
154 DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
156 for (uint32_t i = 0; i < length; ++i) {
157 CameraRegion* r = &regionArray[i];
158 JS::Rooted<JS::Value> v(aCx);
160 JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, nullptr, nullptr));
161 if (!o) {
162 return NS_ERROR_OUT_OF_MEMORY;
165 DOM_CAMERA_LOGI("top=%d\n", r->top);
166 v = INT_TO_JSVAL(r->top);
167 if (!JS_SetProperty(aCx, o, "top", v)) {
168 return NS_ERROR_FAILURE;
170 DOM_CAMERA_LOGI("left=%d\n", r->left);
171 v = INT_TO_JSVAL(r->left);
172 if (!JS_SetProperty(aCx, o, "left", v)) {
173 return NS_ERROR_FAILURE;
175 DOM_CAMERA_LOGI("bottom=%d\n", r->bottom);
176 v = INT_TO_JSVAL(r->bottom);
177 if (!JS_SetProperty(aCx, o, "bottom", v)) {
178 return NS_ERROR_FAILURE;
180 DOM_CAMERA_LOGI("right=%d\n", r->right);
181 v = INT_TO_JSVAL(r->right);
182 if (!JS_SetProperty(aCx, o, "right", v)) {
183 return NS_ERROR_FAILURE;
185 DOM_CAMERA_LOGI("weight=%d\n", r->weight);
186 v = INT_TO_JSVAL(r->weight);
187 if (!JS_SetProperty(aCx, o, "weight", v)) {
188 return NS_ERROR_FAILURE;
191 v = OBJECT_TO_JSVAL(o);
192 if (!JS_SetElement(aCx, array, i, &v)) {
193 return NS_ERROR_FAILURE;
197 *aValue = JS::ObjectValue(*array);
198 return NS_OK;
201 nsresult
202 CameraControlImpl::Set(nsICameraShutterCallback* aOnShutter)
204 mOnShutterCb = new nsMainThreadPtrHolder<nsICameraShutterCallback>(aOnShutter);
205 return NS_OK;
208 nsresult
209 CameraControlImpl::Get(nsICameraShutterCallback** aOnShutter)
211 *aOnShutter = mOnShutterCb;
212 return NS_OK;
215 nsresult
216 CameraControlImpl::Set(nsICameraClosedCallback* aOnClosed)
218 mOnClosedCb = new nsMainThreadPtrHolder<nsICameraClosedCallback>(aOnClosed);
219 return NS_OK;
222 nsresult
223 CameraControlImpl::Get(nsICameraClosedCallback** aOnClosed)
225 *aOnClosed = mOnClosedCb;
226 return NS_OK;
229 nsresult
230 CameraControlImpl::Set(nsICameraRecorderStateChange* aOnRecorderStateChange)
232 mOnRecorderStateChangeCb = new nsMainThreadPtrHolder<nsICameraRecorderStateChange>(aOnRecorderStateChange);
233 return NS_OK;
236 nsresult
237 CameraControlImpl::Get(nsICameraRecorderStateChange** aOnRecorderStateChange)
239 *aOnRecorderStateChange = mOnRecorderStateChangeCb;
240 return NS_OK;
243 nsresult
244 CameraControlImpl::Set(nsICameraPreviewStateChange* aOnPreviewStateChange)
246 mOnPreviewStateChangeCb = new nsMainThreadPtrHolder<nsICameraPreviewStateChange>(aOnPreviewStateChange);
247 return NS_OK;
250 nsresult
251 CameraControlImpl::Get(nsICameraPreviewStateChange** aOnPreviewStateChange)
253 *aOnPreviewStateChange = mOnPreviewStateChangeCb;
254 return NS_OK;
257 nsresult
258 CameraControlImpl::Set(uint32_t aKey, const idl::CameraSize& aSize)
260 SetParameter(aKey, aSize);
261 return NS_OK;
264 nsresult
265 CameraControlImpl::Get(uint32_t aKey, idl::CameraSize& aSize)
267 GetParameter(aKey, aSize);
268 return NS_OK;
271 nsresult
272 CameraControlImpl::Get(uint32_t aKey, int32_t* aValue)
274 MOZ_ASSERT(aValue);
275 *aValue = GetParameterInt32(aKey);
276 return NS_OK;
279 already_AddRefed<RecorderProfileManager>
280 CameraControlImpl::GetRecorderProfileManager()
282 return GetRecorderProfileManagerImpl();
285 void
286 CameraControlImpl::Shutdown()
288 DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
289 mAutoFocusOnSuccessCb = nullptr;
290 mAutoFocusOnErrorCb = nullptr;
291 mTakePictureOnSuccessCb = nullptr;
292 mTakePictureOnErrorCb = nullptr;
293 mOnShutterCb = nullptr;
294 mOnClosedCb = nullptr;
295 mOnRecorderStateChangeCb = nullptr;
296 mOnPreviewStateChangeCb = nullptr;
299 void
300 CameraControlImpl::OnShutterInternal()
302 DOM_CAMERA_LOGI("** SNAP **\n");
303 if (mOnShutterCb.get()) {
304 mOnShutterCb->HandleEvent();
308 void
309 CameraControlImpl::OnShutter()
311 nsCOMPtr<nsIRunnable> onShutter = NS_NewRunnableMethod(this, &CameraControlImpl::OnShutterInternal);
312 nsresult rv = NS_DispatchToMainThread(onShutter);
313 if (NS_FAILED(rv)) {
314 DOM_CAMERA_LOGW("Failed to dispatch onShutter event to main thread (%d)\n", rv);
318 class OnClosedTask : public nsRunnable
320 public:
321 OnClosedTask(nsMainThreadPtrHandle<nsICameraClosedCallback> onClosed, uint64_t aWindowId)
322 : mOnClosedCb(onClosed)
323 , mWindowId(aWindowId)
325 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
328 virtual ~OnClosedTask()
330 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
333 NS_IMETHOD Run()
335 MOZ_ASSERT(NS_IsMainThread());
337 if (mOnClosedCb.get() && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
338 mOnClosedCb->HandleEvent();
340 return NS_OK;
343 protected:
344 nsMainThreadPtrHandle<nsICameraClosedCallback> mOnClosedCb;
345 uint64_t mWindowId;
348 void
349 CameraControlImpl::OnClosed()
351 nsCOMPtr<nsIRunnable> onClosed = new OnClosedTask(mOnClosedCb, mWindowId);
352 nsresult rv = NS_DispatchToMainThread(onClosed);
353 if (NS_FAILED(rv)) {
354 DOM_CAMERA_LOGW("Failed to dispatch onClosed event to main thread (%d)\n", rv);
358 void
359 CameraControlImpl::OnRecorderStateChange(const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber)
361 DOM_CAMERA_LOGI("OnRecorderStateChange: '%s'\n", NS_ConvertUTF16toUTF8(aStateMsg).get());
363 nsCOMPtr<nsIRunnable> onRecorderStateChange = new CameraRecorderStateChange(mOnRecorderStateChangeCb, aStateMsg, aStatus, aTrackNumber, mWindowId);
364 nsresult rv = NS_DispatchToMainThread(onRecorderStateChange);
365 if (NS_FAILED(rv)) {
366 DOM_CAMERA_LOGE("Failed to dispatch onRecorderStateChange event to main thread (%d)\n", rv);
370 void
371 CameraControlImpl::OnPreviewStateChange(PreviewState aNewState)
373 if (aNewState == mPreviewState) {
374 DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState);
375 return;
378 nsString msg;
379 switch (aNewState) {
380 case PREVIEW_STOPPED:
381 msg = NS_LITERAL_STRING("stopped");
382 break;
384 case PREVIEW_STARTED:
385 msg = NS_LITERAL_STRING("started");
386 break;
388 default:
389 MOZ_ASSUME_UNREACHABLE("Preview state can only be PREVIEW_STOPPED or _STARTED!");
392 // const nsString& aStateMsg)
393 DOM_CAMERA_LOGI("OnPreviewStateChange: '%s'\n", NS_ConvertUTF16toUTF8(msg).get());
394 mPreviewState = aNewState;
396 nsCOMPtr<nsIRunnable> onPreviewStateChange = new CameraPreviewStateChange(mOnPreviewStateChangeCb, msg, mWindowId);
397 nsresult rv = NS_DispatchToMainThread(onPreviewStateChange);
398 if (NS_FAILED(rv)) {
399 DOM_CAMERA_LOGE("Failed to dispatch onPreviewStateChange event to main thread (%d)\n", rv);
403 nsresult
404 CameraControlImpl::GetPreviewStream(CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
406 nsCOMPtr<nsIRunnable> getPreviewStreamTask = new GetPreviewStreamTask(this, aSize, onSuccess, onError);
407 return mCameraThread->Dispatch(getPreviewStreamTask, NS_DISPATCH_NORMAL);
410 nsresult
411 CameraControlImpl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
413 MOZ_ASSERT(NS_IsMainThread());
414 bool cancel = false;
416 nsCOMPtr<nsICameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.get();
417 if (cb) {
419 * We already have a callback, so someone has already
420 * called autoFocus() -- cancel it.
422 mAutoFocusOnSuccessCb = nullptr;
423 mAutoFocusOnErrorCb = nullptr;
424 cancel = true;
427 nsCOMPtr<nsIRunnable> autoFocusTask = new AutoFocusTask(this, cancel, onSuccess, onError);
428 return mCameraThread->Dispatch(autoFocusTask, NS_DISPATCH_NORMAL);
431 nsresult
432 CameraControlImpl::TakePicture(const CameraSize& aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, uint64_t aDateTime, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
434 MOZ_ASSERT(NS_IsMainThread());
435 bool cancel = false;
437 nsCOMPtr<nsICameraTakePictureCallback> cb = mTakePictureOnSuccessCb.get();
438 if (cb) {
440 * We already have a callback, so someone has already
441 * called takePicture() -- cancel it.
443 mTakePictureOnSuccessCb = nullptr;
444 mTakePictureOnErrorCb = nullptr;
445 cancel = true;
448 nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, cancel, aSize, aRotation, aFileFormat, aPosition, aDateTime, onSuccess, onError);
449 return mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL);
452 nsresult
453 CameraControlImpl::StartRecording(CameraStartRecordingOptions* aOptions, nsIFile* aFolder, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
455 nsCOMPtr<nsIFile> clone;
456 aFolder->Clone(getter_AddRefs(clone));
458 nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, *aOptions, clone, aFilename, onSuccess, onError, mWindowId);
459 return mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
462 nsresult
463 CameraControlImpl::StopRecording()
465 nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this);
466 return mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
469 nsresult
470 CameraControlImpl::StartPreview(DOMCameraPreview* aDOMPreview)
472 nsCOMPtr<nsIRunnable> startPreviewTask = new StartPreviewTask(this, aDOMPreview);
473 return mCameraThread->Dispatch(startPreviewTask, NS_DISPATCH_NORMAL);
476 void
477 CameraControlImpl::StopPreview()
479 nsCOMPtr<nsIRunnable> stopPreviewTask = new StopPreviewTask(this);
480 mCameraThread->Dispatch(stopPreviewTask, NS_DISPATCH_NORMAL);
483 nsresult
484 CameraControlImpl::GetPreviewStreamVideoMode(CameraRecorderOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
486 nsCOMPtr<nsIRunnable> getPreviewStreamVideoModeTask = new GetPreviewStreamVideoModeTask(this, *aOptions, onSuccess, onError);
487 return mCameraThread->Dispatch(getPreviewStreamVideoModeTask, NS_DISPATCH_NORMAL);
490 nsresult
491 CameraControlImpl::ReleaseHardware(nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError)
493 nsCOMPtr<nsIRunnable> releaseHardwareTask = new ReleaseHardwareTask(this, onSuccess, onError);
494 return mCameraThread->Dispatch(releaseHardwareTask, NS_DISPATCH_NORMAL);
497 bool
498 CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
500 if (!mDOMPreview) {
501 return false;
504 return mDOMPreview->ReceiveFrame(aBuffer, aFormat, aBuilder);
507 NS_IMETHODIMP
508 GetPreviewStreamResult::Run()
511 * The camera preview stream object is DOM-facing, and as such
512 * must be a cycle-collection participant created on the main
513 * thread.
515 MOZ_ASSERT(NS_IsMainThread());
517 nsCOMPtr<nsICameraPreviewStreamCallback> onSuccess = mOnSuccessCb.get();
518 nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
519 if (onSuccess && nsDOMCameraManager::IsWindowStillActive(mWindowId) && window) {
520 nsCOMPtr<nsIDOMMediaStream> stream =
521 new DOMCameraPreview(window, mCameraControl, mWidth, mHeight,
522 mFramesPerSecond);
523 onSuccess->HandleEvent(stream);
525 return NS_OK;