--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -41,16 +41,22 @@
#include "DOMCameraDetectedFace.h"
#include "mozilla/dom/BindingUtils.h"
#include "nsPrintfCString.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
+#ifdef MOZ_WIDGET_GONK
+StaticRefPtr<ICameraControl> nsDOMCameraControl::sCachedCameraControl;
+/* static */ nsresult nsDOMCameraControl::sCachedCameraControlStartResult = NS_OK;
+/* static */ nsCOMPtr<nsITimer> nsDOMCameraControl::sDiscardCachedCameraControlTimer;
+#endif
+
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
NS_INTERFACE_MAP_ENTRY(nsISupports)
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,
@@ -139,16 +145,70 @@ nsDOMCameraControl::DOMCameraConfigurati
MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration);
}
nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration()
{
MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration);
}
+#ifdef MOZ_WIDGET_GONK
+// This shoudl be long enough for even our slowest platforms.
+static const unsigned long kCachedCameraTimeoutMs = 3500;
+
+// Open the battery-door-facing camera by default.
+static const uint32_t kDefaultCameraId = 0;
+
+/* static */ void
+nsDOMCameraControl::PreinitCameraHardware()
+{
+ // Assume a default, minimal configuration. This should initialize the
+ // hardware, but won't (can't) start the preview.
+ nsRefPtr<ICameraControl> cameraControl = ICameraControl::Create(kDefaultCameraId);
+ if (NS_WARN_IF(!cameraControl)) {
+ return;
+ }
+
+ sCachedCameraControlStartResult = cameraControl->Start();
+ if (NS_WARN_IF(NS_FAILED(sCachedCameraControlStartResult))) {
+ return;
+ }
+
+ sCachedCameraControl = cameraControl;
+
+ nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
+ if (NS_WARN_IF(!timer)) {
+ return;
+ }
+
+ nsresult rv = timer->InitWithFuncCallback(DiscardCachedCameraInstance,
+ nullptr,
+ kCachedCameraTimeoutMs,
+ nsITimer::TYPE_ONE_SHOT);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ // If we can't start the timer, it's possible for an app to never grab the
+ // camera, leaving the hardware tied up indefinitely. Better to take the
+ // performance hit.
+ sCachedCameraControl = nullptr;
+ return;
+ }
+
+ sDiscardCachedCameraControlTimer = timer;
+}
+
+/* static */ void
+nsDOMCameraControl::DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ sDiscardCachedCameraControlTimer = nullptr;
+ sCachedCameraControl = nullptr;
+}
+#endif
+
nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
const CameraConfiguration& aInitialConfig,
GetCameraCallback* aOnSuccess,
CameraErrorCallback* aOnError,
Promise* aPromise,
nsPIDOMWindow* aWindow)
: DOMMediaStream()
, mCameraControl(nullptr)
@@ -209,36 +269,56 @@ nsDOMCameraControl::nsDOMCameraControl(u
}
if (haveInitialConfig) {
config.mPreviewSize.width = aInitialConfig.mPreviewSize.mWidth;
config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
config.mRecorderProfile = aInitialConfig.mRecorderProfile;
}
- mCameraControl = ICameraControl::Create(aCameraId);
+#ifdef MOZ_WIDGET_GONK
+ bool gotCached = false;
+ if (sCachedCameraControl && aCameraId == kDefaultCameraId) {
+ mCameraControl = sCachedCameraControl;
+ sCachedCameraControl = nullptr;
+ gotCached = true;
+ } else {
+ sCachedCameraControl = nullptr;
+#endif
+ mCameraControl = ICameraControl::Create(aCameraId);
+#ifdef MOZ_WIDGET_GONK
+ }
+#endif
mCurrentConfiguration = initialConfig.forget();
// Attach our DOM-facing media stream to our viewfinder stream.
mStream = mInput;
MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
if (mWindow->GetExtantDoc()) {
CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
}
// Register a listener for camera events.
mListener = new DOMCameraControlListener(this, mInput);
mCameraControl->AddListener(mListener);
- // Start the camera...
- if (haveInitialConfig) {
- rv = mCameraControl->Start(&config);
+#ifdef MOZ_WIDGET_GONK
+ if (!gotCached || NS_FAILED(sCachedCameraControlStartResult)) {
+#endif
+ // Start the camera...
+ if (haveInitialConfig) {
+ rv = mCameraControl->Start(&config);
+ } else {
+ rv = mCameraControl->Start();
+ }
+#ifdef MOZ_WIDGET_GONK
} else {
- rv = mCameraControl->Start();
+ rv = mCameraControl->SetConfiguration(config);
}
+#endif
if (NS_FAILED(rv)) {
mListener->OnUserError(DOMCameraControlListener::kInStartCamera, rv);
}
}
nsDOMCameraControl::~nsDOMCameraControl()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);