1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/DOMCameraControl.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1354 @@ 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 "DOMCameraControl.h" 1.9 +#include "base/basictypes.h" 1.10 +#include "nsCOMPtr.h" 1.11 +#include "nsDOMClassInfo.h" 1.12 +#include "nsHashPropertyBag.h" 1.13 +#include "nsThread.h" 1.14 +#include "DeviceStorage.h" 1.15 +#include "DeviceStorageFileDescriptor.h" 1.16 +#include "mozilla/dom/TabChild.h" 1.17 +#include "mozilla/ipc/FileDescriptorUtils.h" 1.18 +#include "mozilla/MediaManager.h" 1.19 +#include "mozilla/Services.h" 1.20 +#include "mozilla/unused.h" 1.21 +#include "nsIAppsService.h" 1.22 +#include "nsIObserverService.h" 1.23 +#include "nsIDOMDeviceStorage.h" 1.24 +#include "nsIDOMEventListener.h" 1.25 +#include "nsIScriptSecurityManager.h" 1.26 +#include "Navigator.h" 1.27 +#include "nsXULAppAPI.h" 1.28 +#include "DOMCameraManager.h" 1.29 +#include "DOMCameraCapabilities.h" 1.30 +#include "CameraCommon.h" 1.31 +#include "nsGlobalWindow.h" 1.32 +#include "CameraPreviewMediaStream.h" 1.33 +#include "mozilla/dom/CameraControlBinding.h" 1.34 +#include "mozilla/dom/CameraManagerBinding.h" 1.35 +#include "mozilla/dom/CameraCapabilitiesBinding.h" 1.36 +#include "DOMCameraDetectedFace.h" 1.37 +#include "mozilla/dom/BindingUtils.h" 1.38 + 1.39 +using namespace mozilla; 1.40 +using namespace mozilla::dom; 1.41 +using namespace mozilla::ipc; 1.42 + 1.43 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl) 1.44 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.45 + NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream) 1.46 +NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream) 1.47 + 1.48 +NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream) 1.49 +NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream) 1.50 + 1.51 +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream, 1.52 + mCapabilities, 1.53 + mWindow, 1.54 + mGetCameraOnSuccessCb, 1.55 + mGetCameraOnErrorCb, 1.56 + mAutoFocusOnSuccessCb, 1.57 + mAutoFocusOnErrorCb, 1.58 + mTakePictureOnSuccessCb, 1.59 + mTakePictureOnErrorCb, 1.60 + mStartRecordingOnSuccessCb, 1.61 + mStartRecordingOnErrorCb, 1.62 + mReleaseOnSuccessCb, 1.63 + mReleaseOnErrorCb, 1.64 + mSetConfigurationOnSuccessCb, 1.65 + mSetConfigurationOnErrorCb, 1.66 + mOnShutterCb, 1.67 + mOnClosedCb, 1.68 + mOnRecorderStateChangeCb, 1.69 + mOnPreviewStateChangeCb, 1.70 + mOnAutoFocusMovingCb, 1.71 + mOnFacesDetectedCb) 1.72 + 1.73 +/* static */ 1.74 +bool 1.75 +nsDOMCameraControl::HasSupport(JSContext* aCx, JSObject* aGlobal) 1.76 +{ 1.77 + return Navigator::HasCameraSupport(aCx, aGlobal); 1.78 +} 1.79 + 1.80 +class mozilla::StartRecordingHelper : public nsIDOMEventListener 1.81 +{ 1.82 +public: 1.83 + NS_DECL_ISUPPORTS 1.84 + NS_DECL_NSIDOMEVENTLISTENER 1.85 + 1.86 + StartRecordingHelper(nsDOMCameraControl* aDOMCameraControl) 1.87 + : mDOMCameraControl(aDOMCameraControl) 1.88 + { 1.89 + MOZ_COUNT_CTOR(StartRecordingHelper); 1.90 + } 1.91 + 1.92 +protected: 1.93 + virtual ~StartRecordingHelper() 1.94 + { 1.95 + MOZ_COUNT_DTOR(StartRecordingHelper); 1.96 + } 1.97 + 1.98 +protected: 1.99 + nsRefPtr<nsDOMCameraControl> mDOMCameraControl; 1.100 +}; 1.101 + 1.102 +NS_IMETHODIMP 1.103 +StartRecordingHelper::HandleEvent(nsIDOMEvent* aEvent) 1.104 +{ 1.105 + nsString eventType; 1.106 + aEvent->GetType(eventType); 1.107 + 1.108 + mDOMCameraControl->OnCreatedFileDescriptor(eventType.EqualsLiteral("success")); 1.109 + return NS_OK; 1.110 +} 1.111 + 1.112 +NS_IMPL_ISUPPORTS(mozilla::StartRecordingHelper, nsIDOMEventListener) 1.113 + 1.114 +nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration() 1.115 + : CameraConfiguration() 1.116 + , mMaxFocusAreas(0) 1.117 + , mMaxMeteringAreas(0) 1.118 +{ 1.119 + MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration); 1.120 +} 1.121 + 1.122 +nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration(const CameraConfiguration& aConfiguration) 1.123 + : CameraConfiguration(aConfiguration) 1.124 + , mMaxFocusAreas(0) 1.125 + , mMaxMeteringAreas(0) 1.126 +{ 1.127 + MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration); 1.128 +} 1.129 + 1.130 +nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration() 1.131 +{ 1.132 + MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration); 1.133 +} 1.134 + 1.135 +nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, 1.136 + const CameraConfiguration& aInitialConfig, 1.137 + GetCameraCallback* aOnSuccess, 1.138 + CameraErrorCallback* aOnError, 1.139 + nsPIDOMWindow* aWindow) 1.140 + : DOMMediaStream() 1.141 + , mCameraControl(nullptr) 1.142 + , mAudioChannelAgent(nullptr) 1.143 + , mGetCameraOnSuccessCb(aOnSuccess) 1.144 + , mGetCameraOnErrorCb(aOnError) 1.145 + , mAutoFocusOnSuccessCb(nullptr) 1.146 + , mAutoFocusOnErrorCb(nullptr) 1.147 + , mTakePictureOnSuccessCb(nullptr) 1.148 + , mTakePictureOnErrorCb(nullptr) 1.149 + , mStartRecordingOnSuccessCb(nullptr) 1.150 + , mStartRecordingOnErrorCb(nullptr) 1.151 + , mReleaseOnSuccessCb(nullptr) 1.152 + , mReleaseOnErrorCb(nullptr) 1.153 + , mSetConfigurationOnSuccessCb(nullptr) 1.154 + , mSetConfigurationOnErrorCb(nullptr) 1.155 + , mOnShutterCb(nullptr) 1.156 + , mOnClosedCb(nullptr) 1.157 + , mOnRecorderStateChangeCb(nullptr) 1.158 + , mOnPreviewStateChangeCb(nullptr) 1.159 + , mOnAutoFocusMovingCb(nullptr) 1.160 + , mOnFacesDetectedCb(nullptr) 1.161 + , mWindow(aWindow) 1.162 +{ 1.163 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.164 + mInput = new CameraPreviewMediaStream(this); 1.165 + 1.166 + SetIsDOMBinding(); 1.167 + 1.168 + nsRefPtr<DOMCameraConfiguration> initialConfig = 1.169 + new DOMCameraConfiguration(aInitialConfig); 1.170 + 1.171 + // Create and initialize the underlying camera. 1.172 + ICameraControl::Configuration config; 1.173 + 1.174 + switch (aInitialConfig.mMode) { 1.175 + case CameraMode::Picture: 1.176 + config.mMode = ICameraControl::kPictureMode; 1.177 + break; 1.178 + 1.179 + case CameraMode::Video: 1.180 + config.mMode = ICameraControl::kVideoMode; 1.181 + break; 1.182 + 1.183 + default: 1.184 + MOZ_ASSUME_UNREACHABLE("Unanticipated camera mode!"); 1.185 + } 1.186 + 1.187 + config.mPreviewSize.width = aInitialConfig.mPreviewSize.mWidth; 1.188 + config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight; 1.189 + config.mRecorderProfile = aInitialConfig.mRecorderProfile; 1.190 + 1.191 + mCameraControl = ICameraControl::Create(aCameraId); 1.192 + mCurrentConfiguration = initialConfig.forget(); 1.193 + 1.194 + // Attach our DOM-facing media stream to our viewfinder stream. 1.195 + mStream = mInput; 1.196 + MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!"); 1.197 + if (mWindow->GetExtantDoc()) { 1.198 + CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal()); 1.199 + } 1.200 + 1.201 + // Register a listener for camera events. 1.202 + mListener = new DOMCameraControlListener(this, mInput); 1.203 + mCameraControl->AddListener(mListener); 1.204 + 1.205 + // Start the camera... 1.206 + nsresult rv = mCameraControl->Start(&config); 1.207 + if (NS_FAILED(rv)) { 1.208 + mListener->OnError(DOMCameraControlListener::kInStartCamera, 1.209 + DOMCameraControlListener::kErrorApiFailed); 1.210 + } 1.211 +} 1.212 + 1.213 +nsDOMCameraControl::~nsDOMCameraControl() 1.214 +{ 1.215 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.216 +} 1.217 + 1.218 +JSObject* 1.219 +nsDOMCameraControl::WrapObject(JSContext* aCx) 1.220 +{ 1.221 + return CameraControlBinding::Wrap(aCx, this); 1.222 +} 1.223 + 1.224 +bool 1.225 +nsDOMCameraControl::IsWindowStillActive() 1.226 +{ 1.227 + return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID()); 1.228 +} 1.229 + 1.230 +// JS-to-native helpers 1.231 +// Setter for weighted regions: { top, bottom, left, right, weight } 1.232 +nsresult 1.233 +nsDOMCameraControl::Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit) 1.234 +{ 1.235 + if (aLimit == 0) { 1.236 + DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__); 1.237 + return NS_OK; 1.238 + } 1.239 + 1.240 + if (!aValue.isObject()) { 1.241 + return NS_ERROR_INVALID_ARG; 1.242 + } 1.243 + 1.244 + uint32_t length = 0; 1.245 + 1.246 + JS::Rooted<JSObject*> regions(aCx, &aValue.toObject()); 1.247 + if (!JS_GetArrayLength(aCx, regions, &length)) { 1.248 + return NS_ERROR_FAILURE; 1.249 + } 1.250 + 1.251 + DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit); 1.252 + if (length > aLimit) { 1.253 + length = aLimit; 1.254 + } 1.255 + 1.256 + nsTArray<ICameraControl::Region> regionArray; 1.257 + regionArray.SetCapacity(length); 1.258 + 1.259 + for (uint32_t i = 0; i < length; ++i) { 1.260 + JS::Rooted<JS::Value> v(aCx); 1.261 + 1.262 + if (!JS_GetElement(aCx, regions, i, &v)) { 1.263 + return NS_ERROR_FAILURE; 1.264 + } 1.265 + 1.266 + CameraRegion region; 1.267 + if (!region.Init(aCx, v)) { 1.268 + return NS_ERROR_FAILURE; 1.269 + } 1.270 + 1.271 + ICameraControl::Region* r = regionArray.AppendElement(); 1.272 + r->top = region.mTop; 1.273 + r->left = region.mLeft; 1.274 + r->bottom = region.mBottom; 1.275 + r->right = region.mRight; 1.276 + r->weight = region.mWeight; 1.277 + 1.278 + DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n", 1.279 + i, 1.280 + r->top, 1.281 + r->left, 1.282 + r->bottom, 1.283 + r->right, 1.284 + r->weight 1.285 + ); 1.286 + } 1.287 + return mCameraControl->Set(aKey, regionArray); 1.288 +} 1.289 + 1.290 +// Getter for weighted regions: { top, bottom, left, right, weight } 1.291 +nsresult 1.292 +nsDOMCameraControl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue) 1.293 +{ 1.294 + nsTArray<ICameraControl::Region> regionArray; 1.295 + 1.296 + nsresult rv = mCameraControl->Get(aKey, regionArray); 1.297 + NS_ENSURE_SUCCESS(rv, rv); 1.298 + 1.299 + JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0)); 1.300 + if (!array) { 1.301 + return NS_ERROR_OUT_OF_MEMORY; 1.302 + } 1.303 + 1.304 + uint32_t length = regionArray.Length(); 1.305 + DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length); 1.306 + 1.307 + for (uint32_t i = 0; i < length; ++i) { 1.308 + ICameraControl::Region* r = ®ionArray[i]; 1.309 + JS::Rooted<JS::Value> v(aCx); 1.310 + 1.311 + JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); 1.312 + if (!o) { 1.313 + return NS_ERROR_OUT_OF_MEMORY; 1.314 + } 1.315 + 1.316 + DOM_CAMERA_LOGI("top=%d\n", r->top); 1.317 + v = INT_TO_JSVAL(r->top); 1.318 + if (!JS_SetProperty(aCx, o, "top", v)) { 1.319 + return NS_ERROR_FAILURE; 1.320 + } 1.321 + DOM_CAMERA_LOGI("left=%d\n", r->left); 1.322 + v = INT_TO_JSVAL(r->left); 1.323 + if (!JS_SetProperty(aCx, o, "left", v)) { 1.324 + return NS_ERROR_FAILURE; 1.325 + } 1.326 + DOM_CAMERA_LOGI("bottom=%d\n", r->bottom); 1.327 + v = INT_TO_JSVAL(r->bottom); 1.328 + if (!JS_SetProperty(aCx, o, "bottom", v)) { 1.329 + return NS_ERROR_FAILURE; 1.330 + } 1.331 + DOM_CAMERA_LOGI("right=%d\n", r->right); 1.332 + v = INT_TO_JSVAL(r->right); 1.333 + if (!JS_SetProperty(aCx, o, "right", v)) { 1.334 + return NS_ERROR_FAILURE; 1.335 + } 1.336 + DOM_CAMERA_LOGI("weight=%d\n", r->weight); 1.337 + v = INT_TO_JSVAL(r->weight); 1.338 + if (!JS_SetProperty(aCx, o, "weight", v)) { 1.339 + return NS_ERROR_FAILURE; 1.340 + } 1.341 + 1.342 + if (!JS_SetElement(aCx, array, i, o)) { 1.343 + return NS_ERROR_FAILURE; 1.344 + } 1.345 + } 1.346 + 1.347 + *aValue = JS::ObjectValue(*array); 1.348 + return NS_OK; 1.349 +} 1.350 + 1.351 +void 1.352 +nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv) 1.353 +{ 1.354 + MOZ_ASSERT(mCameraControl); 1.355 + aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect); 1.356 +} 1.357 +void 1.358 +nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv) 1.359 +{ 1.360 + MOZ_ASSERT(mCameraControl); 1.361 + aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect); 1.362 +} 1.363 + 1.364 +void 1.365 +nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv) 1.366 +{ 1.367 + MOZ_ASSERT(mCameraControl); 1.368 + aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode); 1.369 +} 1.370 +void 1.371 +nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv) 1.372 +{ 1.373 + MOZ_ASSERT(mCameraControl); 1.374 + aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode); 1.375 +} 1.376 + 1.377 +void 1.378 +nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv) 1.379 +{ 1.380 + MOZ_ASSERT(mCameraControl); 1.381 + aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode); 1.382 +} 1.383 +void 1.384 +nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv) 1.385 +{ 1.386 + MOZ_ASSERT(mCameraControl); 1.387 + aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode); 1.388 +} 1.389 + 1.390 +void 1.391 +nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv) 1.392 +{ 1.393 + MOZ_ASSERT(mCameraControl); 1.394 + aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode); 1.395 +} 1.396 +void 1.397 +nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv) 1.398 +{ 1.399 + MOZ_ASSERT(mCameraControl); 1.400 + aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode); 1.401 +} 1.402 + 1.403 +void 1.404 +nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv) 1.405 +{ 1.406 + MOZ_ASSERT(mCameraControl); 1.407 + aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode); 1.408 +} 1.409 +void 1.410 +nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv) 1.411 +{ 1.412 + MOZ_ASSERT(mCameraControl); 1.413 + aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode); 1.414 +} 1.415 + 1.416 +void 1.417 +nsDOMCameraControl::GetIsoMode(nsString& aIsoMode, ErrorResult& aRv) 1.418 +{ 1.419 + MOZ_ASSERT(mCameraControl); 1.420 + aRv = mCameraControl->Get(CAMERA_PARAM_ISOMODE, aIsoMode); 1.421 +} 1.422 +void 1.423 +nsDOMCameraControl::SetIsoMode(const nsAString& aIsoMode, ErrorResult& aRv) 1.424 +{ 1.425 + MOZ_ASSERT(mCameraControl); 1.426 + aRv = mCameraControl->Set(CAMERA_PARAM_ISOMODE, aIsoMode); 1.427 +} 1.428 + 1.429 +double 1.430 +nsDOMCameraControl::GetZoom(ErrorResult& aRv) 1.431 +{ 1.432 + MOZ_ASSERT(mCameraControl); 1.433 + 1.434 + double zoom; 1.435 + aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, zoom); 1.436 + return zoom; 1.437 +} 1.438 + 1.439 +void 1.440 +nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv) 1.441 +{ 1.442 + MOZ_ASSERT(mCameraControl); 1.443 + aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom); 1.444 +} 1.445 + 1.446 +/* attribute jsval meteringAreas; */ 1.447 +void 1.448 +nsDOMCameraControl::GetMeteringAreas(JSContext* cx, 1.449 + JS::MutableHandle<JS::Value> aMeteringAreas, 1.450 + ErrorResult& aRv) 1.451 +{ 1.452 + aRv = Get(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas.address()); 1.453 +} 1.454 + 1.455 +void 1.456 +nsDOMCameraControl::SetMeteringAreas(JSContext* cx, JS::Handle<JS::Value> aMeteringAreas, ErrorResult& aRv) 1.457 +{ 1.458 + aRv = Set(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas, 1.459 + mCurrentConfiguration->mMaxMeteringAreas); 1.460 +} 1.461 + 1.462 +void 1.463 +nsDOMCameraControl::GetFocusAreas(JSContext* cx, 1.464 + JS::MutableHandle<JS::Value> aFocusAreas, 1.465 + ErrorResult& aRv) 1.466 +{ 1.467 + aRv = Get(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas.address()); 1.468 +} 1.469 +void 1.470 +nsDOMCameraControl::SetFocusAreas(JSContext* cx, JS::Handle<JS::Value> aFocusAreas, ErrorResult& aRv) 1.471 +{ 1.472 + aRv = Set(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas, 1.473 + mCurrentConfiguration->mMaxFocusAreas); 1.474 +} 1.475 + 1.476 +static nsresult 1.477 +GetSize(JSContext* aCx, JS::Value* aValue, const ICameraControl::Size& aSize) 1.478 +{ 1.479 + JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); 1.480 + if (!o) { 1.481 + return NS_ERROR_OUT_OF_MEMORY; 1.482 + } 1.483 + 1.484 + JS::Rooted<JS::Value> v(aCx); 1.485 + 1.486 + v = INT_TO_JSVAL(aSize.width); 1.487 + if (!JS_SetProperty(aCx, o, "width", v)) { 1.488 + return NS_ERROR_FAILURE; 1.489 + } 1.490 + v = INT_TO_JSVAL(aSize.height); 1.491 + if (!JS_SetProperty(aCx, o, "height", v)) { 1.492 + return NS_ERROR_FAILURE; 1.493 + } 1.494 + 1.495 + *aValue = JS::ObjectValue(*o); 1.496 + return NS_OK; 1.497 +} 1.498 + 1.499 +/* attribute any pictureSize */ 1.500 +void 1.501 +nsDOMCameraControl::GetPictureSize(JSContext* cx, 1.502 + JS::MutableHandle<JS::Value> aSize, 1.503 + ErrorResult& aRv) 1.504 +{ 1.505 + ICameraControl::Size size; 1.506 + aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size); 1.507 + if (aRv.Failed()) { 1.508 + return; 1.509 + } 1.510 + 1.511 + aRv = GetSize(cx, aSize.address(), size); 1.512 +} 1.513 +void 1.514 +nsDOMCameraControl::SetPictureSize(JSContext* aCx, JS::Handle<JS::Value> aSize, ErrorResult& aRv) 1.515 +{ 1.516 + CameraSize size; 1.517 + if (!size.Init(aCx, aSize)) { 1.518 + aRv = NS_ERROR_FAILURE; 1.519 + return; 1.520 + } 1.521 + 1.522 + ICameraControl::Size s = { size.mWidth, size.mHeight }; 1.523 + aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s); 1.524 +} 1.525 + 1.526 +/* attribute any thumbnailSize */ 1.527 +void 1.528 +nsDOMCameraControl::GetThumbnailSize(JSContext* aCx, 1.529 + JS::MutableHandle<JS::Value> aSize, 1.530 + ErrorResult& aRv) 1.531 +{ 1.532 + ICameraControl::Size size; 1.533 + aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size); 1.534 + if (aRv.Failed()) { 1.535 + return; 1.536 + } 1.537 + 1.538 + aRv = GetSize(aCx, aSize.address(), size); 1.539 +} 1.540 +void 1.541 +nsDOMCameraControl::SetThumbnailSize(JSContext* aCx, JS::Handle<JS::Value> aSize, ErrorResult& aRv) 1.542 +{ 1.543 + CameraSize size; 1.544 + if (!size.Init(aCx, aSize)) { 1.545 + aRv = NS_ERROR_FAILURE; 1.546 + return; 1.547 + } 1.548 + 1.549 + ICameraControl::Size s = { size.mWidth, size.mHeight }; 1.550 + aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s); 1.551 +} 1.552 + 1.553 +double 1.554 +nsDOMCameraControl::GetFocalLength(ErrorResult& aRv) 1.555 +{ 1.556 + MOZ_ASSERT(mCameraControl); 1.557 + 1.558 + double focalLength; 1.559 + aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, focalLength); 1.560 + return focalLength; 1.561 +} 1.562 + 1.563 +double 1.564 +nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv) 1.565 +{ 1.566 + MOZ_ASSERT(mCameraControl); 1.567 + 1.568 + double distance; 1.569 + aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, distance); 1.570 + return distance; 1.571 +} 1.572 + 1.573 +double 1.574 +nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv) 1.575 +{ 1.576 + MOZ_ASSERT(mCameraControl); 1.577 + 1.578 + double distance; 1.579 + aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, distance); 1.580 + return distance; 1.581 +} 1.582 + 1.583 +double 1.584 +nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv) 1.585 +{ 1.586 + MOZ_ASSERT(mCameraControl); 1.587 + 1.588 + double distance; 1.589 + aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, distance); 1.590 + return distance; 1.591 +} 1.592 + 1.593 +void 1.594 +nsDOMCameraControl::SetExposureCompensation(const Optional<double>& aCompensation, ErrorResult& aRv) 1.595 +{ 1.596 + MOZ_ASSERT(mCameraControl); 1.597 + 1.598 + if (!aCompensation.WasPassed()) { 1.599 + // use NaN to switch the camera back into auto mode 1.600 + aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN); 1.601 + return; 1.602 + } 1.603 + 1.604 + aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation.Value()); 1.605 +} 1.606 + 1.607 +double 1.608 +nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv) 1.609 +{ 1.610 + MOZ_ASSERT(mCameraControl); 1.611 + 1.612 + double compensation; 1.613 + aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation); 1.614 + return compensation; 1.615 +} 1.616 + 1.617 +int32_t 1.618 +nsDOMCameraControl::SensorAngle() 1.619 +{ 1.620 + MOZ_ASSERT(mCameraControl); 1.621 + 1.622 + int32_t angle = 0; 1.623 + mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle); 1.624 + return angle; 1.625 +} 1.626 + 1.627 +// Callback attributes 1.628 + 1.629 +CameraShutterCallback* 1.630 +nsDOMCameraControl::GetOnShutter() 1.631 +{ 1.632 + return mOnShutterCb; 1.633 +} 1.634 +void 1.635 +nsDOMCameraControl::SetOnShutter(CameraShutterCallback* aCb) 1.636 +{ 1.637 + mOnShutterCb = aCb; 1.638 +} 1.639 + 1.640 +CameraClosedCallback* 1.641 +nsDOMCameraControl::GetOnClosed() 1.642 +{ 1.643 + return mOnClosedCb; 1.644 +} 1.645 +void 1.646 +nsDOMCameraControl::SetOnClosed(CameraClosedCallback* aCb) 1.647 +{ 1.648 + mOnClosedCb = aCb; 1.649 +} 1.650 + 1.651 +CameraRecorderStateChange* 1.652 +nsDOMCameraControl::GetOnRecorderStateChange() 1.653 +{ 1.654 + return mOnRecorderStateChangeCb; 1.655 +} 1.656 +void 1.657 +nsDOMCameraControl::SetOnRecorderStateChange(CameraRecorderStateChange* aCb) 1.658 +{ 1.659 + mOnRecorderStateChangeCb = aCb; 1.660 +} 1.661 + 1.662 +CameraPreviewStateChange* 1.663 +nsDOMCameraControl::GetOnPreviewStateChange() 1.664 +{ 1.665 + return mOnPreviewStateChangeCb; 1.666 +} 1.667 +void 1.668 +nsDOMCameraControl::SetOnPreviewStateChange(CameraPreviewStateChange* aCb) 1.669 +{ 1.670 + mOnPreviewStateChangeCb = aCb; 1.671 +} 1.672 + 1.673 +CameraAutoFocusMovingCallback* 1.674 +nsDOMCameraControl::GetOnAutoFocusMoving() 1.675 +{ 1.676 + return mOnAutoFocusMovingCb; 1.677 +} 1.678 +void 1.679 +nsDOMCameraControl::SetOnAutoFocusMoving(CameraAutoFocusMovingCallback* aCb) 1.680 +{ 1.681 + mOnAutoFocusMovingCb = aCb; 1.682 +} 1.683 + 1.684 +CameraFaceDetectionCallback* 1.685 +nsDOMCameraControl::GetOnFacesDetected() 1.686 +{ 1.687 + return mOnFacesDetectedCb; 1.688 +} 1.689 +void 1.690 +nsDOMCameraControl::SetOnFacesDetected(CameraFaceDetectionCallback* aCb) 1.691 +{ 1.692 + mOnFacesDetectedCb = aCb; 1.693 +} 1.694 + 1.695 +already_AddRefed<dom::CameraCapabilities> 1.696 +nsDOMCameraControl::Capabilities() 1.697 +{ 1.698 + nsRefPtr<CameraCapabilities> caps = mCapabilities; 1.699 + 1.700 + if (!caps) { 1.701 + caps = new CameraCapabilities(mWindow); 1.702 + nsresult rv = caps->Populate(mCameraControl); 1.703 + if (NS_FAILED(rv)) { 1.704 + DOM_CAMERA_LOGW("Failed to populate camera capabilities (%d)\n", rv); 1.705 + return nullptr; 1.706 + } 1.707 + mCapabilities = caps; 1.708 + } 1.709 + 1.710 + return caps.forget(); 1.711 +} 1.712 + 1.713 +// Methods. 1.714 +void 1.715 +nsDOMCameraControl::StartRecording(const CameraStartRecordingOptions& aOptions, 1.716 + nsDOMDeviceStorage& aStorageArea, 1.717 + const nsAString& aFilename, 1.718 + CameraStartRecordingCallback& aOnSuccess, 1.719 + const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, 1.720 + ErrorResult& aRv) 1.721 +{ 1.722 + MOZ_ASSERT(mCameraControl); 1.723 + 1.724 + NotifyRecordingStatusChange(NS_LITERAL_STRING("starting")); 1.725 + 1.726 +#ifdef MOZ_B2G 1.727 + if (!mAudioChannelAgent) { 1.728 + mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1"); 1.729 + if (mAudioChannelAgent) { 1.730 + // Camera app will stop recording when it falls to the background, so no callback is necessary. 1.731 + mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr); 1.732 + // Video recording doesn't output any sound, so it's not necessary to check canPlay. 1.733 + int32_t canPlay; 1.734 + mAudioChannelAgent->StartPlaying(&canPlay); 1.735 + } 1.736 + } 1.737 +#endif 1.738 + 1.739 + nsCOMPtr<nsIDOMDOMRequest> request; 1.740 + mDSFileDescriptor = new DeviceStorageFileDescriptor(); 1.741 + aRv = aStorageArea.CreateFileDescriptor(aFilename, mDSFileDescriptor.get(), 1.742 + getter_AddRefs(request)); 1.743 + if (aRv.Failed()) { 1.744 + return; 1.745 + } 1.746 + 1.747 + mOptions = aOptions; 1.748 + mStartRecordingOnSuccessCb = &aOnSuccess; 1.749 + mStartRecordingOnErrorCb = nullptr; 1.750 + if (aOnError.WasPassed()) { 1.751 + mStartRecordingOnErrorCb = &aOnError.Value(); 1.752 + } 1.753 + 1.754 + nsCOMPtr<nsIDOMEventListener> listener = new StartRecordingHelper(this); 1.755 + request->AddEventListener(NS_LITERAL_STRING("success"), listener, false); 1.756 + request->AddEventListener(NS_LITERAL_STRING("error"), listener, false); 1.757 +} 1.758 + 1.759 +void 1.760 +nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded) 1.761 +{ 1.762 + if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) { 1.763 + ICameraControl::StartRecordingOptions o; 1.764 + 1.765 + o.rotation = mOptions.mRotation; 1.766 + o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes; 1.767 + o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs; 1.768 + o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch; 1.769 + nsresult rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o); 1.770 + if (NS_SUCCEEDED(rv)) { 1.771 + return; 1.772 + } 1.773 + } 1.774 + OnError(CameraControlListener::kInStartRecording, NS_LITERAL_STRING("FAILURE")); 1.775 + 1.776 + if (mDSFileDescriptor->mFileDescriptor.IsValid()) { 1.777 + // An error occured. We need to manually close the file associated with the 1.778 + // FileDescriptor, and we shouldn't do this on the main thread, so we 1.779 + // use a little helper. 1.780 + nsRefPtr<CloseFileRunnable> closer = 1.781 + new CloseFileRunnable(mDSFileDescriptor->mFileDescriptor); 1.782 + closer->Dispatch(); 1.783 + } 1.784 +} 1.785 + 1.786 +void 1.787 +nsDOMCameraControl::StopRecording(ErrorResult& aRv) 1.788 +{ 1.789 + MOZ_ASSERT(mCameraControl); 1.790 + 1.791 +#ifdef MOZ_B2G 1.792 + if (mAudioChannelAgent) { 1.793 + mAudioChannelAgent->StopPlaying(); 1.794 + mAudioChannelAgent = nullptr; 1.795 + } 1.796 +#endif 1.797 + 1.798 + aRv = mCameraControl->StopRecording(); 1.799 +} 1.800 + 1.801 +void 1.802 +nsDOMCameraControl::ResumePreview(ErrorResult& aRv) 1.803 +{ 1.804 + MOZ_ASSERT(mCameraControl); 1.805 + aRv = mCameraControl->StartPreview(); 1.806 +} 1.807 + 1.808 +void 1.809 +nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration, 1.810 + const Optional<OwningNonNull<CameraSetConfigurationCallback> >& aOnSuccess, 1.811 + const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, 1.812 + ErrorResult& aRv) 1.813 +{ 1.814 + MOZ_ASSERT(mCameraControl); 1.815 + 1.816 + nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb; 1.817 + if (cb) { 1.818 + // We're busy taking a picture, can't change modes right now. 1.819 + if (aOnError.WasPassed()) { 1.820 + ErrorResult ignored; 1.821 + aOnError.Value().Call(NS_LITERAL_STRING("Busy"), ignored); 1.822 + } 1.823 + aRv = NS_ERROR_FAILURE; 1.824 + return; 1.825 + } 1.826 + 1.827 + ICameraControl::Configuration config; 1.828 + config.mRecorderProfile = aConfiguration.mRecorderProfile; 1.829 + config.mPreviewSize.width = aConfiguration.mPreviewSize.mWidth; 1.830 + config.mPreviewSize.height = aConfiguration.mPreviewSize.mHeight; 1.831 + config.mMode = ICameraControl::kPictureMode; 1.832 + if (aConfiguration.mMode == CameraMode::Video) { 1.833 + config.mMode = ICameraControl::kVideoMode; 1.834 + } 1.835 + 1.836 + mSetConfigurationOnSuccessCb = nullptr; 1.837 + if (aOnSuccess.WasPassed()) { 1.838 + mSetConfigurationOnSuccessCb = &aOnSuccess.Value(); 1.839 + } 1.840 + mSetConfigurationOnErrorCb = nullptr; 1.841 + if (aOnError.WasPassed()) { 1.842 + mSetConfigurationOnErrorCb = &aOnError.Value(); 1.843 + } 1.844 + 1.845 + aRv = mCameraControl->SetConfiguration(config); 1.846 +} 1.847 + 1.848 +class ImmediateErrorCallback : public nsRunnable 1.849 +{ 1.850 +public: 1.851 + ImmediateErrorCallback(CameraErrorCallback* aCallback, const nsAString& aMessage) 1.852 + : mCallback(aCallback) 1.853 + , mMessage(aMessage) 1.854 + { } 1.855 + 1.856 + NS_IMETHODIMP 1.857 + Run() 1.858 + { 1.859 + MOZ_ASSERT(NS_IsMainThread()); 1.860 + ErrorResult ignored; 1.861 + mCallback->Call(mMessage, ignored); 1.862 + return NS_OK; 1.863 + } 1.864 + 1.865 +protected: 1.866 + nsRefPtr<CameraErrorCallback> mCallback; 1.867 + nsString mMessage; 1.868 +}; 1.869 + 1.870 + 1.871 +void 1.872 +nsDOMCameraControl::AutoFocus(CameraAutoFocusCallback& aOnSuccess, 1.873 + const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, 1.874 + ErrorResult& aRv) 1.875 +{ 1.876 + MOZ_ASSERT(mCameraControl); 1.877 + 1.878 + nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb; 1.879 + if (cb) { 1.880 + if (aOnError.WasPassed()) { 1.881 + // There is already a call to AutoFocus() in progress, abort this new one 1.882 + // and invoke the error callback (if one was passed in). 1.883 + NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(), 1.884 + NS_LITERAL_STRING("AutoFocusAlreadyInProgress"))); 1.885 + } 1.886 + aRv = NS_ERROR_FAILURE; 1.887 + return; 1.888 + } 1.889 + 1.890 + mAutoFocusOnSuccessCb = &aOnSuccess; 1.891 + mAutoFocusOnErrorCb = nullptr; 1.892 + if (aOnError.WasPassed()) { 1.893 + mAutoFocusOnErrorCb = &aOnError.Value(); 1.894 + } 1.895 + 1.896 + aRv = mCameraControl->AutoFocus(); 1.897 +} 1.898 + 1.899 +void 1.900 +nsDOMCameraControl::StartFaceDetection(ErrorResult& aRv) 1.901 +{ 1.902 + MOZ_ASSERT(mCameraControl); 1.903 + aRv = mCameraControl->StartFaceDetection(); 1.904 +} 1.905 + 1.906 +void 1.907 +nsDOMCameraControl::StopFaceDetection(ErrorResult& aRv) 1.908 +{ 1.909 + MOZ_ASSERT(mCameraControl); 1.910 + aRv = mCameraControl->StopFaceDetection(); 1.911 +} 1.912 + 1.913 +void 1.914 +nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions, 1.915 + CameraTakePictureCallback& aOnSuccess, 1.916 + const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, 1.917 + ErrorResult& aRv) 1.918 +{ 1.919 + MOZ_ASSERT(mCameraControl); 1.920 + 1.921 + nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb; 1.922 + if (cb) { 1.923 + if (aOnError.WasPassed()) { 1.924 + // There is already a call to TakePicture() in progress, abort this new 1.925 + // one and invoke the error callback (if one was passed in). 1.926 + NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(), 1.927 + NS_LITERAL_STRING("TakePictureAlreadyInProgress"))); 1.928 + } 1.929 + aRv = NS_ERROR_FAILURE; 1.930 + return; 1.931 + } 1.932 + 1.933 + { 1.934 + ICameraControlParameterSetAutoEnter batch(mCameraControl); 1.935 + 1.936 + // XXXmikeh - remove this: see bug 931155 1.937 + ICameraControl::Size s; 1.938 + s.width = aOptions.mPictureSize.mWidth; 1.939 + s.height = aOptions.mPictureSize.mHeight; 1.940 + 1.941 + ICameraControl::Position p; 1.942 + p.latitude = aOptions.mPosition.mLatitude; 1.943 + p.longitude = aOptions.mPosition.mLongitude; 1.944 + p.altitude = aOptions.mPosition.mAltitude; 1.945 + p.timestamp = aOptions.mPosition.mTimestamp; 1.946 + 1.947 + if (s.width && s.height) { 1.948 + mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s); 1.949 + } 1.950 + mCameraControl->Set(CAMERA_PARAM_PICTURE_ROTATION, aOptions.mRotation); 1.951 + mCameraControl->Set(CAMERA_PARAM_PICTURE_FILEFORMAT, aOptions.mFileFormat); 1.952 + mCameraControl->Set(CAMERA_PARAM_PICTURE_DATETIME, aOptions.mDateTime); 1.953 + mCameraControl->SetLocation(p); 1.954 + } 1.955 + 1.956 + mTakePictureOnSuccessCb = &aOnSuccess; 1.957 + mTakePictureOnErrorCb = nullptr; 1.958 + if (aOnError.WasPassed()) { 1.959 + mTakePictureOnErrorCb = &aOnError.Value(); 1.960 + } 1.961 + 1.962 + aRv = mCameraControl->TakePicture(); 1.963 +} 1.964 + 1.965 +void 1.966 +nsDOMCameraControl::ReleaseHardware(const Optional<OwningNonNull<CameraReleaseCallback> >& aOnSuccess, 1.967 + const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, 1.968 + ErrorResult& aRv) 1.969 +{ 1.970 + MOZ_ASSERT(mCameraControl); 1.971 + 1.972 + mReleaseOnSuccessCb = nullptr; 1.973 + if (aOnSuccess.WasPassed()) { 1.974 + mReleaseOnSuccessCb = &aOnSuccess.Value(); 1.975 + } 1.976 + mReleaseOnErrorCb = nullptr; 1.977 + if (aOnError.WasPassed()) { 1.978 + mReleaseOnErrorCb = &aOnError.Value(); 1.979 + } 1.980 + 1.981 + aRv = mCameraControl->Stop(); 1.982 +} 1.983 + 1.984 +void 1.985 +nsDOMCameraControl::ResumeContinuousFocus(ErrorResult& aRv) 1.986 +{ 1.987 + MOZ_ASSERT(mCameraControl); 1.988 + aRv = mCameraControl->ResumeContinuousFocus(); 1.989 +} 1.990 + 1.991 +void 1.992 +nsDOMCameraControl::Shutdown() 1.993 +{ 1.994 + DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__); 1.995 + MOZ_ASSERT(mCameraControl); 1.996 + 1.997 + // Remove any pending solicited event handlers; these 1.998 + // reference our window object, which in turn references 1.999 + // us. If we don't remove them, we can leak DOM objects. 1.1000 + mGetCameraOnSuccessCb = nullptr; 1.1001 + mGetCameraOnErrorCb = nullptr; 1.1002 + mAutoFocusOnSuccessCb = nullptr; 1.1003 + mAutoFocusOnErrorCb = nullptr; 1.1004 + mTakePictureOnSuccessCb = nullptr; 1.1005 + mTakePictureOnErrorCb = nullptr; 1.1006 + mStartRecordingOnSuccessCb = nullptr; 1.1007 + mStartRecordingOnErrorCb = nullptr; 1.1008 + mReleaseOnSuccessCb = nullptr; 1.1009 + mReleaseOnErrorCb = nullptr; 1.1010 + mSetConfigurationOnSuccessCb = nullptr; 1.1011 + mSetConfigurationOnErrorCb = nullptr; 1.1012 + 1.1013 + // Remove all of the unsolicited event handlers too. 1.1014 + mOnShutterCb = nullptr; 1.1015 + mOnClosedCb = nullptr; 1.1016 + mOnRecorderStateChangeCb = nullptr; 1.1017 + mOnPreviewStateChangeCb = nullptr; 1.1018 + mOnAutoFocusMovingCb = nullptr; 1.1019 + mOnFacesDetectedCb = nullptr; 1.1020 + 1.1021 + mCameraControl->Shutdown(); 1.1022 +} 1.1023 + 1.1024 +nsresult 1.1025 +nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg) 1.1026 +{ 1.1027 + NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE); 1.1028 + 1.1029 + return MediaManager::NotifyRecordingStatusChange(mWindow, 1.1030 + aMsg, 1.1031 + true /* aIsAudio */, 1.1032 + true /* aIsVideo */); 1.1033 +} 1.1034 + 1.1035 +// Camera Control event handlers--must only be called from the Main Thread! 1.1036 +void 1.1037 +nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState) 1.1038 +{ 1.1039 + MOZ_ASSERT(NS_IsMainThread()); 1.1040 + ErrorResult ignored; 1.1041 + 1.1042 + DOM_CAMERA_LOGI("DOM OnHardwareStateChange(%d)\n", aState); 1.1043 + 1.1044 + switch (aState) { 1.1045 + case CameraControlListener::kHardwareOpen: 1.1046 + // The hardware is open, so we can return a camera to JS, even if 1.1047 + // the preview hasn't started yet. 1.1048 + if (mGetCameraOnSuccessCb) { 1.1049 + nsRefPtr<GetCameraCallback> cb = mGetCameraOnSuccessCb.forget(); 1.1050 + ErrorResult ignored; 1.1051 + mGetCameraOnErrorCb = nullptr; 1.1052 + cb->Call(*this, *mCurrentConfiguration, ignored); 1.1053 + } 1.1054 + break; 1.1055 + 1.1056 + case CameraControlListener::kHardwareClosed: 1.1057 + if (mReleaseOnSuccessCb) { 1.1058 + // If we have this event handler, this was a solicited hardware close. 1.1059 + nsRefPtr<CameraReleaseCallback> cb = mReleaseOnSuccessCb.forget(); 1.1060 + mReleaseOnErrorCb = nullptr; 1.1061 + cb->Call(ignored); 1.1062 + } else if(mOnClosedCb) { 1.1063 + // If not, something else closed the hardware. 1.1064 + nsRefPtr<CameraClosedCallback> cb = mOnClosedCb; 1.1065 + cb->Call(ignored); 1.1066 + } 1.1067 + break; 1.1068 + 1.1069 + default: 1.1070 + MOZ_ASSUME_UNREACHABLE("Unanticipated camera hardware state"); 1.1071 + } 1.1072 +} 1.1073 + 1.1074 +void 1.1075 +nsDOMCameraControl::OnShutter() 1.1076 +{ 1.1077 + MOZ_ASSERT(NS_IsMainThread()); 1.1078 + 1.1079 + DOM_CAMERA_LOGI("DOM ** SNAP **\n"); 1.1080 + 1.1081 + nsRefPtr<CameraShutterCallback> cb = mOnShutterCb; 1.1082 + if (cb) { 1.1083 + ErrorResult ignored; 1.1084 + cb->Call(ignored); 1.1085 + } 1.1086 +} 1.1087 + 1.1088 +void 1.1089 +nsDOMCameraControl::OnPreviewStateChange(CameraControlListener::PreviewState aState) 1.1090 +{ 1.1091 + MOZ_ASSERT(NS_IsMainThread()); 1.1092 + 1.1093 + if (!mOnPreviewStateChangeCb) { 1.1094 + return; 1.1095 + } 1.1096 + 1.1097 + nsString state; 1.1098 + switch (aState) { 1.1099 + case CameraControlListener::kPreviewStarted: 1.1100 + state = NS_LITERAL_STRING("started"); 1.1101 + break; 1.1102 + 1.1103 + default: 1.1104 + state = NS_LITERAL_STRING("stopped"); 1.1105 + break; 1.1106 + } 1.1107 + 1.1108 + nsRefPtr<CameraPreviewStateChange> cb = mOnPreviewStateChangeCb; 1.1109 + ErrorResult ignored; 1.1110 + cb->Call(state, ignored); 1.1111 +} 1.1112 + 1.1113 +void 1.1114 +nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState aState, 1.1115 + int32_t aArg, int32_t aTrackNum) 1.1116 +{ 1.1117 + // For now, we do nothing with 'aStatus' and 'aTrackNum'. 1.1118 + MOZ_ASSERT(NS_IsMainThread()); 1.1119 + 1.1120 + ErrorResult ignored; 1.1121 + nsString state; 1.1122 + 1.1123 + switch (aState) { 1.1124 + case CameraControlListener::kRecorderStarted: 1.1125 + if (mStartRecordingOnSuccessCb) { 1.1126 + nsRefPtr<CameraStartRecordingCallback> cb = mStartRecordingOnSuccessCb.forget(); 1.1127 + mStartRecordingOnErrorCb = nullptr; 1.1128 + cb->Call(ignored); 1.1129 + } 1.1130 + state = NS_LITERAL_STRING("Started"); 1.1131 + break; 1.1132 + 1.1133 + case CameraControlListener::kRecorderStopped: 1.1134 + NotifyRecordingStatusChange(NS_LITERAL_STRING("shutdown")); 1.1135 + state = NS_LITERAL_STRING("Stopped"); 1.1136 + break; 1.1137 + 1.1138 +#ifdef MOZ_B2G_CAMERA 1.1139 + case CameraControlListener::kFileSizeLimitReached: 1.1140 + state = NS_LITERAL_STRING("FileSizeLimitReached"); 1.1141 + break; 1.1142 + 1.1143 + case CameraControlListener::kVideoLengthLimitReached: 1.1144 + state = NS_LITERAL_STRING("VideoLengthLimitReached"); 1.1145 + break; 1.1146 + 1.1147 + case CameraControlListener::kTrackCompleted: 1.1148 + state = NS_LITERAL_STRING("TrackCompleted"); 1.1149 + break; 1.1150 + 1.1151 + case CameraControlListener::kTrackFailed: 1.1152 + state = NS_LITERAL_STRING("TrackFailed"); 1.1153 + break; 1.1154 + 1.1155 + case CameraControlListener::kMediaRecorderFailed: 1.1156 + state = NS_LITERAL_STRING("MediaRecorderFailed"); 1.1157 + break; 1.1158 + 1.1159 + case CameraControlListener::kMediaServerFailed: 1.1160 + state = NS_LITERAL_STRING("MediaServerFailed"); 1.1161 + break; 1.1162 +#endif 1.1163 + 1.1164 + default: 1.1165 + MOZ_ASSUME_UNREACHABLE("Unanticipated video recorder error"); 1.1166 + return; 1.1167 + } 1.1168 + 1.1169 + nsRefPtr<CameraRecorderStateChange> cb = mOnRecorderStateChangeCb; 1.1170 + if (cb) { 1.1171 + cb->Call(state, ignored); 1.1172 + } 1.1173 +} 1.1174 + 1.1175 +void 1.1176 +nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration) 1.1177 +{ 1.1178 + MOZ_ASSERT(NS_IsMainThread()); 1.1179 + 1.1180 + // Update our record of the current camera configuration 1.1181 + mCurrentConfiguration = aConfiguration; 1.1182 + 1.1183 + DOM_CAMERA_LOGI("DOM OnConfigurationChange: this=%p\n", this); 1.1184 + DOM_CAMERA_LOGI(" mode : %s\n", 1.1185 + mCurrentConfiguration->mMode == CameraMode::Video ? "video" : "picture"); 1.1186 + DOM_CAMERA_LOGI(" maximum focus areas : %d\n", 1.1187 + mCurrentConfiguration->mMaxFocusAreas); 1.1188 + DOM_CAMERA_LOGI(" maximum metering areas : %d\n", 1.1189 + mCurrentConfiguration->mMaxMeteringAreas); 1.1190 + DOM_CAMERA_LOGI(" preview size (w x h) : %d x %d\n", 1.1191 + mCurrentConfiguration->mPreviewSize.mWidth, mCurrentConfiguration->mPreviewSize.mHeight); 1.1192 + DOM_CAMERA_LOGI(" recorder profile : %s\n", 1.1193 + NS_ConvertUTF16toUTF8(mCurrentConfiguration->mRecorderProfile).get()); 1.1194 + 1.1195 + nsRefPtr<CameraSetConfigurationCallback> cb = mSetConfigurationOnSuccessCb.forget(); 1.1196 + mSetConfigurationOnErrorCb = nullptr; 1.1197 + if (cb) { 1.1198 + ErrorResult ignored; 1.1199 + cb->Call(*mCurrentConfiguration, ignored); 1.1200 + } 1.1201 +} 1.1202 + 1.1203 +void 1.1204 +nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded) 1.1205 +{ 1.1206 + MOZ_ASSERT(NS_IsMainThread()); 1.1207 + 1.1208 + nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.forget(); 1.1209 + mAutoFocusOnErrorCb = nullptr; 1.1210 + if (cb) { 1.1211 + ErrorResult ignored; 1.1212 + cb->Call(aAutoFocusSucceeded, ignored); 1.1213 + } 1.1214 +} 1.1215 + 1.1216 +void 1.1217 +nsDOMCameraControl::OnAutoFocusMoving(bool aIsMoving) 1.1218 +{ 1.1219 + MOZ_ASSERT(NS_IsMainThread()); 1.1220 + 1.1221 + nsRefPtr<CameraAutoFocusMovingCallback> cb = mOnAutoFocusMovingCb; 1.1222 + if (cb) { 1.1223 + ErrorResult ignored; 1.1224 + cb->Call(aIsMoving, ignored); 1.1225 + } 1.1226 +} 1.1227 + 1.1228 +void 1.1229 +nsDOMCameraControl::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces) 1.1230 +{ 1.1231 + DOM_CAMERA_LOGI("DOM OnFacesDetected %u face(s)\n", aFaces.Length()); 1.1232 + MOZ_ASSERT(NS_IsMainThread()); 1.1233 + 1.1234 + nsRefPtr<CameraFaceDetectionCallback> cb = mOnFacesDetectedCb; 1.1235 + if (!cb) { 1.1236 + return; 1.1237 + } 1.1238 + 1.1239 + Sequence<OwningNonNull<DOMCameraDetectedFace> > faces; 1.1240 + uint32_t len = aFaces.Length(); 1.1241 + 1.1242 + if (faces.SetCapacity(len)) { 1.1243 + nsRefPtr<DOMCameraDetectedFace> f; 1.1244 + for (uint32_t i = 0; i < len; ++i) { 1.1245 + f = new DOMCameraDetectedFace(this, aFaces[i]); 1.1246 + *faces.AppendElement() = f.forget().take(); 1.1247 + } 1.1248 + } 1.1249 + 1.1250 + ErrorResult ignored; 1.1251 + cb->Call(faces, ignored); 1.1252 +} 1.1253 + 1.1254 +void 1.1255 +nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture) 1.1256 +{ 1.1257 + MOZ_ASSERT(NS_IsMainThread()); 1.1258 + 1.1259 + nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget(); 1.1260 + mTakePictureOnErrorCb = nullptr; 1.1261 + if (!cb) { 1.1262 + // Warn because it shouldn't be possible to get here without 1.1263 + // having passed a success callback into takePicture(), even 1.1264 + // though we guard against a nullptr dereference. 1.1265 + NS_WARNING("DOM Null success callback in OnTakePictureComplete()"); 1.1266 + return; 1.1267 + } 1.1268 + 1.1269 + ErrorResult ignored; 1.1270 + cb->Call(aPicture, ignored); 1.1271 +} 1.1272 + 1.1273 +void 1.1274 +nsDOMCameraControl::OnError(CameraControlListener::CameraErrorContext aContext, const nsAString& aError) 1.1275 +{ 1.1276 + DOM_CAMERA_LOGI("DOM OnError context=%d, error='%s'\n", aContext, 1.1277 + NS_LossyConvertUTF16toASCII(aError).get()); 1.1278 + MOZ_ASSERT(NS_IsMainThread()); 1.1279 + 1.1280 + nsRefPtr<CameraErrorCallback> errorCb; 1.1281 + 1.1282 + switch (aContext) { 1.1283 + case CameraControlListener::kInStartCamera: 1.1284 + mGetCameraOnSuccessCb = nullptr; 1.1285 + errorCb = mGetCameraOnErrorCb.forget(); 1.1286 + break; 1.1287 + 1.1288 + case CameraControlListener::kInStopCamera: 1.1289 + mReleaseOnSuccessCb = nullptr; 1.1290 + errorCb = mReleaseOnErrorCb.forget(); 1.1291 + break; 1.1292 + 1.1293 + case CameraControlListener::kInSetConfiguration: 1.1294 + mSetConfigurationOnSuccessCb = nullptr; 1.1295 + errorCb = mSetConfigurationOnErrorCb.forget(); 1.1296 + break; 1.1297 + 1.1298 + case CameraControlListener::kInAutoFocus: 1.1299 + mAutoFocusOnSuccessCb = nullptr; 1.1300 + errorCb = mAutoFocusOnErrorCb.forget(); 1.1301 + break; 1.1302 + 1.1303 + case CameraControlListener::kInTakePicture: 1.1304 + mTakePictureOnSuccessCb = nullptr; 1.1305 + errorCb = mTakePictureOnErrorCb.forget(); 1.1306 + break; 1.1307 + 1.1308 + case CameraControlListener::kInStartRecording: 1.1309 + mStartRecordingOnSuccessCb = nullptr; 1.1310 + errorCb = mStartRecordingOnErrorCb.forget(); 1.1311 + break; 1.1312 + 1.1313 + case CameraControlListener::kInStopRecording: 1.1314 + // This method doesn't have any callbacks, so all we can do is log the 1.1315 + // failure. This only happens after the hardware has been released. 1.1316 + NS_WARNING("Failed to stop recording"); 1.1317 + return; 1.1318 + 1.1319 + case CameraControlListener::kInStartPreview: 1.1320 + // This method doesn't have any callbacks, so all we can do is log the 1.1321 + // failure. This only happens after the hardware has been released. 1.1322 + NS_WARNING("Failed to (re)start preview"); 1.1323 + return; 1.1324 + 1.1325 + case CameraControlListener::kInUnspecified: 1.1326 + if (aError.EqualsASCII("ErrorServiceFailed")) { 1.1327 + // If the camera service fails, we will get preview-stopped and 1.1328 + // hardware-closed events, so nothing to do here. 1.1329 + NS_WARNING("Camera service failed"); 1.1330 + return; 1.1331 + } 1.1332 + if (aError.EqualsASCII("ErrorSetPictureSizeFailed") || 1.1333 + aError.EqualsASCII("ErrorSetThumbnailSizeFailed")) { 1.1334 + // We currently don't handle attribute setter failure. Practically, 1.1335 + // this only ever happens if a setter is called after the hardware 1.1336 + // has gone away before an asynchronous set gets to happen, so we 1.1337 + // swallow these. 1.1338 + NS_WARNING("Failed to set either picture or thumbnail size"); 1.1339 + return; 1.1340 + } 1.1341 + // fallthrough 1.1342 + 1.1343 + default: 1.1344 + MOZ_ASSUME_UNREACHABLE("Error occurred in unanticipated camera state"); 1.1345 + return; 1.1346 + } 1.1347 + 1.1348 + if (!errorCb) { 1.1349 + DOM_CAMERA_LOGW("DOM No error handler for error '%s' in context=%d\n", 1.1350 + NS_LossyConvertUTF16toASCII(aError).get(), aContext); 1.1351 + return; 1.1352 + } 1.1353 + 1.1354 + ErrorResult ignored; 1.1355 + errorCb->Call(aError, ignored); 1.1356 +} 1.1357 +