diff -r 000000000000 -r 6474c204b198 dom/camera/DOMCameraControlListener.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/camera/DOMCameraControlListener.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,406 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this file, +* You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DOMCameraControlListener.h" +#include "nsThreadUtils.h" +#include "nsDOMFile.h" +#include "CameraCommon.h" +#include "DOMCameraControl.h" +#include "CameraPreviewMediaStream.h" +#include "mozilla/dom/CameraManagerBinding.h" + +using namespace mozilla; +using namespace mozilla::dom; + +DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl, + CameraPreviewMediaStream* aStream) + : mDOMCameraControl(new nsMainThreadPtrHolder(aDOMCameraControl)) + , mStream(aStream) +{ + DOM_CAMERA_LOGT("%s:%d : this=%p, camera=%p, stream=%p\n", + __func__, __LINE__, this, aDOMCameraControl, aStream); +} + +DOMCameraControlListener::~DOMCameraControlListener() +{ + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); +} + +// Boilerplate callback runnable +class DOMCameraControlListener::DOMCallback : public nsRunnable +{ +public: + DOMCallback(nsMainThreadPtrHandle aDOMCameraControl) + : mDOMCameraControl(aDOMCameraControl) + { + MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback); + } + virtual ~DOMCallback() + { + MOZ_COUNT_DTOR(DOMCameraControlListener::DOMCallback); + } + + virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0; + + NS_IMETHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + nsRefPtr camera = mDOMCameraControl.get(); + if (camera) { + RunCallback(camera); + } + return NS_OK; + } + +protected: + nsMainThreadPtrHandle mDOMCameraControl; +}; + +// Specific callback handlers +void +DOMCameraControlListener::OnHardwareStateChange(HardwareState aState) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + HardwareState aState) + : DOMCallback(aDOMCameraControl) + , mState(aState) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + aDOMCameraControl->OnHardwareStateChange(mState); + } + + protected: + HardwareState mState; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState)); +} + +void +DOMCameraControlListener::OnPreviewStateChange(PreviewState aState) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + PreviewState aState) + : DOMCallback(aDOMCameraControl) + , mState(aState) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + aDOMCameraControl->OnPreviewStateChange(mState); + } + + protected: + PreviewState mState; + }; + + switch (aState) { + case kPreviewStopped: + // Clear the current frame right away, without dispatching a + // runnable. This is an ugly coupling between the camera's + // SurfaceTextureClient and the MediaStream/ImageContainer, + // but without it, the preview can fail to start. + DOM_CAMERA_LOGI("Preview stopped, clearing current frame\n"); + mStream->ClearCurrentFrame(); + break; + + case kPreviewPaused: + // In the paused state, we still want to reflect the change + // in preview state, but we don't want to clear the current + // frame as above, since doing so seems to cause genlock + // problems when we restart the preview. See bug 957749. + DOM_CAMERA_LOGI("Preview paused\n"); + break; + + case kPreviewStarted: + DOM_CAMERA_LOGI("Preview started\n"); + break; + + default: + DOM_CAMERA_LOGE("Unknown preview state %d\n", aState); + MOZ_ASSUME_UNREACHABLE("Invalid preview state"); + return; + } + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState)); +} + +void +DOMCameraControlListener::OnRecorderStateChange(RecorderState aState, + int32_t aStatus, int32_t aTrackNum) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + RecorderState aState, + int32_t aStatus, + int32_t aTrackNum) + : DOMCallback(aDOMCameraControl) + , mState(aState) + , mStatus(aStatus) + , mTrackNum(aTrackNum) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + aDOMCameraControl->OnRecorderStateChange(mState, mStatus, mTrackNum); + } + + protected: + RecorderState mState; + int32_t mStatus; + int32_t mTrackNum; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState, aStatus, aTrackNum)); +} + +void +DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + const CameraListenerConfiguration& aConfiguration) + : DOMCallback(aDOMCameraControl) + , mConfiguration(aConfiguration) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + nsRefPtr config = + new nsDOMCameraControl::DOMCameraConfiguration(); + + switch (mConfiguration.mMode) { + case ICameraControl::kVideoMode: + config->mMode = CameraMode::Video; + break; + + case ICameraControl::kPictureMode: + config->mMode = CameraMode::Picture; + break; + + default: + DOM_CAMERA_LOGI("Camera mode still unspecified, nothing to do\n"); + return; + } + + // Map CameraControl parameters to their DOM-facing equivalents + config->mRecorderProfile = mConfiguration.mRecorderProfile; + config->mPreviewSize.mWidth = mConfiguration.mPreviewSize.width; + config->mPreviewSize.mHeight = mConfiguration.mPreviewSize.height; + config->mMaxMeteringAreas = mConfiguration.mMaxMeteringAreas; + config->mMaxFocusAreas = mConfiguration.mMaxFocusAreas; + + aDOMCameraControl->OnConfigurationChange(config); + } + + protected: + const CameraListenerConfiguration mConfiguration; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aConfiguration)); +} + +void +DOMCameraControlListener::OnAutoFocusMoving(bool aIsMoving) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, bool aIsMoving) + : DOMCallback(aDOMCameraControl) + , mIsMoving(aIsMoving) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + aDOMCameraControl->OnAutoFocusMoving(mIsMoving); + } + + protected: + bool mIsMoving; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aIsMoving)); +} + +void +DOMCameraControlListener::OnFacesDetected(const nsTArray& aFaces) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + const nsTArray& aFaces) + : DOMCallback(aDOMCameraControl) + , mFaces(aFaces) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + aDOMCameraControl->OnFacesDetected(mFaces); + } + + protected: + const nsTArray mFaces; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aFaces)); +} + +void +DOMCameraControlListener::OnShutter() +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl) + : DOMCallback(aDOMCameraControl) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + aDOMCameraControl->OnShutter(); + } + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl)); +} + +bool +DOMCameraControlListener::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) +{ + DOM_CAMERA_LOGI("OnNewPreviewFrame: got %d x %d frame\n", aWidth, aHeight); + + mStream->SetCurrentFrame(gfxIntSize(aWidth, aHeight), aImage); + return true; +} + +void +DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + bool aAutoFocusSucceeded) + : DOMCallback(aDOMCameraControl) + , mAutoFocusSucceeded(aAutoFocusSucceeded) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + aDOMCameraControl->OnAutoFocusComplete(mAutoFocusSucceeded); + } + + protected: + bool mAutoFocusSucceeded; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aAutoFocusSucceeded)); +} + +void +DOMCameraControlListener::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) + : DOMCallback(aDOMCameraControl) + , mData(aData) + , mLength(aLength) + , mMimeType(aMimeType) + { } + + void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + nsCOMPtr picture = new nsDOMMemoryFile(static_cast(mData), + static_cast(mLength), + mMimeType); + aDOMCameraControl->OnTakePictureComplete(picture); + } + + protected: + uint8_t* mData; + uint32_t mLength; + nsString mMimeType; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aData, aLength, aMimeType)); +} + +void +DOMCameraControlListener::OnError(CameraErrorContext aContext, CameraError aError) +{ + class Callback : public DOMCallback + { + public: + Callback(nsMainThreadPtrHandle aDOMCameraControl, + CameraErrorContext aContext, + CameraError aError) + : DOMCallback(aDOMCameraControl) + , mContext(aContext) + , mError(aError) + { } + + virtual void + RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE + { + nsString error; + + switch (mError) { + case kErrorServiceFailed: + error = NS_LITERAL_STRING("ErrorServiceFailed"); + break; + + case kErrorSetPictureSizeFailed: + error = NS_LITERAL_STRING("ErrorSetPictureSizeFailed"); + break; + + case kErrorSetThumbnailSizeFailed: + error = NS_LITERAL_STRING("ErrorSetThumbnailSizeFailed"); + break; + + case kErrorApiFailed: + // XXXmikeh legacy error placeholder + error = NS_LITERAL_STRING("FAILURE"); + break; + + default: + error = NS_LITERAL_STRING("ErrorUnknown"); + break; + } + aDOMCameraControl->OnError(mContext, error); + } + + protected: + CameraErrorContext mContext; + CameraError mError; + }; + + NS_DispatchToMainThread(new Callback(mDOMCameraControl, aContext, aError)); +}