merge b2g-inbound to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2014-02-20 12:54:27 +01:00
commit edbdb02e8e
39 changed files with 995 additions and 244 deletions

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

View File

@ -1,4 +1,4 @@
{
"revision": "b9f86acc02f79d37ad0e10e9ee3b9cc75f870126",
"revision": "973662e5df416f77550a9cdbc7ec597c623489c3",
"repo_path": "/integration/gaia-central"
}

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -10,7 +10,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e71ab4da1b08586ea0c758edb7aa199ee34cd2f"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bb2e2f3d03f258c84d633b7767bc95d9546d39fe"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -154,12 +154,16 @@ public:
return false;
}
#ifndef MOZ_B2G_CAMERA
NS_DECL_THREADSAFE_ISUPPORTS
#ifdef MOZ_B2G_CAMERA
#else
// We are subclassed from CameraControlListener, which implements a
// threadsafe reference-count for us.
NS_DECL_ISUPPORTS_INHERITED
void OnHardwareStateChange(HardwareState aState);
void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration);
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
void OnError(CameraErrorContext aContext, const nsACString& aError);
void OnError(CameraErrorContext aContext, CameraError aError);
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
void AllocImpl();

View File

@ -25,7 +25,13 @@ extern PRLogModuleInfo* GetMediaManagerLog();
/**
* Webrtc video source.
*/
#ifndef MOZ_B2G_CAMERA
NS_IMPL_ISUPPORTS1(MediaEngineWebRTCVideoSource, nsIRunnable)
#else
NS_IMPL_QUERY_INTERFACE1(MediaEngineWebRTCVideoSource, nsIRunnable)
NS_IMPL_ADDREF_INHERITED(MediaEngineWebRTCVideoSource, CameraControlListener)
NS_IMPL_RELEASE_INHERITED(MediaEngineWebRTCVideoSource, CameraControlListener)
#endif
// ViEExternalRenderer Callback.
#ifndef MOZ_B2G_CAMERA
@ -494,15 +500,21 @@ void
MediaEngineWebRTCVideoSource::AllocImpl() {
MOZ_ASSERT(NS_IsMainThread());
mCameraControl = ICameraControl::Create(mCaptureIndex, nullptr);
mCameraControl->AddListener(this);
mCameraControl = ICameraControl::Create(mCaptureIndex);
if (mCameraControl) {
mState = kAllocated;
// Add this as a listener for CameraControl events. We don't need
// to explicitly remove this--destroying the CameraControl object
// in DeallocImpl() will do that for us.
mCameraControl->AddListener(this);
}
mCallbackMonitor.Notify();
}
void
MediaEngineWebRTCVideoSource::DeallocImpl() {
MOZ_ASSERT(NS_IsMainThread());
mCameraControl->ReleaseHardware();
mCameraControl = nullptr;
}
@ -514,7 +526,7 @@ MediaEngineWebRTCVideoSource::StartImpl(webrtc::CaptureCapability aCapability) {
config.mMode = ICameraControl::kPictureMode;
config.mPreviewSize.width = aCapability.width;
config.mPreviewSize.height = aCapability.height;
mCameraControl->SetConfiguration(config);
mCameraControl->Start(&config);
mCameraControl->Set(CAMERA_PARAM_PICTURESIZE, config.mPreviewSize);
}
@ -522,7 +534,7 @@ void
MediaEngineWebRTCVideoSource::StopImpl() {
MOZ_ASSERT(NS_IsMainThread());
mCameraControl->StopPreview();
mCameraControl->Stop();
}
void
@ -535,25 +547,23 @@ void
MediaEngineWebRTCVideoSource::OnHardwareStateChange(HardwareState aState)
{
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
if (aState == CameraControlListener::kHardwareOpen) {
mState = kAllocated;
if (aState == CameraControlListener::kHardwareClosed) {
// When the first CameraControl listener is added, it gets pushed
// the current state of the camera--normally 'closed'. We only
// pay attention to that state if we've progressed out of the
// allocated state.
if (mState != kAllocated) {
mState = kReleased;
mCallbackMonitor.Notify();
}
} else {
mState = kReleased;
mCameraControl->RemoveListener(this);
mState = kStarted;
mCallbackMonitor.Notify();
}
mCallbackMonitor.Notify();
}
void
MediaEngineWebRTCVideoSource::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration)
{
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
mState = kStarted;
mCallbackMonitor.Notify();
}
void
MediaEngineWebRTCVideoSource::OnError(CameraErrorContext aContext, const nsACString& aError)
MediaEngineWebRTCVideoSource::OnError(CameraErrorContext aContext, CameraError aError)
{
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
mCallbackMonitor.Notify();

View File

@ -41,7 +41,7 @@ function runTest() {
iframe.src = browserElementTestHelpers.emptyPage1;
}
addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
addEventListener('testready', runTest);
</script>

View File

@ -42,7 +42,7 @@ function runTest() {
iframe.src = browserElementTestHelpers.emptyPage1;
}
addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
addEventListener('testready', runTest);
</script>

View File

@ -235,12 +235,33 @@ CameraControlImpl::OnError(CameraControlListener::CameraErrorContext aContext,
RwLockAutoEnterRead lock(mListenerLock);
#ifdef PR_LOGGING
const char* error[] = { "camera-service-failed", "unknown" };
if (static_cast<unsigned int>(aError) < sizeof(error) / sizeof(error[0])) {
DOM_CAMERA_LOGW("CameraControlImpl::OnError : aContext=%u, msg='%s'\n",
aContext, error[aError]);
const char* error[] = {
"api-failed",
"init-failed",
"invalid-configuration",
"service-failed",
"set-picture-size-failred",
"set-thumbnail-size-failed",
"unknown"
};
const char* context[] = {
"StartCamera",
"StopCamera",
"AutoFocus",
"TakePicture",
"StartRecording",
"StopRecording",
"SetConfiguration",
"StartPreview",
"StopPreview",
"Unspecified"
};
if (static_cast<unsigned int>(aError) < sizeof(error) / sizeof(error[0]) &&
static_cast<unsigned int>(aContext) < sizeof(context) / sizeof(context[0])) {
DOM_CAMERA_LOGW("CameraControlImpl::OnError : aContext='%s' (%u), aError='%s' (%u)\n",
context[aContext], aContext, error[aError], aError);
} else {
DOM_CAMERA_LOGE("CameraControlImpl::OnError : aContext=%u, unknown error=%d\n",
DOM_CAMERA_LOGE("CameraControlImpl::OnError : aContext=%u, aError=%d\n",
aContext, aError);
}
#endif
@ -293,6 +314,42 @@ protected:
CameraControlListener::CameraErrorContext mContext;
};
nsresult
CameraControlImpl::Start(const Configuration* aConfig)
{
class Message : public ControlMessage
{
public:
Message(CameraControlImpl* aCameraControl,
CameraControlListener::CameraErrorContext aContext,
const Configuration* aConfig)
: ControlMessage(aCameraControl, aContext)
, mHaveInitialConfig(false)
{
if (aConfig) {
mConfig = *aConfig;
mHaveInitialConfig = true;
}
}
nsresult
RunImpl() MOZ_OVERRIDE
{
if (mHaveInitialConfig) {
return mCameraControl->StartImpl(&mConfig);
}
return mCameraControl->StartImpl();
}
protected:
bool mHaveInitialConfig;
Configuration mConfig;
};
return mCameraThread->Dispatch(
new Message(this, CameraControlListener::kInStartCamera, aConfig), NS_DISPATCH_NORMAL);
}
nsresult
CameraControlImpl::SetConfiguration(const Configuration& aConfig)
{
@ -475,7 +532,7 @@ CameraControlImpl::StopPreview()
}
nsresult
CameraControlImpl::ReleaseHardware()
CameraControlImpl::Stop()
{
class Message : public ControlMessage
{
@ -488,12 +545,12 @@ CameraControlImpl::ReleaseHardware()
nsresult
RunImpl() MOZ_OVERRIDE
{
return mCameraControl->ReleaseHardwareImpl();
return mCameraControl->StopImpl();
}
};
return mCameraThread->Dispatch(
new Message(this, CameraControlListener::kInReleaseHardware), NS_DISPATCH_NORMAL);
new Message(this, CameraControlListener::kInStopCamera), NS_DISPATCH_NORMAL);
}
class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage
@ -515,6 +572,7 @@ CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aList
RwLockAutoEnterWrite lock(mListenerLock);
CameraControlListener* l = *mListeners.AppendElement() = aListener;
DOM_CAMERA_LOGI("Added camera control listener %p\n", l);
// Update the newly-added listener's state
l->OnConfigurationChange(mCurrentConfiguration);
@ -551,6 +609,7 @@ CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener)
nsRefPtr<CameraControlListener> l(aListener);
mListeners.RemoveElement(l);
DOM_CAMERA_LOGI("Removed camera control listener %p\n", l.get());
// XXXmikeh - do we want to notify the listener that it has been removed?
}

View File

@ -36,6 +36,9 @@ public:
virtual void AddListener(CameraControlListener* aListener) MOZ_OVERRIDE;
virtual void RemoveListener(CameraControlListener* aListener) MOZ_OVERRIDE;
virtual nsresult Start(const Configuration* aConfig = nullptr) MOZ_OVERRIDE;
virtual nsresult Stop() MOZ_OVERRIDE;
virtual nsresult SetConfiguration(const Configuration& aConfig) MOZ_OVERRIDE;
virtual nsresult StartPreview() MOZ_OVERRIDE;
virtual nsresult StopPreview() MOZ_OVERRIDE;
@ -44,7 +47,6 @@ public:
virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
const StartRecordingOptions* aOptions) MOZ_OVERRIDE;
virtual nsresult StopRecording() MOZ_OVERRIDE;
virtual nsresult ReleaseHardware() MOZ_OVERRIDE;
already_AddRefed<RecorderProfileManager> GetRecorderProfileManager();
uint32_t GetCameraId() { return mCameraId; }
@ -63,7 +65,7 @@ protected:
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
void OnRecorderStateChange(CameraControlListener::RecorderState aState,
int32_t aStatus, int32_t aTrackNumber);
int32_t aStatus = -1, int32_t aTrackNumber = -1);
void OnPreviewStateChange(CameraControlListener::PreviewState aState);
void OnHardwareStateChange(CameraControlListener::HardwareState aState);
void OnConfigurationChange();
@ -90,6 +92,8 @@ protected:
class ControlMessage;
class ListenerMessage;
virtual nsresult StartImpl(const Configuration* aConfig = nullptr) = 0;
virtual nsresult StopImpl() = 0;
virtual nsresult SetConfigurationImpl(const Configuration& aConfig) = 0;
virtual nsresult StartPreviewImpl() = 0;
virtual nsresult StopPreviewImpl() = 0;
@ -100,7 +104,6 @@ protected:
virtual nsresult StopRecordingImpl() = 0;
virtual nsresult PushParametersImpl() = 0;
virtual nsresult PullParametersImpl() = 0;
virtual nsresult ReleaseHardwareImpl() = 0;
virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() = 0;
void OnShutterInternal();

View File

@ -17,7 +17,15 @@ namespace layers {
class CameraControlListener
{
public:
virtual ~CameraControlListener() { }
CameraControlListener()
{
MOZ_COUNT_CTOR(CameraControlListener);
}
virtual ~CameraControlListener()
{
MOZ_COUNT_DTOR(CameraControlListener);
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CameraControlListener);
@ -71,13 +79,13 @@ public:
enum CameraErrorContext
{
kInGetCamera,
kInStartCamera,
kInStopCamera,
kInAutoFocus,
kInTakePicture,
kInStartRecording,
kInStopRecording,
kInSetConfiguration,
kInReleaseHardware,
kInStartPreview,
kInStopPreview,
kInUnspecified

View File

@ -201,7 +201,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
config.mRecorderProfile = aInitialConfig.mRecorderProfile;
mCameraControl = ICameraControl::Create(aCameraId, &config);
mCameraControl = ICameraControl::Create(aCameraId);
mCurrentConfiguration = initialConfig.forget();
// Attach our DOM-facing media stream to our viewfinder stream.
@ -214,6 +214,13 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
// Register a listener for camera events.
mListener = new DOMCameraControlListener(this, mInput);
mCameraControl->AddListener(mListener);
// Start the camera...
nsresult rv = mCameraControl->Start(&config);
if (NS_FAILED(rv)) {
mListener->OnError(DOMCameraControlListener::kInStartCamera,
DOMCameraControlListener::kErrorApiFailed);
}
}
nsDOMCameraControl::~nsDOMCameraControl()
@ -911,7 +918,7 @@ nsDOMCameraControl::ReleaseHardware(const Optional<OwningNonNull<CameraReleaseCa
mReleaseOnErrorCb = &aOnError.Value();
}
aRv = mCameraControl->ReleaseHardware();
aRv = mCameraControl->Stop();
}
void
@ -1157,11 +1164,16 @@ nsDOMCameraControl::OnError(CameraControlListener::CameraErrorContext aContext,
nsCOMPtr<CameraErrorCallback>* errorCb;
switch (aContext) {
case CameraControlListener::kInGetCamera:
case CameraControlListener::kInStartCamera:
mGetCameraOnSuccessCb = nullptr;
errorCb = &mGetCameraOnErrorCb;
break;
case CameraControlListener::kInStopCamera:
mReleaseOnSuccessCb = nullptr;
errorCb = &mReleaseOnErrorCb;
break;
case CameraControlListener::kInSetConfiguration:
mSetConfigurationOnSuccessCb = nullptr;
errorCb = &mSetConfigurationOnErrorCb;
@ -1182,11 +1194,6 @@ nsDOMCameraControl::OnError(CameraControlListener::CameraErrorContext aContext,
errorCb = &mStartRecordingOnErrorCb;
break;
case CameraControlListener::kInReleaseHardware:
mReleaseOnSuccessCb = nullptr;
errorCb = &mReleaseOnErrorCb;
break;
case CameraControlListener::kInStopRecording:
NS_WARNING("Failed to stop recording (which shouldn't happen)!");
MOZ_CRASH();

View File

@ -13,14 +13,33 @@
using namespace mozilla;
using namespace mozilla::dom;
DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl,
CameraPreviewMediaStream* aStream)
: mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(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<nsDOMCameraControl> aDOMCameraControl)
: mDOMCameraControl(aDOMCameraControl)
{ }
virtual ~DOMCallback() { }
{
MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback);
}
virtual ~DOMCallback()
{
MOZ_COUNT_DTOR(DOMCameraControlListener::DOMCallback);
}
virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0;
@ -178,7 +197,8 @@ DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguratio
break;
default:
MOZ_ASSUME_UNREACHABLE("Unanticipated camera mode!");
DOM_CAMERA_LOGI("Camera mode still unspecified, nothing to do\n");
return;
}
// Map CameraControl parameters to their DOM-facing equivalents
@ -298,7 +318,7 @@ DOMCameraControlListener::OnError(CameraErrorContext aContext, CameraError aErro
, mError(aError)
{ }
void
virtual void
RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
{
nsString error;

View File

@ -15,29 +15,28 @@ class CameraPreviewMediaStream;
class DOMCameraControlListener : public CameraControlListener
{
public:
DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl, CameraPreviewMediaStream* aStream);
virtual void OnAutoFocusComplete(bool aAutoFocusSucceeded) MOZ_OVERRIDE;
virtual void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) MOZ_OVERRIDE;
virtual void OnHardwareStateChange(HardwareState aState) MOZ_OVERRIDE;
virtual void OnPreviewStateChange(PreviewState aState) MOZ_OVERRIDE;
virtual void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum) MOZ_OVERRIDE;
virtual void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration) MOZ_OVERRIDE;
virtual void OnShutter() MOZ_OVERRIDE;
virtual bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) MOZ_OVERRIDE;
virtual void OnError(CameraErrorContext aContext, CameraError aError) MOZ_OVERRIDE;
protected:
virtual ~DOMCameraControlListener();
nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
CameraPreviewMediaStream* mStream;
class DOMCallback;
public:
DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl, CameraPreviewMediaStream* aStream)
: mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(aDOMCameraControl))
, mStream(aStream)
{ }
void OnAutoFocusComplete(bool aAutoFocusSucceeded);
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
void OnHardwareStateChange(HardwareState aState);
void OnPreviewStateChange(PreviewState aState);
void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum);
void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration);
void OnShutter();
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
void OnError(CameraErrorContext aContext, CameraError aError);
private:
DOMCameraControlListener(const DOMCameraControlListener&) MOZ_DELETE;
DOMCameraControlListener& operator=(const DOMCameraControlListener&) MOZ_DELETE;

View File

@ -26,7 +26,7 @@ ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
}
already_AddRefed<ICameraControl>
ICameraControl::Create(uint32_t aCameraId, const Configuration* aInitialConfig)
ICameraControl::Create(uint32_t aCameraId)
{
return nullptr;
}

View File

@ -77,90 +77,50 @@ nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
}
nsresult
nsGonkCameraControl::Init(const Configuration* aInitialConfig)
nsGonkCameraControl::StartImpl(const Configuration* aInitialConfig)
{
class InitGonkCameraControl : public nsRunnable
{
public:
InitGonkCameraControl(nsGonkCameraControl* aCameraControl,
const Configuration* aConfig)
: mCameraControl(aCameraControl)
, mHaveInitialConfig(false)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (aConfig) {
mConfig = *aConfig;
mHaveInitialConfig = true;
}
/**
* For initialization, we try to return the camera control to the upper
* upper layer (i.e. the DOM) as quickly as possible. To do this, the
* camera is initialized in the following stages:
*
* 0. Initialize() initializes the hardware;
* 1. SetConfigurationInternal() does the minimal configuration
* required so that we can start the preview -and- report a valid
* configuration to the upper layer;
* 2. OnHardwareStateChange() reports that the hardware is ready,
* which the upper (e.g. DOM) layer can (and does) use to return
* the camera control object;
* 3. StartPreviewImpl() starts the flow of preview frames from the
* camera hardware.
*
* The intent of the above flow is to let the Main Thread do as much work
* up-front as possible without waiting for blocking Camera Thread calls
* to complete.
*/
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
nsresult rv = Initialize();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aInitialConfig) {
rv = SetConfigurationInternal(*aInitialConfig);
if (NS_WARN_IF(NS_FAILED(rv))) {
// The initial configuration failed, close up the hardware
StopImpl();
return rv;
}
}
~InitGonkCameraControl()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
/**
* For initialization, we try to return the camera control to the upper
* upper layer (i.e. the DOM) as quickly as possible. To do this, the
* camera is initialized in the following stages:
*
* 0. InitImpl() initializes the hardware;
* 1. SetConfigurationInternal() does the minimal configuration
* required so that we can start the preview -and- report a valid
* configuration to the upper layer;
* 2. OnHardwareStateChange() reports that the hardware is ready,
* which the upper layer can (and does) use to return the camera
* control object;
* 3. StartPreviewImpl() starts the flow of preview frames from the
* camera hardware.
*
* The intent of the above flow is to let the Main Thread do as much work
* up-front as possible without waiting for blocking Camera Thread calls
* to complete.
*/
NS_IMETHODIMP
Run() MOZ_OVERRIDE
{
nsresult rv = mCameraControl->InitImpl();
if (NS_FAILED(rv)) {
mCameraControl->OnError(CameraControlListener::kInGetCamera,
CameraControlListener::kErrorInitFailed);
// The hardware failed to initialize, so close it up
mCameraControl->ReleaseHardware();
return rv;
}
if (mHaveInitialConfig) {
rv = mCameraControl->SetConfigurationInternal(mConfig);
if (NS_FAILED(rv)) {
mCameraControl->OnError(CameraControlListener::kInGetCamera,
CameraControlListener::kErrorInvalidConfiguration);
// The initial configuration failed, close up the hardware
mCameraControl->ReleaseHardware();
return rv;
}
}
mCameraControl->OnHardwareStateChange(CameraControlListener::kHardwareOpen);
return mCameraControl->StartPreviewImpl();
}
protected:
nsRefPtr<nsGonkCameraControl> mCameraControl;
Configuration mConfig;
bool mHaveInitialConfig;
};
// Initialization is carried out on the camera thread.
return mCameraThread->Dispatch(
new InitGonkCameraControl(this, aInitialConfig), NS_DISPATCH_NORMAL);
OnHardwareStateChange(CameraControlListener::kHardwareOpen);
return StartPreviewImpl();
}
nsresult
nsGonkCameraControl::InitImpl()
nsGonkCameraControl::Initialize()
{
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
mCameraHw = GonkCameraHardware::Connect(this, mCameraId);
if (!mCameraHw.get()) {
DOM_CAMERA_LOGE("Failed to connect to camera %d (this=%p)\n", mCameraId, this);
@ -211,7 +171,7 @@ nsGonkCameraControl::~nsGonkCameraControl()
{
DOM_CAMERA_LOGT("%s:%d : this=%p, mCameraHw = %p\n", __func__, __LINE__, this, mCameraHw.get());
ReleaseHardwareImpl();
StopImpl();
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
}
@ -255,11 +215,18 @@ nsGonkCameraControl::SetConfigurationImpl(const Configuration& aConfig)
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
// Stop any currently running preview
StopPreviewImpl();
nsresult rv = PausePreview();
if (NS_FAILED(rv)) {
// warn, but plow ahead
NS_WARNING("PausePreview() in SetConfigurationImpl() failed");
}
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
nsresult rv = SetConfigurationInternal(aConfig);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetConfigurationInternal(aConfig);
if (NS_WARN_IF(NS_FAILED(rv))) {
StopPreviewImpl();
return rv;
}
// Restart the preview
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
@ -546,11 +513,22 @@ nsGonkCameraControl::StopPreviewImpl()
DOM_CAMERA_LOGI("Stopping preview (this=%p)\n", this);
mCameraHw->StopPreview();
OnPreviewStateChange(CameraControlListener::kPreviewStopped);
return NS_OK;
}
nsresult
nsGonkCameraControl::PausePreview()
{
RETURN_IF_NO_CAMERA_HW();
DOM_CAMERA_LOGI("Pausing preview (this=%p)\n", this);
mCameraHw->StopPreview();
OnPreviewStateChange(CameraControlListener::kPreviewPaused);
return NS_OK;
}
nsresult
nsGonkCameraControl::AutoFocusImpl(bool aCancelExistingCall)
{
@ -892,7 +870,7 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri
return NS_ERROR_FAILURE;
}
OnRecorderStateChange(CameraControlListener::kRecorderStarted, -1, -1);
OnRecorderStateChange(CameraControlListener::kRecorderStarted);
return NS_OK;
}
@ -929,7 +907,7 @@ nsGonkCameraControl::StopRecordingImpl()
mRecorder->stop();
mRecorder = nullptr;
OnRecorderStateChange(CameraControlListener::kRecorderStopped, -1, -1);
OnRecorderStateChange(CameraControlListener::kRecorderStopped);
// notify DeviceStorage that the new video file is closed and ready
return NS_DispatchToMainThread(new RecordingComplete(mVideoFile), NS_DISPATCH_NORMAL);
@ -1339,15 +1317,16 @@ nsGonkCameraControl::SetupRecording(int aFd, int aRotation, int64_t aMaxFileSize
}
nsresult
nsGonkCameraControl::ReleaseHardwareImpl()
nsGonkCameraControl::StopImpl()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
// if we're recording, stop recording
if (mRecorder) {
DOM_CAMERA_LOGI("shutting down existing video recorder\n");
DOM_CAMERA_LOGI("Stopping existing video recorder\n");
mRecorder->stop();
mRecorder = nullptr;
OnRecorderStateChange(CameraControlListener::kRecorderStopped);
}
// stop the preview

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012-2013 Mozilla Foundation
* Copyright (C) 2012-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -47,8 +47,6 @@ class nsGonkCameraControl : public CameraControlImpl
{
public:
nsGonkCameraControl(uint32_t aCameraId);
nsresult Init(const Configuration* aInitialConfig);
nsresult InitImpl();
void OnAutoFocusComplete(bool aSuccess);
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength);
@ -92,6 +90,10 @@ protected:
virtual void BeginBatchParameterSet() MOZ_OVERRIDE;
virtual void EndBatchParameterSet() MOZ_OVERRIDE;
virtual nsresult StartImpl(const Configuration* aInitialConfig = nullptr) MOZ_OVERRIDE;
virtual nsresult StopImpl() MOZ_OVERRIDE;
nsresult Initialize();
virtual nsresult SetConfigurationImpl(const Configuration& aConfig) MOZ_OVERRIDE;
nsresult SetConfigurationInternal(const Configuration& aConfig);
nsresult SetPictureConfiguration(const Configuration& aConfig);
@ -108,13 +110,13 @@ protected:
virtual nsresult StopRecordingImpl() MOZ_OVERRIDE;
virtual nsresult PushParametersImpl() MOZ_OVERRIDE;
virtual nsresult PullParametersImpl() MOZ_OVERRIDE;
virtual nsresult ReleaseHardwareImpl() MOZ_OVERRIDE;
virtual already_AddRefed<RecorderProfileManager> GetRecorderProfileManagerImpl() MOZ_OVERRIDE;
already_AddRefed<GonkRecorderProfileManager> GetGonkRecorderProfileManager();
nsresult SetupRecording(int aFd, int aRotation, int64_t aMaxFileSizeBytes, int64_t aMaxVideoLengthMs);
nsresult SetupVideoMode(const nsAString& aProfile);
nsresult SetPreviewSize(const Size& aSize);
nsresult PausePreview();
friend class SetPictureSize;
friend class SetThumbnailSize;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012-2013 Mozilla Foundation
* Copyright (C) 2012-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,12 +15,14 @@
*/
#include "GonkCameraHwMgr.h"
#include "TestGonkCameraHardware.h"
#include <binder/IPCThreadState.h>
#include <sys/system_properties.h>
#include "base/basictypes.h"
#include "nsDebug.h"
#include "mozilla/Preferences.h"
#include "GonkCameraControl.h"
#include "GonkNativeWindow.h"
#include "CameraCommon.h"
@ -35,11 +37,9 @@ GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, ui
, mNumFrames(0)
, mCamera(aCamera)
, mTarget(aTarget)
, mInitialized(false)
, mSensorOrientation(0)
{
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget);
Init();
}
void
@ -127,7 +127,7 @@ GonkCameraHardware::postDataTimestamp(nsecs_t aTimestamp, int32_t aMsgType, cons
}
}
void
nsresult
GonkCameraHardware::Init()
{
DOM_CAMERA_LOGT("%s: this=%p\n", __func__, (void* )this);
@ -136,7 +136,7 @@ GonkCameraHardware::Init()
int rv = Camera::getCameraInfo(mCameraId, &info);
if (rv != 0) {
DOM_CAMERA_LOGE("%s: failed to get CameraInfo mCameraId %d\n", __func__, mCameraId);
return;
return NS_ERROR_FAILURE;
}
mRawSensorOrientation = info.orientation;
@ -168,7 +168,8 @@ GonkCameraHardware::Init()
#else
mCamera->setPreviewTexture(mNativeWindow);
#endif
mInitialized = true;
return NS_OK;
}
sp<GonkCameraHardware>
@ -180,18 +181,33 @@ GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCam
sp<Camera> camera = Camera::connect(aCameraId);
#endif
if (camera.get() == nullptr) {
return nullptr;
}
sp<GonkCameraHardware> cameraHardware = new GonkCameraHardware(aTarget, aCameraId, camera);
const nsAdoptingCString& test =
mozilla::Preferences::GetCString("camera.control.test.enabled");
sp<GonkCameraHardware> cameraHardware;
if (test.EqualsASCII("hardware")) {
NS_WARNING("Using test Gonk hardware layer");
cameraHardware = new TestGonkCameraHardware(aTarget, aCameraId, camera);
} else {
cameraHardware = new GonkCameraHardware(aTarget, aCameraId, camera);
}
nsresult rv = cameraHardware->Init();
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGE("Failed to initialize camera hardware (0x%X)\n", rv);
return nullptr;
}
return cameraHardware;
}
}
void
GonkCameraHardware::Close()
{
DOM_CAMERA_LOGT( "%s:%d : this=%p\n", __func__, __LINE__, (void*)this );
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this);
mClosing = true;
mCamera->stopPreview();
@ -208,7 +224,7 @@ GonkCameraHardware::Close()
GonkCameraHardware::~GonkCameraHardware()
{
DOM_CAMERA_LOGT( "%s:%d : this=%p\n", __func__, __LINE__, (void*)this );
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this);
mCamera.clear();
mNativeWindow.clear();
@ -308,7 +324,7 @@ void
GonkCameraHardware::StopPreview()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
return mCamera->stopPreview();
mCamera->stopPreview();
}
int

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Mozilla Foundation
* Copyright (C) 2012-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -43,14 +43,14 @@ class GonkCameraHardware : public GonkNativeWindowNewFrameCallback
protected:
GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera);
virtual ~GonkCameraHardware();
void Init();
virtual nsresult Init();
public:
static sp<GonkCameraHardware> Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId);
void Close();
static sp<GonkCameraHardware> Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId);
virtual void Close();
// derived from GonkNativeWindowNewFrameCallback
virtual void OnNewFrame() MOZ_OVERRIDE;
virtual void OnNewFrame() MOZ_OVERRIDE;
// derived from CameraListener
virtual void notify(int32_t aMsgType, int32_t ext1, int32_t ext2);
@ -75,26 +75,25 @@ public:
RAW_SENSOR_ORIENTATION,
OFFSET_SENSOR_ORIENTATION
};
int GetSensorOrientation(uint32_t aType = RAW_SENSOR_ORIENTATION);
virtual int GetSensorOrientation(uint32_t aType = RAW_SENSOR_ORIENTATION);
int AutoFocus();
void CancelAutoFocus();
int TakePicture();
void CancelTakePicture();
int StartPreview();
void StopPreview();
int PushParameters(const mozilla::GonkCameraParameters& aParams);
int PushParameters(const CameraParameters& aParams);
nsresult PullParameters(mozilla::GonkCameraParameters& aParams);
void PullParameters(CameraParameters& aParams);
int StartRecording();
int StopRecording();
int SetListener(const sp<GonkCameraListener>& aListener);
void ReleaseRecordingFrame(const sp<IMemory>& aFrame);
int StoreMetaDataInBuffers(bool aEnabled);
virtual int AutoFocus();
virtual void CancelAutoFocus();
virtual int TakePicture();
virtual void CancelTakePicture();
virtual int StartPreview();
virtual void StopPreview();
virtual int PushParameters(const mozilla::GonkCameraParameters& aParams);
virtual int PushParameters(const CameraParameters& aParams);
virtual nsresult PullParameters(mozilla::GonkCameraParameters& aParams);
virtual void PullParameters(CameraParameters& aParams);
virtual int StartRecording();
virtual int StopRecording();
virtual int SetListener(const sp<GonkCameraListener>& aListener);
virtual void ReleaseRecordingFrame(const sp<IMemory>& aFrame);
virtual int StoreMetaDataInBuffers(bool aEnabled);
protected:
uint32_t mCameraId;
bool mClosing;
uint32_t mNumFrames;
@ -102,15 +101,9 @@ protected:
mozilla::nsGonkCameraControl* mTarget;
sp<GonkNativeWindow> mNativeWindow;
sp<GonkCameraListener> mListener;
bool mInitialized;
int mRawSensorOrientation;
int mSensorOrientation;
bool IsInitialized()
{
return mInitialized;
}
private:
GonkCameraHardware(const GonkCameraHardware&) MOZ_DELETE;
GonkCameraHardware& operator=(const GonkCameraHardware&) MOZ_DELETE;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Mozilla Foundation
* Copyright (C) 2012-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -115,18 +115,8 @@ ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
// implementation-specific camera factory
already_AddRefed<ICameraControl>
ICameraControl::Create(uint32_t aCameraId, const Configuration* aInitialConfig)
ICameraControl::Create(uint32_t aCameraId)
{
if (aInitialConfig) {
DOM_CAMERA_LOGI("Creating camera %d control, initial mode '%s'\n",
aCameraId, aInitialConfig->mMode == kVideoMode ? "video" : "picture");
} else {
DOM_CAMERA_LOGI("Creating camera %d control, no intial configuration\n", aCameraId);
}
nsRefPtr<nsGonkCameraControl> control = new nsGonkCameraControl(aCameraId);
nsresult rv = control->Init(aInitialConfig);
NS_ENSURE_SUCCESS(rv, nullptr);
return control.forget();
}

View File

@ -117,8 +117,11 @@ public:
Size mPreviewSize;
nsString mRecorderProfile;
};
static already_AddRefed<ICameraControl> Create(uint32_t aCameraId,
const Configuration* aInitialConfig);
static already_AddRefed<ICameraControl> Create(uint32_t aCameraId);
virtual nsresult Start(const Configuration* aInitialConfig = nullptr) = 0;
virtual nsresult Stop() = 0;
virtual nsresult SetConfiguration(const Configuration& aConfig) = 0;
virtual void AddListener(CameraControlListener* aListener) = 0;
@ -131,7 +134,6 @@ public:
virtual nsresult StartRecording(DeviceStorageFileDescriptor *aFileDescriptor,
const StartRecordingOptions* aOptions = nullptr) = 0;
virtual nsresult StopRecording() = 0;
virtual nsresult ReleaseHardware() = 0;
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0;
virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0;

View File

@ -0,0 +1,218 @@
/*
* Copyright (C) 2013-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "TestGonkCameraHardware.h"
#include "mozilla/Preferences.h"
#include "nsThreadUtils.h"
using namespace android;
using namespace mozilla;
TestGonkCameraHardware::TestGonkCameraHardware(nsGonkCameraControl* aTarget,
uint32_t aCameraId,
const sp<Camera>& aCamera)
: GonkCameraHardware(aTarget, aCameraId, aCamera)
{
DOM_CAMERA_LOGA("+===== Created TestGonkCameraHardware =====+\n");
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n",
__func__, __LINE__, this, aTarget);
MOZ_COUNT_CTOR(TestGonkCameraHardware);
}
TestGonkCameraHardware::~TestGonkCameraHardware()
{
MOZ_COUNT_DTOR(TestGonkCameraHardware);
DOM_CAMERA_LOGA("+===== Destroyed TestGonkCameraHardware =====+\n");
}
nsresult
TestGonkCameraHardware::Init()
{
if (IsTestCase("init-failure")) {
return NS_ERROR_FAILURE;
}
return GonkCameraHardware::Init();
}
const nsCString
TestGonkCameraHardware::TestCase()
{
const nsCString test = Preferences::GetCString("camera.control.test.hardware");
return test;
}
bool
TestGonkCameraHardware::IsTestCaseInternal(const char* aTest, const char* aFile, int aLine)
{
if (TestCase().EqualsASCII(aTest)) {
DOM_CAMERA_LOGA("TestGonkCameraHardware : test-case '%s' (%s:%d)\n",
aTest, aFile, aLine);
return true;
}
return false;
}
int
TestGonkCameraHardware::TestCaseError(int aDefaultError)
{
// for now, just return the default error
return aDefaultError;
}
int
TestGonkCameraHardware::AutoFocus()
{
class AutoFocusFailure : public nsRunnable
{
public:
AutoFocusFailure(nsGonkCameraControl* aTarget)
: mTarget(aTarget)
{ }
NS_IMETHODIMP
Run()
{
OnAutoFocusComplete(mTarget, false);
return NS_OK;
}
protected:
nsGonkCameraControl* mTarget;
};
if (IsTestCase("auto-focus-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
if (IsTestCase("auto-focus-process-failure")) {
nsresult rv = NS_DispatchToCurrentThread(new AutoFocusFailure(mTarget));
if (NS_SUCCEEDED(rv)) {
return OK;
}
DOM_CAMERA_LOGE("Failed to dispatch AutoFocusFailure runnable (0x%08x)\n", rv);
return UNKNOWN_ERROR;
}
return GonkCameraHardware::AutoFocus();
}
int
TestGonkCameraHardware::TakePicture()
{
class TakePictureFailure : public nsRunnable
{
public:
TakePictureFailure(nsGonkCameraControl* aTarget)
: mTarget(aTarget)
{ }
NS_IMETHODIMP
Run()
{
OnTakePictureError(mTarget);
return NS_OK;
}
protected:
nsGonkCameraControl* mTarget;
};
if (IsTestCase("take-picture-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
if (IsTestCase("take-picture-process-failure")) {
nsresult rv = NS_DispatchToCurrentThread(new TakePictureFailure(mTarget));
if (NS_SUCCEEDED(rv)) {
return OK;
}
DOM_CAMERA_LOGE("Failed to dispatch TakePictureFailure runnable (0x%08x)\n", rv);
return UNKNOWN_ERROR;
}
return GonkCameraHardware::TakePicture();
}
int
TestGonkCameraHardware::StartPreview()
{
if (IsTestCase("start-preview-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
return GonkCameraHardware::StartPreview();
}
int
TestGonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
{
if (IsTestCase("push-parameters-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
return GonkCameraHardware::PushParameters(aParams);
}
nsresult
TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
{
if (IsTestCase("pull-parameters-failure")) {
return static_cast<nsresult>(TestCaseError(UNKNOWN_ERROR));
}
return GonkCameraHardware::PullParameters(aParams);
}
int
TestGonkCameraHardware::StartRecording()
{
if (IsTestCase("start-recording-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
return GonkCameraHardware::StartRecording();
}
int
TestGonkCameraHardware::StopRecording()
{
if (IsTestCase("stop-recording-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
return GonkCameraHardware::StopRecording();
}
int
TestGonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener)
{
if (IsTestCase("set-listener-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
return GonkCameraHardware::SetListener(aListener);
}
int
TestGonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
{
if (IsTestCase("store-metadata-in-buffers-failure")) {
return TestCaseError(UNKNOWN_ERROR);
}
return GonkCameraHardware::StoreMetaDataInBuffers(aEnabled);
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2013-2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DOM_CAMERA_TESTGONKCAMERAHARDWARE_H
#define DOM_CAMERA_TESTGONKCAMERAHARDWARE_H
#include "GonkCameraHwMgr.h"
namespace android {
class TestGonkCameraHardware : public android::GonkCameraHardware
{
public:
virtual int AutoFocus() MOZ_OVERRIDE;
virtual int TakePicture() MOZ_OVERRIDE;
virtual int StartPreview() MOZ_OVERRIDE;
virtual int PushParameters(const mozilla::GonkCameraParameters& aParams) MOZ_OVERRIDE;
virtual nsresult PullParameters(mozilla::GonkCameraParameters& aParams) MOZ_OVERRIDE;
virtual int StartRecording() MOZ_OVERRIDE;
virtual int StopRecording() MOZ_OVERRIDE;
virtual int SetListener(const sp<GonkCameraListener>& aListener) MOZ_OVERRIDE;
virtual int StoreMetaDataInBuffers(bool aEnabled) MOZ_OVERRIDE;
virtual int
PushParameters(const CameraParameters& aParams) MOZ_OVERRIDE
{
return GonkCameraHardware::PushParameters(aParams);
}
virtual void
PullParameters(CameraParameters& aParams) MOZ_OVERRIDE
{
GonkCameraHardware::PullParameters(aParams);
}
TestGonkCameraHardware(mozilla::nsGonkCameraControl* aTarget,
uint32_t aCameraId,
const sp<Camera>& aCamera);
virtual ~TestGonkCameraHardware();
virtual nsresult Init() MOZ_OVERRIDE;
protected:
const nsCString TestCase();
bool IsTestCaseInternal(const char* aTest, const char* aFile, int aLine);
int TestCaseError(int aDefaultError);
private:
TestGonkCameraHardware(const TestGonkCameraHardware&) MOZ_DELETE;
TestGonkCameraHardware& operator=(const TestGonkCameraHardware&) MOZ_DELETE;
};
#define IsTestCase(test) IsTestCaseInternal((test), __FILE__, __LINE__)
} // namespace android
#endif // DOM_CAMERA_TESTGONKCAMERAHARDWARE_H

View File

@ -33,6 +33,7 @@ if CONFIG['MOZ_B2G_CAMERA']:
'GonkCameraSource.cpp',
'GonkRecorder.cpp',
'GonkRecorderProfiles.cpp',
'TestGonkCameraHardware.cpp',
]
else:
SOURCES += [

View File

@ -0,0 +1,105 @@
var CameraTest = (function() {
'use strict';
/**
* 'camera.control.test.enabled' is queried in Gecko to enable different
* test modes in the camera stack. The only currently-supported setting
* is 'hardware', which wraps the Gonk camera abstraction class in a
* shim class that supports injecting hardware camera API failures into
* the execution path.
*
* The affected API is specified by the 'camera.control.test.hardware'
* pref. Currently supported values should be determined by inspecting
* TestGonkCameraHardware.cpp.
*
* Some API calls are simple: e.g. 'start-recording-failure' will cause
* the DOM-facing startRecording() call to fail. More complex tests like
* 'take-picture-failure' will cause the takePicture() API to fail, while
* 'take-picture-process-failure' will simulate a failure of the
* asynchronous picture-taking process, even if the initial API call
* path seems to have succeeded.
*/
const PREF_TEST_ENABLED = "camera.control.test.enabled";
const PREF_TEST_HARDWARE = "camera.control.test.hardware";
var oldTestEnabled;
var oldTestHw;
var testMode;
function testHardwareSet(test, callback) {
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_HARDWARE, test]]}, function() {
var setTest = SpecialPowers.getCharPref(PREF_TEST_HARDWARE);
ise(setTest, test, "Test subtype set to " + setTest);
if (callback) {
callback(setTest);
}
});
}
function testHardwareDone(callback) {
testMode = null;
if (oldTestHw) {
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_HARDWARE, oldTestHw]]}, callback);
} else {
SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_HARDWARE]]}, callback);
}
}
function testBegin(mode, callback) {
SimpleTest.waitForExplicitFinish();
try {
oldTestEnabled = SpecialPowers.getCharPref(PREF_TEST_ENABLED);
} catch(e) { }
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_ENABLED, mode]]}, function() {
var setMode = SpecialPowers.getCharPref(PREF_TEST_ENABLED);
ise(setMode, mode, "Test mode set to " + setMode);
if (setMode === "hardware") {
try {
oldTestHw = SpecialPowers.getCharPref(PREF_TEST_HARDWARE);
} catch(e) { }
testMode = {
set: testHardwareSet,
done: testHardwareDone
};
if (callback) {
callback(testMode);
}
}
});
}
function testEnd(callback) {
function allDone(cb) {
function cb2() {
SimpleTest.finish();
if (cb) {
cb();
}
}
if (oldTestEnabled) {
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_ENABLED, oldTestEnabled]]}, cb2);
} else {
SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_ENABLED]]}, cb2);
}
}
if (testMode) {
testMode.done(function() {
allDone(callback);
});
testMode = null;
} else {
allDone(function() {
if (callback) {
callback();
}
});
}
}
ise(SpecialPowers.sanityCheck(), "foo", "SpecialPowers passed sanity check");
return {
begin: testBegin,
end: testEnd
};
})();

View File

@ -1,4 +1,8 @@
[DEFAULT]
support-files = camera_common.js
[test_camera.html]
[test_camera_2.html]
[test_camera_3.html]
[test_camera_hardware_init_failure.html]
[test_camera_hardware_failures.html]

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" |width = "200" height = "200| autoplay></video>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
@ -30,9 +30,6 @@ var config = {
function onError(e) {
ok(false, "Error" + JSON.stringify(e));
Camera.cameraObj.release();
Camera.cameraObj = null;
Camera.viewfinder.mozSrcObject = null;
}
var capabilities = [ 'previewSizes', 'pictureSizes', 'fileFormats', 'maxFocusAreas', 'minExposureCompensation',
@ -105,10 +102,6 @@ var Camera = {
Camera._testsCompleted++;
if(Camera._testsCompleted == Camera._tests.length) {
ok(true, "test finishing");
Camera.cameraObj.release(function() {
Camera.cameraObj = null;
}, onError);
Camera.viewfinder.mozSrcObject = null;
SimpleTest.finish();
} else {
Camera.runTests();
@ -200,6 +193,8 @@ SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.mozSrcObject = null;
Camera.cameraObj.release();
Camera.cameraObj = null;
});
Camera.setUp();

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" |width = "200" height = "200| autoplay></video>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
@ -30,9 +30,6 @@ var config = {
function onError(e) {
ok(false, "Error" + JSON.stringify(e));
Camera.cameraObj.release();
Camera.cameraObj = null;
Camera.viewfinder.mozSrcObject = null;
}
var capabilities = [ 'previewSizes', 'pictureSizes', 'fileFormats', 'maxFocusAreas', 'minExposureCompensation',
@ -105,10 +102,6 @@ var Camera = {
Camera._testsCompleted++;
if(Camera._testsCompleted == Camera._tests.length) {
ok(true, "test finishing");
Camera.cameraObj.release(function() {
Camera.cameraObj = null;
}, onError);
Camera.viewfinder.mozSrcObject = null;
SimpleTest.finish();
} else {
Camera.runTests();
@ -195,6 +188,8 @@ SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.mozSrcObject = null;
Camera.cameraObj.release();
Camera.cameraObj = null;
});
Camera.setUp();

View File

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for multiple calls to mozCameras.getCamera()</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var options = {
mode: 'picture',
recorderProfile: 'cif',
previewSize: {
width: 352,
height: 288
}
};
function onError(e) {
ok(false, "Error" + JSON.stringify(e));
}
var Camera = {
cameraObj: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
onReady: function take_two() {
function onSuccess(camera, config) {
ok(false, "Unexpectedly got second camera instance: " + config.toSource);
}
function onFailure(error) {
ok(true, "Correctly failed to get camera again");
SimpleTest.finish();
}
navigator.mozCameras.getCamera(whichCamera, options, onSuccess, onFailure);
},
release: function release() {
cameraObj = null;
},
start: function run_test() {
function onSuccess(camera, config) {
Camera.cameraObj = camera;
Camera.viewfinder.mozSrcObject = camera;
Camera.viewfinder.play();
Camera.cameraObj.onPreviewStateChange = function(state) {
if (state === 'started') {
ok(true, "viewfinder is ready and playing");
Camera.cameraObj.onPreviewStateChange = null;
Camera.onReady();
}
};
};
navigator.mozCameras.getCamera(whichCamera, options, onSuccess, onError);
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.mozSrcObject = null;
Camera.cameraObj.release();
Camera.cameraObj = null;
});
Camera.start();
</script>
</body>
</html>

View File

@ -0,0 +1,145 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=940424
-->
<head>
<title>Bug 940424 - Test camera hardware API failure handling</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=940424">Mozilla Bug 940424</a>
<video id="viewfinder" width = "200" height = "200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var initialConfig = {
mode: 'picture',
recorderProfile: 'cif',
previewSize: {
width: 352,
height: 288
}
};
var cameraObj;
// Shorthand functions
function end() {
CameraTest.end();
}
function next() {
CameraTest.next();
}
// The array of tests
var tests = [
{
key: "auto-focus-failure",
func: function testAutoFocusApiFailure(camera) {
function onSuccess(success) {
ok(false, "autoFocus() succeeded incorrectly");
end();
}
function onError(error) {
ok(true, "autoFocus() failed correctly with: " + error);
next();
}
camera.autoFocus(onSuccess, onError);
}
},
{
key: "auto-focus-process-failure",
func: function testAutoFocusProcessFailure(camera) {
function onSuccess(success) {
if (success) {
ok(false, "autoFocus() process succeeded incorrectly");
end();
} else {
ok(true, "autoFocus() process failed correctly");
next();
}
}
function onError(error) {
ok(false, "autoFocus() process failed incorrectly with: " + error);
end();
}
camera.autoFocus(onSuccess, onError);
}
},
{
key: "take-picture-failure",
func: function testTakePictureApiFailure(camera) {
function onSuccess(picture) {
ok(false, "takePicture() succeeded incorrectly");
end();
}
function onError(error) {
ok(true, "takePicture() failed correctly with: " + error);
next();
}
camera.takePicture(null, onSuccess, onError);
}
},
{
key: "take-picture-process-failure",
func: function testTakePictureProcessFailure(camera) {
function onSuccess(picture) {
ok(false, "takePicture() process succeeded incorrectly");
end();
}
function onError(error) {
ok(true, "takePicture() process failed correctly with: " + error);
next();
}
camera.takePicture(null, onSuccess, onError);
}
},
];
var testGenerator = function() {
for (var i = 0; i < tests.length; ++i ) {
yield tests[i];
}
}();
window.addEventListener('beforeunload', function() {
document.getElementById('viewfinder').mozSrcObject = null;
cameraObj.release();
cameraObj = null;
});
CameraTest.begin("hardware", function(test) {
function onSuccess(camera, config) {
document.getElementById('viewfinder').mozSrcObject = camera;
cameraObj = camera;
CameraTest.next = function() {
try {
var t = testGenerator.next();
test.set(t.key, t.func.bind(undefined, camera));
} catch(e) {
if (e instanceof StopIteration) {
end();
} else {
throw e;
}
}
};
next();
}
function onError(error) {
ok(false, "getCamera() failed with: " + error);
end();
}
navigator.mozCameras.getCamera(whichCamera, initialConfig, onSuccess, onError);
});
</script>
</body>
</html>

View File

@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=940424
-->
<head>
<title>Bug 940424 - Test camera hardware init failure handling</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="camera_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=940424">Mozilla Bug 940424</a>
<video id="viewfinder" width="200" height="200" autoplay></video>
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var initialConfig = {
mode: 'picture',
recorderProfile: 'cif',
previewSize: {
width: 352,
height: 288
}
};
function end() {
CameraTest.end();
}
CameraTest.begin("hardware", function(test) {
test.set("init-failure", function(type) {
function onSuccess(camera, config) {
ok(false, "onSuccess called incorrectly");
camera.release();
test.done(end);
}
function onError(error) {
ok(true, "onError called correctly on init failure");
test.done(end);
}
info("Running test: " + type);
navigator.mozCameras.getCamera(whichCamera, initialConfig, onSuccess, onError);
});
});
</script>
</body>
</html>

View File

@ -1075,8 +1075,8 @@ var WifiManager = (function() {
manager.getConfiguredNetworks = function(callback) {
wifiCommand.listNetworks(function (reply) {
var networks = Object.create(null);
var lines = reply.split("\n");
if (lines.length === 1) {
var lines = reply ? reply.split("\n") : 0;
if (lines.length <= 1) {
// We need to make sure we call the callback even if there are no
// configured networks.
callback(networks);

View File

@ -249,9 +249,6 @@
"dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected.html":"",
"dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html":"",
"dom/browser-element/mochitest/test_browserElement_inproc_TargetBlank.html":"",
"dom/browser-element/mochitest/test_browserElement_NoPref.html":"bug 970290 - Should not send mozbrowserloadstart event.",
"dom/browser-element/mochitest/test_browserElement_NoWhitelist.html":"bug 970290 - Should not send mozbrowserloadstart event.",
"dom/browser-element/mochitest/test_browserElement_oop_AppFramePermission.html":"",
"dom/browser-element/mochitest/test_browserElement_oop_AppWindowNamespace.html":"",