Bug 1104055 - fix CameraControl memory leak, r=aosmond

This commit is contained in:
Mike Habicher 2014-12-12 21:18:03 -05:00
parent b019406846
commit e402bc1164
17 changed files with 403 additions and 120 deletions

View File

@ -15,11 +15,10 @@
using namespace mozilla;
nsWeakPtr CameraControlImpl::sCameraThread;
/* static */ StaticRefPtr<nsIThread> CameraControlImpl::sCameraThread;
CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
CameraControlImpl::CameraControlImpl()
: mListenerLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"))
, mCameraId(aCameraId)
, mPreviewState(CameraControlListener::kPreviewStopped)
, mHardwareState(CameraControlListener::kHardwareClosed)
, mHardwareStateChangeReason(NS_OK)
@ -27,7 +26,7 @@ CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
// reuse the same camera thread to conserve resources
nsCOMPtr<nsIThread> ct = do_QueryReferent(sCameraThread);
nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
if (ct) {
mCameraThread = ct.forget();
} else {
@ -35,9 +34,7 @@ CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
if (NS_FAILED(rv)) {
MOZ_CRASH("Failed to create new Camera Thread");
}
// keep a weak reference to the new thread
sCameraThread = do_GetWeakReference(mCameraThread);
sCameraThread = mCameraThread;
}
// Care must be taken with the mListenerLock read-write lock to prevent
@ -58,6 +55,8 @@ CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
CameraControlImpl::~CameraControlImpl()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(mListenerLock, "mListenerLock missing in ~CameraControlImpl()");
if (mListenerLock) {
PR_DestroyRWLock(mListenerLock);
@ -65,12 +64,6 @@ CameraControlImpl::~CameraControlImpl()
}
}
void
CameraControlImpl::Shutdown()
{
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
}
void
CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState,
nsresult aReason)

View File

@ -28,7 +28,7 @@ namespace layers {
class CameraControlImpl : public ICameraControl
{
public:
explicit CameraControlImpl(uint32_t aCameraId);
explicit CameraControlImpl();
virtual void AddListener(CameraControlListener* aListener) MOZ_OVERRIDE;
virtual void RemoveListener(CameraControlListener* aListener) MOZ_OVERRIDE;
@ -47,10 +47,6 @@ public:
virtual nsresult StopRecording() MOZ_OVERRIDE;
virtual nsresult ResumeContinuousFocus() MOZ_OVERRIDE;
uint32_t GetCameraId() { return mCameraId; }
virtual void Shutdown() MOZ_OVERRIDE;
// Event handlers called directly from outside this class.
void OnShutter();
void OnUserError(CameraControlListener::UserContext aContext, nsresult aError);
@ -77,7 +73,7 @@ protected:
// don't want that reference to keep the thread object around unnecessarily,
// so we make it a weak reference. The strong dynamic references will keep
// the thread object alive as needed.
static nsWeakPtr sCameraThread;
static StaticRefPtr<nsIThread> sCameraThread;
nsCOMPtr<nsIThread> mCameraThread;
virtual ~CameraControlImpl();
@ -128,8 +124,6 @@ protected:
void OnShutterInternal();
void OnClosedInternal();
uint32_t mCameraId;
CameraControlListener::CameraListenerConfiguration mCurrentConfiguration;
CameraControlListener::PreviewState mPreviewState;

View File

@ -136,6 +136,7 @@ void
CameraPreviewMediaStream::Destroy()
{
MutexAutoLock lock(mMutex);
mMainThreadDestroyed = true;
DestroyImpl();
}

View File

@ -32,8 +32,8 @@ protected:
* This is a stream for camera preview.
*
* XXX It is a temporary fix of SourceMediaStream.
* A camera preview requests no delay and no buffering stream.
* But the SourceMediaStream do not support it.
* A camera preview requests no delay and no buffering stream,
* but the SourceMediaStream does not support it.
*/
class CameraPreviewMediaStream : public MediaStream
{
@ -50,7 +50,7 @@ public:
virtual void ChangeExplicitBlockerCount(int32_t aDelta) MOZ_OVERRIDE;
virtual void AddListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
virtual void RemoveListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
virtual void Destroy();
virtual void Destroy() MOZ_OVERRIDE;
void OnPreviewStateChange(bool aActive);
void Invalidate();

View File

@ -7,15 +7,79 @@
#include "DOMCameraCapabilities.h"
#include "nsPIDOMWindow.h"
#include "nsContentUtils.h"
#include "nsProxyRelease.h"
#include "mozilla/dom/CameraManagerBinding.h"
#include "mozilla/dom/CameraCapabilitiesBinding.h"
#include "Navigator.h"
#include "CameraCommon.h"
#include "ICameraControl.h"
#include "CameraControlListener.h"
namespace mozilla {
namespace dom {
/**
* CameraClosedListenerProxy and CameraClosedMessage
*/
template<class T>
class CameraClosedMessage : public nsRunnable
{
public:
CameraClosedMessage(nsMainThreadPtrHandle<T> aListener)
: mListener(aListener)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
NS_IMETHODIMP
Run() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<T> listener = mListener.get();
if (listener) {
listener->OnHardwareClosed();
}
return NS_OK;
}
protected:
virtual ~CameraClosedMessage()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
nsMainThreadPtrHandle<T> mListener;
};
template<class T>
class CameraClosedListenerProxy : public CameraControlListener
{
public:
CameraClosedListenerProxy(T* aListener)
: mListener(new nsMainThreadPtrHolder<T>(aListener))
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
virtual void
OnHardwareStateChange(HardwareState aState, nsresult aReason) MOZ_OVERRIDE
{
if (aState != kHardwareClosed) {
return;
}
NS_DispatchToMainThread(new CameraClosedMessage<T>(mListener));
}
protected:
virtual ~CameraClosedListenerProxy()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
nsMainThreadPtrHandle<T> mListener;
};
/**
* CameraRecorderVideoProfile
*/
@ -96,7 +160,10 @@ CameraRecorderAudioProfile::~CameraRecorderAudioProfile()
/**
* CameraRecorderProfile
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfile, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfile,
mParent,
mVideo,
mAudio)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderProfile)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderProfile)
@ -136,7 +203,9 @@ CameraRecorderProfile::~CameraRecorderProfile()
/**
* CameraRecorderProfiles
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfiles, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfiles,
mParent,
mProfiles)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderProfiles)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderProfiles)
@ -158,6 +227,10 @@ CameraRecorderProfiles::CameraRecorderProfiles(nsISupports* aParent,
, mCameraControl(aCameraControl)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (mCameraControl) {
mListener = new CameraClosedListenerProxy<CameraRecorderProfiles>(this);
mCameraControl->AddListener(mListener);
}
}
CameraRecorderProfiles::~CameraRecorderProfiles()
@ -170,6 +243,10 @@ CameraRecorderProfiles::GetSupportedNames(unsigned aFlags, nsTArray<nsString>& a
{
DOM_CAMERA_LOGT("%s:%d : this=%p, flags=0x%x\n",
__func__, __LINE__, this, aFlags);
if (!mCameraControl) {
aNames.Clear();
return;
}
nsresult rv = mCameraControl->GetRecorderProfiles(aNames);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -182,6 +259,9 @@ CameraRecorderProfiles::NamedGetter(const nsAString& aName, bool& aFound)
{
DOM_CAMERA_LOGT("%s:%d : this=%p, name='%s'\n", __func__, __LINE__, this,
NS_ConvertUTF16toUTF8(aName).get());
if (!mCameraControl) {
return nullptr;
}
CameraRecorderProfile* profile = mProfiles.GetWeak(aName, &aFound);
if (!aFound || !profile) {
@ -204,10 +284,25 @@ CameraRecorderProfiles::NameIsEnumerable(const nsAString& aName)
return true;
}
void
CameraRecorderProfiles::OnHardwareClosed()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
if (mCameraControl) {
mCameraControl->RemoveListener(mListener);
mCameraControl = nullptr;
}
mListener = nullptr;
}
/**
* CameraCapabilities
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraCapabilities, mWindow)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraCapabilities,
mWindow,
mRecorderProfiles)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraCapabilities)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraCapabilities)
@ -236,7 +331,10 @@ CameraCapabilities::CameraCapabilities(nsPIDOMWindow* aWindow,
, mCameraControl(aCameraControl)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_COUNT_CTOR(CameraCapabilities);
if (mCameraControl) {
mListener = new CameraClosedListenerProxy<CameraCapabilities>(this);
mCameraControl->AddListener(mListener);
}
}
CameraCapabilities::~CameraCapabilities()
@ -245,6 +343,19 @@ CameraCapabilities::~CameraCapabilities()
MOZ_COUNT_DTOR(CameraCapabilities);
}
void
CameraCapabilities::OnHardwareClosed()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
if (mCameraControl) {
mCameraControl->RemoveListener(mListener);
mCameraControl = nullptr;
}
mListener = nullptr;
}
JSObject*
CameraCapabilities::WrapObject(JSContext* aCx)
{
@ -262,6 +373,10 @@ CameraCapabilities::WrapObject(JSContext* aCx)
nsresult
CameraCapabilities::TranslateToDictionary(uint32_t aKey, nsTArray<CameraSize>& aSizes)
{
if (NS_WARN_IF(!mCameraControl)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv;
nsTArray<ICameraControl::Size> sizes;
@ -328,6 +443,10 @@ CameraCapabilities::GetVideoSizes(nsTArray<dom::CameraSize>& retval)
void
CameraCapabilities::GetFileFormats(nsTArray<nsString>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mFileFormats.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
mFileFormats);
@ -339,6 +458,10 @@ CameraCapabilities::GetFileFormats(nsTArray<nsString>& retval)
void
CameraCapabilities::GetWhiteBalanceModes(nsTArray<nsString>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mWhiteBalanceModes.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
mWhiteBalanceModes);
@ -350,6 +473,10 @@ CameraCapabilities::GetWhiteBalanceModes(nsTArray<nsString>& retval)
void
CameraCapabilities::GetSceneModes(nsTArray<nsString>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mSceneModes.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_SCENEMODES,
mSceneModes);
@ -361,6 +488,10 @@ CameraCapabilities::GetSceneModes(nsTArray<nsString>& retval)
void
CameraCapabilities::GetEffects(nsTArray<nsString>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mEffects.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EFFECTS,
mEffects);
@ -372,6 +503,10 @@ CameraCapabilities::GetEffects(nsTArray<nsString>& retval)
void
CameraCapabilities::GetFlashModes(nsTArray<nsString>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mFlashModes.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FLASHMODES,
mFlashModes);
@ -383,6 +518,10 @@ CameraCapabilities::GetFlashModes(nsTArray<nsString>& retval)
void
CameraCapabilities::GetFocusModes(nsTArray<nsString>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mFocusModes.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FOCUSMODES,
mFocusModes);
@ -394,6 +533,10 @@ CameraCapabilities::GetFocusModes(nsTArray<nsString>& retval)
void
CameraCapabilities::GetZoomRatios(nsTArray<double>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mZoomRatios.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS,
mZoomRatios);
@ -405,6 +548,10 @@ CameraCapabilities::GetZoomRatios(nsTArray<double>& retval)
uint32_t
CameraCapabilities::MaxFocusAreas()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0;
}
if (mMaxFocusAreas == 0) {
int32_t areas;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
@ -418,6 +565,10 @@ CameraCapabilities::MaxFocusAreas()
uint32_t
CameraCapabilities::MaxMeteringAreas()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0;
}
if (mMaxMeteringAreas == 0) {
int32_t areas;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
@ -431,6 +582,10 @@ CameraCapabilities::MaxMeteringAreas()
uint32_t
CameraCapabilities::MaxDetectedFaces()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0;
}
if (mMaxDetectedFaces == 0) {
int32_t faces;
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES,
@ -444,6 +599,10 @@ CameraCapabilities::MaxDetectedFaces()
double
CameraCapabilities::MinExposureCompensation()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0.0;
}
if (mMinExposureCompensation == 0.0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
mMinExposureCompensation);
@ -455,6 +614,10 @@ CameraCapabilities::MinExposureCompensation()
double
CameraCapabilities::MaxExposureCompensation()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0.0;
}
if (mMaxExposureCompensation == 0.0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
mMaxExposureCompensation);
@ -466,6 +629,10 @@ CameraCapabilities::MaxExposureCompensation()
double
CameraCapabilities::ExposureCompensationStep()
{
if (NS_WARN_IF(!mCameraControl)) {
return 0.0;
}
if (mExposureCompensationStep == 0.0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
mExposureCompensationStep);
@ -477,6 +644,10 @@ CameraCapabilities::ExposureCompensationStep()
CameraRecorderProfiles*
CameraCapabilities::RecorderProfiles()
{
if (NS_WARN_IF(!mCameraControl)) {
return nullptr;
}
nsRefPtr<CameraRecorderProfiles> profiles = mRecorderProfiles;
if (!mRecorderProfiles) {
profiles = new CameraRecorderProfiles(this, mCameraControl);
@ -488,6 +659,10 @@ CameraCapabilities::RecorderProfiles()
void
CameraCapabilities::GetIsoModes(nsTArray<nsString>& retval)
{
if (NS_WARN_IF(!mCameraControl)) {
return;
}
if (mIsoModes.Length() == 0) {
nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ISOMODES,
mIsoModes);

View File

@ -146,6 +146,8 @@ private:
/**
* CameraRecorderProfiles
*/
template<class T> class CameraClosedListenerProxy;
class CameraRecorderProfiles MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
@ -162,12 +164,15 @@ public:
bool NameIsEnumerable(const nsAString& aName);
void GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames);
virtual void OnHardwareClosed();
protected:
virtual ~CameraRecorderProfiles();
nsCOMPtr<nsISupports> mParent;
nsRefPtr<ICameraControl> mCameraControl;
nsRefPtrHashtable<nsStringHashKey, CameraRecorderProfile> mProfiles;
nsRefPtr<CameraClosedListenerProxy<CameraRecorderProfiles>> mListener;
private:
DISALLOW_EVIL_CONSTRUCTORS(CameraRecorderProfiles);
@ -218,6 +223,8 @@ public:
CameraRecorderProfiles* RecorderProfiles();
virtual void OnHardwareClosed();
protected:
~CameraCapabilities();
@ -249,6 +256,7 @@ protected:
nsRefPtr<nsPIDOMWindow> mWindow;
nsRefPtr<ICameraControl> mCameraControl;
nsRefPtr<CameraRecorderProfiles> mRecorderProfiles;
nsRefPtr<CameraClosedListenerProxy<CameraCapabilities>> mListener;
private:
DISALLOW_EVIL_CONSTRUCTORS(CameraCapabilities);

View File

@ -54,13 +54,19 @@ StaticRefPtr<ICameraControl> nsDOMCameraControl::sCachedCameraControl;
#endif
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
// nsISupports is an ambiguous base of nsDOMCameraControl
// so we have to work around that.
if ( aIID.Equals(NS_GET_IID(nsDOMCameraControl)) )
foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
else
NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream)
NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream)
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream,
mAudioChannelAgent,
mCapabilities,
mWindow,
mGetCameraPromise,
@ -133,7 +139,7 @@ nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration()
}
#ifdef MOZ_WIDGET_GONK
// This shoudl be long enough for even our slowest platforms.
// This should be long enough for even our slowest platforms.
static const unsigned long kCachedCameraTimeoutMs = 3500;
// Open the battery-door-facing camera by default.
@ -383,88 +389,97 @@ nsDOMCameraControl::Get(uint32_t aKey, nsTArray<CameraRegion>& aValue)
return NS_OK;
}
#define THROW_IF_NO_CAMERACONTROL(...) \
do { \
if (!mCameraControl) { \
DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__); \
aRv = NS_ERROR_NOT_AVAILABLE; \
return __VA_ARGS__; \
} \
} while (0)
void
nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
}
void
nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
}
void
nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
}
void
nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
}
void
nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
}
void
nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
}
void
nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
}
void
nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
}
void
nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
}
void
nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
}
void
nsDOMCameraControl::GetIsoMode(nsString& aIsoMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Get(CAMERA_PARAM_ISOMODE, aIsoMode);
}
void
nsDOMCameraControl::SetIsoMode(const nsAString& aIsoMode, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_ISOMODE, aIsoMode);
}
double
nsDOMCameraControl::GetPictureQuality(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL(1.0);
double quality;
aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_QUALITY, quality);
@ -473,14 +488,14 @@ nsDOMCameraControl::GetPictureQuality(ErrorResult& aRv)
void
nsDOMCameraControl::SetPictureQuality(double aQuality, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_QUALITY, aQuality);
}
double
nsDOMCameraControl::GetZoom(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL(1.0);
double zoom = 1.0;
aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, zoom);
@ -490,7 +505,7 @@ nsDOMCameraControl::GetZoom(ErrorResult& aRv)
void
nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
}
@ -521,6 +536,8 @@ nsDOMCameraControl::SetFocusAreas(const Optional<Sequence<CameraRegion> >& aFocu
void
nsDOMCameraControl::GetPictureSize(CameraSize& aSize, ErrorResult& aRv)
{
THROW_IF_NO_CAMERACONTROL();
ICameraControl::Size size;
aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size);
if (aRv.Failed()) {
@ -534,6 +551,7 @@ nsDOMCameraControl::GetPictureSize(CameraSize& aSize, ErrorResult& aRv)
void
nsDOMCameraControl::SetPictureSize(const CameraSize& aSize, ErrorResult& aRv)
{
THROW_IF_NO_CAMERACONTROL();
ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
}
@ -541,6 +559,7 @@ nsDOMCameraControl::SetPictureSize(const CameraSize& aSize, ErrorResult& aRv)
void
nsDOMCameraControl::GetThumbnailSize(CameraSize& aSize, ErrorResult& aRv)
{
THROW_IF_NO_CAMERACONTROL();
ICameraControl::Size size;
aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size);
if (aRv.Failed()) {
@ -554,6 +573,7 @@ nsDOMCameraControl::GetThumbnailSize(CameraSize& aSize, ErrorResult& aRv)
void
nsDOMCameraControl::SetThumbnailSize(const CameraSize& aSize, ErrorResult& aRv)
{
THROW_IF_NO_CAMERACONTROL();
ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s);
}
@ -561,7 +581,7 @@ nsDOMCameraControl::SetThumbnailSize(const CameraSize& aSize, ErrorResult& aRv)
double
nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL(0.0);
double focalLength;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, focalLength);
@ -571,7 +591,7 @@ nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
double
nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL(0.0);
double distance;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, distance);
@ -581,7 +601,7 @@ nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv)
double
nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL(0.0);
double distance;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, distance);
@ -591,7 +611,7 @@ nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv)
double
nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL(0.0);
double distance;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, distance);
@ -601,14 +621,14 @@ nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv)
void
nsDOMCameraControl::SetExposureCompensation(double aCompensation, ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation);
}
double
nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
THROW_IF_NO_CAMERACONTROL(0.0);
double compensation;
aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
@ -618,18 +638,22 @@ nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
int32_t
nsDOMCameraControl::SensorAngle()
{
MOZ_ASSERT(mCameraControl);
int32_t angle = 0;
mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
if (mCameraControl) {
mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
}
return angle;
}
already_AddRefed<dom::CameraCapabilities>
nsDOMCameraControl::Capabilities()
{
nsRefPtr<CameraCapabilities> caps = mCapabilities;
if (!mCameraControl) {
DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
return nullptr;
}
nsRefPtr<CameraCapabilities> caps = mCapabilities;
if (!caps) {
caps = new CameraCapabilities(mWindow, mCameraControl);
mCapabilities = caps;
@ -645,7 +669,7 @@ nsDOMCameraControl::StartRecording(const CameraStartRecordingOptions& aOptions,
const nsAString& aFilename,
ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
nsRefPtr<Promise> promise = CreatePromise(aRv);
if (aRv.Failed()) {
@ -694,7 +718,9 @@ nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
{
nsresult rv = NS_ERROR_FAILURE;
if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
if (!mCameraControl) {
rv = NS_ERROR_NOT_AVAILABLE;
} else if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
ICameraControl::StartRecordingOptions o;
o.rotation = mOptions.mRotation;
@ -722,7 +748,8 @@ nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
void
nsDOMCameraControl::StopRecording(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL();
#ifdef MOZ_B2G
if (mAudioChannelAgent) {
@ -737,7 +764,8 @@ nsDOMCameraControl::StopRecording(ErrorResult& aRv)
void
nsDOMCameraControl::ResumePreview(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->StartPreview();
}
@ -745,7 +773,8 @@ already_AddRefed<Promise>
nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL(nullptr);
nsRefPtr<Promise> promise = CreatePromise(aRv);
if (aRv.Failed()) {
@ -779,7 +808,8 @@ nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
already_AddRefed<Promise>
nsDOMCameraControl::AutoFocus(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL(nullptr);
nsRefPtr<Promise> promise = mAutoFocusPromise.forget();
if (promise) {
@ -807,14 +837,16 @@ nsDOMCameraControl::AutoFocus(ErrorResult& aRv)
void
nsDOMCameraControl::StartFaceDetection(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->StartFaceDetection();
}
void
nsDOMCameraControl::StopFaceDetection(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->StopFaceDetection();
}
@ -822,7 +854,8 @@ already_AddRefed<Promise>
nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions,
ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL(nullptr);
nsRefPtr<Promise> promise = CreatePromise(aRv);
if (aRv.Failed()) {
@ -871,34 +904,45 @@ nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions,
already_AddRefed<Promise>
nsDOMCameraControl::ReleaseHardware(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
nsRefPtr<Promise> promise = CreatePromise(aRv);
if (aRv.Failed()) {
return nullptr;
}
if (!mCameraControl) {
// Always succeed if the camera instance is already closed.
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
aRv = mCameraControl->Stop();
if (aRv.Failed()) {
return nullptr;
}
// Once we stop the camera, there's nothing we can do with it,
// so we can throw away this reference. (This won't prevent us
// from receiving the last underlying events.)
mCameraControl = nullptr;
mReleasePromise = promise;
return promise.forget();
}
void
nsDOMCameraControl::ResumeContinuousFocus(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
THROW_IF_NO_CAMERACONTROL();
aRv = mCameraControl->ResumeContinuousFocus();
}
void
nsDOMCameraControl::Shutdown()
{
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
MOZ_ASSERT(mCameraControl);
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
// Remove any pending solicited event handlers; these
// reference our window object, which in turn references
@ -910,7 +954,10 @@ nsDOMCameraControl::Shutdown()
AbortPromise(mReleasePromise);
AbortPromise(mSetConfigurationPromise);
mCameraControl->Shutdown();
if (mCameraControl) {
mCameraControl->Stop();
mCameraControl = nullptr;
}
}
nsresult
@ -986,7 +1033,9 @@ void
nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState,
nsresult aReason)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
ErrorResult ignored;
switch (aState) {
@ -1058,15 +1107,15 @@ nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState a
void
nsDOMCameraControl::OnShutter()
{
MOZ_ASSERT(NS_IsMainThread());
DOM_CAMERA_LOGI("DOM ** SNAP **\n");
MOZ_ASSERT(NS_IsMainThread());
DispatchTrustedEvent(NS_LITERAL_STRING("shutter"));
}
void
nsDOMCameraControl::OnPreviewStateChange(CameraControlListener::PreviewState aState)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
mPreviewState = aState;
@ -1089,6 +1138,7 @@ nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState a
int32_t aArg, int32_t aTrackNum)
{
// For now, we do nothing with 'aStatus' and 'aTrackNum'.
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
ErrorResult ignored;
@ -1148,6 +1198,7 @@ nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState a
void
nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aConfiguration != nullptr);
@ -1174,7 +1225,7 @@ nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration
CameraConfigurationEventInit eventInit;
eventInit.mMode = mCurrentConfiguration->mMode;
eventInit.mRecorderProfile = mCurrentConfiguration->mRecorderProfile;
eventInit.mPreviewSize = new DOMRect(this, 0, 0,
eventInit.mPreviewSize = new DOMRect(static_cast<DOMMediaStream*>(this), 0, 0,
mCurrentConfiguration->mPreviewSize.mWidth,
mCurrentConfiguration->mPreviewSize.mHeight);
@ -1189,6 +1240,7 @@ nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration
void
nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<Promise> promise = mAutoFocusPromise.forget();
@ -1206,6 +1258,7 @@ nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
void
nsDOMCameraControl::OnAutoFocusMoving(bool aIsMoving)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
if (aIsMoving) {
@ -1225,7 +1278,7 @@ nsDOMCameraControl::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces
if (faces.SetCapacity(len)) {
nsRefPtr<DOMCameraDetectedFace> f;
for (uint32_t i = 0; i < len; ++i) {
f = new DOMCameraDetectedFace(this, aFaces[i]);
f = new DOMCameraDetectedFace(static_cast<DOMMediaStream*>(this), aFaces[i]);
*faces.AppendElement() = f.forget().take();
}
}
@ -1244,6 +1297,7 @@ nsDOMCameraControl::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces
void
nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPicture);
@ -1267,7 +1321,8 @@ nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
void
nsDOMCameraControl::OnUserError(CameraControlListener::UserContext aContext, nsresult aError)
{
DOM_CAMERA_LOGI("DOM OnUserError aContext=%u, aError=0x%x\n", aContext, aError);
DOM_CAMERA_LOGI("DOM OnUserError : this=%paContext=%u, aError=0x%x\n",
this, aContext, aError);
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<Promise> promise;

View File

@ -18,6 +18,7 @@
#include "nsHashPropertyBag.h"
#include "DeviceStorage.h"
#include "DOMCameraControlListener.h"
#include "nsWeakReference.h"
#ifdef MOZ_WIDGET_GONK
#include "nsITimer.h"
#endif
@ -39,10 +40,17 @@ namespace dom {
class ErrorResult;
class StartRecordingHelper;
#define NS_DOM_CAMERA_CONTROL_CID \
{ 0x3700c096, 0xf920, 0x438d, \
{ 0x8b, 0x3f, 0x15, 0xb3, 0xc9, 0x96, 0x23, 0x62 } }
// Main camera control.
class nsDOMCameraControl MOZ_FINAL : public DOMMediaStream
, public nsSupportsWeakReference
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_CAMERA_CONTROL_CID)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMCameraControl, DOMMediaStream)
NS_DECL_ISUPPORTS_INHERITED
@ -115,6 +123,8 @@ public:
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
operator nsISupports*() { return static_cast<DOMMediaStream*>(this); }
#ifdef MOZ_WIDGET_GONK
static void PreinitCameraHardware();
static void DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure);
@ -222,6 +232,8 @@ private:
nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMCameraControl, NS_DOM_CAMERA_CONTROL_CID)
} // namespace mozilla
#endif // DOM_CAMERA_DOMCAMERACONTROL_H

View File

@ -15,7 +15,8 @@ using namespace mozilla::dom;
DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl,
CameraPreviewMediaStream* aStream)
: mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(aDOMCameraControl))
: mDOMCameraControl(
new nsMainThreadPtrHolder<nsISupports>(static_cast<DOMMediaStream*>(aDOMCameraControl)))
, mStream(aStream)
{
DOM_CAMERA_LOGT("%s:%d : this=%p, camera=%p, stream=%p\n",
@ -31,7 +32,7 @@ DOMCameraControlListener::~DOMCameraControlListener()
class DOMCameraControlListener::DOMCallback : public nsRunnable
{
public:
explicit DOMCallback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
explicit DOMCallback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
: mDOMCameraControl(aDOMCameraControl)
{
MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback);
@ -51,15 +52,17 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<nsDOMCameraControl> camera = mDOMCameraControl.get();
if (camera) {
RunCallback(camera);
nsRefPtr<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<nsDOMCameraControl> mDOMCameraControl;
nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
};
// Specific callback handlers
@ -70,7 +73,7 @@ DOMCameraControlListener::OnHardwareStateChange(HardwareState aState,
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
HardwareState aState, nsresult aReason)
: DOMCallback(aDOMCameraControl)
, mState(aState)
@ -97,7 +100,7 @@ DOMCameraControlListener::OnPreviewStateChange(PreviewState aState)
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
PreviewState aState)
: DOMCallback(aDOMCameraControl)
, mState(aState)
@ -151,7 +154,7 @@ DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
RecorderState aState,
int32_t aStatus,
int32_t aTrackNum)
@ -182,7 +185,7 @@ DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguratio
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
const CameraListenerConfiguration& aConfiguration)
: DOMCallback(aDOMCameraControl)
, mConfiguration(aConfiguration)
@ -231,7 +234,7 @@ DOMCameraControlListener::OnAutoFocusMoving(bool aIsMoving)
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, bool aIsMoving)
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl, bool aIsMoving)
: DOMCallback(aDOMCameraControl)
, mIsMoving(aIsMoving)
{ }
@ -255,7 +258,7 @@ DOMCameraControlListener::OnFacesDetected(const nsTArray<ICameraControl::Face>&
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
const nsTArray<ICameraControl::Face>& aFaces)
: DOMCallback(aDOMCameraControl)
, mFaces(aFaces)
@ -280,7 +283,7 @@ DOMCameraControlListener::OnShutter()
class Callback : public DOMCallback
{
public:
explicit Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
explicit Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
: DOMCallback(aDOMCameraControl)
{ }
@ -315,7 +318,7 @@ DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded)
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
bool aAutoFocusSucceeded)
: DOMCallback(aDOMCameraControl)
, mAutoFocusSucceeded(aAutoFocusSucceeded)
@ -340,7 +343,7 @@ DOMCameraControlListener::OnTakePictureComplete(uint8_t* aData, uint32_t aLength
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
: DOMCallback(aDOMCameraControl)
, mData(aData)
@ -352,7 +355,7 @@ DOMCameraControlListener::OnTakePictureComplete(uint8_t* aData, uint32_t aLength
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
{
nsCOMPtr<nsIDOMBlob> picture =
File::CreateMemoryFile(mDOMCameraControl,
File::CreateMemoryFile(mDOMCameraControl.get(),
static_cast<void*>(mData),
static_cast<uint64_t>(mLength),
mMimeType);
@ -374,7 +377,7 @@ DOMCameraControlListener::OnUserError(UserContext aContext, nsresult aError)
class Callback : public DOMCallback
{
public:
Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
UserContext aContext,
nsresult aError)
: DOMCallback(aDOMCameraControl)

View File

@ -35,7 +35,7 @@ public:
protected:
virtual ~DOMCameraControlListener();
nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
CameraPreviewMediaStream* mStream;
class DOMCallback;

View File

@ -342,13 +342,27 @@ nsDOMCameraManager::Register(nsDOMCameraControl* aDOMCameraControl)
DOM_CAMERA_LOGI(">>> Register( aDOMCameraControl = %p ) mWindowId = 0x%" PRIx64 "\n", aDOMCameraControl, mWindowId);
MOZ_ASSERT(NS_IsMainThread());
// Put the camera control into the hash table
CameraControls* controls = sActiveWindows->Get(mWindowId);
if (!controls) {
controls = new CameraControls;
controls = new CameraControls();
sActiveWindows->Put(mWindowId, controls);
}
controls->AppendElement(aDOMCameraControl);
// Remove any stale CameraControl objects to limit our memory usage
uint32_t i = controls->Length();
while (i > 0) {
--i;
nsRefPtr<nsDOMCameraControl> cameraControl =
do_QueryObject(controls->ElementAt(i));
if (!cameraControl) {
controls->RemoveElementAt(i);
}
}
// Put the camera control into the hash table
nsWeakPtr cameraControl =
do_GetWeakReference(static_cast<DOMMediaStream*>(aDOMCameraControl));
controls->AppendElement(cameraControl);
}
void
@ -362,10 +376,14 @@ nsDOMCameraManager::Shutdown(uint64_t aWindowId)
return;
}
uint32_t length = controls->Length();
for (uint32_t i = 0; i < length; i++) {
nsRefPtr<nsDOMCameraControl> cameraControl = controls->ElementAt(i);
cameraControl->Shutdown();
uint32_t i = controls->Length();
while (i > 0) {
--i;
nsRefPtr<nsDOMCameraControl> cameraControl =
do_QueryObject(controls->ElementAt(i));
if (cameraControl) {
cameraControl->Shutdown();
}
}
controls->Clear();

View File

@ -29,7 +29,7 @@ namespace mozilla {
}
}
typedef nsTArray<nsRefPtr<mozilla::nsDOMCameraControl> > CameraControls;
typedef nsTArray<nsWeakPtr> CameraControls;
typedef nsClassHashtable<nsUint64HashKey, CameraControls> WindowTable;
class nsDOMCameraManager MOZ_FINAL

View File

@ -22,7 +22,7 @@ namespace mozilla {
class FallbackCameraControl : public CameraControlImpl
{
public:
explicit FallbackCameraControl(uint32_t aCameraId) : CameraControlImpl(aCameraId) { }
explicit FallbackCameraControl() : CameraControlImpl() { }
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }

View File

@ -61,7 +61,7 @@ using namespace android;
// Construct nsGonkCameraControl on the main thread.
nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
: CameraControlImpl(aCameraId)
: mCameraId(aCameraId)
, mLastPictureSize({0, 0})
, mLastThumbnailSize({0, 0})
, mPreviewFps(30)

View File

@ -154,6 +154,8 @@ protected:
int32_t RationalizeRotation(int32_t aRotation);
uint32_t mCameraId;
android::sp<android::GonkCameraHardware> mCameraHw;
Size mLastPictureSize;

View File

@ -251,7 +251,7 @@ public:
virtual nsresult StopPreview() = 0;
virtual nsresult AutoFocus() = 0;
virtual nsresult TakePicture() = 0;
virtual nsresult StartRecording(DeviceStorageFileDescriptor *aFileDescriptor,
virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions = nullptr) = 0;
virtual nsresult StopRecording() = 0;
virtual nsresult StartFaceDetection() = 0;
@ -293,10 +293,6 @@ public:
virtual nsresult GetRecorderProfiles(nsTArray<nsString>& aProfiles) = 0;
virtual RecorderProfile* GetProfileInfo(const nsAString& aProfile) = 0;
virtual uint32_t GetCameraId() = 0;
virtual void Shutdown() = 0;
protected:
virtual ~ICameraControl() { }

View File

@ -12,6 +12,8 @@
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
const Cr = Components.results;
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
@ -55,15 +57,25 @@ var tests = [
{
key: "set-picture-size-after-release",
func: function testSetPictureSize(camera) {
camera.setPictureSize({ width: 0, height: 0 });
next();
try {
camera.setPictureSize({ width: 0, height: 0 });
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setPictureSize() failed with: " + e.name);
next();
}
}
},
{
key: "set-thumbnail-size-after-release",
func: function testSetThumbnailSize(camera) {
camera.setThumbnailSize({ width: 0, height: 0 });
next();
try {
camera.setThumbnailSize({ width: 0, height: 0 });
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setThumbnailSize() failed with: " + e.name);
next();
}
}
},
{
@ -76,8 +88,13 @@ var tests = [
{
key: "resume-preview-after-release",
func: function testResumePreview(camera) {
camera.resumePreview();
next();
try {
camera.resumePreview();
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"resumePreview() failed with: " + e.name);
next();
}
}
},
{
@ -87,7 +104,8 @@ var tests = [
ok(false, "autoFocus() succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_NOT_INITIALIZED", "autoFocus() failed with: " + error);
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"autoFocus() failed with: " + error.name);
next();
}
camera.autoFocus().then(onSuccess, onError);
@ -100,7 +118,8 @@ var tests = [
ok(false, "takePicture() succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_NOT_INITIALIZED", "takePicture() failed with: " + error);
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
next();
}
camera.takePicture(null).then(onSuccess, onError);
@ -113,7 +132,8 @@ var tests = [
ok(false, "startRecording() process succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_FAILURE", "startRecording() failed with: " + error);
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"startRecording() failed with: " + error.name);
next();
}
var recordingOptions = {
@ -128,8 +148,13 @@ var tests = [
{
key: "stop-recording-after-release",
func: function testStopRecording(camera) {
camera.stopRecording();
next();
try {
camera.stopRecording();
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"stopRecording() failed with: " + e.name);
next();
}
}
},
{
@ -139,7 +164,8 @@ var tests = [
ok(false, "setConfiguration() process succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_NOT_INITIALIZED", "setConfiguration() failed with: " + error);
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"setConfiguration() failed with: " + error.name);
next();
}
camera.setConfiguration(config).then(onSuccess, onError);