tenfourfox/dom/camera/DOMCameraControlListener.cpp

437 lines
12 KiB
C++

/* 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 "CameraCommon.h"
#include "DOMCameraControl.h"
#include "CameraPreviewMediaStream.h"
#include "mozilla/dom/CameraManagerBinding.h"
#include "mozilla/dom/File.h"
#include "nsQueryObject.h"
using namespace mozilla;
using namespace mozilla::dom;
DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl,
CameraPreviewMediaStream* aStream)
: mDOMCameraControl(
new nsMainThreadPtrHolder<nsISupports>(static_cast<DOMMediaStream*>(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:
explicit DOMCallback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
: mDOMCameraControl(aDOMCameraControl)
{
MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback);
}
protected:
virtual ~DOMCallback()
{
MOZ_COUNT_DTOR(DOMCameraControlListener::DOMCallback);
}
public:
virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0;
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<nsDOMCameraControl> camera = do_QueryObject(mDOMCameraControl.get());
if (!camera) {
DOM_CAMERA_LOGE("do_QueryObject failed to get an nsDOMCameraControl\n");
return NS_ERROR_INVALID_ARG;
}
RunCallback(camera);
return NS_OK;
}
protected:
nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
};
// Specific callback handlers
void
DOMCameraControlListener::OnHardwareStateChange(HardwareState aState,
nsresult aReason)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
HardwareState aState, nsresult aReason)
: DOMCallback(aDOMCameraControl)
, mState(aState)
, mReason(aReason)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnHardwareStateChange(mState, mReason);
}
protected:
HardwareState mState;
nsresult mReason;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState, aReason));
}
void
DOMCameraControlListener::OnPreviewStateChange(PreviewState aState)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
PreviewState aState)
: DOMCallback(aDOMCameraControl)
, mState(aState)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) 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_ASSERT_UNREACHABLE("Invalid preview state");
return;
}
mStream->OnPreviewStateChange(aState == kPreviewStarted);
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState));
}
void
DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
int32_t aStatus, int32_t aTrackNum)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
RecorderState aState,
int32_t aStatus,
int32_t aTrackNum)
: DOMCallback(aDOMCameraControl)
, mState(aState)
, mStatus(aStatus)
, mTrackNum(aTrackNum)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) 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<nsISupports> aDOMCameraControl,
const CameraListenerConfiguration& aConfiguration)
: DOMCallback(aDOMCameraControl)
, mConfiguration(aConfiguration)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
RefPtr<nsDOMCameraControl::DOMCameraConfiguration> 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->mPictureSize.mWidth = mConfiguration.mPictureSize.width;
config->mPictureSize.mHeight = mConfiguration.mPictureSize.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<nsISupports> aDOMCameraControl, bool aIsMoving)
: DOMCallback(aDOMCameraControl)
, mIsMoving(aIsMoving)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnAutoFocusMoving(mIsMoving);
}
protected:
bool mIsMoving;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aIsMoving));
}
void
DOMCameraControlListener::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
const nsTArray<ICameraControl::Face>& aFaces)
: DOMCallback(aDOMCameraControl)
, mFaces(aFaces)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnFacesDetected(mFaces);
}
protected:
const nsTArray<ICameraControl::Face> mFaces;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aFaces));
}
void
DOMCameraControlListener::OnShutter()
{
class Callback : public DOMCallback
{
public:
explicit Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
: DOMCallback(aDOMCameraControl)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnShutter();
}
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl));
}
void
DOMCameraControlListener::OnRateLimitPreview(bool aLimit)
{
mStream->RateLimit(aLimit);
}
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(gfx::IntSize(aWidth, aHeight), aImage);
return true;
}
void
DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
bool aAutoFocusSucceeded)
: DOMCallback(aDOMCameraControl)
, mAutoFocusSucceeded(aAutoFocusSucceeded)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnAutoFocusComplete(mAutoFocusSucceeded);
}
protected:
bool mAutoFocusSucceeded;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aAutoFocusSucceeded));
}
void
DOMCameraControlListener::OnTakePictureComplete(const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
const uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
: DOMCallback(aDOMCameraControl)
, mLength(aLength)
, mMimeType(aMimeType)
{
mData = (uint8_t*) malloc(aLength);
memcpy(mData, aData, aLength);
}
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
nsCOMPtr<nsIDOMBlob> picture =
Blob::CreateMemoryBlob(mDOMCameraControl.get(),
static_cast<void*>(mData),
static_cast<uint64_t>(mLength),
mMimeType);
aDOMCameraControl->OnTakePictureComplete(picture);
mData = NULL;
}
protected:
virtual
~Callback()
{
free(mData);
}
uint8_t* mData;
uint32_t mLength;
nsString mMimeType;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aData, aLength, aMimeType));
}
void
DOMCameraControlListener::OnUserError(UserContext aContext, nsresult aError)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
UserContext aContext,
nsresult aError)
: DOMCallback(aDOMCameraControl)
, mContext(aContext)
, mError(aError)
{ }
virtual void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnUserError(mContext, mError);
}
protected:
UserContext mContext;
nsresult mError;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aContext, aError));
}
void
DOMCameraControlListener::OnPoster(BlobImpl* aBlobImpl)
{
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl, BlobImpl* aBlobImpl)
: DOMCallback(aDOMCameraControl)
, mBlobImpl(aBlobImpl)
{ }
void
RunCallback(nsDOMCameraControl* aDOMCameraControl) override
{
aDOMCameraControl->OnPoster(mBlobImpl);
}
protected:
RefPtr<BlobImpl> mBlobImpl;
};
NS_DispatchToMainThread(new Callback(mDOMCameraControl, aBlobImpl));
}