1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/DOMCameraControlListener.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,406 @@ 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 "DOMCameraControlListener.h" 1.9 +#include "nsThreadUtils.h" 1.10 +#include "nsDOMFile.h" 1.11 +#include "CameraCommon.h" 1.12 +#include "DOMCameraControl.h" 1.13 +#include "CameraPreviewMediaStream.h" 1.14 +#include "mozilla/dom/CameraManagerBinding.h" 1.15 + 1.16 +using namespace mozilla; 1.17 +using namespace mozilla::dom; 1.18 + 1.19 +DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl, 1.20 + CameraPreviewMediaStream* aStream) 1.21 + : mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(aDOMCameraControl)) 1.22 + , mStream(aStream) 1.23 +{ 1.24 + DOM_CAMERA_LOGT("%s:%d : this=%p, camera=%p, stream=%p\n", 1.25 + __func__, __LINE__, this, aDOMCameraControl, aStream); 1.26 +} 1.27 + 1.28 +DOMCameraControlListener::~DOMCameraControlListener() 1.29 +{ 1.30 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.31 +} 1.32 + 1.33 +// Boilerplate callback runnable 1.34 +class DOMCameraControlListener::DOMCallback : public nsRunnable 1.35 +{ 1.36 +public: 1.37 + DOMCallback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl) 1.38 + : mDOMCameraControl(aDOMCameraControl) 1.39 + { 1.40 + MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback); 1.41 + } 1.42 + virtual ~DOMCallback() 1.43 + { 1.44 + MOZ_COUNT_DTOR(DOMCameraControlListener::DOMCallback); 1.45 + } 1.46 + 1.47 + virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0; 1.48 + 1.49 + NS_IMETHOD 1.50 + Run() MOZ_OVERRIDE 1.51 + { 1.52 + MOZ_ASSERT(NS_IsMainThread()); 1.53 + 1.54 + nsRefPtr<nsDOMCameraControl> camera = mDOMCameraControl.get(); 1.55 + if (camera) { 1.56 + RunCallback(camera); 1.57 + } 1.58 + return NS_OK; 1.59 + } 1.60 + 1.61 +protected: 1.62 + nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl; 1.63 +}; 1.64 + 1.65 +// Specific callback handlers 1.66 +void 1.67 +DOMCameraControlListener::OnHardwareStateChange(HardwareState aState) 1.68 +{ 1.69 + class Callback : public DOMCallback 1.70 + { 1.71 + public: 1.72 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.73 + HardwareState aState) 1.74 + : DOMCallback(aDOMCameraControl) 1.75 + , mState(aState) 1.76 + { } 1.77 + 1.78 + void 1.79 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.80 + { 1.81 + aDOMCameraControl->OnHardwareStateChange(mState); 1.82 + } 1.83 + 1.84 + protected: 1.85 + HardwareState mState; 1.86 + }; 1.87 + 1.88 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState)); 1.89 +} 1.90 + 1.91 +void 1.92 +DOMCameraControlListener::OnPreviewStateChange(PreviewState aState) 1.93 +{ 1.94 + class Callback : public DOMCallback 1.95 + { 1.96 + public: 1.97 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.98 + PreviewState aState) 1.99 + : DOMCallback(aDOMCameraControl) 1.100 + , mState(aState) 1.101 + { } 1.102 + 1.103 + void 1.104 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.105 + { 1.106 + aDOMCameraControl->OnPreviewStateChange(mState); 1.107 + } 1.108 + 1.109 + protected: 1.110 + PreviewState mState; 1.111 + }; 1.112 + 1.113 + switch (aState) { 1.114 + case kPreviewStopped: 1.115 + // Clear the current frame right away, without dispatching a 1.116 + // runnable. This is an ugly coupling between the camera's 1.117 + // SurfaceTextureClient and the MediaStream/ImageContainer, 1.118 + // but without it, the preview can fail to start. 1.119 + DOM_CAMERA_LOGI("Preview stopped, clearing current frame\n"); 1.120 + mStream->ClearCurrentFrame(); 1.121 + break; 1.122 + 1.123 + case kPreviewPaused: 1.124 + // In the paused state, we still want to reflect the change 1.125 + // in preview state, but we don't want to clear the current 1.126 + // frame as above, since doing so seems to cause genlock 1.127 + // problems when we restart the preview. See bug 957749. 1.128 + DOM_CAMERA_LOGI("Preview paused\n"); 1.129 + break; 1.130 + 1.131 + case kPreviewStarted: 1.132 + DOM_CAMERA_LOGI("Preview started\n"); 1.133 + break; 1.134 + 1.135 + default: 1.136 + DOM_CAMERA_LOGE("Unknown preview state %d\n", aState); 1.137 + MOZ_ASSUME_UNREACHABLE("Invalid preview state"); 1.138 + return; 1.139 + } 1.140 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState)); 1.141 +} 1.142 + 1.143 +void 1.144 +DOMCameraControlListener::OnRecorderStateChange(RecorderState aState, 1.145 + int32_t aStatus, int32_t aTrackNum) 1.146 +{ 1.147 + class Callback : public DOMCallback 1.148 + { 1.149 + public: 1.150 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.151 + RecorderState aState, 1.152 + int32_t aStatus, 1.153 + int32_t aTrackNum) 1.154 + : DOMCallback(aDOMCameraControl) 1.155 + , mState(aState) 1.156 + , mStatus(aStatus) 1.157 + , mTrackNum(aTrackNum) 1.158 + { } 1.159 + 1.160 + void 1.161 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.162 + { 1.163 + aDOMCameraControl->OnRecorderStateChange(mState, mStatus, mTrackNum); 1.164 + } 1.165 + 1.166 + protected: 1.167 + RecorderState mState; 1.168 + int32_t mStatus; 1.169 + int32_t mTrackNum; 1.170 + }; 1.171 + 1.172 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState, aStatus, aTrackNum)); 1.173 +} 1.174 + 1.175 +void 1.176 +DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration) 1.177 +{ 1.178 + class Callback : public DOMCallback 1.179 + { 1.180 + public: 1.181 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.182 + const CameraListenerConfiguration& aConfiguration) 1.183 + : DOMCallback(aDOMCameraControl) 1.184 + , mConfiguration(aConfiguration) 1.185 + { } 1.186 + 1.187 + void 1.188 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.189 + { 1.190 + nsRefPtr<nsDOMCameraControl::DOMCameraConfiguration> config = 1.191 + new nsDOMCameraControl::DOMCameraConfiguration(); 1.192 + 1.193 + switch (mConfiguration.mMode) { 1.194 + case ICameraControl::kVideoMode: 1.195 + config->mMode = CameraMode::Video; 1.196 + break; 1.197 + 1.198 + case ICameraControl::kPictureMode: 1.199 + config->mMode = CameraMode::Picture; 1.200 + break; 1.201 + 1.202 + default: 1.203 + DOM_CAMERA_LOGI("Camera mode still unspecified, nothing to do\n"); 1.204 + return; 1.205 + } 1.206 + 1.207 + // Map CameraControl parameters to their DOM-facing equivalents 1.208 + config->mRecorderProfile = mConfiguration.mRecorderProfile; 1.209 + config->mPreviewSize.mWidth = mConfiguration.mPreviewSize.width; 1.210 + config->mPreviewSize.mHeight = mConfiguration.mPreviewSize.height; 1.211 + config->mMaxMeteringAreas = mConfiguration.mMaxMeteringAreas; 1.212 + config->mMaxFocusAreas = mConfiguration.mMaxFocusAreas; 1.213 + 1.214 + aDOMCameraControl->OnConfigurationChange(config); 1.215 + } 1.216 + 1.217 + protected: 1.218 + const CameraListenerConfiguration mConfiguration; 1.219 + }; 1.220 + 1.221 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aConfiguration)); 1.222 +} 1.223 + 1.224 +void 1.225 +DOMCameraControlListener::OnAutoFocusMoving(bool aIsMoving) 1.226 +{ 1.227 + class Callback : public DOMCallback 1.228 + { 1.229 + public: 1.230 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, bool aIsMoving) 1.231 + : DOMCallback(aDOMCameraControl) 1.232 + , mIsMoving(aIsMoving) 1.233 + { } 1.234 + 1.235 + void 1.236 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.237 + { 1.238 + aDOMCameraControl->OnAutoFocusMoving(mIsMoving); 1.239 + } 1.240 + 1.241 + protected: 1.242 + bool mIsMoving; 1.243 + }; 1.244 + 1.245 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aIsMoving)); 1.246 +} 1.247 + 1.248 +void 1.249 +DOMCameraControlListener::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces) 1.250 +{ 1.251 + class Callback : public DOMCallback 1.252 + { 1.253 + public: 1.254 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.255 + const nsTArray<ICameraControl::Face>& aFaces) 1.256 + : DOMCallback(aDOMCameraControl) 1.257 + , mFaces(aFaces) 1.258 + { } 1.259 + 1.260 + void 1.261 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.262 + { 1.263 + aDOMCameraControl->OnFacesDetected(mFaces); 1.264 + } 1.265 + 1.266 + protected: 1.267 + const nsTArray<ICameraControl::Face> mFaces; 1.268 + }; 1.269 + 1.270 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aFaces)); 1.271 +} 1.272 + 1.273 +void 1.274 +DOMCameraControlListener::OnShutter() 1.275 +{ 1.276 + class Callback : public DOMCallback 1.277 + { 1.278 + public: 1.279 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl) 1.280 + : DOMCallback(aDOMCameraControl) 1.281 + { } 1.282 + 1.283 + void 1.284 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.285 + { 1.286 + aDOMCameraControl->OnShutter(); 1.287 + } 1.288 + }; 1.289 + 1.290 + NS_DispatchToMainThread(new Callback(mDOMCameraControl)); 1.291 +} 1.292 + 1.293 +bool 1.294 +DOMCameraControlListener::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) 1.295 +{ 1.296 + DOM_CAMERA_LOGI("OnNewPreviewFrame: got %d x %d frame\n", aWidth, aHeight); 1.297 + 1.298 + mStream->SetCurrentFrame(gfxIntSize(aWidth, aHeight), aImage); 1.299 + return true; 1.300 +} 1.301 + 1.302 +void 1.303 +DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded) 1.304 +{ 1.305 + class Callback : public DOMCallback 1.306 + { 1.307 + public: 1.308 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.309 + bool aAutoFocusSucceeded) 1.310 + : DOMCallback(aDOMCameraControl) 1.311 + , mAutoFocusSucceeded(aAutoFocusSucceeded) 1.312 + { } 1.313 + 1.314 + void 1.315 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.316 + { 1.317 + aDOMCameraControl->OnAutoFocusComplete(mAutoFocusSucceeded); 1.318 + } 1.319 + 1.320 + protected: 1.321 + bool mAutoFocusSucceeded; 1.322 + }; 1.323 + 1.324 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aAutoFocusSucceeded)); 1.325 +} 1.326 + 1.327 +void 1.328 +DOMCameraControlListener::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) 1.329 +{ 1.330 + class Callback : public DOMCallback 1.331 + { 1.332 + public: 1.333 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.334 + uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) 1.335 + : DOMCallback(aDOMCameraControl) 1.336 + , mData(aData) 1.337 + , mLength(aLength) 1.338 + , mMimeType(aMimeType) 1.339 + { } 1.340 + 1.341 + void 1.342 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.343 + { 1.344 + nsCOMPtr<nsIDOMBlob> picture = new nsDOMMemoryFile(static_cast<void*>(mData), 1.345 + static_cast<uint64_t>(mLength), 1.346 + mMimeType); 1.347 + aDOMCameraControl->OnTakePictureComplete(picture); 1.348 + } 1.349 + 1.350 + protected: 1.351 + uint8_t* mData; 1.352 + uint32_t mLength; 1.353 + nsString mMimeType; 1.354 + }; 1.355 + 1.356 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aData, aLength, aMimeType)); 1.357 +} 1.358 + 1.359 +void 1.360 +DOMCameraControlListener::OnError(CameraErrorContext aContext, CameraError aError) 1.361 +{ 1.362 + class Callback : public DOMCallback 1.363 + { 1.364 + public: 1.365 + Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, 1.366 + CameraErrorContext aContext, 1.367 + CameraError aError) 1.368 + : DOMCallback(aDOMCameraControl) 1.369 + , mContext(aContext) 1.370 + , mError(aError) 1.371 + { } 1.372 + 1.373 + virtual void 1.374 + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE 1.375 + { 1.376 + nsString error; 1.377 + 1.378 + switch (mError) { 1.379 + case kErrorServiceFailed: 1.380 + error = NS_LITERAL_STRING("ErrorServiceFailed"); 1.381 + break; 1.382 + 1.383 + case kErrorSetPictureSizeFailed: 1.384 + error = NS_LITERAL_STRING("ErrorSetPictureSizeFailed"); 1.385 + break; 1.386 + 1.387 + case kErrorSetThumbnailSizeFailed: 1.388 + error = NS_LITERAL_STRING("ErrorSetThumbnailSizeFailed"); 1.389 + break; 1.390 + 1.391 + case kErrorApiFailed: 1.392 + // XXXmikeh legacy error placeholder 1.393 + error = NS_LITERAL_STRING("FAILURE"); 1.394 + break; 1.395 + 1.396 + default: 1.397 + error = NS_LITERAL_STRING("ErrorUnknown"); 1.398 + break; 1.399 + } 1.400 + aDOMCameraControl->OnError(mContext, error); 1.401 + } 1.402 + 1.403 + protected: 1.404 + CameraErrorContext mContext; 1.405 + CameraError mError; 1.406 + }; 1.407 + 1.408 + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aContext, aError)); 1.409 +}