/*!
* This file is part of CameraPlus.
*
- * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
+ * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*/
#include "cameraresources.h"
+#if defined(QT4)
+#include <dbusconnectioneventloop.h>
+#endif
#include <QDebug>
-using namespace ResourcePolicy;
+#define APPLICATION_CLASS "camera"
CameraResources::CameraResources(QObject *parent) :
QObject(parent),
- m_set(new ResourceSet("camera", this, true, true)),
- m_mode(None), m_acquired(false) {
+ m_worker(new CameraResourcesWorker) {
+
+ m_worker->moveToThread(&m_thread);
+
+#if defined(QT4)
+ DBUSConnectionEventLoop::getInstance().moveToThread(&m_thread);
+#endif
+
+ QObject::connect(&m_thread, SIGNAL(started()), m_worker, SLOT(init()));
+ m_thread.start();
+
+ qRegisterMetaType<CameraResources::Mode>("CameraResources::Mode");
+ qRegisterMetaType<bool *>("bool *");
+
+ QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(acquiredChanged()));
+ QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(hijackedChanged()));
+ QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(updated()));
+ QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(scaleAcquisitionChanged()));
+ QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(scaleAcquisitionChanged()));
+ QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(scaleAcquisitionChanged()));
+}
+
+CameraResources::~CameraResources() {
+ acquire(CameraResources::None);
+ m_thread.exit(0);
+
+ while (m_thread.isRunning()) {
+ m_thread.wait(10);
+ }
+
+ delete m_worker;
+ m_worker = 0;
+}
+
+bool CameraResources::isResourceGranted(const ResourcePolicy::ResourceType& resource) const {
+ bool ok = false;
+
+ QMetaObject::invokeMethod(m_worker, "isResourceGranted", Qt::BlockingQueuedConnection,
+ Q_ARG(bool *, &ok), Q_ARG(int, resource));
+
+ return ok;
+}
+
+bool CameraResources::acquire(const Mode& mode) {
+ bool ok = false;
+
+ QMetaObject::invokeMethod(m_worker, "acquire", Qt::BlockingQueuedConnection,
+ Q_ARG(bool *, &ok), Q_ARG(CameraResources::Mode, mode));
+
+ return ok;
+}
+
+bool CameraResources::acquired() const {
+ bool ok = false;
+
+ QMetaObject::invokeMethod(m_worker, "acquired", Qt::BlockingQueuedConnection,
+ Q_ARG(bool *, &ok));
+
+ return ok;
+}
+
+bool CameraResources::hijacked() const {
+ bool ok = false;
+
+ QMetaObject::invokeMethod(m_worker, "hijacked", Qt::BlockingQueuedConnection,
+ Q_ARG(bool *, &ok));
+
+ return ok;
+}
+
+bool CameraResources::isScaleAcquired() const {
+ return isResourceGranted(ResourcePolicy::ScaleButtonType);
+}
+
+CameraResourcesWorker::CameraResourcesWorker(QObject *parent) :
+ QObject(parent),
+ m_set(0),
+ m_mode(CameraResources::None),
+ m_acquired(false),
+ m_acquiring(false),
+ m_hijacked(false) {
+
+}
+
+CameraResourcesWorker::~CameraResourcesWorker() {
+
+}
+
+void CameraResourcesWorker::init() {
+ m_set = new ResourcePolicy::ResourceSet(APPLICATION_CLASS, this);
+ m_set->setAlwaysReply();
QObject::connect(m_set, SIGNAL(resourcesReleased()), this, SLOT(resourcesReleased()));
QObject::connect(m_set, SIGNAL(lostResources()), this, SLOT(lostResources()));
QObject::connect(m_set, SIGNAL(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)),
this, SLOT(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)));
- QObject::connect(m_set, SIGNAL(updateOK()), this, SLOT(updateOK()));
+ QObject::connect(m_set, SIGNAL(resourcesDenied()), this, SLOT(resourcesDenied()));
if (!m_set->initAndConnect()) {
qCritical() << "Failed to connect to resource policy engine";
}
}
-CameraResources::~CameraResources() {
- acquire(None);
+void CameraResourcesWorker::resourcesReleased() {
+ setHijacked(false);
+ setAcquired(false);
+
+ m_acquiring = false;
+}
+
+void CameraResourcesWorker::lostResources() {
+ setAcquired(false);
+ setHijacked(true);
+
+ m_acquiring = false;
+}
+
+void CameraResourcesWorker::resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional) {
+ Q_UNUSED(optional);
+
+ if (!m_acquiring) {
+ // This can happen when:
+ // 1) We lose/gain optional resources.
+ // 2) A higher priority application releases resources back.
+ emit updated();
+ }
+
+ m_acquiring = false;
+
+ setAcquired(true);
+ setHijacked(false);
+}
+
+void CameraResourcesWorker::resourcesDenied() {
+ setAcquired(false);
+ setHijacked(true);
+
+ m_acquiring = false;
}
-void CameraResources::acquire(const CameraResources::Mode& mode) {
+QList<ResourcePolicy::ResourceType> CameraResourcesWorker::listSet() {
+ QList<ResourcePolicy::Resource *> resources = m_set->resources();
+
+ QList<ResourcePolicy::ResourceType> set;
+
+ foreach (ResourcePolicy::Resource *r, resources) {
+ set << r->type();
+ }
+
+ return set;
+}
+
+void CameraResourcesWorker::acquire(bool *ok, const CameraResources::Mode& mode) {
if (mode == m_mode) {
- // We need to emit this because the UI migh be waiting
- emit acquiredChanged();
+ *ok = true;
return;
}
m_mode = mode;
+ *ok = false;
+
switch (m_mode) {
- case None:
- m_set->release();
+ case CameraResources::None:
+ *ok = release();
break;
- case Image:
- updateSet(QList<ResourcePolicy::ResourceType>()
- << ResourcePolicy::VideoPlaybackType
- << ResourcePolicy::VideoRecorderType
- << ResourcePolicy::ScaleButtonType
- << ResourcePolicy::SnapButtonType);
+ case CameraResources::Image:
+ *ok = updateSet(QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::VideoPlaybackType
+ << ResourcePolicy::VideoRecorderType,
+ QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::ScaleButtonType);
break;
- case Video:
- updateSet(QList<ResourcePolicy::ResourceType>()
- << ResourcePolicy::VideoPlaybackType
- << ResourcePolicy::VideoRecorderType
- << ResourcePolicy::ScaleButtonType
- << ResourcePolicy::SnapButtonType);
+ case CameraResources::Video:
+ *ok = updateSet(QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::VideoPlaybackType
+ << ResourcePolicy::VideoRecorderType,
+ QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::ScaleButtonType);
break;
- case Recording:
- updateSet(QList<ResourcePolicy::ResourceType>()
- << ResourcePolicy::VideoPlaybackType
- << ResourcePolicy::VideoRecorderType
- << ResourcePolicy::ScaleButtonType
- << ResourcePolicy::SnapButtonType
- << ResourcePolicy::AudioRecorderType,
- QList<ResourcePolicy::ResourceType>()
- << ResourcePolicy::AudioPlaybackType);
+ case CameraResources::Recording:
+ *ok = updateSet(QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::VideoPlaybackType
+ << ResourcePolicy::VideoRecorderType,
+ QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::ScaleButtonType
+ << ResourcePolicy::AudioRecorderType
+ << ResourcePolicy::AudioPlaybackType);
break;
- case PostCapture:
- updateSet(QList<ResourcePolicy::ResourceType>()
- << ResourcePolicy::VideoPlaybackType
- << ResourcePolicy::ScaleButtonType,
- QList<ResourcePolicy::ResourceType>()
- << ResourcePolicy::AudioPlaybackType);
-
+ case CameraResources::Player:
+ *ok = updateSet(QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::VideoPlaybackType
+ << ResourcePolicy::AudioPlaybackType,
+ QList<ResourcePolicy::ResourceType>()
+ << ResourcePolicy::ScaleButtonType);
break;
default:
qWarning() << "Unknown mode" << mode;
- break;
+ *ok = false;
}
}
-bool CameraResources::acquired() const {
- return m_acquired;
+void CameraResourcesWorker::acquired(bool *ok) {
+ *ok = m_acquired;
}
-void CameraResources::resourcesReleased() {
- m_mode = None;
- m_acquired = false;
- emit acquiredChanged();
+void CameraResourcesWorker::hijacked(bool *ok) {
+ *ok = m_hijacked;
}
-void CameraResources::lostResources() {
- m_mode = None;
- m_acquired = false;
- emit acquiredChanged();
-}
+bool CameraResourcesWorker::updateSet(const QList<ResourcePolicy::ResourceType>& required,
+ const QList<ResourcePolicy::ResourceType>& optional) {
-void CameraResources::resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional) {
- Q_UNUSED(optional);
- m_acquired = true;
- emit acquiredChanged();
-}
+ QList<ResourcePolicy::ResourceType> set = listSet();
-void CameraResources::updateOK() {
- m_acquired = true;
- emit acquiredChanged();
-}
+ foreach (ResourcePolicy::ResourceType r, set) {
+ if (required.indexOf(r) != -1) {
+ m_set->resource(r)->setOptional(false);
+ }
+ else if (optional.indexOf(r) != -1) {
+ m_set->resource(r)->setOptional(true);
+ }
+ else {
+ m_set->deleteResource(r);
+ }
+ }
-QList<ResourcePolicy::ResourceType> CameraResources::listSet() {
- QList<Resource *> resources = m_set->resources();
- QList<ResourcePolicy::ResourceType> set;
+ foreach (ResourcePolicy::ResourceType r, required) {
+ m_set->addResource(r);
+ }
- foreach (Resource *r, resources) {
- set << r->type();
+ foreach (ResourcePolicy::ResourceType r, optional) {
+ m_set->addResource(r);
+ ResourcePolicy::Resource *res = m_set->resource(r);
+ if (res) {
+ res->setOptional(true);
+ }
}
- return set;
-}
+ if (m_set->contains(ResourcePolicy::AudioPlaybackType)) {
+ bool isOptional = m_set->resource(ResourcePolicy::AudioPlaybackType)->isOptional();
-void CameraResources::updateSet(const QList<ResourcePolicy::ResourceType>& required,
- const QList<ResourcePolicy::ResourceType>& optional) {
+ ResourcePolicy::AudioResource *audio = new ResourcePolicy::AudioResource(APPLICATION_CLASS);
+ audio->setProcessID(QCoreApplication::applicationPid());
+ audio->setStreamTag("media.name", "*");
+ audio->setOptional(isOptional);
+ m_set->addResourceObject(audio);
+ }
- bool isEmpty = m_set->resources().isEmpty();
+ m_acquiring = true;
- QList<ResourcePolicy::ResourceType> set = listSet();
+ m_set->update();
+ m_set->acquire();
- foreach (ResourceType r, set) {
- // Check for acquired resources that should be dropped.
- if (required.indexOf(r) == -1) {
- m_set->deleteResource(r);
- }
+ while (m_acquiring) {
+ QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
- foreach (ResourceType r, required) {
- // TODO: AudioPlayback needs special handling
- m_set->addResource(r);
+ return m_acquired;
+}
+
+bool CameraResourcesWorker::release() {
+ m_acquiring = true;
+
+ m_set->release();
+
+ while (m_acquiring) {
+ QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
- // TODO: optional resources
+ m_mode = CameraResources::None;
- // Odd. If we don't do it that way then policy ignores our requests
- // when we get minimized then maximized.
- if (isEmpty) {
- m_set->update();
+ return true;
+}
+
+void CameraResourcesWorker::setAcquired(bool acquired) {
+ if (m_acquired != acquired) {
+ m_acquired = acquired;
+ emit acquiredChanged();
}
- else {
- m_set->acquire();
+}
+
+void CameraResourcesWorker::setHijacked(bool hijacked) {
+ if (m_hijacked != hijacked) {
+ m_hijacked = hijacked;
+ emit hijackedChanged();
+ }
+}
+
+void CameraResourcesWorker::isResourceGranted(bool *ok, int resource) {
+
+ ResourcePolicy::ResourceType rt = (ResourcePolicy::ResourceType)resource;
+
+ ResourcePolicy::Resource *r = m_set->resource(rt);
+ if (r) {
+ *ok = r->isGranted();
}
}