--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -27,17 +27,16 @@
#include "CameraCommon.h"
#include "nsGlobalWindow.h"
#include "CameraPreviewMediaStream.h"
#include "mozilla/dom/CameraControlBinding.h"
#include "mozilla/dom/CameraManagerBinding.h"
#include "mozilla/dom/CameraCapabilitiesBinding.h"
#include "DOMCameraDetectedFace.h"
#include "mozilla/dom/BindingUtils.h"
-#include "nsPrintfCString.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream)
@@ -198,17 +197,18 @@ nsDOMCameraControl::nsDOMCameraControl(u
// 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->OnUserError(DOMCameraControlListener::kInStartCamera, rv);
+ mListener->OnError(DOMCameraControlListener::kInStartCamera,
+ DOMCameraControlListener::kErrorApiFailed);
}
}
nsDOMCameraControl::~nsDOMCameraControl()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
@@ -733,17 +733,17 @@ nsDOMCameraControl::StartRecording(const
mAudioChannelAgent->StartPlaying(&canPlay);
}
}
#endif
nsCOMPtr<nsIDOMDOMRequest> request;
mDSFileDescriptor = new DeviceStorageFileDescriptor();
aRv = aStorageArea.CreateFileDescriptor(aFilename, mDSFileDescriptor.get(),
- getter_AddRefs(request));
+ getter_AddRefs(request));
if (aRv.Failed()) {
return;
}
mOptions = aOptions;
mStartRecordingOnSuccessCb = &aOnSuccess;
mStartRecordingOnErrorCb = nullptr;
if (aOnError.WasPassed()) {
@@ -753,32 +753,29 @@ nsDOMCameraControl::StartRecording(const
nsCOMPtr<nsIDOMEventListener> listener = new StartRecordingHelper(this);
request->AddEventListener(NS_LITERAL_STRING("success"), listener, false);
request->AddEventListener(NS_LITERAL_STRING("error"), listener, false);
}
void
nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
{
- nsresult rv = NS_ERROR_FAILURE;
-
if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
ICameraControl::StartRecordingOptions o;
o.rotation = mOptions.mRotation;
o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes;
o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs;
o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch;
- rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o);
+ nsresult rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o);
if (NS_SUCCEEDED(rv)) {
return;
}
}
-
- OnUserError(CameraControlListener::kInStartRecording, rv);
+ OnError(CameraControlListener::kInStartRecording, NS_LITERAL_STRING("FAILURE"));
if (mDSFileDescriptor->mFileDescriptor.IsValid()) {
// An error occured. We need to manually close the file associated with the
// FileDescriptor, and we shouldn't do this on the main thread, so we
// use a little helper.
nsRefPtr<CloseFileRunnable> closer =
new CloseFileRunnable(mDSFileDescriptor->mFileDescriptor);
closer->Dispatch();
@@ -802,58 +799,32 @@ nsDOMCameraControl::StopRecording(ErrorR
void
nsDOMCameraControl::ResumePreview(ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
aRv = mCameraControl->StartPreview();
}
-class ImmediateErrorCallback : public nsRunnable
-{
-public:
- ImmediateErrorCallback(CameraErrorCallback* aCallback, const nsAString& aMessage)
- : mCallback(aCallback)
- , mMessage(aMessage)
- { }
-
- NS_IMETHODIMP
- Run()
- {
- MOZ_ASSERT(NS_IsMainThread());
- ErrorResult ignored;
- mCallback->Call(mMessage, ignored);
- return NS_OK;
- }
-
-protected:
- nsRefPtr<CameraErrorCallback> mCallback;
- nsString mMessage;
-};
-
void
nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
const Optional<OwningNonNull<CameraSetConfigurationCallback> >& aOnSuccess,
const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
if (cb) {
// We're busy taking a picture, can't change modes right now.
if (aOnError.WasPassed()) {
- // There is already a call to TakePicture() in progress, abort this
- // call and invoke the error callback (if one was passed in).
- NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
- NS_LITERAL_STRING("TakePictureInProgress")));
- } else {
- // Only throw if no error callback was passed in.
- aRv = NS_ERROR_FAILURE;
+ ErrorResult ignored;
+ aOnError.Value().Call(NS_LITERAL_STRING("Busy"), ignored);
}
+ aRv = NS_ERROR_FAILURE;
return;
}
ICameraControl::Configuration config;
config.mRecorderProfile = aConfiguration.mRecorderProfile;
config.mPreviewSize.width = aConfiguration.mPreviewSize.mWidth;
config.mPreviewSize.height = aConfiguration.mPreviewSize.mHeight;
config.mMode = ICameraControl::kPictureMode;
@@ -868,34 +839,55 @@ nsDOMCameraControl::SetConfiguration(con
mSetConfigurationOnErrorCb = nullptr;
if (aOnError.WasPassed()) {
mSetConfigurationOnErrorCb = &aOnError.Value();
}
aRv = mCameraControl->SetConfiguration(config);
}
+class ImmediateErrorCallback : public nsRunnable
+{
+public:
+ ImmediateErrorCallback(CameraErrorCallback* aCallback, const nsAString& aMessage)
+ : mCallback(aCallback)
+ , mMessage(aMessage)
+ { }
+
+ NS_IMETHODIMP
+ Run()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ ErrorResult ignored;
+ mCallback->Call(mMessage, ignored);
+ return NS_OK;
+ }
+
+protected:
+ nsRefPtr<CameraErrorCallback> mCallback;
+ nsString mMessage;
+};
+
+
void
nsDOMCameraControl::AutoFocus(CameraAutoFocusCallback& aOnSuccess,
const Optional<OwningNonNull<CameraErrorCallback> >& aOnError,
ErrorResult& aRv)
{
MOZ_ASSERT(mCameraControl);
nsRefPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb;
if (cb) {
if (aOnError.WasPassed()) {
// There is already a call to AutoFocus() in progress, abort this new one
// and invoke the error callback (if one was passed in).
NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
NS_LITERAL_STRING("AutoFocusAlreadyInProgress")));
- } else {
- // Only throw if no error callback was passed in.
- aRv = NS_ERROR_FAILURE;
}
+ aRv = NS_ERROR_FAILURE;
return;
}
mAutoFocusOnSuccessCb = &aOnSuccess;
mAutoFocusOnErrorCb = nullptr;
if (aOnError.WasPassed()) {
mAutoFocusOnErrorCb = &aOnError.Value();
}
@@ -927,20 +919,18 @@ nsDOMCameraControl::TakePicture(const Ca
nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
if (cb) {
if (aOnError.WasPassed()) {
// There is already a call to TakePicture() in progress, abort this new
// one and invoke the error callback (if one was passed in).
NS_DispatchToMainThread(new ImmediateErrorCallback(&aOnError.Value(),
NS_LITERAL_STRING("TakePictureAlreadyInProgress")));
- } else {
- // Only throw if no error callback was passed in.
- aRv = NS_ERROR_FAILURE;
}
+ aRv = NS_ERROR_FAILURE;
return;
}
{
ICameraControlParameterSetAutoEnter batch(mCameraControl);
// XXXmikeh - remove this: see bug 931155
ICameraControl::Size s;
@@ -1275,18 +1265,20 @@ nsDOMCameraControl::OnTakePictureComplet
return;
}
ErrorResult ignored;
cb->Call(aPicture, ignored);
}
void
-nsDOMCameraControl::OnUserError(CameraControlListener::UserContext aContext, nsresult aError)
+nsDOMCameraControl::OnError(CameraControlListener::CameraErrorContext aContext, const nsAString& aError)
{
+ DOM_CAMERA_LOGI("DOM OnError context=%d, error='%s'\n", aContext,
+ NS_LossyConvertUTF16toASCII(aError).get());
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<CameraErrorCallback> errorCb;
switch (aContext) {
case CameraControlListener::kInStartCamera:
mGetCameraOnSuccessCb = nullptr;
errorCb = mGetCameraOnErrorCb.forget();
@@ -1324,84 +1316,41 @@ nsDOMCameraControl::OnUserError(CameraCo
return;
case CameraControlListener::kInStartPreview:
// This method doesn't have any callbacks, so all we can do is log the
// failure. This only happens after the hardware has been released.
NS_WARNING("Failed to (re)start preview");
return;
- case CameraControlListener::kInStopPreview:
- // This method doesn't have any callbacks, so all we can do is log the
- // failure. This only happens after the hardware has been released.
- NS_WARNING("Failed to stop preview");
- return;
-
- case CameraControlListener::kInSetPictureSize:
- // This method doesn't have any callbacks, so all we can do is log the
- // failure. This only happens after the hardware has been released.
- NS_WARNING("Failed to set picture size");
- return;
-
- case CameraControlListener::kInSetThumbnailSize:
- // This method doesn't have any callbacks, so all we can do is log the
- // failure. This only happens after the hardware has been released.
- NS_WARNING("Failed to set thumbnail size");
- return;
+ case CameraControlListener::kInUnspecified:
+ if (aError.EqualsASCII("ErrorServiceFailed")) {
+ // If the camera service fails, we will get preview-stopped and
+ // hardware-closed events, so nothing to do here.
+ NS_WARNING("Camera service failed");
+ return;
+ }
+ if (aError.EqualsASCII("ErrorSetPictureSizeFailed") ||
+ aError.EqualsASCII("ErrorSetThumbnailSizeFailed")) {
+ // We currently don't handle attribute setter failure. Practically,
+ // this only ever happens if a setter is called after the hardware
+ // has gone away before an asynchronous set gets to happen, so we
+ // swallow these.
+ NS_WARNING("Failed to set either picture or thumbnail size");
+ return;
+ }
+ // fallthrough
default:
- {
- nsPrintfCString msg("Unhandled aContext=%u, aError=0x%x\n", aContext, aError);
- NS_WARNING(msg.get());
- }
- MOZ_ASSUME_UNREACHABLE("Unhandled user error");
+ MOZ_ASSUME_UNREACHABLE("Error occurred in unanticipated camera state");
return;
}
if (!errorCb) {
- DOM_CAMERA_LOGW("DOM No error handler for aError=0x%x in aContext=%u\n",
- aError, aContext);
+ DOM_CAMERA_LOGW("DOM No error handler for error '%s' in context=%d\n",
+ NS_LossyConvertUTF16toASCII(aError).get(), aContext);
return;
}
- nsString error;
- switch (aError) {
- case NS_ERROR_INVALID_ARG:
- error = NS_LITERAL_STRING("InvalidArgument");
- break;
-
- case NS_ERROR_NOT_AVAILABLE:
- error = NS_LITERAL_STRING("NotAvailable");
- break;
-
- case NS_ERROR_NOT_IMPLEMENTED:
- error = NS_LITERAL_STRING("NotImplemented");
- break;
-
- case NS_ERROR_NOT_INITIALIZED:
- error = NS_LITERAL_STRING("HardwareClosed");
- break;
-
- case NS_ERROR_ALREADY_INITIALIZED:
- error = NS_LITERAL_STRING("HardwareAlreadyOpen");
- break;
+ ErrorResult ignored;
+ errorCb->Call(aError, ignored);
+}
- case NS_ERROR_OUT_OF_MEMORY:
- error = NS_LITERAL_STRING("OutOfMemory");
- break;
-
- default:
- {
- nsPrintfCString msg("Reporting aError=0x%x as generic\n", aError);
- NS_WARNING(msg.get());
- }
- // fallthrough
-
- case NS_ERROR_FAILURE:
- error = NS_LITERAL_STRING("GeneralFailure");
- break;
- }
-
- DOM_CAMERA_LOGI("DOM OnUserError aContext=%u, error='%s'\n", aContext,
- NS_ConvertUTF16toUTF8(error).get());
- ErrorResult ignored;
- errorCb->Call(error, ignored);
-}