Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
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 "DOMCameraControl.h" |
michael@0 | 6 | #include "base/basictypes.h" |
michael@0 | 7 | #include "nsCOMPtr.h" |
michael@0 | 8 | #include "nsDOMClassInfo.h" |
michael@0 | 9 | #include "nsHashPropertyBag.h" |
michael@0 | 10 | #include "nsThread.h" |
michael@0 | 11 | #include "DeviceStorage.h" |
michael@0 | 12 | #include "DeviceStorageFileDescriptor.h" |
michael@0 | 13 | #include "mozilla/dom/TabChild.h" |
michael@0 | 14 | #include "mozilla/ipc/FileDescriptorUtils.h" |
michael@0 | 15 | #include "mozilla/MediaManager.h" |
michael@0 | 16 | #include "mozilla/Services.h" |
michael@0 | 17 | #include "mozilla/unused.h" |
michael@0 | 18 | #include "nsIAppsService.h" |
michael@0 | 19 | #include "nsIObserverService.h" |
michael@0 | 20 | #include "nsIDOMDeviceStorage.h" |
michael@0 | 21 | #include "nsIDOMEventListener.h" |
michael@0 | 22 | #include "nsIScriptSecurityManager.h" |
michael@0 | 23 | #include "Navigator.h" |
michael@0 | 24 | #include "nsXULAppAPI.h" |
michael@0 | 25 | #include "DOMCameraManager.h" |
michael@0 | 26 | #include "DOMCameraCapabilities.h" |
michael@0 | 27 | #include "CameraCommon.h" |
michael@0 | 28 | #include "nsGlobalWindow.h" |
michael@0 | 29 | #include "CameraPreviewMediaStream.h" |
michael@0 | 30 | #include "mozilla/dom/CameraControlBinding.h" |
michael@0 | 31 | #include "mozilla/dom/CameraManagerBinding.h" |
michael@0 | 32 | #include "mozilla/dom/CameraCapabilitiesBinding.h" |
michael@0 | 33 | #include "DOMCameraDetectedFace.h" |
michael@0 | 34 | #include "mozilla/dom/BindingUtils.h" |
michael@0 | 35 | |
michael@0 | 36 | using namespace mozilla; |
michael@0 | 37 | using namespace mozilla::dom; |
michael@0 | 38 | using namespace mozilla::ipc; |
michael@0 | 39 | |
michael@0 | 40 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl) |
michael@0 | 41 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
michael@0 | 42 | NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream) |
michael@0 | 43 | NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream) |
michael@0 | 44 | |
michael@0 | 45 | NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream) |
michael@0 | 46 | NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream) |
michael@0 | 47 | |
michael@0 | 48 | NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream, |
michael@0 | 49 | mCapabilities, |
michael@0 | 50 | mWindow, |
michael@0 | 51 | mGetCameraOnSuccessCb, |
michael@0 | 52 | mGetCameraOnErrorCb, |
michael@0 | 53 | mAutoFocusOnSuccessCb, |
michael@0 | 54 | mAutoFocusOnErrorCb, |
michael@0 | 55 | mTakePictureOnSuccessCb, |
michael@0 | 56 | mTakePictureOnErrorCb, |
michael@0 | 57 | mStartRecordingOnSuccessCb, |
michael@0 | 58 | mStartRecordingOnErrorCb, |
michael@0 | 59 | mReleaseOnSuccessCb, |
michael@0 | 60 | mReleaseOnErrorCb, |
michael@0 | 61 | mSetConfigurationOnSuccessCb, |
michael@0 | 62 | mSetConfigurationOnErrorCb, |
michael@0 | 63 | mOnShutterCb, |
michael@0 | 64 | mOnClosedCb, |
michael@0 | 65 | mOnRecorderStateChangeCb, |
michael@0 | 66 | mOnPreviewStateChangeCb, |
michael@0 | 67 | mOnAutoFocusMovingCb, |
michael@0 | 68 | mOnFacesDetectedCb) |
michael@0 | 69 | |
michael@0 | 70 | /* static */ |
michael@0 | 71 | bool |
michael@0 | 72 | nsDOMCameraControl::HasSupport(JSContext* aCx, JSObject* aGlobal) |
michael@0 | 73 | { |
michael@0 | 74 | return Navigator::HasCameraSupport(aCx, aGlobal); |
michael@0 | 75 | } |
michael@0 | 76 | |
michael@0 | 77 | class mozilla::StartRecordingHelper : public nsIDOMEventListener |
michael@0 | 78 | { |
michael@0 | 79 | public: |
michael@0 | 80 | NS_DECL_ISUPPORTS |
michael@0 | 81 | NS_DECL_NSIDOMEVENTLISTENER |
michael@0 | 82 | |
michael@0 | 83 | StartRecordingHelper(nsDOMCameraControl* aDOMCameraControl) |
michael@0 | 84 | : mDOMCameraControl(aDOMCameraControl) |
michael@0 | 85 | { |
michael@0 | 86 | MOZ_COUNT_CTOR(StartRecordingHelper); |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | protected: |
michael@0 | 90 | virtual ~StartRecordingHelper() |
michael@0 | 91 | { |
michael@0 | 92 | MOZ_COUNT_DTOR(StartRecordingHelper); |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | protected: |
michael@0 | 96 | nsRefPtr<nsDOMCameraControl> mDOMCameraControl; |
michael@0 | 97 | }; |
michael@0 | 98 | |
michael@0 | 99 | NS_IMETHODIMP |
michael@0 | 100 | StartRecordingHelper::HandleEvent(nsIDOMEvent* aEvent) |
michael@0 | 101 | { |
michael@0 | 102 | nsString eventType; |
michael@0 | 103 | aEvent->GetType(eventType); |
michael@0 | 104 | |
michael@0 | 105 | mDOMCameraControl->OnCreatedFileDescriptor(eventType.EqualsLiteral("success")); |
michael@0 | 106 | return NS_OK; |
michael@0 | 107 | } |
michael@0 | 108 | |
michael@0 | 109 | NS_IMPL_ISUPPORTS(mozilla::StartRecordingHelper, nsIDOMEventListener) |
michael@0 | 110 | |
michael@0 | 111 | nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration() |
michael@0 | 112 | : CameraConfiguration() |
michael@0 | 113 | , mMaxFocusAreas(0) |
michael@0 | 114 | , mMaxMeteringAreas(0) |
michael@0 | 115 | { |
michael@0 | 116 | MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration); |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | nsDOMCameraControl::DOMCameraConfiguration::DOMCameraConfiguration(const CameraConfiguration& aConfiguration) |
michael@0 | 120 | : CameraConfiguration(aConfiguration) |
michael@0 | 121 | , mMaxFocusAreas(0) |
michael@0 | 122 | , mMaxMeteringAreas(0) |
michael@0 | 123 | { |
michael@0 | 124 | MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration); |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration() |
michael@0 | 128 | { |
michael@0 | 129 | MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration); |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, |
michael@0 | 133 | const CameraConfiguration& aInitialConfig, |
michael@0 | 134 | GetCameraCallback* aOnSuccess, |
michael@0 | 135 | CameraErrorCallback* aOnError, |
michael@0 | 136 | nsPIDOMWindow* aWindow) |
michael@0 | 137 | : DOMMediaStream() |
michael@0 | 138 | , mCameraControl(nullptr) |
michael@0 | 139 | , mAudioChannelAgent(nullptr) |
michael@0 | 140 | , mGetCameraOnSuccessCb(aOnSuccess) |
michael@0 | 141 | , mGetCameraOnErrorCb(aOnError) |
michael@0 | 142 | , mAutoFocusOnSuccessCb(nullptr) |
michael@0 | 143 | , mAutoFocusOnErrorCb(nullptr) |
michael@0 | 144 | , mTakePictureOnSuccessCb(nullptr) |
michael@0 | 145 | , mTakePictureOnErrorCb(nullptr) |
michael@0 | 146 | , mStartRecordingOnSuccessCb(nullptr) |
michael@0 | 147 | , mStartRecordingOnErrorCb(nullptr) |
michael@0 | 148 | , mReleaseOnSuccessCb(nullptr) |
michael@0 | 149 | , mReleaseOnErrorCb(nullptr) |
michael@0 | 150 | , mSetConfigurationOnSuccessCb(nullptr) |
michael@0 | 151 | , mSetConfigurationOnErrorCb(nullptr) |
michael@0 | 152 | , mOnShutterCb(nullptr) |
michael@0 | 153 | , mOnClosedCb(nullptr) |
michael@0 | 154 | , mOnRecorderStateChangeCb(nullptr) |
michael@0 | 155 | , mOnPreviewStateChangeCb(nullptr) |
michael@0 | 156 | , mOnAutoFocusMovingCb(nullptr) |
michael@0 | 157 | , mOnFacesDetectedCb(nullptr) |
michael@0 | 158 | , mWindow(aWindow) |
michael@0 | 159 | { |
michael@0 | 160 | DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); |
michael@0 | 161 | mInput = new CameraPreviewMediaStream(this); |
michael@0 | 162 | |
michael@0 | 163 | SetIsDOMBinding(); |
michael@0 | 164 | |
michael@0 | 165 | nsRefPtr<DOMCameraConfiguration> initialConfig = |
michael@0 | 166 | new DOMCameraConfiguration(aInitialConfig); |
michael@0 | 167 | |
michael@0 | 168 | // Create and initialize the underlying camera. |
michael@0 | 169 | ICameraControl::Configuration config; |
michael@0 | 170 | |
michael@0 | 171 | switch (aInitialConfig.mMode) { |
michael@0 | 172 | case CameraMode::Picture: |
michael@0 | 173 | config.mMode = ICameraControl::kPictureMode; |
michael@0 | 174 | break; |
michael@0 | 175 | |
michael@0 | 176 | case CameraMode::Video: |
michael@0 | 177 | config.mMode = ICameraControl::kVideoMode; |
michael@0 | 178 | break; |
michael@0 | 179 | |
michael@0 | 180 | default: |
michael@0 | 181 | MOZ_ASSUME_UNREACHABLE("Unanticipated camera mode!"); |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | config.mPreviewSize.width = aInitialConfig.mPreviewSize.mWidth; |
michael@0 | 185 | config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight; |
michael@0 | 186 | config.mRecorderProfile = aInitialConfig.mRecorderProfile; |
michael@0 | 187 | |
michael@0 | 188 | mCameraControl = ICameraControl::Create(aCameraId); |
michael@0 | 189 | mCurrentConfiguration = initialConfig.forget(); |
michael@0 | 190 | |
michael@0 | 191 | // Attach our DOM-facing media stream to our viewfinder stream. |
michael@0 | 192 | mStream = mInput; |
michael@0 | 193 | MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!"); |
michael@0 | 194 | if (mWindow->GetExtantDoc()) { |
michael@0 | 195 | CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal()); |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | // Register a listener for camera events. |
michael@0 | 199 | mListener = new DOMCameraControlListener(this, mInput); |
michael@0 | 200 | mCameraControl->AddListener(mListener); |
michael@0 | 201 | |
michael@0 | 202 | // Start the camera... |
michael@0 | 203 | nsresult rv = mCameraControl->Start(&config); |
michael@0 | 204 | if (NS_FAILED(rv)) { |
michael@0 | 205 | mListener->OnError(DOMCameraControlListener::kInStartCamera, |
michael@0 | 206 | DOMCameraControlListener::kErrorApiFailed); |
michael@0 | 207 | } |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | nsDOMCameraControl::~nsDOMCameraControl() |
michael@0 | 211 | { |
michael@0 | 212 | DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | JSObject* |
michael@0 | 216 | nsDOMCameraControl::WrapObject(JSContext* aCx) |
michael@0 | 217 | { |
michael@0 | 218 | return CameraControlBinding::Wrap(aCx, this); |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | bool |
michael@0 | 222 | nsDOMCameraControl::IsWindowStillActive() |
michael@0 | 223 | { |
michael@0 | 224 | return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID()); |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | // JS-to-native helpers |
michael@0 | 228 | // Setter for weighted regions: { top, bottom, left, right, weight } |
michael@0 | 229 | nsresult |
michael@0 | 230 | nsDOMCameraControl::Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit) |
michael@0 | 231 | { |
michael@0 | 232 | if (aLimit == 0) { |
michael@0 | 233 | DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__); |
michael@0 | 234 | return NS_OK; |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | if (!aValue.isObject()) { |
michael@0 | 238 | return NS_ERROR_INVALID_ARG; |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | uint32_t length = 0; |
michael@0 | 242 | |
michael@0 | 243 | JS::Rooted<JSObject*> regions(aCx, &aValue.toObject()); |
michael@0 | 244 | if (!JS_GetArrayLength(aCx, regions, &length)) { |
michael@0 | 245 | return NS_ERROR_FAILURE; |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit); |
michael@0 | 249 | if (length > aLimit) { |
michael@0 | 250 | length = aLimit; |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | nsTArray<ICameraControl::Region> regionArray; |
michael@0 | 254 | regionArray.SetCapacity(length); |
michael@0 | 255 | |
michael@0 | 256 | for (uint32_t i = 0; i < length; ++i) { |
michael@0 | 257 | JS::Rooted<JS::Value> v(aCx); |
michael@0 | 258 | |
michael@0 | 259 | if (!JS_GetElement(aCx, regions, i, &v)) { |
michael@0 | 260 | return NS_ERROR_FAILURE; |
michael@0 | 261 | } |
michael@0 | 262 | |
michael@0 | 263 | CameraRegion region; |
michael@0 | 264 | if (!region.Init(aCx, v)) { |
michael@0 | 265 | return NS_ERROR_FAILURE; |
michael@0 | 266 | } |
michael@0 | 267 | |
michael@0 | 268 | ICameraControl::Region* r = regionArray.AppendElement(); |
michael@0 | 269 | r->top = region.mTop; |
michael@0 | 270 | r->left = region.mLeft; |
michael@0 | 271 | r->bottom = region.mBottom; |
michael@0 | 272 | r->right = region.mRight; |
michael@0 | 273 | r->weight = region.mWeight; |
michael@0 | 274 | |
michael@0 | 275 | DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n", |
michael@0 | 276 | i, |
michael@0 | 277 | r->top, |
michael@0 | 278 | r->left, |
michael@0 | 279 | r->bottom, |
michael@0 | 280 | r->right, |
michael@0 | 281 | r->weight |
michael@0 | 282 | ); |
michael@0 | 283 | } |
michael@0 | 284 | return mCameraControl->Set(aKey, regionArray); |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | // Getter for weighted regions: { top, bottom, left, right, weight } |
michael@0 | 288 | nsresult |
michael@0 | 289 | nsDOMCameraControl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue) |
michael@0 | 290 | { |
michael@0 | 291 | nsTArray<ICameraControl::Region> regionArray; |
michael@0 | 292 | |
michael@0 | 293 | nsresult rv = mCameraControl->Get(aKey, regionArray); |
michael@0 | 294 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 295 | |
michael@0 | 296 | JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0)); |
michael@0 | 297 | if (!array) { |
michael@0 | 298 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | uint32_t length = regionArray.Length(); |
michael@0 | 302 | DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length); |
michael@0 | 303 | |
michael@0 | 304 | for (uint32_t i = 0; i < length; ++i) { |
michael@0 | 305 | ICameraControl::Region* r = ®ionArray[i]; |
michael@0 | 306 | JS::Rooted<JS::Value> v(aCx); |
michael@0 | 307 | |
michael@0 | 308 | JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); |
michael@0 | 309 | if (!o) { |
michael@0 | 310 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | DOM_CAMERA_LOGI("top=%d\n", r->top); |
michael@0 | 314 | v = INT_TO_JSVAL(r->top); |
michael@0 | 315 | if (!JS_SetProperty(aCx, o, "top", v)) { |
michael@0 | 316 | return NS_ERROR_FAILURE; |
michael@0 | 317 | } |
michael@0 | 318 | DOM_CAMERA_LOGI("left=%d\n", r->left); |
michael@0 | 319 | v = INT_TO_JSVAL(r->left); |
michael@0 | 320 | if (!JS_SetProperty(aCx, o, "left", v)) { |
michael@0 | 321 | return NS_ERROR_FAILURE; |
michael@0 | 322 | } |
michael@0 | 323 | DOM_CAMERA_LOGI("bottom=%d\n", r->bottom); |
michael@0 | 324 | v = INT_TO_JSVAL(r->bottom); |
michael@0 | 325 | if (!JS_SetProperty(aCx, o, "bottom", v)) { |
michael@0 | 326 | return NS_ERROR_FAILURE; |
michael@0 | 327 | } |
michael@0 | 328 | DOM_CAMERA_LOGI("right=%d\n", r->right); |
michael@0 | 329 | v = INT_TO_JSVAL(r->right); |
michael@0 | 330 | if (!JS_SetProperty(aCx, o, "right", v)) { |
michael@0 | 331 | return NS_ERROR_FAILURE; |
michael@0 | 332 | } |
michael@0 | 333 | DOM_CAMERA_LOGI("weight=%d\n", r->weight); |
michael@0 | 334 | v = INT_TO_JSVAL(r->weight); |
michael@0 | 335 | if (!JS_SetProperty(aCx, o, "weight", v)) { |
michael@0 | 336 | return NS_ERROR_FAILURE; |
michael@0 | 337 | } |
michael@0 | 338 | |
michael@0 | 339 | if (!JS_SetElement(aCx, array, i, o)) { |
michael@0 | 340 | return NS_ERROR_FAILURE; |
michael@0 | 341 | } |
michael@0 | 342 | } |
michael@0 | 343 | |
michael@0 | 344 | *aValue = JS::ObjectValue(*array); |
michael@0 | 345 | return NS_OK; |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | void |
michael@0 | 349 | nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv) |
michael@0 | 350 | { |
michael@0 | 351 | MOZ_ASSERT(mCameraControl); |
michael@0 | 352 | aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect); |
michael@0 | 353 | } |
michael@0 | 354 | void |
michael@0 | 355 | nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv) |
michael@0 | 356 | { |
michael@0 | 357 | MOZ_ASSERT(mCameraControl); |
michael@0 | 358 | aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect); |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | void |
michael@0 | 362 | nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv) |
michael@0 | 363 | { |
michael@0 | 364 | MOZ_ASSERT(mCameraControl); |
michael@0 | 365 | aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode); |
michael@0 | 366 | } |
michael@0 | 367 | void |
michael@0 | 368 | nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv) |
michael@0 | 369 | { |
michael@0 | 370 | MOZ_ASSERT(mCameraControl); |
michael@0 | 371 | aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode); |
michael@0 | 372 | } |
michael@0 | 373 | |
michael@0 | 374 | void |
michael@0 | 375 | nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv) |
michael@0 | 376 | { |
michael@0 | 377 | MOZ_ASSERT(mCameraControl); |
michael@0 | 378 | aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode); |
michael@0 | 379 | } |
michael@0 | 380 | void |
michael@0 | 381 | nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv) |
michael@0 | 382 | { |
michael@0 | 383 | MOZ_ASSERT(mCameraControl); |
michael@0 | 384 | aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode); |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | void |
michael@0 | 388 | nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv) |
michael@0 | 389 | { |
michael@0 | 390 | MOZ_ASSERT(mCameraControl); |
michael@0 | 391 | aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode); |
michael@0 | 392 | } |
michael@0 | 393 | void |
michael@0 | 394 | nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv) |
michael@0 | 395 | { |
michael@0 | 396 | MOZ_ASSERT(mCameraControl); |
michael@0 | 397 | aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode); |
michael@0 | 398 | } |
michael@0 | 399 | |
michael@0 | 400 | void |
michael@0 | 401 | nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv) |
michael@0 | 402 | { |
michael@0 | 403 | MOZ_ASSERT(mCameraControl); |
michael@0 | 404 | aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode); |
michael@0 | 405 | } |
michael@0 | 406 | void |
michael@0 | 407 | nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv) |
michael@0 | 408 | { |
michael@0 | 409 | MOZ_ASSERT(mCameraControl); |
michael@0 | 410 | aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode); |
michael@0 | 411 | } |
michael@0 | 412 | |
michael@0 | 413 | void |
michael@0 | 414 | nsDOMCameraControl::GetIsoMode(nsString& aIsoMode, ErrorResult& aRv) |
michael@0 | 415 | { |
michael@0 | 416 | MOZ_ASSERT(mCameraControl); |
michael@0 | 417 | aRv = mCameraControl->Get(CAMERA_PARAM_ISOMODE, aIsoMode); |
michael@0 | 418 | } |
michael@0 | 419 | void |
michael@0 | 420 | nsDOMCameraControl::SetIsoMode(const nsAString& aIsoMode, ErrorResult& aRv) |
michael@0 | 421 | { |
michael@0 | 422 | MOZ_ASSERT(mCameraControl); |
michael@0 | 423 | aRv = mCameraControl->Set(CAMERA_PARAM_ISOMODE, aIsoMode); |
michael@0 | 424 | } |
michael@0 | 425 | |
michael@0 | 426 | double |
michael@0 | 427 | nsDOMCameraControl::GetZoom(ErrorResult& aRv) |
michael@0 | 428 | { |
michael@0 | 429 | MOZ_ASSERT(mCameraControl); |
michael@0 | 430 | |
michael@0 | 431 | double zoom; |
michael@0 | 432 | aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, zoom); |
michael@0 | 433 | return zoom; |
michael@0 | 434 | } |
michael@0 | 435 | |
michael@0 | 436 | void |
michael@0 | 437 | nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv) |
michael@0 | 438 | { |
michael@0 | 439 | MOZ_ASSERT(mCameraControl); |
michael@0 | 440 | aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom); |
michael@0 | 441 | } |
michael@0 | 442 | |
michael@0 | 443 | /* attribute jsval meteringAreas; */ |
michael@0 | 444 | void |
michael@0 | 445 | nsDOMCameraControl::GetMeteringAreas(JSContext* cx, |
michael@0 | 446 | JS::MutableHandle<JS::Value> aMeteringAreas, |
michael@0 | 447 | ErrorResult& aRv) |
michael@0 | 448 | { |
michael@0 | 449 | aRv = Get(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas.address()); |
michael@0 | 450 | } |
michael@0 | 451 | |
michael@0 | 452 | void |
michael@0 | 453 | nsDOMCameraControl::SetMeteringAreas(JSContext* cx, JS::Handle<JS::Value> aMeteringAreas, ErrorResult& aRv) |
michael@0 | 454 | { |
michael@0 | 455 | aRv = Set(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas, |
michael@0 | 456 | mCurrentConfiguration->mMaxMeteringAreas); |
michael@0 | 457 | } |
michael@0 | 458 | |
michael@0 | 459 | void |
michael@0 | 460 | nsDOMCameraControl::GetFocusAreas(JSContext* cx, |
michael@0 | 461 | JS::MutableHandle<JS::Value> aFocusAreas, |
michael@0 | 462 | ErrorResult& aRv) |
michael@0 | 463 | { |
michael@0 | 464 | aRv = Get(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas.address()); |
michael@0 | 465 | } |
michael@0 | 466 | void |
michael@0 | 467 | nsDOMCameraControl::SetFocusAreas(JSContext* cx, JS::Handle<JS::Value> aFocusAreas, ErrorResult& aRv) |
michael@0 | 468 | { |
michael@0 | 469 | aRv = Set(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas, |
michael@0 | 470 | mCurrentConfiguration->mMaxFocusAreas); |
michael@0 | 471 | } |
michael@0 | 472 | |
michael@0 | 473 | static nsresult |
michael@0 | 474 | GetSize(JSContext* aCx, JS::Value* aValue, const ICameraControl::Size& aSize) |
michael@0 | 475 | { |
michael@0 | 476 | JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); |
michael@0 | 477 | if (!o) { |
michael@0 | 478 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 479 | } |
michael@0 | 480 | |
michael@0 | 481 | JS::Rooted<JS::Value> v(aCx); |
michael@0 | 482 | |
michael@0 | 483 | v = INT_TO_JSVAL(aSize.width); |
michael@0 | 484 | if (!JS_SetProperty(aCx, o, "width", v)) { |
michael@0 | 485 | return NS_ERROR_FAILURE; |
michael@0 | 486 | } |
michael@0 | 487 | v = INT_TO_JSVAL(aSize.height); |
michael@0 | 488 | if (!JS_SetProperty(aCx, o, "height", v)) { |
michael@0 | 489 | return NS_ERROR_FAILURE; |
michael@0 | 490 | } |
michael@0 | 491 | |
michael@0 | 492 | *aValue = JS::ObjectValue(*o); |
michael@0 | 493 | return NS_OK; |
michael@0 | 494 | } |
michael@0 | 495 | |
michael@0 | 496 | /* attribute any pictureSize */ |
michael@0 | 497 | void |
michael@0 | 498 | nsDOMCameraControl::GetPictureSize(JSContext* cx, |
michael@0 | 499 | JS::MutableHandle<JS::Value> aSize, |
michael@0 | 500 | ErrorResult& aRv) |
michael@0 | 501 | { |
michael@0 | 502 | ICameraControl::Size size; |
michael@0 | 503 | aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size); |
michael@0 | 504 | if (aRv.Failed()) { |
michael@0 | 505 | return; |
michael@0 | 506 | } |
michael@0 | 507 | |
michael@0 | 508 | aRv = GetSize(cx, aSize.address(), size); |
michael@0 | 509 | } |
michael@0 | 510 | void |
michael@0 | 511 | nsDOMCameraControl::SetPictureSize(JSContext* aCx, JS::Handle<JS::Value> aSize, ErrorResult& aRv) |
michael@0 | 512 | { |
michael@0 | 513 | CameraSize size; |
michael@0 | 514 | if (!size.Init(aCx, aSize)) { |
michael@0 | 515 | aRv = NS_ERROR_FAILURE; |
michael@0 | 516 | return; |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | ICameraControl::Size s = { size.mWidth, size.mHeight }; |
michael@0 | 520 | aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s); |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | /* attribute any thumbnailSize */ |
michael@0 | 524 | void |
michael@0 | 525 | nsDOMCameraControl::GetThumbnailSize(JSContext* aCx, |
michael@0 | 526 | JS::MutableHandle<JS::Value> aSize, |
michael@0 | 527 | ErrorResult& aRv) |
michael@0 | 528 | { |
michael@0 | 529 | ICameraControl::Size size; |
michael@0 | 530 | aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size); |
michael@0 | 531 | if (aRv.Failed()) { |
michael@0 | 532 | return; |
michael@0 | 533 | } |
michael@0 | 534 | |
michael@0 | 535 | aRv = GetSize(aCx, aSize.address(), size); |
michael@0 | 536 | } |
michael@0 | 537 | void |
michael@0 | 538 | nsDOMCameraControl::SetThumbnailSize(JSContext* aCx, JS::Handle<JS::Value> aSize, ErrorResult& aRv) |
michael@0 | 539 | { |
michael@0 | 540 | CameraSize size; |
michael@0 | 541 | if (!size.Init(aCx, aSize)) { |
michael@0 | 542 | aRv = NS_ERROR_FAILURE; |
michael@0 | 543 | return; |
michael@0 | 544 | } |
michael@0 | 545 | |
michael@0 | 546 | ICameraControl::Size s = { size.mWidth, size.mHeight }; |
michael@0 | 547 | aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s); |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | double |
michael@0 | 551 | nsDOMCameraControl::GetFocalLength(ErrorResult& aRv) |
michael@0 | 552 | { |
michael@0 | 553 | MOZ_ASSERT(mCameraControl); |
michael@0 | 554 | |
michael@0 | 555 | double focalLength; |
michael@0 | 556 | aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, focalLength); |
michael@0 | 557 | return focalLength; |
michael@0 | 558 | } |
michael@0 | 559 | |
michael@0 | 560 | double |
michael@0 | 561 | nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv) |
michael@0 | 562 | { |
michael@0 | 563 | MOZ_ASSERT(mCameraControl); |
michael@0 | 564 | |
michael@0 | 565 | double distance; |
michael@0 | 566 | aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, distance); |
michael@0 | 567 | return distance; |
michael@0 | 568 | } |
michael@0 | 569 | |
michael@0 | 570 | double |
michael@0 | 571 | nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv) |
michael@0 | 572 | { |
michael@0 | 573 | MOZ_ASSERT(mCameraControl); |
michael@0 | 574 | |
michael@0 | 575 | double distance; |
michael@0 | 576 | aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, distance); |
michael@0 | 577 | return distance; |
michael@0 | 578 | } |
michael@0 | 579 | |
michael@0 | 580 | double |
michael@0 | 581 | nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv) |
michael@0 | 582 | { |
michael@0 | 583 | MOZ_ASSERT(mCameraControl); |
michael@0 | 584 | |
michael@0 | 585 | double distance; |
michael@0 | 586 | aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, distance); |
michael@0 | 587 | return distance; |
michael@0 | 588 | } |
michael@0 | 589 | |
michael@0 | 590 | void |
michael@0 | 591 | nsDOMCameraControl::SetExposureCompensation(const Optional<double>& aCompensation, ErrorResult& aRv) |
michael@0 | 592 | { |
michael@0 | 593 | MOZ_ASSERT(mCameraControl); |
michael@0 | 594 | |
michael@0 | 595 | if (!aCompensation.WasPassed()) { |
michael@0 | 596 | // use NaN to switch the camera back into auto mode |
michael@0 | 597 | aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN); |
michael@0 | 598 | return; |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation.Value()); |
michael@0 | 602 | } |
michael@0 | 603 | |
michael@0 | 604 | double |
michael@0 | 605 | nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv) |
michael@0 | 606 | { |
michael@0 | 607 | MOZ_ASSERT(mCameraControl); |
michael@0 | 608 | |
michael@0 | 609 | double compensation; |
michael@0 | 610 | aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation); |
michael@0 | 611 | return compensation; |
michael@0 | 612 | } |
michael@0 | 613 | |
michael@0 | 614 | int32_t |
michael@0 | 615 | nsDOMCameraControl::SensorAngle() |
michael@0 | 616 | { |
michael@0 | 617 | MOZ_ASSERT(mCameraControl); |
michael@0 | 618 | |
michael@0 | 619 | int32_t angle = 0; |
michael@0 | 620 | mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle); |
michael@0 | 621 | return angle; |
michael@0 | 622 | } |
michael@0 | 623 | |
michael@0 | 624 | // Callback attributes |
michael@0 | 625 | |
michael@0 | 626 | CameraShutterCallback* |
michael@0 | 627 | nsDOMCameraControl::GetOnShutter() |
michael@0 | 628 | { |
michael@0 | 629 | return mOnShutterCb; |
michael@0 | 630 | } |
michael@0 | 631 | void |
michael@0 | 632 | nsDOMCameraControl::SetOnShutter(CameraShutterCallback* aCb) |
michael@0 | 633 | { |
michael@0 | 634 | mOnShutterCb = aCb; |
michael@0 | 635 | } |
michael@0 | 636 | |
michael@0 | 637 | CameraClosedCallback* |
michael@0 | 638 | nsDOMCameraControl::GetOnClosed() |
michael@0 | 639 | { |
michael@0 | 640 | return mOnClosedCb; |
michael@0 | 641 | } |
michael@0 | 642 | void |
michael@0 | 643 | nsDOMCameraControl::SetOnClosed(CameraClosedCallback* aCb) |
michael@0 | 644 | { |
michael@0 | 645 | mOnClosedCb = aCb; |
michael@0 | 646 | } |
michael@0 | 647 | |
michael@0 | 648 | CameraRecorderStateChange* |
michael@0 | 649 | nsDOMCameraControl::GetOnRecorderStateChange() |
michael@0 | 650 | { |
michael@0 | 651 | return mOnRecorderStateChangeCb; |
michael@0 | 652 | } |
michael@0 | 653 | void |
michael@0 | 654 | nsDOMCameraControl::SetOnRecorderStateChange(CameraRecorderStateChange* aCb) |
michael@0 | 655 | { |
michael@0 | 656 | mOnRecorderStateChangeCb = aCb; |
michael@0 | 657 | } |
michael@0 | 658 | |
michael@0 | 659 | CameraPreviewStateChange* |
michael@0 | 660 | nsDOMCameraControl::GetOnPreviewStateChange() |
michael@0 | 661 | { |
michael@0 | 662 | return mOnPreviewStateChangeCb; |
michael@0 | 663 | } |
michael@0 | 664 | void |
michael@0 | 665 | nsDOMCameraControl::SetOnPreviewStateChange(CameraPreviewStateChange* aCb) |
michael@0 | 666 | { |
michael@0 | 667 | mOnPreviewStateChangeCb = aCb; |
michael@0 | 668 | } |
michael@0 | 669 | |
michael@0 | 670 | CameraAutoFocusMovingCallback* |
michael@0 | 671 | nsDOMCameraControl::GetOnAutoFocusMoving() |
michael@0 | 672 | { |
michael@0 | 673 | return mOnAutoFocusMovingCb; |
michael@0 | 674 | } |
michael@0 | 675 | void |
michael@0 | 676 | nsDOMCameraControl::SetOnAutoFocusMoving(CameraAutoFocusMovingCallback* aCb) |
michael@0 | 677 | { |
michael@0 | 678 | mOnAutoFocusMovingCb = aCb; |
michael@0 | 679 | } |
michael@0 | 680 | |
michael@0 | 681 | CameraFaceDetectionCallback* |
michael@0 | 682 | nsDOMCameraControl::GetOnFacesDetected() |
michael@0 | 683 | { |
michael@0 | 684 | return mOnFacesDetectedCb; |
michael@0 | 685 | } |
michael@0 | 686 | void |
michael@0 | 687 | nsDOMCameraControl::SetOnFacesDetected(CameraFaceDetectionCallback* aCb) |
michael@0 | 688 | { |
michael@0 | 689 | mOnFacesDetectedCb = aCb; |
michael@0 | 690 | } |
michael@0 | 691 | |
michael@0 | 692 | already_AddRefed<dom::CameraCapabilities> |
michael@0 | 693 | nsDOMCameraControl::Capabilities() |
michael@0 | 694 | { |
michael@0 | 695 | nsRefPtr<CameraCapabilities> caps = mCapabilities; |
michael@0 | 696 | |
michael@0 | 697 | if (!caps) { |
michael@0 | 698 | caps = new CameraCapabilities(mWindow); |
michael@0 | 699 | nsresult rv = caps->Populate(mCameraControl); |
michael@0 | 700 | if (NS_FAILED(rv)) { |
michael@0 | 701 | DOM_CAMERA_LOGW("Failed to populate camera capabilities (%d)\n", rv); |
michael@0 | 702 | return nullptr; |
michael@0 | 703 | } |
michael@0 | 704 | mCapabilities = caps; |
michael@0 | 705 | } |
michael@0 | 706 | |
michael@0 | 707 | return caps.forget(); |
michael@0 | 708 | } |
michael@0 | 709 | |
michael@0 | 710 | // Methods. |
michael@0 | 711 | void |
michael@0 | 712 | nsDOMCameraControl::StartRecording(const CameraStartRecordingOptions& aOptions, |
michael@0 | 713 | nsDOMDeviceStorage& aStorageArea, |
michael@0 | 714 | const nsAString& aFilename, |
michael@0 | 715 | CameraStartRecordingCallback& aOnSuccess, |
michael@0 | 716 | const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, |
michael@0 | 717 | ErrorResult& aRv) |
michael@0 | 718 | { |
michael@0 | 719 | MOZ_ASSERT(mCameraControl); |
michael@0 | 720 | |
michael@0 | 721 | NotifyRecordingStatusChange(NS_LITERAL_STRING("starting")); |
michael@0 | 722 | |
michael@0 | 723 | #ifdef MOZ_B2G |
michael@0 | 724 | if (!mAudioChannelAgent) { |
michael@0 | 725 | mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1"); |
michael@0 | 726 | if (mAudioChannelAgent) { |
michael@0 | 727 | // Camera app will stop recording when it falls to the background, so no callback is necessary. |
michael@0 | 728 | mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr); |
michael@0 | 729 | // Video recording doesn't output any sound, so it's not necessary to check canPlay. |
michael@0 | 730 | int32_t canPlay; |
michael@0 | 731 | mAudioChannelAgent->StartPlaying(&canPlay); |
michael@0 | 732 | } |
michael@0 | 733 | } |
michael@0 | 734 | #endif |
michael@0 | 735 | |
michael@0 | 736 | nsCOMPtr<nsIDOMDOMRequest> request; |
michael@0 | 737 | mDSFileDescriptor = new DeviceStorageFileDescriptor(); |
michael@0 | 738 | aRv = aStorageArea.CreateFileDescriptor(aFilename, mDSFileDescriptor.get(), |
michael@0 | 739 | getter_AddRefs(request)); |
michael@0 | 740 | if (aRv.Failed()) { |
michael@0 | 741 | return; |
michael@0 | 742 | } |
michael@0 | 743 | |
michael@0 | 744 | mOptions = aOptions; |
michael@0 | 745 | mStartRecordingOnSuccessCb = &aOnSuccess; |
michael@0 | 746 | mStartRecordingOnErrorCb = nullptr; |
michael@0 | 747 | if (aOnError.WasPassed()) { |
michael@0 | 748 | mStartRecordingOnErrorCb = &aOnError.Value(); |
michael@0 | 749 | } |
michael@0 | 750 | |
michael@0 | 751 | nsCOMPtr<nsIDOMEventListener> listener = new StartRecordingHelper(this); |
michael@0 | 752 | request->AddEventListener(NS_LITERAL_STRING("success"), listener, false); |
michael@0 | 753 | request->AddEventListener(NS_LITERAL_STRING("error"), listener, false); |
michael@0 | 754 | } |
michael@0 | 755 | |
michael@0 | 756 | void |
michael@0 | 757 | nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded) |
michael@0 | 758 | { |
michael@0 | 759 | if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) { |
michael@0 | 760 | ICameraControl::StartRecordingOptions o; |
michael@0 | 761 | |
michael@0 | 762 | o.rotation = mOptions.mRotation; |
michael@0 | 763 | o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes; |
michael@0 | 764 | o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs; |
michael@0 | 765 | o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch; |
michael@0 | 766 | nsresult rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o); |
michael@0 | 767 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 768 | return; |
michael@0 | 769 | } |
michael@0 | 770 | } |
michael@0 | 771 | OnError(CameraControlListener::kInStartRecording, NS_LITERAL_STRING("FAILURE")); |
michael@0 | 772 | |
michael@0 | 773 | if (mDSFileDescriptor->mFileDescriptor.IsValid()) { |
michael@0 | 774 | // An error occured. We need to manually close the file associated with the |
michael@0 | 775 | // FileDescriptor, and we shouldn't do this on the main thread, so we |
michael@0 | 776 | // use a little helper. |
michael@0 | 777 | nsRefPtr<CloseFileRunnable> closer = |
michael@0 | 778 | new CloseFileRunnable(mDSFileDescriptor->mFileDescriptor); |
michael@0 | 779 | closer->Dispatch(); |
michael@0 | 780 | } |
michael@0 | 781 | } |
michael@0 | 782 | |
michael@0 | 783 | void |
michael@0 | 784 | nsDOMCameraControl::StopRecording(ErrorResult& aRv) |
michael@0 | 785 | { |
michael@0 | 786 | MOZ_ASSERT(mCameraControl); |
michael@0 | 787 | |
michael@0 | 788 | #ifdef MOZ_B2G |
michael@0 | 789 | if (mAudioChannelAgent) { |
michael@0 | 790 | mAudioChannelAgent->StopPlaying(); |
michael@0 | 791 | mAudioChannelAgent = nullptr; |
michael@0 | 792 | } |
michael@0 | 793 | #endif |
michael@0 | 794 | |
michael@0 | 795 | aRv = mCameraControl->StopRecording(); |
michael@0 | 796 | } |
michael@0 | 797 | |
michael@0 | 798 | void |
michael@0 | 799 | nsDOMCameraControl::ResumePreview(ErrorResult& aRv) |
michael@0 | 800 | { |
michael@0 | 801 | MOZ_ASSERT(mCameraControl); |
michael@0 | 802 | aRv = mCameraControl->StartPreview(); |
michael@0 | 803 | } |
michael@0 | 804 | |
michael@0 | 805 | void |
michael@0 | 806 | nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration, |
michael@0 | 807 | const Optional<OwningNonNull<CameraSetConfigurationCallback> >& aOnSuccess, |
michael@0 | 808 | const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, |
michael@0 | 809 | ErrorResult& aRv) |
michael@0 | 810 | { |
michael@0 | 811 | MOZ_ASSERT(mCameraControl); |
michael@0 | 812 | |
michael@0 | 813 | nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb; |
michael@0 | 814 | if (cb) { |
michael@0 | 815 | // We're busy taking a picture, can't change modes right now. |
michael@0 | 816 | if (aOnError.WasPassed()) { |
michael@0 | 817 | ErrorResult ignored; |
michael@0 | 818 | aOnError.Value().Call(NS_LITERAL_STRING("Busy"), ignored); |
michael@0 | 819 | } |
michael@0 | 820 | aRv = NS_ERROR_FAILURE; |
michael@0 | 821 | return; |
michael@0 | 822 | } |
michael@0 | 823 | |
michael@0 | 824 | ICameraControl::Configuration config; |
michael@0 | 825 | config.mRecorderProfile = aConfiguration.mRecorderProfile; |
michael@0 | 826 | config.mPreviewSize.width = aConfiguration.mPreviewSize.mWidth; |
michael@0 | 827 | config.mPreviewSize.height = aConfiguration.mPreviewSize.mHeight; |
michael@0 | 828 | config.mMode = ICameraControl::kPictureMode; |
michael@0 | 829 | if (aConfiguration.mMode == CameraMode::Video) { |
michael@0 | 830 | config.mMode = ICameraControl::kVideoMode; |
michael@0 | 831 | } |
michael@0 | 832 | |
michael@0 | 833 | mSetConfigurationOnSuccessCb = nullptr; |
michael@0 | 834 | if (aOnSuccess.WasPassed()) { |
michael@0 | 835 | mSetConfigurationOnSuccessCb = &aOnSuccess.Value(); |
michael@0 | 836 | } |
michael@0 | 837 | mSetConfigurationOnErrorCb = nullptr; |
michael@0 | 838 | if (aOnError.WasPassed()) { |
michael@0 | 839 | mSetConfigurationOnErrorCb = &aOnError.Value(); |
michael@0 | 840 | } |
michael@0 | 841 | |
michael@0 | 842 | aRv = mCameraControl->SetConfiguration(config); |
michael@0 | 843 | } |
michael@0 | 844 | |
michael@0 | 845 | class ImmediateErrorCallback : public nsRunnable |
michael@0 | 846 | { |
michael@0 | 847 | public: |
michael@0 | 848 | ImmediateErrorCallback(CameraErrorCallback* aCallback, const nsAString& aMessage) |
michael@0 | 849 | : mCallback(aCallback) |
michael@0 | 850 | , mMessage(aMessage) |
michael@0 | 851 | { } |
michael@0 | 852 | |
michael@0 | 853 | NS_IMETHODIMP |
michael@0 | 854 | Run() |
michael@0 | 855 | { |
michael@0 | 856 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 857 | ErrorResult ignored; |
michael@0 | 858 | mCallback->Call(mMessage, ignored); |
michael@0 | 859 | return NS_OK; |
michael@0 | 860 | } |
michael@0 | 861 | |
michael@0 | 862 | protected: |
michael@0 | 863 | nsRefPtr<CameraErrorCallback> mCallback; |
michael@0 | 864 | nsString mMessage; |
michael@0 | 865 | }; |
michael@0 | 866 | |
michael@0 | 867 | |
michael@0 | 868 | void |
michael@0 | 869 | nsDOMCameraControl::AutoFocus(CameraAutoFocusCallback& aOnSuccess, |
michael@0 | 870 | const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, |
michael@0 | 871 | ErrorResult& aRv) |
michael@0 | 872 | { |
michael@0 | 873 | MOZ_ASSERT(mCameraControl); |
michael@0 | 874 | |
michael@0 | 875 | nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb; |
michael@0 | 876 | if (cb) { |
michael@0 | 877 | if (aOnError.WasPassed()) { |
michael@0 | 878 | // There is already a call to AutoFocus() in progress, abort this new one |
michael@0 | 879 | // and invoke the error callback (if one was passed in). |
michael@0 | 880 | NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(), |
michael@0 | 881 | NS_LITERAL_STRING("AutoFocusAlreadyInProgress"))); |
michael@0 | 882 | } |
michael@0 | 883 | aRv = NS_ERROR_FAILURE; |
michael@0 | 884 | return; |
michael@0 | 885 | } |
michael@0 | 886 | |
michael@0 | 887 | mAutoFocusOnSuccessCb = &aOnSuccess; |
michael@0 | 888 | mAutoFocusOnErrorCb = nullptr; |
michael@0 | 889 | if (aOnError.WasPassed()) { |
michael@0 | 890 | mAutoFocusOnErrorCb = &aOnError.Value(); |
michael@0 | 891 | } |
michael@0 | 892 | |
michael@0 | 893 | aRv = mCameraControl->AutoFocus(); |
michael@0 | 894 | } |
michael@0 | 895 | |
michael@0 | 896 | void |
michael@0 | 897 | nsDOMCameraControl::StartFaceDetection(ErrorResult& aRv) |
michael@0 | 898 | { |
michael@0 | 899 | MOZ_ASSERT(mCameraControl); |
michael@0 | 900 | aRv = mCameraControl->StartFaceDetection(); |
michael@0 | 901 | } |
michael@0 | 902 | |
michael@0 | 903 | void |
michael@0 | 904 | nsDOMCameraControl::StopFaceDetection(ErrorResult& aRv) |
michael@0 | 905 | { |
michael@0 | 906 | MOZ_ASSERT(mCameraControl); |
michael@0 | 907 | aRv = mCameraControl->StopFaceDetection(); |
michael@0 | 908 | } |
michael@0 | 909 | |
michael@0 | 910 | void |
michael@0 | 911 | nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions, |
michael@0 | 912 | CameraTakePictureCallback& aOnSuccess, |
michael@0 | 913 | const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, |
michael@0 | 914 | ErrorResult& aRv) |
michael@0 | 915 | { |
michael@0 | 916 | MOZ_ASSERT(mCameraControl); |
michael@0 | 917 | |
michael@0 | 918 | nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb; |
michael@0 | 919 | if (cb) { |
michael@0 | 920 | if (aOnError.WasPassed()) { |
michael@0 | 921 | // There is already a call to TakePicture() in progress, abort this new |
michael@0 | 922 | // one and invoke the error callback (if one was passed in). |
michael@0 | 923 | NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(), |
michael@0 | 924 | NS_LITERAL_STRING("TakePictureAlreadyInProgress"))); |
michael@0 | 925 | } |
michael@0 | 926 | aRv = NS_ERROR_FAILURE; |
michael@0 | 927 | return; |
michael@0 | 928 | } |
michael@0 | 929 | |
michael@0 | 930 | { |
michael@0 | 931 | ICameraControlParameterSetAutoEnter batch(mCameraControl); |
michael@0 | 932 | |
michael@0 | 933 | // XXXmikeh - remove this: see bug 931155 |
michael@0 | 934 | ICameraControl::Size s; |
michael@0 | 935 | s.width = aOptions.mPictureSize.mWidth; |
michael@0 | 936 | s.height = aOptions.mPictureSize.mHeight; |
michael@0 | 937 | |
michael@0 | 938 | ICameraControl::Position p; |
michael@0 | 939 | p.latitude = aOptions.mPosition.mLatitude; |
michael@0 | 940 | p.longitude = aOptions.mPosition.mLongitude; |
michael@0 | 941 | p.altitude = aOptions.mPosition.mAltitude; |
michael@0 | 942 | p.timestamp = aOptions.mPosition.mTimestamp; |
michael@0 | 943 | |
michael@0 | 944 | if (s.width && s.height) { |
michael@0 | 945 | mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s); |
michael@0 | 946 | } |
michael@0 | 947 | mCameraControl->Set(CAMERA_PARAM_PICTURE_ROTATION, aOptions.mRotation); |
michael@0 | 948 | mCameraControl->Set(CAMERA_PARAM_PICTURE_FILEFORMAT, aOptions.mFileFormat); |
michael@0 | 949 | mCameraControl->Set(CAMERA_PARAM_PICTURE_DATETIME, aOptions.mDateTime); |
michael@0 | 950 | mCameraControl->SetLocation(p); |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | mTakePictureOnSuccessCb = &aOnSuccess; |
michael@0 | 954 | mTakePictureOnErrorCb = nullptr; |
michael@0 | 955 | if (aOnError.WasPassed()) { |
michael@0 | 956 | mTakePictureOnErrorCb = &aOnError.Value(); |
michael@0 | 957 | } |
michael@0 | 958 | |
michael@0 | 959 | aRv = mCameraControl->TakePicture(); |
michael@0 | 960 | } |
michael@0 | 961 | |
michael@0 | 962 | void |
michael@0 | 963 | nsDOMCameraControl::ReleaseHardware(const Optional<OwningNonNull<CameraReleaseCallback> >& aOnSuccess, |
michael@0 | 964 | const Optional<OwningNonNull<CameraErrorCallback> >& aOnError, |
michael@0 | 965 | ErrorResult& aRv) |
michael@0 | 966 | { |
michael@0 | 967 | MOZ_ASSERT(mCameraControl); |
michael@0 | 968 | |
michael@0 | 969 | mReleaseOnSuccessCb = nullptr; |
michael@0 | 970 | if (aOnSuccess.WasPassed()) { |
michael@0 | 971 | mReleaseOnSuccessCb = &aOnSuccess.Value(); |
michael@0 | 972 | } |
michael@0 | 973 | mReleaseOnErrorCb = nullptr; |
michael@0 | 974 | if (aOnError.WasPassed()) { |
michael@0 | 975 | mReleaseOnErrorCb = &aOnError.Value(); |
michael@0 | 976 | } |
michael@0 | 977 | |
michael@0 | 978 | aRv = mCameraControl->Stop(); |
michael@0 | 979 | } |
michael@0 | 980 | |
michael@0 | 981 | void |
michael@0 | 982 | nsDOMCameraControl::ResumeContinuousFocus(ErrorResult& aRv) |
michael@0 | 983 | { |
michael@0 | 984 | MOZ_ASSERT(mCameraControl); |
michael@0 | 985 | aRv = mCameraControl->ResumeContinuousFocus(); |
michael@0 | 986 | } |
michael@0 | 987 | |
michael@0 | 988 | void |
michael@0 | 989 | nsDOMCameraControl::Shutdown() |
michael@0 | 990 | { |
michael@0 | 991 | DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__); |
michael@0 | 992 | MOZ_ASSERT(mCameraControl); |
michael@0 | 993 | |
michael@0 | 994 | // Remove any pending solicited event handlers; these |
michael@0 | 995 | // reference our window object, which in turn references |
michael@0 | 996 | // us. If we don't remove them, we can leak DOM objects. |
michael@0 | 997 | mGetCameraOnSuccessCb = nullptr; |
michael@0 | 998 | mGetCameraOnErrorCb = nullptr; |
michael@0 | 999 | mAutoFocusOnSuccessCb = nullptr; |
michael@0 | 1000 | mAutoFocusOnErrorCb = nullptr; |
michael@0 | 1001 | mTakePictureOnSuccessCb = nullptr; |
michael@0 | 1002 | mTakePictureOnErrorCb = nullptr; |
michael@0 | 1003 | mStartRecordingOnSuccessCb = nullptr; |
michael@0 | 1004 | mStartRecordingOnErrorCb = nullptr; |
michael@0 | 1005 | mReleaseOnSuccessCb = nullptr; |
michael@0 | 1006 | mReleaseOnErrorCb = nullptr; |
michael@0 | 1007 | mSetConfigurationOnSuccessCb = nullptr; |
michael@0 | 1008 | mSetConfigurationOnErrorCb = nullptr; |
michael@0 | 1009 | |
michael@0 | 1010 | // Remove all of the unsolicited event handlers too. |
michael@0 | 1011 | mOnShutterCb = nullptr; |
michael@0 | 1012 | mOnClosedCb = nullptr; |
michael@0 | 1013 | mOnRecorderStateChangeCb = nullptr; |
michael@0 | 1014 | mOnPreviewStateChangeCb = nullptr; |
michael@0 | 1015 | mOnAutoFocusMovingCb = nullptr; |
michael@0 | 1016 | mOnFacesDetectedCb = nullptr; |
michael@0 | 1017 | |
michael@0 | 1018 | mCameraControl->Shutdown(); |
michael@0 | 1019 | } |
michael@0 | 1020 | |
michael@0 | 1021 | nsresult |
michael@0 | 1022 | nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg) |
michael@0 | 1023 | { |
michael@0 | 1024 | NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE); |
michael@0 | 1025 | |
michael@0 | 1026 | return MediaManager::NotifyRecordingStatusChange(mWindow, |
michael@0 | 1027 | aMsg, |
michael@0 | 1028 | true /* aIsAudio */, |
michael@0 | 1029 | true /* aIsVideo */); |
michael@0 | 1030 | } |
michael@0 | 1031 | |
michael@0 | 1032 | // Camera Control event handlers--must only be called from the Main Thread! |
michael@0 | 1033 | void |
michael@0 | 1034 | nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState) |
michael@0 | 1035 | { |
michael@0 | 1036 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1037 | ErrorResult ignored; |
michael@0 | 1038 | |
michael@0 | 1039 | DOM_CAMERA_LOGI("DOM OnHardwareStateChange(%d)\n", aState); |
michael@0 | 1040 | |
michael@0 | 1041 | switch (aState) { |
michael@0 | 1042 | case CameraControlListener::kHardwareOpen: |
michael@0 | 1043 | // The hardware is open, so we can return a camera to JS, even if |
michael@0 | 1044 | // the preview hasn't started yet. |
michael@0 | 1045 | if (mGetCameraOnSuccessCb) { |
michael@0 | 1046 | nsRefPtr<GetCameraCallback> cb = mGetCameraOnSuccessCb.forget(); |
michael@0 | 1047 | ErrorResult ignored; |
michael@0 | 1048 | mGetCameraOnErrorCb = nullptr; |
michael@0 | 1049 | cb->Call(*this, *mCurrentConfiguration, ignored); |
michael@0 | 1050 | } |
michael@0 | 1051 | break; |
michael@0 | 1052 | |
michael@0 | 1053 | case CameraControlListener::kHardwareClosed: |
michael@0 | 1054 | if (mReleaseOnSuccessCb) { |
michael@0 | 1055 | // If we have this event handler, this was a solicited hardware close. |
michael@0 | 1056 | nsRefPtr<CameraReleaseCallback> cb = mReleaseOnSuccessCb.forget(); |
michael@0 | 1057 | mReleaseOnErrorCb = nullptr; |
michael@0 | 1058 | cb->Call(ignored); |
michael@0 | 1059 | } else if(mOnClosedCb) { |
michael@0 | 1060 | // If not, something else closed the hardware. |
michael@0 | 1061 | nsRefPtr<CameraClosedCallback> cb = mOnClosedCb; |
michael@0 | 1062 | cb->Call(ignored); |
michael@0 | 1063 | } |
michael@0 | 1064 | break; |
michael@0 | 1065 | |
michael@0 | 1066 | default: |
michael@0 | 1067 | MOZ_ASSUME_UNREACHABLE("Unanticipated camera hardware state"); |
michael@0 | 1068 | } |
michael@0 | 1069 | } |
michael@0 | 1070 | |
michael@0 | 1071 | void |
michael@0 | 1072 | nsDOMCameraControl::OnShutter() |
michael@0 | 1073 | { |
michael@0 | 1074 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1075 | |
michael@0 | 1076 | DOM_CAMERA_LOGI("DOM ** SNAP **\n"); |
michael@0 | 1077 | |
michael@0 | 1078 | nsRefPtr<CameraShutterCallback> cb = mOnShutterCb; |
michael@0 | 1079 | if (cb) { |
michael@0 | 1080 | ErrorResult ignored; |
michael@0 | 1081 | cb->Call(ignored); |
michael@0 | 1082 | } |
michael@0 | 1083 | } |
michael@0 | 1084 | |
michael@0 | 1085 | void |
michael@0 | 1086 | nsDOMCameraControl::OnPreviewStateChange(CameraControlListener::PreviewState aState) |
michael@0 | 1087 | { |
michael@0 | 1088 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1089 | |
michael@0 | 1090 | if (!mOnPreviewStateChangeCb) { |
michael@0 | 1091 | return; |
michael@0 | 1092 | } |
michael@0 | 1093 | |
michael@0 | 1094 | nsString state; |
michael@0 | 1095 | switch (aState) { |
michael@0 | 1096 | case CameraControlListener::kPreviewStarted: |
michael@0 | 1097 | state = NS_LITERAL_STRING("started"); |
michael@0 | 1098 | break; |
michael@0 | 1099 | |
michael@0 | 1100 | default: |
michael@0 | 1101 | state = NS_LITERAL_STRING("stopped"); |
michael@0 | 1102 | break; |
michael@0 | 1103 | } |
michael@0 | 1104 | |
michael@0 | 1105 | nsRefPtr<CameraPreviewStateChange> cb = mOnPreviewStateChangeCb; |
michael@0 | 1106 | ErrorResult ignored; |
michael@0 | 1107 | cb->Call(state, ignored); |
michael@0 | 1108 | } |
michael@0 | 1109 | |
michael@0 | 1110 | void |
michael@0 | 1111 | nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState aState, |
michael@0 | 1112 | int32_t aArg, int32_t aTrackNum) |
michael@0 | 1113 | { |
michael@0 | 1114 | // For now, we do nothing with 'aStatus' and 'aTrackNum'. |
michael@0 | 1115 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1116 | |
michael@0 | 1117 | ErrorResult ignored; |
michael@0 | 1118 | nsString state; |
michael@0 | 1119 | |
michael@0 | 1120 | switch (aState) { |
michael@0 | 1121 | case CameraControlListener::kRecorderStarted: |
michael@0 | 1122 | if (mStartRecordingOnSuccessCb) { |
michael@0 | 1123 | nsRefPtr<CameraStartRecordingCallback> cb = mStartRecordingOnSuccessCb.forget(); |
michael@0 | 1124 | mStartRecordingOnErrorCb = nullptr; |
michael@0 | 1125 | cb->Call(ignored); |
michael@0 | 1126 | } |
michael@0 | 1127 | state = NS_LITERAL_STRING("Started"); |
michael@0 | 1128 | break; |
michael@0 | 1129 | |
michael@0 | 1130 | case CameraControlListener::kRecorderStopped: |
michael@0 | 1131 | NotifyRecordingStatusChange(NS_LITERAL_STRING("shutdown")); |
michael@0 | 1132 | state = NS_LITERAL_STRING("Stopped"); |
michael@0 | 1133 | break; |
michael@0 | 1134 | |
michael@0 | 1135 | #ifdef MOZ_B2G_CAMERA |
michael@0 | 1136 | case CameraControlListener::kFileSizeLimitReached: |
michael@0 | 1137 | state = NS_LITERAL_STRING("FileSizeLimitReached"); |
michael@0 | 1138 | break; |
michael@0 | 1139 | |
michael@0 | 1140 | case CameraControlListener::kVideoLengthLimitReached: |
michael@0 | 1141 | state = NS_LITERAL_STRING("VideoLengthLimitReached"); |
michael@0 | 1142 | break; |
michael@0 | 1143 | |
michael@0 | 1144 | case CameraControlListener::kTrackCompleted: |
michael@0 | 1145 | state = NS_LITERAL_STRING("TrackCompleted"); |
michael@0 | 1146 | break; |
michael@0 | 1147 | |
michael@0 | 1148 | case CameraControlListener::kTrackFailed: |
michael@0 | 1149 | state = NS_LITERAL_STRING("TrackFailed"); |
michael@0 | 1150 | break; |
michael@0 | 1151 | |
michael@0 | 1152 | case CameraControlListener::kMediaRecorderFailed: |
michael@0 | 1153 | state = NS_LITERAL_STRING("MediaRecorderFailed"); |
michael@0 | 1154 | break; |
michael@0 | 1155 | |
michael@0 | 1156 | case CameraControlListener::kMediaServerFailed: |
michael@0 | 1157 | state = NS_LITERAL_STRING("MediaServerFailed"); |
michael@0 | 1158 | break; |
michael@0 | 1159 | #endif |
michael@0 | 1160 | |
michael@0 | 1161 | default: |
michael@0 | 1162 | MOZ_ASSUME_UNREACHABLE("Unanticipated video recorder error"); |
michael@0 | 1163 | return; |
michael@0 | 1164 | } |
michael@0 | 1165 | |
michael@0 | 1166 | nsRefPtr<CameraRecorderStateChange> cb = mOnRecorderStateChangeCb; |
michael@0 | 1167 | if (cb) { |
michael@0 | 1168 | cb->Call(state, ignored); |
michael@0 | 1169 | } |
michael@0 | 1170 | } |
michael@0 | 1171 | |
michael@0 | 1172 | void |
michael@0 | 1173 | nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration) |
michael@0 | 1174 | { |
michael@0 | 1175 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1176 | |
michael@0 | 1177 | // Update our record of the current camera configuration |
michael@0 | 1178 | mCurrentConfiguration = aConfiguration; |
michael@0 | 1179 | |
michael@0 | 1180 | DOM_CAMERA_LOGI("DOM OnConfigurationChange: this=%p\n", this); |
michael@0 | 1181 | DOM_CAMERA_LOGI(" mode : %s\n", |
michael@0 | 1182 | mCurrentConfiguration->mMode == CameraMode::Video ? "video" : "picture"); |
michael@0 | 1183 | DOM_CAMERA_LOGI(" maximum focus areas : %d\n", |
michael@0 | 1184 | mCurrentConfiguration->mMaxFocusAreas); |
michael@0 | 1185 | DOM_CAMERA_LOGI(" maximum metering areas : %d\n", |
michael@0 | 1186 | mCurrentConfiguration->mMaxMeteringAreas); |
michael@0 | 1187 | DOM_CAMERA_LOGI(" preview size (w x h) : %d x %d\n", |
michael@0 | 1188 | mCurrentConfiguration->mPreviewSize.mWidth, mCurrentConfiguration->mPreviewSize.mHeight); |
michael@0 | 1189 | DOM_CAMERA_LOGI(" recorder profile : %s\n", |
michael@0 | 1190 | NS_ConvertUTF16toUTF8(mCurrentConfiguration->mRecorderProfile).get()); |
michael@0 | 1191 | |
michael@0 | 1192 | nsRefPtr<CameraSetConfigurationCallback> cb = mSetConfigurationOnSuccessCb.forget(); |
michael@0 | 1193 | mSetConfigurationOnErrorCb = nullptr; |
michael@0 | 1194 | if (cb) { |
michael@0 | 1195 | ErrorResult ignored; |
michael@0 | 1196 | cb->Call(*mCurrentConfiguration, ignored); |
michael@0 | 1197 | } |
michael@0 | 1198 | } |
michael@0 | 1199 | |
michael@0 | 1200 | void |
michael@0 | 1201 | nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded) |
michael@0 | 1202 | { |
michael@0 | 1203 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1204 | |
michael@0 | 1205 | nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.forget(); |
michael@0 | 1206 | mAutoFocusOnErrorCb = nullptr; |
michael@0 | 1207 | if (cb) { |
michael@0 | 1208 | ErrorResult ignored; |
michael@0 | 1209 | cb->Call(aAutoFocusSucceeded, ignored); |
michael@0 | 1210 | } |
michael@0 | 1211 | } |
michael@0 | 1212 | |
michael@0 | 1213 | void |
michael@0 | 1214 | nsDOMCameraControl::OnAutoFocusMoving(bool aIsMoving) |
michael@0 | 1215 | { |
michael@0 | 1216 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1217 | |
michael@0 | 1218 | nsRefPtr<CameraAutoFocusMovingCallback> cb = mOnAutoFocusMovingCb; |
michael@0 | 1219 | if (cb) { |
michael@0 | 1220 | ErrorResult ignored; |
michael@0 | 1221 | cb->Call(aIsMoving, ignored); |
michael@0 | 1222 | } |
michael@0 | 1223 | } |
michael@0 | 1224 | |
michael@0 | 1225 | void |
michael@0 | 1226 | nsDOMCameraControl::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces) |
michael@0 | 1227 | { |
michael@0 | 1228 | DOM_CAMERA_LOGI("DOM OnFacesDetected %u face(s)\n", aFaces.Length()); |
michael@0 | 1229 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1230 | |
michael@0 | 1231 | nsRefPtr<CameraFaceDetectionCallback> cb = mOnFacesDetectedCb; |
michael@0 | 1232 | if (!cb) { |
michael@0 | 1233 | return; |
michael@0 | 1234 | } |
michael@0 | 1235 | |
michael@0 | 1236 | Sequence<OwningNonNull<DOMCameraDetectedFace> > faces; |
michael@0 | 1237 | uint32_t len = aFaces.Length(); |
michael@0 | 1238 | |
michael@0 | 1239 | if (faces.SetCapacity(len)) { |
michael@0 | 1240 | nsRefPtr<DOMCameraDetectedFace> f; |
michael@0 | 1241 | for (uint32_t i = 0; i < len; ++i) { |
michael@0 | 1242 | f = new DOMCameraDetectedFace(this, aFaces[i]); |
michael@0 | 1243 | *faces.AppendElement() = f.forget().take(); |
michael@0 | 1244 | } |
michael@0 | 1245 | } |
michael@0 | 1246 | |
michael@0 | 1247 | ErrorResult ignored; |
michael@0 | 1248 | cb->Call(faces, ignored); |
michael@0 | 1249 | } |
michael@0 | 1250 | |
michael@0 | 1251 | void |
michael@0 | 1252 | nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture) |
michael@0 | 1253 | { |
michael@0 | 1254 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1255 | |
michael@0 | 1256 | nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget(); |
michael@0 | 1257 | mTakePictureOnErrorCb = nullptr; |
michael@0 | 1258 | if (!cb) { |
michael@0 | 1259 | // Warn because it shouldn't be possible to get here without |
michael@0 | 1260 | // having passed a success callback into takePicture(), even |
michael@0 | 1261 | // though we guard against a nullptr dereference. |
michael@0 | 1262 | NS_WARNING("DOM Null success callback in OnTakePictureComplete()"); |
michael@0 | 1263 | return; |
michael@0 | 1264 | } |
michael@0 | 1265 | |
michael@0 | 1266 | ErrorResult ignored; |
michael@0 | 1267 | cb->Call(aPicture, ignored); |
michael@0 | 1268 | } |
michael@0 | 1269 | |
michael@0 | 1270 | void |
michael@0 | 1271 | nsDOMCameraControl::OnError(CameraControlListener::CameraErrorContext aContext, const nsAString& aError) |
michael@0 | 1272 | { |
michael@0 | 1273 | DOM_CAMERA_LOGI("DOM OnError context=%d, error='%s'\n", aContext, |
michael@0 | 1274 | NS_LossyConvertUTF16toASCII(aError).get()); |
michael@0 | 1275 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 1276 | |
michael@0 | 1277 | nsRefPtr<CameraErrorCallback> errorCb; |
michael@0 | 1278 | |
michael@0 | 1279 | switch (aContext) { |
michael@0 | 1280 | case CameraControlListener::kInStartCamera: |
michael@0 | 1281 | mGetCameraOnSuccessCb = nullptr; |
michael@0 | 1282 | errorCb = mGetCameraOnErrorCb.forget(); |
michael@0 | 1283 | break; |
michael@0 | 1284 | |
michael@0 | 1285 | case CameraControlListener::kInStopCamera: |
michael@0 | 1286 | mReleaseOnSuccessCb = nullptr; |
michael@0 | 1287 | errorCb = mReleaseOnErrorCb.forget(); |
michael@0 | 1288 | break; |
michael@0 | 1289 | |
michael@0 | 1290 | case CameraControlListener::kInSetConfiguration: |
michael@0 | 1291 | mSetConfigurationOnSuccessCb = nullptr; |
michael@0 | 1292 | errorCb = mSetConfigurationOnErrorCb.forget(); |
michael@0 | 1293 | break; |
michael@0 | 1294 | |
michael@0 | 1295 | case CameraControlListener::kInAutoFocus: |
michael@0 | 1296 | mAutoFocusOnSuccessCb = nullptr; |
michael@0 | 1297 | errorCb = mAutoFocusOnErrorCb.forget(); |
michael@0 | 1298 | break; |
michael@0 | 1299 | |
michael@0 | 1300 | case CameraControlListener::kInTakePicture: |
michael@0 | 1301 | mTakePictureOnSuccessCb = nullptr; |
michael@0 | 1302 | errorCb = mTakePictureOnErrorCb.forget(); |
michael@0 | 1303 | break; |
michael@0 | 1304 | |
michael@0 | 1305 | case CameraControlListener::kInStartRecording: |
michael@0 | 1306 | mStartRecordingOnSuccessCb = nullptr; |
michael@0 | 1307 | errorCb = mStartRecordingOnErrorCb.forget(); |
michael@0 | 1308 | break; |
michael@0 | 1309 | |
michael@0 | 1310 | case CameraControlListener::kInStopRecording: |
michael@0 | 1311 | // This method doesn't have any callbacks, so all we can do is log the |
michael@0 | 1312 | // failure. This only happens after the hardware has been released. |
michael@0 | 1313 | NS_WARNING("Failed to stop recording"); |
michael@0 | 1314 | return; |
michael@0 | 1315 | |
michael@0 | 1316 | case CameraControlListener::kInStartPreview: |
michael@0 | 1317 | // This method doesn't have any callbacks, so all we can do is log the |
michael@0 | 1318 | // failure. This only happens after the hardware has been released. |
michael@0 | 1319 | NS_WARNING("Failed to (re)start preview"); |
michael@0 | 1320 | return; |
michael@0 | 1321 | |
michael@0 | 1322 | case CameraControlListener::kInUnspecified: |
michael@0 | 1323 | if (aError.EqualsASCII("ErrorServiceFailed")) { |
michael@0 | 1324 | // If the camera service fails, we will get preview-stopped and |
michael@0 | 1325 | // hardware-closed events, so nothing to do here. |
michael@0 | 1326 | NS_WARNING("Camera service failed"); |
michael@0 | 1327 | return; |
michael@0 | 1328 | } |
michael@0 | 1329 | if (aError.EqualsASCII("ErrorSetPictureSizeFailed") || |
michael@0 | 1330 | aError.EqualsASCII("ErrorSetThumbnailSizeFailed")) { |
michael@0 | 1331 | // We currently don't handle attribute setter failure. Practically, |
michael@0 | 1332 | // this only ever happens if a setter is called after the hardware |
michael@0 | 1333 | // has gone away before an asynchronous set gets to happen, so we |
michael@0 | 1334 | // swallow these. |
michael@0 | 1335 | NS_WARNING("Failed to set either picture or thumbnail size"); |
michael@0 | 1336 | return; |
michael@0 | 1337 | } |
michael@0 | 1338 | // fallthrough |
michael@0 | 1339 | |
michael@0 | 1340 | default: |
michael@0 | 1341 | MOZ_ASSUME_UNREACHABLE("Error occurred in unanticipated camera state"); |
michael@0 | 1342 | return; |
michael@0 | 1343 | } |
michael@0 | 1344 | |
michael@0 | 1345 | if (!errorCb) { |
michael@0 | 1346 | DOM_CAMERA_LOGW("DOM No error handler for error '%s' in context=%d\n", |
michael@0 | 1347 | NS_LossyConvertUTF16toASCII(aError).get(), aContext); |
michael@0 | 1348 | return; |
michael@0 | 1349 | } |
michael@0 | 1350 | |
michael@0 | 1351 | ErrorResult ignored; |
michael@0 | 1352 | errorCb->Call(aError, ignored); |
michael@0 | 1353 | } |
michael@0 | 1354 |